Forum: Compiler & IDEs [AVR] UART Interrupt und FIFO. Ich finde den Fehler nicht


von Malte _. (malte) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo,
in meinem Programm empfange ich Daten von der Seriellen Schnittstelle 
per Interrupt und speichere sie in einem FIFO zwischen, bis sie vom 
Hauptprogramm ausgelesen werden. Das funktioniert auch meistens. Aber 
alle 1:100 bis 1:1000 Zeichen geht plötzlich mal irgendwie eins 
verloren. Jetzt habe ich bereits den ganzen Vormittag den Fehler gesucht 
und werde aber einfach nicht fündig.

Die Abfrage im Hauptprogramm sieht wie folgt aus:
1
void analyse_income_cmd(void) { //Dekodiert die per RS232 erhaltenen Befehle
2
  u08 uart_emp_local[4];
3
  u08 i;
4
  u08 in_number = 0;
5
  //Look if there are at least 4 bytes in the RX FIFO
6
  cli();
7
  if ((UART_RX_BUF_SIZE-uart_rx_free()) < 4) {
8
    sei();
9
    return;
10
  }
11
  for (i = 0; i < 4; i++) {
12
    if ((UART_RX_BUF_SIZE-uart_rx_free()) == 0) { //may not happen
13
      sei();
14
      print_p(DEV_UART, fifoe2); //but happens in 1:1000 cases
15
      return;
16
    }
17
    uart_emp_local[i] = uart_rx_get();
18
    processed_rx_bytes++; //for debugging
19
    if ((uart_emp_local[i] == 13) && (i < 3)) {
20
      sei();
21
      cmd_error(uart_emp_local, i+1);
22
      return;
23
    }
24
    if (uart_emp_local[i] == 255) { //may not happen
25
      sei();
26
      print_p(DEV_UART, fifoe1);
27
      return;
28
    }
29
  }
30
  sei();
Die Konstanten sind:
#define UART_RX_BUF_SIZE 32
#define UART_TX_BUF_SIZE 64

Mit den ganzen cli() und sei() in dem Abfragecode funktioniert es 
fehlerfrei. Nehme ich die aber raus, ist der FIFO manchmal unerwartet 
leer.
Ich hatte den FIFO so gebaut, dass er eigentlich ohne Interruptsperren 
funktionieren müsste. Ein Schreib und ein Lesezeiger laufen auf einem 
Array immer "im Kreis". Eine leere Speicherzelle wird dadurch markiert, 
dass 0xff drin steht, so dass die beiden Zeigen nicht miteinander 
verglichen werden müssen um Unter und Überläufe auszuschließen. Der Code 
für die RS232 Verbindung ist im Anhang.

Hat jemand eine Idee was falsch läuft?

von Stefan E. (sternst)


Lesenswert?

Malte __ wrote:

> Hat jemand eine Idee was falsch läuft?

Ja. Schau dir folgendes an:
1
u08 uart_rx_free(void) {
2
  u08 f = 0;
3
  u08 p = uart_rx_wp;
4
// hier kommt ein Receive-Interrupt
5
  while ((uart_rx_buf[p] == 0xff) && (f < UART_RX_BUF_SIZE)) {
6
    f++;
7
    p++;
8
    p %= UART_RX_BUF_SIZE;
9
  }
10
  return f;
11
}
-> uart_rx_buf[p] ist nicht 0xff
-> Funktion liefert 0 zurück, obwohl der Puffer vielleicht alles andere 
als voll ist

Dieser Test:
1
  if ((UART_RX_BUF_SIZE-uart_rx_free()) < 4) {
ist daher nicht zuverlässig.

Es kann also passieren, dass du in die Schleife läufst, obwohl weniger 
als 4 Zeichen im FIFO sind.

von Malte _. (malte) Benutzerseite


Lesenswert?

Danke, den Fall hatte ich übersehen. Ich habe jetzt die Funktion in eine 
verwandelt, welche stattdessen den Lesepointer verwendet.
u08 uart_rx_available(void)
Damit geht es jetzt fehlerfrei.

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.