Forum: Mikrocontroller und Digitale Elektronik Fleury´s Ringbuffer- fehlt da was?


von Stephan (Gast)


Lesenswert?

Hallo!

Die Funktion der Ringbuffer von Fleury hab ich verstanden.
Doch an welcher Stelle kommt sinnvollerweise die Abfrage, ob der Buffer 
gefüllt ist? Und müsste nicht in die Rx-ISR eine Abfrage, ob das 
String-Ende-anzeigende-Zeichen empfangen wurde?

Zur Info:

ISR(UART1_RECEIVE_INTERRUPT)
{
    unsigned char tmphead;
    unsigned char data;
    unsigned char usr;
    unsigned char lastRxError;

    usr  = UART1_STATUS;
    data = UART1_DATA;
    lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) );
    tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK;    /* calculate 
buffer index */
    if ( tmphead == UART1_RxTail ) {
        lastRxError = UART_BUFFER_OVERFLOW >> 8;        /* error: 
receive buffer overflow */
    }
  else
  {
        UART1_RxHead = tmphead;        /* store new index */
        UART1_RxBuf[tmphead] = data;        /* store received data in 
buffer */
    }
    UART1_LastRxError = lastRxError;
}

von Tom M. (tomm) Benutzerseite


Lesenswert?

Stephan schrieb:
> Doch an welcher Stelle kommt sinnvollerweise die Abfrage, ob der Buffer
> gefüllt ist?

Die Stelle ist hier:
1
  tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK;    /* calculate buffer index */
2
  if ( tmphead == UART1_RxTail )

Stephan schrieb:
> Und müsste nicht in die Rx-ISR eine Abfrage, ob das
> String-Ende-anzeigende-Zeichen empfangen wurde?

Wozu? Das interessiert die Empfangsroutine überhaupt nicht.

von Stephan (Gast)


Lesenswert?

Moment.. wodurch erfährt die Welt ausserhalb der ISR, dass etwas zum 
Auslesen vorhanden ist?

von Tom M. (tomm) Benutzerseite


Lesenswert?

Dadurch:
1
        UART1_RxHead = tmphead;        /* store new index */

von Stephan (Gast)


Lesenswert?

D.h., durch ständiges Gucken, ob sich DIE Variable verändert hat?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ja, so ist es.
Wobei ein FIFO erst dann wirklich Sinn macht, wenn man eben nicht 
dauernd nachsehen kann, ob was da ist. Sondern nur ab und zu mal...

von Stephan (Gast)


Lesenswert?

Aber wie groß ist die Pause zwischen "ab und zu"? Wenn ich an anderer 
Stelle im Programm eine *duck, räusper* Totzeit habe, zB 10ms für die 
Wandlung eines ADC-Wertes, denn ist der Buffer ungünstigstenfalls 
ratzfatz übervoll?! Schickt es sich, die Abfrage von einem Timer zu 
"pollen"?

von Karl H. (kbuchegg)


Lesenswert?

Stephan schrieb:
> Aber wie groß ist die Pause zwischen "ab und zu"?

Das kommt drauf an, wie viel der Sender in einem Rutsch sendet, wie groß 
der Buffer ist, mit welcher Baudrate gesendet wird und was das restliche 
Programm sonst noch so zu tun hat.

> Wenn ich an anderer
> Stelle im Programm eine *duck, räusper* Totzeit habe, zB 10ms für die
> Wandlung eines ADC-Wertes, denn ist der Buffer ungünstigstenfalls
> ratzfatz übervoll?!

Na ja.
Ein ADC Wert dauert keine 10ms. Und bei einer moderaten Baudrate lassen 
sich in 10ms auch nicht so wahnsinnig viele Zeichen übertragen. 10ms 
sind für einen mit 1Mhz getakteten µC schon eine sehr lange Zeit. In 
dieser zeit kann er immerhin rund 9000 Instruktionen ausführen. Bei 
10Mhz Taktfrequenz sinds schon ca 90tausend Instruktionen. Das reicht 
dann auch noch für einen Kaffeplausch zwischendurch :-)

> Schickt es sich, die Abfrage von einem Timer zu
> "pollen"?

Und was machst du dann mit den gepollten Zeichen?
richtig. du wirst sie irgendwo zwischenspeichern.
Da kannst du auch gleich den Bufferspeicher im Ringbuffer erhöhen.


Die Funktion des Ringbuffers an dieser Stelle ist es, dem restlichen 
Programm ein wenig Zeit zu verschaffen, so dass eine mal etwas längere 
Programmausführung ohne Nachsehen an den UART Routinen ob was da ist, 
nicht gleich zum Verlust von Zeichen führt. Das diese Zeit nicht endlos 
ausgedehnt werden kann, ist auch klar. Denn irgendwo müssen die Zeichen 
zwischendurch geparkt werden - und irgendwann ist jeder Speicher voll. 
Dann bleibt nur noch ein Handshake nachzurüsten und dem Sender die 
Redeerlaubnis zu entziehen oder das Problem mit einem Protokoll zu 
regeln.

Was denkst du eigentlich, warum hier immer alle aufheulen, wenn jemand 
ein Programm präsentiert, in dem es an allen Ecken und Enden nur so von 
_delay_ms wimmelt? Es ist nun mal der falsche Weg, wenn man ein Programm 
schreibt, welches 'scheinbar' mehrere Dinge gleichzeitig überwacht 
und/oder ausführt.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Abgesehen davon, dass 10ms wirklich ne große Totzeit sind:
Bei 38400Baud haste in 10ms 38 Zeichen Empfangen, machste den Buffer 
also 64 groß.
UART ist kein D-Zug ;)

von Harald M. (mare_crisium)


Lesenswert?

Stephan,

der admin hat Dir erklärt, wie man die Überlaufgefahr entschärfen kann. 
Die Abfrage, ob im Ringpuffer Daten auf die Verwertung warten, plaziert 
man üblicherweise in die Hauptschleife des Hauptprogramms. Dort kommt 
der MC immer nur dann vorbei, wenn er gerade nix anderes zu tun hat.

ABER: Es kann passieren, dass dann schon mehr als eine Botschaft im 
Ringpuffer steht. Das "Verwertungsprogramm" kann das nicht erkennen und 
behandelt die Botschaften, als wäre es eine einzige.

Wenn das zu Problem führt, dann kann man z.B. folgendes machen: Man baut 
einen zweiten Ringpuffer ein, in dem man von jeder eingehenden Botschaft 
die Länge speichert. Das "Verwertungsgprogramm" kann dort nachgucken, 
wieviele Botschaften im Empfangs-Ringpuffer stehen, wie lang jede 
einzelne von ihnen ist und kann dann immer nur so viele Bytes aus dem 
Empfangspuffer verwerten, wie es der Länge der Botschaft entspricht.

Das ist natürlich nicht die einzige Lösungsmöglichkeit; man kann auch 
an jede Botschaft einen NUL-Character anhängen, um das Ende zu 
markieren. Nur darf das NUL-Zeichen dann nicht als Datenbyte in der 
Botschaft vorkommen. Das kann man nur dadurch sicher vermeiden, dass man 
jedes Datenbyte als zwei Hex-Characters übermittelt.

Man muss eben immer betrachten, welche Möglichkeit mit allen Vor- und 
Nachteilen am besten zum Programm passt. Die Lösung mit dem zweiten 
Ringpuffer hat sich in meinen Programmen sehr bewährt.

Ciao,

mare_crisium

von Peter D. (peda)


Lesenswert?

Der UART-FIFO speichert einfach nur. Er wertet kein Protokoll aus. Es 
könnte ja sein, daß ein Block Binärdaten übertragen wird.

Das Main holt sich dann jedes Byte ab in einen Paketpuffer und prüft auf 
das jeweilige Protokoll.

Der weitere Puffer ist notwendig, damit auf dem Paket geparst werden 
kann.
In der FIFO kann ja ein Paket genau auf dem Wrap Around liegen, dann 
kann man nicht mit strcmp(), atoi() usw. parsen.


Peter

von Patrick (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Der UART-FIFO speichert einfach nur. Er wertet kein Protokoll aus. Es
> könnte ja sein, daß ein Block Binärdaten übertragen wird.

Man könnte es natürlich noch ein wenig anders formulieren: Der 
Ringbuffer ist ein - wie der Name schon sagt und der TO auch richtig 
erkannt hat - Buffer, d. h. er speichert einfach nur zwischen. Von 
"Protokoll auswerten" hat niemand etwas gesagt...

von Fabian O. (xfr)


Lesenswert?

Harald M. schrieb:
> ABER: Es kann passieren, dass dann schon mehr als eine Botschaft im
> Ringpuffer steht. Das "Verwertungsprogramm" kann das nicht erkennen und
> behandelt die Botschaften, als wäre es eine einzige.
>
> Wenn das zu Problem führt, dann kann man z.B. folgendes machen: Man baut
> einen zweiten Ringpuffer ein, in dem man von jeder eingehenden Botschaft
> die Länge speichert.

Woher weiß denn das UART-Empfangsmodul die Länge der Botschaften, wenn 
das "Verwertungsprogramm" es nicht erkennen kann? Aus dem Timing?

von Harald M. (mare_crisium)


Lesenswert?

@Fabian,

damit hast Du allerdings recht. In meinen Programmen stelle ich die 
Botschaftslänge fest, indem ich in der Empfangsroutine die Charcters bis 
zum NUL-Zeichen zähle. Das ist tatsächlich "doppelt gemoppelt".

@peda,

nein, der TO erwähnt "Protokoll auswerten" nicht, aber seine Frage 
schien mir darauf hinauszulaufen. Sozusagen eine vorauseilende Erklärung 
;-).

Ciao,

mare_crisium

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.