[AVR] UART Interrupt und FIFO. Ich finde den Fehler nicht

OP Persönliche Seite #1176218
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?
Angehängte Dateien:
#1176232
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren