PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Rechenzeitbedarf beim Zahlenausgabe



oberallgeier
14.09.2013, 19:02
Das hatte mich nun doch überrascht. Bei einem Testaufbau hatte ich schnell eine Dummyausgabe geschrieben, die mir in Abständen etwas über UART aufs Terminal ausgibt. Der Code im Hauptprogrammabschnitt als Auszug und dazu die Subroutine für die Zahlenausgabe:


/ - - - - - - - - - - - - - - -
...
if ( Isec_lk2 == sd ) // Testweise Zeitanzeige und Wobbeln der irLED
{ //
Isec_lk2 = 0; //
uputs0 ("\r\tBoardzeit [sek]\t"); //
uputs0u ( Isecundn ); //
uputs0 ("\ttupsi = "); //
uputs0u ( Izeit_1 ); //
if ( Isecundn == 60 ) sd = 60; // Ab hier Anzeige alle Minuten
if ( Isecundn == 10 ) IRLEDset(275); //
if ( Isecundn == 20 ) IRLEDset( 10);
if ( Isecundn == 30 ) IRLEDset(127);
if ( Isecundn == 300 ) sd = 300; // Ab hier Anzeige alle fünf Minuten
} // Ende if
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// ================================================== ============================ =
// ================================================== ============================ =
// Hilfsfunktion, um Zahlen über das UART auszugeben
void uputs0u (uint16_t val) // Zahlen unsigned_Int_16 über UART0 ausgeben
{
char buffer[8];
uputs0 ( utoa(val, buffer, 10) );
}
// ================================================== ============================ =
// ================================================== ============================ =

Und siehe da, der Controller braucht für eine Zehnerpotenz mehr gleich etliche Mikrosekunden mehr. Zur Zeitberechnung: mega168/20MHz, ein tupsi ist eine Zeitscheibe (des internen heart beat) von 50 µs - - also tausend Maschinenzyklen!! Und wenn ich eine Zehnerpotenz mehr über UART ausgeben möchte, rechnet der Ärmste gleich drei von diesen Zeitscheibchen länger . . . das hätte ich nicht gedacht:


Boardtimer on
C506x00 CiCo m168/babyo/20MHz 14. Sep 2013 18:20
CIR-Controller, irLED auf PB1
UART (PD) mit 57 k Boardzeit [sek] 10 tupsi = 19958
Boardzeit [sek] 20 tupsi = 19958
Boardzeit [sek] 30 tupsi = 19958
Boardzeit [sek] 40 tupsi = 19958
Boardzeit [sek] 50 tupsi = 19958
Boardzeit [sek] 60 tupsi = 19958
Boardzeit [sek] 120 tupsi = 19954
Boardzeit [sek] 180 tupsi = 19954
Boardzeit [sek] 240 tupsi = 19954
Boardzeit [sek] 300 tupsi = 19954
Boardzeit [sek] 600 tupsi = 19954
Boardzeit [sek] 900 tupsi = 19954
Boardzeit [sek] 1200 tupsi = 19951
Boardzeit [sek] 1500 tupsi = 19951
Boardzeit [sek] 1800 tupsi = 19951
Boardzeit [sek] 2100 tupsi = 19951
Boardzeit [sek] 2400 tupsi = 19951
Boardzeit [sek] 2700 tupsi = 19951
Boardzeit [sek] 3000 tupsi = 19951
Boardzeit [sek] 3300 tupsi = 19951
Boardzeit [sek] 3600 tupsi = 19951
Boardzeit [sek] 3900 tupsi = 19951

Klebwax
15.09.2013, 07:26
@oberallgeier

Wenn ich dich richtig verstehe, geht es um diese Zeile:

uputs0 ( utoa(val, buffer, 10) );

Da verbrauchen zwei Funktionen Zeit: utoa() und uputs0(). Versuch die Zeiten mal zu messen. Mal so als Pseudocode:

setportbit();
utoa(val, buffer, 10);
clearportbit();
uputs0(buffer);

Wenn man das Portbit auf dem Scope ansieht, kann man die "utoa-Zeit" messen, die "uputs0-Zeit" kann man an der TX-Leitung der seriellen ansehen.

MfG Klebwax

malthy
15.09.2013, 09:37
Hey,

habe mich jetzt nicht weiter gedanklich vertieft, aber kann es sein, dass hier die Zeit zum Tragen kommt, die das eigentliche Senden hardwaremäßig benötigt? Bei 57 kbaud solltest du etwa 1/(57000 kbaud/9 bit) = 1.58e-4 s/byte = 158 µs/byte benötigen - solange dauert das serielle(!) Senden auf dem UART. Also will sagen, bis das nächste Byte verschickt werden kann, dauert es unter allen Umständen ca. 160 µs (wenn ich mich nicht verrechnet habe). Kann aber natürlich auch sein, dass ich das Problem falsch verstanden habe ... :-)

Gruß
Malte

oberallgeier
15.09.2013, 18:58
... Versuch die Zeiten mal zu messen. Mal so als Pseudocode: ...Danke für den Tip, ich habe manchmal so meine Schwierigkeiten mit dem Messen von Zeiten - mit nem simplen, analogen Oskar - ohne Speicher, nicht triggerbar auf ein bestimmtes Vorkommnis - da bleibt mir halt in einigen Fällen nur das Messen wie hier gezeigt. Und das reicht doch ... siehe unten.


... kann es sein, dass hier die Zeit ... die das eigentliche Senden hardwaremäßig benötigt ...Ja, so sehe ich das auch - und das ist ja das Erschreckende. Gefühlt ist so eine kleine Meldung schnell draussen. Da ich demnächst Daten per UART von einem Controller an den anderen senden will, sollte ich mal etwas genauer hinsehen - hat sich ja auch gelohnt (denn die Nachrechnerei hatte nicht so mit den Messwerten zusammengepasst). Gelohnt? Ich habe den RX- und den TX-Puffer zum FIFO von 16 auf 240 gesetzt - und siehe da - es geht schon recht ratzfatzer als vorher *ggg*.

Erste Messung: RX- und TX-Puffer sind 16 Bytes
Zeite Messung: Kleinere Byteanzahl (Text in Kurzform)
Dritte Messung: RX- und TX-Puffer sind 240 Bytes und Text wieder in Langform wie 1.

Boardtimer on
C506x00 CiCo m168/babyo/20MHz 14. Sep 2013 19:55
CIR-Controller, irLED auf PB1
UART (PD) mit 57 k Boardzeit [sek] 10 tupsi = 19958
Boardzeit [sek] 20 tupsi = 19958
Boardzeit [sek] 30 tupsi = 19958
Boardzeit [sek] 40 tupsi = 19958
Boardzeit [sek] 50 tupsi = 19958
Boardzeit [sek] 60 tupsi = 19958
Boardzeit [sek] 120 tupsi = 19954

Boardtimer on
C506x00 CiCo m168/babyo/20MHz 15. Sep 2013 19:10
CIR-Controller, irLED auf PB1
UART (PD) mit 57 k
B 10 t 19999
B 20 t 19999
B 30 t 19999
B 40 t 19999
B 50 t 19999
B 60 t 19999
B 120 t 19999
B 180 t 19999
B 240 t 19999
B 300 t 19999

Boardtimer on
C506x00 CiCo m168/babyo/20MHz 15. Sep 2013 19:40
CIR-Controller, irLED auf PB1
UART (PD) mit 57 k RX/TX-Puffer 240
Boardzeit [sek] 10 tupsi = 19998
Boardzeit [sek] 20 tupsi = 19998
Boardzeit [sek] 30 tupsi = 19998
Boardzeit [sek] 40 tupsi = 19998
Boardzeit [sek] 50 tupsi = 19998
Boardzeit [sek] 60 tupsi = 19998
Boardzeit [sek] 120 tupsi = 19998
Boardzeit [sek] 180 tupsi = 19998
Boardzeit [sek] 240 tupsi = 19998
Boardzeit [sek] 300 tupsi = 19998
Boardzeit [sek] 600 tupsi = 19998

Kleine Erläuterung zur Messzeit in "tupsi". Mein Heartbeat wird über meinen üblichen 50µs-Timer getoggelt - alle Sekunden einmal toggeln. Der 50µs-Timer ist für viele Zwecke praktisch, es gibt für bestimmte Auslöser auch lokale Counter, hier der "Isec_lk2", der mit dem Heartbeat-Toggle und der Zählung der Boardzeitsekunde hochgetickert wird. Die Ausgabe im Test, siehe erstes Posting, erfolgt, sobald der Isec_lk2 den abgefragten Wert erreicht hat - dieses Umschalten geschieht genau dann, wenn der 50-µs-Counter Izeit_1 von 0 auf 20000 gesetzt wird. Die Messzeiten sind also von 20000 abwärts zu werten.

Manchmal lohnt sich das Nachgucken, -denken, -fragen, -posten ...
Jedenfalls danke euch Beiden für die Denkanstöße. Schönen Sonntag

malthy
15.09.2013, 19:30
Ja, so sehe ich das auch - und das ist ja das Erschreckende.

Naja, "erschreckend" ist vielleicht übertrieben, denn was den eigentlichen Sendevorgang angeht, ist "57000 baud" und "158 µs/byte" ja gleichbedeutend (bei 8 Datenbits/ 1 Stoppbit) - und in dem Sinne zu erwarten. Ich wollte auch nur den Unterschied machen zwischen "solange dauert das Senden" und "solange ist die CPU blockiert". Letzteres ist nämlich m. M. n. eben nicht der Fall, der UART kümmert sich ja um Verschicken, in der Zeit kann man ja gut was anderes machen.

Gruß
Malte

Klebwax
15.09.2013, 22:51
Danke für den Tip, ich habe manchmal so meine Schwierigkeiten mit dem Messen von Zeiten - mit nem simplen, analogen Oskar - ohne Speicher, nicht triggerbar auf ein bestimmtes Vorkommnis - da bleibt mir halt in einigen Fällen nur das Messen wie hier gezeigt.

Da gibts ein paar Möglichkeiten. Wenn das, was man messen will wiederholt vorkommt, kann man es auch auf einem analogen Scope darstellen. Wenn es sich schlecht triggern läßt, kann man ein Triggersignal auf einem freien Portpin programmieren und das auf den zweiten Scopekanal (oder falls vorhanden auf den externen Trigger) geben und damit triggern.

Ist das Ereignis nicht periodisch genug, hab ich ab und an schon mal zum Messen das Program umgeschrieben.

Inzwischen benutze ich dafür eigentlich immer den saleae.


Ja, so sehe ich das auch - und das ist ja das Erschreckende. Gefühlt ist so eine kleine Meldung schnell draussen.

Schnittstellen, insbesondere die asynchrone serielle, sind schon eine ziemliche Bremse. Sie können das Echtzeitverhalten eines Systems empfindlich stören. Ich benutze die serielle daher sehr selten. Leider ist der UART via USB die einfachste Schnittstelle und daher das Mittel der Wahl zum Datenaustausch. Ethernet wäre wesentlich besser, ist aber leider aufwendig auf einem µC und hat seine eigenen Zeitanforderungen. SPI mit einigen 10MHz wäre ganz gut, kann aber ein PC nicht wirklich.

Ein größerer Buffer oder ein UART mit FIFO sind schon mal gut, aber wenn mehr Daten gesendet werden sollen, als Zeit vorhanden ist, hilft auch kein größerer Buffer. Was bleibt, ist die serielle gezielt und sparsam einsetzen.

Ein LCD, am besten im 8 Bit Mode an einem kompletten Port, ist auch hilreich. Man darf dann nur nicht auf die gängigen Ratschläge hören und den Code mit Delays vollpflastern, sondern geschickt das Ready-Signal auswerten. Dann kann man ein Zeichen so in 2 µs ausgeben. Da kann man dann schon im PWM Interrupt den PWM-Wert Live ausgeben.

Wenn man die Leistung moderner µCs wirklich ausnuzt, ist eine Datenausgabe schon problematisch. Leider

MfG Klebwax

malthy
15.09.2013, 22:59
Schnittstellen, insbesondere die asynchrone serielle, sind schon eine ziemliche Bremse.

Naja, in welchem Sinne? Klar, bei einer gegebenen Übertragungsrate kann man eben nur eine dementsprechende Datenmenge drüberblasen. Aber das ist doch völlig deterministisch, oder? Und das reine Schreiben in das UART Register geht ja dann wieder recht schnell, das meinte ich oben, als ich schrieb, dass man während des Sendens dann ja durchaus wieder andere Dinge tun kann. Oder übersehe ich etwas?

Gruß
Malte

oberallgeier
15.09.2013, 23:19
... ist die CPU blockiert" ... eben nicht der Fall, der UART kümmert sich ... in der Zeit kann man ...Genauso dachte (hoffte) ich eben auch. Daher meine Verwunderung (ok, "Erschrecken" wars nicht) über den Zeitbedarf von schlappen 46 tupsi, siehe mein erstes Posting, Boardzeit 300 s. In üblichen Zeitenheiten also 46 x 50 µs, das sind 2300 µs. Verschickt wurden dabei 37 Byte (incl. Zeilenvorschüben und Tabs), das macht bei meinen 57600 Bd und 9 Bit/Byte rund 156 µs/Byte 5,78 ms oder 115 tupsi. Benötigt hatte ich aber nur 46 - also ist könnte doch alles in Butter und ich zufrieden sein ! ?

Neee, denn das genaue Hinsehen hatte sich gelohnt, hatte mich zu einer Vergrößerung der Puffer überredet, die vergrößerten Puffer haben dazu geführt, dass nur rund 100 µs (2 tupsi) benötigt wurden für theoretisch 5,8 ms Sendezeit des UART (- also genau Deine Rede malthy!). Und da steckt dann tatsächlich die Arbeit des Hardware-UART - der ja im Hintergrund rödelt. Wenn man ihm nur genug Puffer zuweist, sogar sehr effektiv.

Wobei ich ja ziemlich sicher bin (könnte fast sagen ich wüsste es) dass die Zeitangabe de fakto geschönt ist - der Controller ist im Programm weitergegangen, weil er ja in dieser Zeit die Bytes schon/nur in den Puffer geschrieben hatte - damit der UART sie danach gemächlich über den Draht schicken kann, während er - der Controller, weiter arbeitet.

Klebwax
17.09.2013, 02:47
Naja, in welchem Sinne? Klar, bei einer gegebenen Übertragungsrate kann man eben nur eine dementsprechende Datenmenge drüberblasen. Aber das ist doch völlig deterministisch, oder? Und das reine Schreiben in das UART Register geht ja dann wieder recht schnell, das meinte ich oben, als ich schrieb, dass man während des Sendens dann ja durchaus wieder andere Dinge tun kann. Oder übersehe ich etwas?

Das reine Laden eines Registers ist schnell, das Warten, bis das Register wieder frei ist, eine andere Sache.

Was ich aber meinte ist, daß leicht viel mehr Daten entstehen als die serielle transportieren kann. So ein ADC liefert schon mal 10k bis 100k Daten pro Sekunde, andere Sensoren leicht ebensoviel. Jetzt mal eine komplexe Rechnung, Sensorfusion oder Filterung durch ein paar serielle Ausgaben live zu Debuggen oder Darzustellen kann leicht dazu führen, daß das Zeitverhalten mehr von der seriellen Schnittstelle als von den Sensoren abhängt.

Wenn man jetzt vom PC gewöhnt ist, daß so ein paar printf() mit einigen 10kB oder auch MB (auch mal in eine Datei umgeleitet) ohne ein paar PWMs oder Schrittmotoren im Hintergrund und mit einigen Gigabyte als Speicher kein Problem sind, kann einen das schon "Erschrecken".

MfG Klebwax

Peter(TOO)
17.09.2013, 03:06
Naja, "erschreckend" ist vielleicht übertrieben, denn was den eigentlichen Sendevorgang angeht, ist "57000 baud" und "158 µs/byte" ja gleichbedeutend (bei 8 Datenbits/ 1 Stoppbit) - und in dem Sinne zu erwarten.

Die Rechnung stimmt so gar nicht.
Du hast ein Startbit, die Daten und das Stoppbit.
Bei 8-Bit Daten sind das dann mindestens 10 Bitzellen, ergibt dann etwa 175µs.
Dann könnte man noch das Parity-Bit zuschalten und das Stoppbit, kann1, 1.5 oder 2 Bit-Zellen lang sein.
Im Extremfall kommt man dann auf 1+8+1+2 = 12 Bitzellen.
Die längeren Stoppbits waren eigentlich dafür gedacht, dem Empfänger etwas mehr Zeit zum Abholen und Auswerten des gerade Empfangenen Bytes zu geben. Sonst haben sie technisch keine Bedeutung.
Die Verwendung von 5 Datenbits stammt noch vom Telex. So vor 35 Jahren wurden Telexe als TTY oft als Terminal für Computer verwendet.
7 Datenbits war die Norm für den alten ASCII-Code, welcher nur 7 Bits benutzte, dass es auch noch Umlaute und andere Sonderzeichen gibt, wussten die AMIs lange Zeit nicht :-(

MfG Peter(TOO)

malthy
17.09.2013, 08:55
@Peter(TOO): Ja hast Recht, hab das Startbit nicht mitgerechnet. Die anderen Bits verwenden die meisten Leute meines Wissens nicht, aber full ack, das Datenpaket ist u. U. noch länger. Mir ging's ja auch nur darum zu Überlegen, wo die Zeit bleibt.

@Klebwax: ja, stimme Dir natürlich zu. Im Verhältnis zu Datenraten, die man auf einem mC erzeugen kann, ist der UART recht lahm. Wobei man mit UART2USB-Bridge natürlich schon relativ hohe Baudraten hinbekommt. Da ist dann eher das Problem, dass USB so ein billig-Bus ist und das Timing schlecht ist. Aber wie gesagt, wollte nur darauf raus, dass man nicht geduldig auf den Sendevorgang warten muss :-).

Gruß
Malte