www.mikrocontroller.net

Forum: Compiler & IDEs Problem mit UART-Interrupt


Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

habe ein Problem mit meiner UART-Receive-ISR (kein AVR!). Die ISR ist so 
aufgebaut, dass ich die Zeichen in einem Buffer ablege und wenn mein 
Ende-Zeichen '\r' erreicht ist, wird ein Flag gesetzt, was dann in der 
main-Funktion abgefragt wird. Falls es gesetzt ist, springt der 
Befehlshandler ein.

Wenn ich genug Zeit zwischen dem Senden der Befehle lasse, funktioniert 
alles bestens. Wenn ich allerdings zwei Befehle auf einmal sende, also 
z.B. die Befehle RT und SI mit Uart_Send ("RT\rSI\r"), dann werden nicht 
immer beide ausgeführt, der letzte scheint in mind. 50% der Fälle 
verloren zu gehen.

Ich dachte eigentlich, dass ich meine ISR so aufgebaut habe dass mehrere 
Befehle auf einmal eigentlich ordentlich umgesetzt werden sollten. Hier 
der (Pseudo-)Code (habe ihn aus dem Kopf aufgeschrieben und hoffentlich 
nichts vergessen):

volatile char cmdReceived=0;
 char tempBuffer[50]="";
char byteCount=0;
char cmdBuffer[50]="";

void UartReceiveHandler(void) {

  tempBuffer[byteCount++]=UartGetByte();
  if (tempBuffer[byteCount-1]=='\r') {
    cmdReceived=1;
    tempBuffer[byteCount]='\0';
  }

int main (void) {

  while(1) {
    if (cmdReceived){
      disable_interrupts();
      strcpy(cmdBuffer, tempBuffer);
      tempBuffer="";
      cmdReceived=0;
      byteCount=0;
      enable_interrupts();
      Befehlsbehandlung(cmdBuffer);
      cmdBuffer="";
    }
  }
}


Wo steckt also das Problem und wie kann ich es lösen? Wäre es sinnvoll, 
in der ISR einfach den kompletten UART-Fifo auszulesen und nicht nur ein 
Byte? Andere Interrupt-Quellen gibt es nicht.

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
if (tempBuffer[byteCount-1]=='\r') {
    cmdReceived=1;
    tempBuffer[byteCount]='\0';//<--
/* Musst du nicht hier auch byteCount erhoehen? 
*/
  }
Sonst wird die 0 doch mit dem nächsten empfangenen Byte überschrieben, 
oder?
Und wenn du den Puffer nicht als Rignpuffer auslegst, musst du 
wahrscheinlich den Interrupt sperren solange du den Puffer leerst 
(strcopy wird ja auch ein paar takte brauchen)

hth. --Jörg

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg X. wrote:

> Sonst wird die 0 doch mit dem nächsten empfangenen Byte überschrieben,
> oder?

Wenn die Hauptschleife nicht schnell genug mit der Abarbeitung
der Eingabe anfängt ( weil sie zb. noch in einer Befehlsabarbeitung
steckte), dann wird das sogar mit Sicherheit passieren.

> Und wenn du den Puffer nicht als Rignpuffer auslegst, musst du
> wahrscheinlich den Interrupt sperren solange du den Puffer leerst
> (strcopy wird ja auch ein paar takte brauchen)
>

Das hat er ja eigentlich in der main-Schleife gemacht.
Aber wie du richtig sagst, wird ja auch der strcpy ein
paar Takte brauchen.
Nehmen wir einfach mal an, die main-Schleife hat das gesetzt
cmdReceived entdeckt, während es sich anschickt die
Interrupts zu sperren, trudelt bereits das nächste Zeichen
ein (das 'S' aus dem OP-Beispiel). Da Interrupts gesperrt sind,
wird das 'S' nicht gleich abgeholt. Aber: Die Übertragung geht
ja weiter. Während zb. der strcpy abgearbeitet wird, kommt
schon das nächste Zeichen daher (das 'I'). Und wie man so
schön sagt: der Teufel schläft nicht, der Empfang dieses I
ist beendet, noch bevor die Interrupts wieder aktiviert
werden. Im Empmfangsregister des UART steht das 'I'. Aber
wo ist das 'S' hingekommen? Antwort: nirgends, es ist in der
UART überschrieben worden, weil die main-Schleife die Interrupts
zulange disabled hatte, so dass die Interrupt Routine keine Chance
hatte, das Zeichen abzuholen.


Um Festzustellen, was wirklich passiert, würde ich mich
mal an Grundregel #1 halten:
Überprüfe immer deinen Input. Im einfachsten Fall, gib den
Input zur Kontrolle immer gleich als Output aus. Auf diese
Art kannst du feststellen, was dein Programm wirklich gelesen
hast.
int main (void) {

  while(1) {
    if (cmdReceived){
      disable_interrupts();
      strcpy(cmdBuffer, tempBuffer);
      tempBuffer="";
      cmdReceived=0;
      byteCount=0;
      enable_interrupts();

      uart_Ausgabe( "\r\nHabe empfangen: " );
      uart_Ausgabe( cmdBuffer );

      Befehlsbehandlung(cmdBuffer);
      cmdBuffer="";
    }
  }
}

  

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Sonst wird die 0 doch mit dem nächsten empfangenen Byte überschrieben,
>> oder?

>Wenn die Hauptschleife nicht schnell genug mit der Abarbeitung
>der Eingabe anfängt ( weil sie zb. noch in einer Befehlsabarbeitung
>steckte), dann wird das sogar mit Sicherheit passieren.

Genau das soll ja passieren! Wenn zwei Befehle relativ schnell 
hintereinander eintreffen, soll die '\0' des ersten Befehles in 
tempBuffer überschrieben werden mit dem nächsten Zeichen, also dem 
ersten des zweiten Befehls. Dadurch bekommt man dann 
"Befehl1\rBefehl2\r" und damit kann der Befehlshandler dann umgehen und 
erkennt zwei Befehle.

>Nehmen wir einfach mal an, die main-Schleife hat das gesetzt
>cmdReceived entdeckt, während es sich anschickt die
>Interrupts zu sperren, trudelt bereits das nächste Zeichen
>ein (das 'S' aus dem OP-Beispiel). Da Interrupts gesperrt sind,
>wird das 'S' nicht gleich abgeholt. Aber: Die Übertragung geht
>ja weiter. Während zb. der strcpy abgearbeitet wird, kommt
>schon das nächste Zeichen daher (das 'I'). Und wie man so
>schön sagt: der Teufel schläft nicht, der Empfang dieses I
>ist beendet, noch bevor die Interrupts wieder aktiviert
>werden. Im Empmfangsregister des UART steht das 'I'. Aber
>wo ist das 'S' hingekommen? Antwort: nirgends, es ist in der
>UART überschrieben worden, weil die main-Schleife die Interrupts
>zulange disabled hatte, so dass die Interrupt Routine keine Chance
>hatte, das Zeichen abzuholen.

Der UART besitzt einen 16-Byte großen FIFO! Da darf doch dann gar nichts 
verloren gehen. Wenn das S und das I eintreffen, während die Interrupts 
disabled sind, werden sich doch wohl die zwei Interrupts gemerkt und 
dann nach sie wieder enabled sind zweimal die ISR aufgerufen, um zuerst 
S (First in First Out!) und danach das I zu empfangen. Wofür bräuchte 
die UART sonst einen FIFO-Puffer?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
>>> Sonst wird die 0 doch mit dem nächsten empfangenen Byte überschrieben,
>>> oder?
>
>>Wenn die Hauptschleife nicht schnell genug mit der Abarbeitung
>>der Eingabe anfängt ( weil sie zb. noch in einer Befehlsabarbeitung
>>steckte), dann wird das sogar mit Sicherheit passieren.
>
> Genau das soll ja passieren!

Nein. Das soll ja gerade nicht passieren

Situation:
  Dein Befehlshandeler läuft
  Jetzt kommt ein Zeichen: 'R'  Der Interrupthandler speichert es
  Der Befehlshandler läuft noch immer
  Das nächste Zeichen kommt: 'I'. Der Interrupthandler speichert es
  Der Befehlshandler läuft noch immer
  Das nächste Zeichen kommt: '\r'. Wird wieder gespeichert
  Der Befehlshandler ist immer noch nicht fertig
  Das nächste Zeichen kommt: 'S'. AUch das wird im I-Handler gespeichert

Frage: An welcher Stelle im Array wird dieses 'S' gespeichert, und wie
beeinflusst dieser Vorgang das "RI\n", welches schon gespeichert wurde,
welchen Zustand hat cmdReceived dann und ist der 'String', der im
Array gespeichert ist, überhaupt noch ein gültiger String?

Frag dich auch was passiert wenn genau in diesem Moment der
Befehlshandler fertig wird und anfängt mittels strcpy() den
String aus dem Buffer zu holen und ob dein Befehlshandler
in der Lage ist mit einem 'halben' Befehl, das 'I' für "SI"
wurde ja noch nicht empfangen, umzugehen.

Du hast dich hier selbst ausgetrickst!
Aber spiel das erst mal am Papier durch und frage dich obige Fragen.

>
>>Nehmen wir einfach mal an, die main-Schleife hat das gesetzt
>>cmdReceived entdeckt, während es sich anschickt die
>>Interrupts zu sperren, trudelt bereits das nächste Zeichen
>>ein (das 'S' aus dem OP-Beispiel). Da Interrupts gesperrt sind,
>>wird das 'S' nicht gleich abgeholt. Aber: Die Übertragung geht
>>ja weiter. Während zb. der strcpy abgearbeitet wird, kommt
>>schon das nächste Zeichen daher (das 'I'). Und wie man so
>>schön sagt: der Teufel schläft nicht, der Empfang dieses I
>>ist beendet, noch bevor die Interrupts wieder aktiviert
>>werden. Im Empmfangsregister des UART steht das 'I'. Aber
>>wo ist das 'S' hingekommen? Antwort: nirgends, es ist in der
>>UART überschrieben worden, weil die main-Schleife die Interrupts
>>zulange disabled hatte, so dass die Interrupt Routine keine Chance
>>hatte, das Zeichen abzuholen.
>
> Der UART besitzt einen 16-Byte großen FIFO!

OK. Das wusste ich ja nicht. Ich bin von einem Zeichen ausgegangen.
Frage: Wenn in dieser FIFO mehrere Zeichen zwischengespeichert sind,
wieviele Interrupt aufrufe bekommst du dann? (Musst du in der
Doku nachsehen)

> verloren gehen. Wenn das S und das I eintreffen, während die Interrupts
> disabled sind, werden sich doch wohl die zwei Interrupts gemerkt und
> dann nach sie wieder enabled sind zweimal die ISR aufgerufen, um zuerst
> S (First in First Out!) und danach das I zu empfangen. Wofür bräuchte
> die UART sonst einen FIFO-Puffer?

Die Existenz einer FIFO sagt noch lange nichts darüber aus, wieviele
Interrupts du bekommst. Hast du das überprüft?

Ansonsten: Ich stehe immer noch zu meiner Aussage, dass man bei
einem Empfang vno Zeichen in der Debug-Phase die empfangenen Zeichen
echot um zu sehen ob auch wirklich das empfangen wurde, was man
glaubt empfangen zu haben. Sehr oft unterscheidet sich das nämlich.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Situation:
>  Dein Befehlshandeler läuft
>  Jetzt kommt ein Zeichen: 'R'  Der Interrupthandler speichert es
>  Der Befehlshandler läuft noch immer
>  Das nächste Zeichen kommt: 'I'. Der Interrupthandler speichert es
>  Der Befehlshandler läuft noch immer
>  Das nächste Zeichen kommt: '\r'. Wird wieder gespeichert
>  Der Befehlshandler ist immer noch nicht fertig
>  Das nächste Zeichen kommt: 'S'. AUch das wird im I-Handler gespeichert
>
>Frage: An welcher Stelle im Array wird dieses 'S' gespeichert, und wie
>beeinflusst dieser Vorgang das "RI\n", welches schon gespeichert wurde,
>welchen Zustand hat cmdReceived dann und ist der 'String', der im
>Array gespeichert ist, überhaupt noch ein gültiger String?

Nachdem das \r-Zeichen (mein Ende-Zeichen) empfangen wurde, wird an die 
nächste Stelle im String ein String-Ende (\0) gesetzt. Das heißt, man 
hat nach dem ersten Befehl "RI\n\0" im Buffer stehen. Jetzt kommt das S 
und wird an die Stelle von \0 gespeichert. Da die Befehle ja in einer 
Anweisung gesendet wurden, kommt direkt danach auch noch das I (von SI) 
sowie das Ende-Zeichen \r. Wurde dieses empfangen, wird ein \0 angefügt. 
Danach steht im String RI\nSI\n\0 und somit ein String, mit dem der 
Befehlshandler umgehen kann.
cmdReceived ist, solange es nicht in dem interrupt-disabled-Teil auf 0 
gesetzt wurde, 1.

Oder meinst du den Fall, wenn der zweite Befehl noch nicht komplett 
übertragen und gespeichert wurde und in der main der Programmzähler 
grade zu der if-Abfrage von cmdReceived kommt? Dann könnte es allerdings 
zu einem Problem kommen, fällt mir grade auf...


>Die Existenz einer FIFO sagt noch lange nichts darüber aus, wieviele
>Interrupts du bekommst. Hast du das überprüft?

Das ist natürlich richtig.

Also ich fasse zusammen: Es könnte hier zwei Probleme geben: Einmal das 
oben beschriebene, dass der zweite Befehl noch nicht komplett empfangen 
ist, wenn das Programm die Interrupts disabled und deshalb nur den 
ersten Befehl erkennt.

Und zweitens könnten es quasi nur ein Interrupt-Flag geben, so dass 
selbst bei Ankunft mehrerer Zeichen die ISR nur einmal ausgeführt wird. 
Die einzige Lösung ist doch hier, gleich den kompletten FIFO auszulesen, 
oder?

>Ansonsten: Ich stehe immer noch zu meiner Aussage, dass man bei
>einem Empfang vno Zeichen in der Debug-Phase die empfangenen Zeichen
>echot um zu sehen ob auch wirklich das empfangen wurde, was man
>glaubt empfangen zu haben. Sehr oft unterscheidet sich das nämlich.

Ja du hast recht. Kann ich aber leider erst am Montag auf der Arbeit 
testen. Das Problem beschäftigt mich aber trotzdem jetzt schon.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
>>Situation:
>>  Dein Befehlshandeler läuft
>>  Jetzt kommt ein Zeichen: 'R'  Der Interrupthandler speichert es
>>  Der Befehlshandler läuft noch immer
>>  Das nächste Zeichen kommt: 'I'. Der Interrupthandler speichert es
>>  Der Befehlshandler läuft noch immer
>>  Das nächste Zeichen kommt: '\r'. Wird wieder gespeichert
>>  Der Befehlshandler ist immer noch nicht fertig
>>  Das nächste Zeichen kommt: 'S'. AUch das wird im I-Handler gespeichert
>>
>>Frage: An welcher Stelle im Array wird dieses 'S' gespeichert, und wie
>>beeinflusst dieser Vorgang das "RI\n", welches schon gespeichert wurde,
>>welchen Zustand hat cmdReceived dann und ist der 'String', der im
>>Array gespeichert ist, überhaupt noch ein gültiger String?
>
> Nachdem das \r-Zeichen (mein Ende-Zeichen) empfangen wurde, wird an die
> nächste Stelle im String ein String-Ende (\0) gesetzt. Das heißt, man
> hat nach dem ersten Befehl "RI\n\0" im Buffer stehen. Jetzt kommt das S
> und wird an die Stelle von \0 gespeichert. Da die Befehle ja in einer
> Anweisung gesendet wurden, kommt direkt danach auch noch das I (von SI)
> sowie das Ende-Zeichen \r.

Hier hast du einen Denkfehler.
Es hängt einzig und alleine vom Zeitverhalten des empfangenen
Programms ab, ob das I und der \r noch empfangen werden während
die main-Schleife immer wieder das cmdReceived abfrägt. Und von
sonst nichts anderem! Eine Übertragung ist ja nicht atomar in dem
Sinne, dass sie auf der Empfangsseite erst dann sichtbar wird,
wenn alle Zeichen übertragen wurden. Die Zeichen werden einzeln
auf die Reise geschickt, egal ob du das Absenden in einer
Anweisung oder in vielen machst.

> Danach steht im String RI\nSI\n\0 und somit ein String, mit dem der
> Befehlshandler umgehen kann.

Nicht notwendigerweise.

> cmdReceived ist, solange es nicht in dem interrupt-disabled-Teil auf 0
> gesetzt wurde, 1.

Wenn die Dinge so laufen, wie oben dargestellt, dann enthält
dein Buffer zu diesem Zeitpunkt die Zeichen

RI\rS

kein abschliessendes \0 und cmdReceived ist auf 1 gesetzt.

Nur: Ich bezweifle ernsthaft ob dein Befehlsauswerter mit diesem
unvollständigen String umgehen kann. Der strcpy() kurz davor kann
es jedenfalls nicht.

>
> Oder meinst du den Fall, wenn der zweite Befehl noch nicht komplett
> übertragen und gespeichert wurde und in der main der Programmzähler
> grade zu der if-Abfrage von cmdReceived kommt?

Sorry. Jetzt erst gesehen. Genau den Fall meine ich.

>
>>Die Existenz einer FIFO sagt noch lange nichts darüber aus, wieviele
>>Interrupts du bekommst. Hast du das überprüft?
>
> Das ist natürlich richtig.
>
> Also ich fasse zusammen: Es könnte hier zwei Probleme geben: Einmal das
> oben beschriebene, dass der zweite Befehl noch nicht komplett empfangen
> ist, wenn das Programm die Interrupts disabled und deshalb nur den
> ersten Befehl erkennt.
>
> Und zweitens könnten es quasi nur ein Interrupt-Flag geben, so dass
> selbst bei Ankunft mehrerer Zeichen die ISR nur einmal ausgeführt wird.
> Die einzige Lösung ist doch hier, gleich den kompletten FIFO auszulesen,
> oder?

So sehe ich das. Ich weiss allerdings nicht, wieviele Interrupts
in so einem Fall wirklich ausgelöst werden.


> Ja du hast recht. Kann ich aber leider erst am Montag auf der Arbeit
> testen. Das Problem beschäftigt mich aber trotzdem jetzt schon.

Ich denke du versuchst das zu trickreich anzugehen. Mach einen
Ringbuffer und gut ists.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich denke du versuchst das zu trickreich anzugehen. Mach einen
>Ringbuffer und gut ists.

Und das heißt? Wie programmiert man sowas, und was hat es für Vorteile? 
Warum treten dann diese zwei beschrieben Probleme nicht auf?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
>>Ich denke du versuchst das zu trickreich anzugehen. Mach einen
>>Ringbuffer und gut ists.

Ein Ringbuffer ist ein Array, das logisch gesehen zu einem
Kreis gebogen wird.
Neue Elemente wird immer hinten angehängt (und irgendwann wenn
das Ende das Arrays erreicht ist gehts wieder von vorne los.
Wie in einem logischen Ring eben)

>
> Und das heißt?

Die Trickserei mit dem \0 Byte entfällt komplett. Wenn dein
cmdReceived auf 1 geht, dann enthält der Ringbuffer ein Kommando,
auch wenn in der Zwischenzeit weitere Bytes empfangen wurden.
die werden im Ringbuffer solange zwischengespeichert, bis wieder
ein komplettes Kommando vorliegt.

> Wie programmiert man sowas, und was hat es für Vorteile?

zb.
http://www.zeiner.at/c/ringbuffer.html

> Warum treten dann diese zwei beschrieben Probleme nicht auf?

Das 2-te tritt nach wie vor auf, da es ja unabhängig davon ist,
wie du die Daten speicherst. Im zweiten Problem geht es einzig
und alleine darum ob du auch alle Zeichen von der UART kriegst,
die diese empfangen hat.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Die Trickserei mit dem \0 Byte entfällt komplett. Wenn dein
>cmdReceived auf 1 geht, dann enthält der Ringbuffer ein Kommando,
>auch wenn in der Zwischenzeit weitere Bytes empfangen wurden.
>die werden im Ringbuffer solange zwischengespeichert, bis wieder
>ein komplettes Kommando vorliegt.

Das heißt, zwischen interrupts_disabled() und interrupts_enabled() wird 
dann quasi nur der empfangene Befehl in einen anderen ("Arbeits-")Buffer 
kopiert und dann aus dem tempBuffer gelöscht, der restliche Inhalt nach 
vorne geschoben sowie cmdReceived auf 0 gesetzt. Letzteres ist dann erst 
wieder 1, wenn der restliche Inhalt von tempBuffer zu einem kompletten 
Befehl vervollständigt wurde. Richtig?

Dann müßte ich also diesen Teil des Programmes so ändern:
if (cmdReceived){
      disable_interrupts();
      KopiereAllesBisEndeZeichen(cmdBuffer);
      EntferneAllesBisEndeZeichen(tempBuffer);
      cmdReceived=0;
      byteCount=0;
      enable_interrupts();

>Das 2-te tritt nach wie vor auf, da es ja unabhängig davon ist,
>wie du die Daten speicherst. Im zweiten Problem geht es einzig
>und alleine darum ob du auch alle Zeichen von der UART kriegst,
>die diese empfangen hat.

Dies ließe sich doch damit bewerkstelligen, dass man alle Zeichen aus 
dem UART-FIFO ausliest. Also nach Auslesen eines Zeichen abfragt, ob der 
UART-FIFO noch weitere Daten enthält.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wäre es nicht auch möglich, innerhalb der ISR noch einen dritten Buffer 
(static) zu definieren, dessen Inhalt erst in tempBuffer kopiert wird, 
wenn ein kompletter Befehl angekommen ist? Dadurch ist immer 
gewährleistet, dass in tmpBuffer nur Daten drin stehen, die auch 
verarbeitet werden können. tempBuffer wird dann wie gehabt in einen 
cmdBuffer umkopiert. Kommt zwischenzeitlich ein Teil eines Befehles an, 
wird er eben im statischen Buffer gespeichert und beeinflusst nicht die 
Abarbeitung.

Das würde doch Problem 1 auch lösen.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Die Trickserei mit dem \0 Byte entfällt komplett. Wenn dein
>cmdReceived auf 1 geht, dann enthält der Ringbuffer ein Kommando,
>auch wenn in der Zwischenzeit weitere Bytes empfangen wurden.
>die werden im Ringbuffer solange zwischengespeichert, bis wieder
>ein komplettes Kommando vorliegt.

Und wenn im Ringbuffer zwei Kommandos vorliegen bei Abarbeitung? Mit dem 
get() aus dem Link bekommt man ja nur das nächste Zeichen. Bei einem 
Befehl könnte man ja solange get() ausführen, bis '\r' erreicht ist. 
Aber was, wenn dahinter noch ein vollwertiger Befehl liegt?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
> Das heißt, zwischen interrupts_disabled() und interrupts_enabled() wird
> dann quasi nur der empfangene Befehl in einen anderen ("Arbeits-")Buffer
> kopiert und dann aus dem tempBuffer gelöscht,

Nein. Bei einem Rungbuffer brauchst du nichts löschen, das ist
ja gerade der Trick dabei. Neu ankommende Zeichen werden einfach
weiter in den Buffer geschrieben. Ist die Schreibposition am
Ende angekommen, dann wird vorne im Buffer weitergemacht.
Gelöscht wird erst, wenn die Schreibposition wieder an dieser
Stelle vorbeikommt und das Zeichen überschreibt. Zu diesem
Zeitpunkt sollte allerdings das Ergebnis schon abgeholt worden sein :-)

Ein Ringbuffer hat 2 spezielle Positionen:
* an welche Stelle wird das nächste Zeichen eingefügt.
* von welcher Stelle wird das nächste Zeichen gelesen.

Beide Positionen wandern im Laufe der Zeit durch das Array
und fangen wieder vorne an, wenn sie hinten rausfallen.
Daher der Name: Ringbuffer, weil logisch gesehen das
Array ein Kreis ist und die Positinen Zeigern entsprechen, die
in der Mitte des Kreises sitzen und sich um ihre Achse drehen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beispiel: Ringbuffer der Größe 8

  +---+---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe
  +---+    +---+
  | 0 |    | 0 |
  +---+    +---+

Per Konvention gilt: der Ringbuffer sei leer,
wenn Lese gleich Schreibe ist.

Jetzt kommt ein Zeichen: R

  +---+---+---+---+---+---+---+---+
  | R |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe
  +---+    +---+
  | 0 |    | 1 |
  +---+    +---+

das nächste Zeichen kommt: I

  +---+---+---+---+---+---+---+---+
  | R | I |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe
  +---+    +---+
  | 0 |    | 2 |
  +---+    +---+

Ankunft: \r

  +---+---+---+---+---+---+---+---+
  | R | I | \r|   |   |   |   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe
  +---+    +---+
  | 0 |    | 3 |
  +---+    +---+

zu diesem Zeitpunkt erhöhst du deinen cmdReceived um 1, um anzuzeigen
dass ein Kommando im Ringbuffer ist. Angenommen die main-Schleife
hätte keine Zeit sich darum zu kümmern. Die Zeichen bleiben also
im Buffer

Ankunft: S

  +---+---+---+---+---+---+---+---+
  | R | I | \r| S |   |   |   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 0 |    | 4 |      | 1 |
  +---+    +---+      +---+

Die main-Schleife hat jetzt endlich Zeit und da cmdReceived ungleich
0 ist, beginnt sie Zeichen aus dem Ringbuffer zu holen (bis sie auf
den \r stösst). Das ganze natürlich bei disableten Interrupts:

Sie holt das erste Zeichen und bekommt das R

  +---+---+---+---+---+---+---+---+
  | R | I | \r| S |   |   |   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 1 |    | 4 |      | 1 |
  +---+    +---+      +---+

Sie holt das nächste Zeichen und kriegt das I

  +---+---+---+---+---+---+---+---+
  | R | I | \r| S |   |   |   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 2 |    | 4 |      | 1 |
  +---+    +---+      +---+

Am derauffoglenden Zeichen, welches sie kriegt, \r, erkennt
die main-Schleife, dass hier das Kommando zuende ist.
cmdReceived um 1 runtergezählt und Interrupts freigegeben.
Das gelesene Kommando RI kann bearbeitet werden.

  +---+---+---+---+---+---+---+---+
  | R | I | \r| S |   |   |   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 4 |      | 0 |
  +---+    +---+      +---+

Während die Bearbeitung läuft, kommt wieder ein Zeichen über die
UART rein: I

  +---+---+---+---+---+---+---+---+
  | R | I | \r| S | I |   |   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 5 |      | 0 |
  +---+    +---+      +---+

und das nächste: \r

  +---+---+---+---+---+---+---+---+
  | R | I | \r| S | I | \r|   |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 6 |      | 1 |
  +---+    +---+      +---+

wieder wird gleichzeitig cmdReceived um 1 erhöht um anzuzeigen,
dass ein Kommando vollständig im Buffer ist.

und noch eines: T

  +---+---+---+---+---+---+---+---+
  | R | I | \r| S | I | \r| T |   |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 7 |      | 1 |
  +---+    +---+      +---+

das nächste Zeichen: U

  +---+---+---+---+---+---+---+---+
  | R | I | \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 0 |      | 1 |
  +---+    +---+      +---+

Hier kommt die Kreisstruktur zum Tragen. Die Schreibposition wird
nicht auf 8 gesetzt, sondern auf 0, weil ja das Array zu Ende ist.
Die Leseposition zeigt auch an, dass das geht, denn Arraypositionen
0 bis 2 wurden ja schon gelesen, sind also brachliegend.

das nächste Zeichen kommt rein: M

  +---+---+---+---+---+---+---+---+
  | M | I | \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 1 |      | 1 |
  +---+    +---+      +---+

und noch eines: \r

  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 2 |      | 2 |
  +---+    +---+      +---+

cmdRecevied ist wieder um 1 erhöht worden. D.h. im Buffer warten
2 Kommandos auf Abarbeitung.
Sagen wir mal zu diesem Zeitpunkt hat die main-Schleife wieder
Zeit und beginnt wieder Zeichen aus dem Ringbuffer zu holen
(weil ja cmdReceived ungleich 0 ist).

Gelesen wird: S

  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 4 |    | 2 |      | 2 |
  +---+    +---+      +---+

als nächstes kriegt sie: I

  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 5 |    | 2 |      | 2 |
  +---+    +---+      +---+

und dann noch ein \r

  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 6 |    | 2 |      | 2 |
  +---+    +---+      +---+

zu diesem Zeitpunkt hört die Leseschleife wieder auf, weil
ja \r das Ende des Kommandos anzeigt. Folgerichtig erniedrigt
sie cmdReceived um 1

  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 6 |    | 2 |      | 1 |
  +---+    +---+      +---+

und bearbeitet das Kommando: SI

jetzt soll kein Zeichen mehr eintrudeln, die main Loop hat das
Kommando abgearbeitet und da cmdReceived immer noch ungleich 0
ist, beginnt sie wieder Zeichen zu holen.

Sie kriegt: T

  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 7 |    | 2 |      | 1 |
  +---+    +---+      +---+

danach: U

  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 0 |    | 2 |      | 1 |
  +---+    +---+      +---+

(Beachte: die nächste Leseposition ist 0, nicht 8!)

danach: M

  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 1 |    | 2 |      | 1 |
  +---+    +---+      +---+

und schliesslich auch den \r


  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 2 |    | 2 |      | 0 |
  +---+    +---+      +---+

Da ein \r empfangen wurde wird cmdReceived um 1 erniedrigt
und es beginnt die Abarbeitung des Kommandos TUM

Danch ist der Ringpuffer leer, angezeigt dadurch dass Lese == Schreibe
ist. Das braucht aber die main Loop nicht kümmern, für die ist nur
interessant, dass keine vollständigen Kommandos im Ringbuffer sind,
angezeigt dadurch dass cmdReceived gleich 0 ist.

Und so geht das immer weiter: Reihum werden die Zeichen geschrieben
oder gelesen, je nachdem.
Man muss nur auf eines aufpassen: Es kann natürlich passieren,
dass der Buffer irgendwann einmal voll wird: Wenn mehr Zeichen
eintrudeln als von der Leseschleife geholt werden.

Ausgangsposition:
  +---+---+---+---+---+---+---+---+
  | M | \r| \r| S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 2 |      | 2 |
  +---+    +---+      +---+

(also: nachdem TUM\r in den Buffer geschrieben wurde und bevor
die Leseschleife angefangen hat Zeichen zu holen)

Annahme: da trudeln weiterhin Zeichen ein. Sagen wir mal ein A

  +---+---+---+---+---+---+---+---+
  | M | \r| A | S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 3 |      | 2 |
  +---+    +---+      +---+

Beim nächsten Zeichen das reinkommt, B, gibt es ein Problem:
Dieses B kann nicht an Position Buffer[3} geschrieben werden,
dann das dort befindliche Zeichen S ist ja von der Leseschleife
noch nicht abgeholt worden.
Erkennbar ist das daran, dass Lese gleich Schreibe ist. D.h.
das nächste Zeichen würde an die Position geschrieben, von der
auch das nächste Zeichen gelesen werden müsste.
Aber: dieselbe Situation, Lese == Schreibe, gibt es auch wenn
der Buffer leer ist. Ein möglicher Ausweg ist es, ganz einfach
mitzuzählen, wieviele Zeichen im Buffer sind. Bei der Schreib-
operation wird dieser Zähler um 1 erhöht, bei der Leseoperation
wird der Zähler erniedrigt. In den Buffer geschrieben werden
kann daher nur dann, wenn Lese != Schreib ist oder wenn
dieser Zähler gleich 0 ist.

Eine andere Möglichkeit für dieses Problem ist es, den Buffer
nicht bis aufs letzte Byte auszunutzen und zu sagen, dass
obiges

  +---+---+---+---+---+---+---+---+
  | M | \r| A | S | I | \r| T | U |
  +---+---+---+---+---+---+---+---+
    0   1   2   3   4   5   6   7

  Lese     Schreibe   cmdReceived
  +---+    +---+      +---+
  | 3 |    | 3 |      | 2 |
  +---+    +---+      +---+

gar nicht zulässig ist. Durch eine Schreiboperation kann niemals
der Fall eintreten, dass Lese == Schreib entsteht und bereits
die Abspeicherung des A war nicht korrekt.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah na klar, sorry habe mir den Link jetzt auch mal gründlich 
durchgelesen und das Prinzip verstanden.

Ich würde also, wenn man den Link als Beispiel nimmt, in der ISR mit 
put() das empfangene Zeichen in den Ringbuffer schreiben. Falls das 
empfangene Zeichen ein '\r' ist, setze ich zusätzlich das cmdRcvd-Flag.

In der main hole ich dann mittels get() immer alle Zeichen bis zum 
Ende-Zeichen ab, speichere sie im cmdBuffer und verarbeite sie. Außerdem 
wird cmdReceived auf 0 gesetzt. Diese Operationen müssen aber doch bei 
ausgeschalteten Interrupts passieren, oder? Es wäre ja fatal, wenn ein 
Interrupt auftritt, während das Programm grade in der get()-Funktion 
steckt. Z.B. hat dann hinterher n den falschen Wert, weil diese Variable 
ja sowohl von get() also auch put() verändert wird.

Und was passiert, wenn vor Abfrage des cmdReceived-Flags schon zwei 
vollwertige Befehle im Ringbuffer stehen? Es würden dann bis zum ersten 
'\r' die Zeichen abgeholt und dann cmdReceived auf 0 gesetzt. Der zweite 
Befehl würde somit nicht berücksichtigt. Erst wenn wieder irgendwann ein 
Befehl reinschneit, der cmdReceived auf 1 setzt, würde dieser Befehl 
abgearbeitet - aber vielleicht viel zu spät.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
> Ah na klar, sorry habe mir den Link jetzt auch mal gründlich
> durchgelesen und das Prinzip verstanden.

Wahrscheinlich hatten wir jetzt eine Zeitüberschneidung :-)
Arbeite mal das Beispiel weiter oben durch.


>
> Ich würde also, wenn man den Link als Beispiel nimmt, in der ISR mit
> put() das empfangene Zeichen in den Ringbuffer schreiben. Falls das
> empfangene Zeichen ein '\r' ist, setze ich zusätzlich das cmdRcvd-Flag.
....
> Befehl reinschneit, der cmdReceived auf 1 setzt, würde dieser Befehl
> abgearbeitet - aber vielleicht viel zu spät.

Das cmdReceived Flag sollte ein cmdReceived Zähler sein.
Warum geht aus dem Beispiel hervor.

Den Rest hast du richtig erkannt.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@karl-heinz:

Super Erklärung! Vielen Dank!

Dadurch haben sich auch meine zwei Fragen geklärt:

1. Muss das Holen der Zeichen passieren, während die Interrupts disabled 
sind.
Mich irritierte hier die Aussage von Jörg:

>Und wenn du den Puffer nicht als Rignpuffer auslegst, musst du
>wahrscheinlich den Interrupt sperren solange du den Puffer leerst

Das kann man ja so verstehen, dass wenn man einen Ringpuffer benutzt, 
dieser eben nicht bei gesperrten Interrupts geleert werden muss.

Müssen dann die Variablen Lese und Schreibe auch volatile deklariert 
werden?

2. Das Problem mit mehreren Befehlen im Buffer löse ich dadurch, dass 
cmdReceived nicht einfach ein Flag ist, sondern die Anzahl der 
eingegangenen Befehle enthält.


Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Aber: dieselbe Situation, Lese == Schreibe, gibt es auch wenn
>der Buffer leer ist. Ein möglicher Ausweg ist es, ganz einfach
>mitzuzählen, wieviele Zeichen im Buffer sind. Bei der Schreib-
>operation wird dieser Zähler um 1 erhöht, bei der Leseoperation
>wird der Zähler erniedrigt. In den Buffer geschrieben werden
>kann daher nur dann, wenn Lese != Schreib ist oder wenn
>dieser Zähler gleich 0 ist.
>
>Eine andere Möglichkeit für dieses Problem ist es, den Buffer
>nicht bis aufs letzte Byte auszunutzen und zu sagen, dass
>obiges gar nicht zulässig ist. Durch eine Schreiboperation kann niemals
>der Fall eintreten, dass Lese == Schreib entsteht und bereits
>die Abspeicherung des A war nicht korrekt.

Die dritte Möglichkeit wäre doch, das überschreiben zuzulassen. Im 
Endeffekt geht mir ja so oder so ein Befehl verloren: Wenn ich die 
Schreiboperation verbiete, weil der Buffer voll ist, gehen mir die grade 
über UART eintreffenden Zeichen verloren. Wenn ich die Schreiboperation 
zulasse, wird ein im Buffer enthaltener Befehl überschrieben, dafür wird 
der neu angekommene Befehl aufgenommen.

Was ist jetzt günstiger? Oder hängt das von der Anwendung ab?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
> Die dritte Möglichkeit wäre doch, das überschreiben zuzulassen. Im
> Endeffekt geht mir ja so oder so ein Befehl verloren

Nicht unbedingt.
Wenn der Buffer voll zu werden droht, wird man der sendenden
Seite per Handshake (die Sache mit CTS/RTS oder XON/XOFF)
mitteilen, doch bitte mal mit dem Senden aufzuhören.

>
> Was ist jetzt günstiger? Oder hängt das von der Anwendung ab?

Im Prinzip ist es Wurscht. Wenn man es richtig macht, dann wird
man den 'Hör-mal-zu-senden-auf' auslösen noch bevor der Buffer
zu, sagen wir mal, 80% voll ist.
Grund: Auch die sendende Seite braucht eine gewisse Zeit um das
Senden einzustellen. Nach dem Auslösen des 'Hör auf zu
senden' muss man also damit rechnen, dass noch ein paar Zeichen
eintrudeln werden. Also schickt man das Handshake rechtzeitig,
so dass diese paar Zeichen noch gefahrlos gespeichert
werden können. Wenn es dabei auf 1 Zeichen mehr oder weniger
ankommt, dann bewegt man sich zu dicht am Limit.


Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Nicht unbedingt.
>Wenn der Buffer voll zu werden droht, wird man der sendenden
>Seite per Handshake (die Sache mit CTS/RTS oder XON/XOFF)
>mitteilen, doch bitte mal mit dem Senden aufzuhören.

Hm, im Befehlsprotokoll dass ich benutze, ist festgelegt, dass nur zwei 
Befehle pro Sekunde geschickt werden dürfen. Bei entsprechend großem 
Buffer dürfte das doch dann kein Problem geben.

Aber nochmal zum Problem, wenn mehrere Zeichen angekommen sind und nur 
ein Interrupt ausgelöst wird: Falls dem so ist, ist doch meine einzige 
Möglichkeit, den FIFO-Buffer komplett auszulesen, oder?

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aus dem Datenblatt des UART:

If interrupts are enabled, an interrupt is generated when one of the 
following conditions is true:
1.When there exists any valid character in the receive FIFO, the 
interrupt stays active until the receive FIFO is empty.

Das hört sich doch gut an. Somit dürfte dieser Fehler nicht auftreten.

Du hattest aber meine Frage noch nicht beantwortet, ob die Variablen 
Lese und Schreibe volatile deklariert werden müssen? Auf sie wird ja aus 
der main und auch aus der ISR zugegriffen

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:
>>Nicht unbedingt.
>>Wenn der Buffer voll zu werden droht, wird man der sendenden
>>Seite per Handshake (die Sache mit CTS/RTS oder XON/XOFF)
>>mitteilen, doch bitte mal mit dem Senden aufzuhören.
>
> Hm, im Befehlsprotokoll dass ich benutze, ist festgelegt, dass nur zwei
> Befehle pro Sekunde geschickt werden dürfen. Bei entsprechend großem
> Buffer dürfte das doch dann kein Problem geben.

Auch das ist eine Möglichkeit. Der Ringbuffer ist dann deine
Versicherung, dass eine Befehlsbearbeitung ab und an auch
mal länger als eine halbe Sekunde dauern darf, ohne dass
gleich alles zusammenbricht.

>
> Aber nochmal zum Problem, wenn mehrere Zeichen angekommen sind und nur
> ein Interrupt ausgelöst wird: Falls dem so ist, ist doch meine einzige
> Möglichkeit, den FIFO-Buffer komplett auszulesen, oder?

Ja. Aber klär im Vorfeld ab, ob das tatsächlich so ist, dass
nur 1 Interrupt kommt. Das ganze war mehr eine Vermutung
von mir um zu erklären wo den noch Zeichen verschwinden können.
Es wäre eine Möglichkeit, muss aber nicht so sein.


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TechInfo wrote:

> Du hattest aber meine Frage noch nicht beantwortet, ob die Variablen
> Lese und Schreibe volatile deklariert werden müssen? Auf sie wird ja aus
> der main und auch aus der ISR zugegriffen

main greift überhaupt nicht auf diese Variablen zu.
Du musst auch anfangen in Komponenten zu denken.

Es gibt da eine Komponente namens Ringbuffer. Jeglich
Verwaltung des Ringbuffers obliegt dieser Komponente.
main() hat sich per Definition nicht an diesen Variablen
zu vergreifen. Die Komponente stellt aber main()
eni paar Funktionen zur Verfügung, mit denen main()
bestimmte Funktionalität zur Verfügung gestellt wird.
Konkret: Es wird eine Funktion get() geben. Es wird auch
eine Funktion geben, die Auskunft gibt, wieviele Kommandos
im Ringbuffer sind.
Die Lese und Schreibpositionen brauchen nicht volatile sein,
weil ja:
  * keine Schleifen mit ihnen aufgebaut werden und dadurch
    keine Gefahr besteht, dass der Compiler den aktuellen
    Wert in ein Register optimiert.
  * durch die Interrupts bzw. Interruptsperre sichergestellt
    ist, dass get() und put() nicht gleichzeitig an den
    Variablen dran sind.
  * Die Optimierung von Variablen in Registern sowieso an
    Funktionsgrenzen endet. D.h. spätestens beim return in
    der Funktion get(), muessen die Variablen up to date
    sein.

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles klar. Nochmal vielen Dank. Werde den Ringbuffer am Montag testen. 
Da Problem 2 ja laut Datenblatt nicht auftreten kann, und Problem 2 mit 
dem Ringbuffer behoben wird, müßte dann ja alles rund laufen (so wie ich 
die Programmierarbeit kenne, wird es aber dann wohl ein ganz anderes 
Problem sein :)  )

Autor: TechInfo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So,

ich habe jetzt den Code folgendermaßen geändert:

Der Interrupt-Handler
void UartIntHandler (void* InstancePointer) 
{
  Xuint8 c=0;
  Xuint8 i=0;
  
  /*Falls UART-FIFO gefüllt...*/
  if (!XUartLite_mIsReceiveEmpty(XPAR_RS232_BASEADDR))
  {  
    /*...UART-Zeichen abholenn und in Ringbuffer schieben*/
    c=XUartLite_RecvByte(XPAR_RS232_BASEADDR);
    PutRing(c);
    
    /* Ende-Zeichen erhalten: Befehlszähler erhöhen */
    if (c=='\r')
      cmdRcvd++;
    
  }    
}
Und in der main:
if (cmdRcvd) 
    {
      microblaze_disable_interrupts();
      cmdRcvd--;
      do
        command[i]=GetRing();
      while(command[i++]!='\r');
      command[i]='\0';
      i=0;
      microblaze_enable_interrupts();
      print(command);

Der empfangene Befehl wird also gleich wieder zurückgesendet und auf 
einem Display ausgegeben.

Allerdings habe ich die Probleme immer noch. Selbst wenn ich nur einen 
Befehl schicke, wird dieser nicht immer zurückgesendet.

Hier der UART-Handler der Gegenseite, ein Atmega128 mit I2C-Display:
void UartRxHandler (unsigned char c)
{
  static unsigned char tmpBuffer [50]="";
  static short i=0;
  
  if (c!='\r')
    tmpBuffer[i++]=c;
  else
  {
    tmpBuffer[i]='\0';
    lcdPrintString(tmpBuffer);
    i=0;
    tmpBuffer[0]=0;
  }
}

Kann jemand eine Fehlerquelle entdecken oder liegt es an der 
physikalischen Verbindung?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.