Forum: Compiler & IDEs Fragen zum double buffering beim Einlesen von GPS-Daten


von Ralf Weinert (Gast)


Lesenswert?

Hallo,

ich möchte gerne Binärdaten von zwei GPS-Modulen an zwei USARTs 
gleichzeitig einlesen und baue mir dafür gerade ein Progrämmchen für 
einen Atmel AVR. Beim Protokoll handelt es sich um UBX.

Damit ich in der Interrupt-Routine Daten sammlen und im Hauptprogramm 
parallel in Ruhe parsen kann, brauche ich für jeden USART zwei Puffer, 
also insgesamt vier.

Um das Kopieren von Puffern in der Interrupt-Routine zu vermeiden 
(soviel Zeit habe ich nicht, UBX-Messages können sehr lang werden), 
wollte ich für jedes GPS-Modul zwei Zeiger auf Puffer vorhalten, einen 
Zeiger für die Interruptroutine und einen Zeiger für den Parser. Diese 
Zeiger wollte ich dann jeweils in der Interruptroutine tauschen, wenn 
ein kompletter Datensatz eingetroffen ist.

Es sollte sich folgender Ablauf ergeben:
1. Sammeln der Daten in Puffer 1, bis vollständiger Datensatz da
2. Auswerten der Daten in Puffer 1, gleichzeitig Sammeln der Daten in 
Puffer zwei, bis vollständiger Datensatz da
3. Auswerten der Daten in Puffer 2, gleichzeitig Sammeln der Daten in 
Puffer eins, bis vollständiger Datensatz da

usw.

Der Code soll später auf noch mehr GPS-Module erweitert werden können, 
deshalb möchte ich mit Arrays arbeiten.

Ich definiere also die Puffer und die Zeiger darauf:
1
#define NO_RECEIVERS 2
2
#define UBX_BUFFER_SIZE 1024
3
4
typedef struct
5
{
6
  uint8_t  message_class;
7
  uint8_t  message_id;
8
  uint16_t data_length;
9
  uint8_t  data[UBX_BUFFER_SIZE];
10
  uint8_t  checksum_a;
11
  uint8_t  checksum_b;
12
} ubx_buffer_t;
13
14
ubx_buffer_t gps_buffer[2 * NO_RECEIVERS];
15
ubx_buffer_t *gps_input_buffer[NO_RECEIVERS];
16
ubx_buffer_t *gps_parse_buffer[NO_RECEIVERS];

Zur Initialisierung setze ich die Zeiger per Hand:
1
uint8_t i;
2
3
for (i = 0; i < NO_RECEIVERS; i++)
4
{
5
  gps_input_buffer[i] = &gps_buffer[2 * i];
6
  gps_parse_buffer[i] = &gps_buffer[2 * i + 1];
7
}

Jetzt meine Frage: Kann man das so machen, oder habt ihr bessere Ideen? 
Wie implementiert man am besten das Austauschen der 
Zeiger-"Zieladressen" von gps_input_buffer und gps_parse_buffer? Wie 
verhindert man, dass die Interruptroutine dem Parser die Variablen 
"unter dem Arsch" wegnimmt? Sprich, was ist, wenn der Parser mal länger 
braucht, als die Interruptroutine zum Sammeln eines Datensatzes?

von Karl H. (kbuchegg)


Lesenswert?

Ralf Weinert schrieb:


> Jetzt meine Frage: Kann man das so machen, oder habt ihr bessere Ideen?

Ist in Ordnung.
genau so macht man das.

(ich würde lediglich meine Sichtweise anders wählen. Zu jedem Gerät 
gehören ein Schreib und ein Lesepuffer. Und es gibt deren 2 Geräte.
Du siehst die Dinge momentan anders rum.
Ist aber nur ein logischer Unterschied.

> Wie implementiert man am besten das Austauschen der
> Zeiger-"Zieladressen" von gps_input_buffer und gps_parse_buffer?

Durch zuweisen?

> Wie
> verhindert man, dass die Interruptroutine dem Parser die Variablen
> "unter dem Arsch" wegnimmt?

Indem man sich eine zusätzliche Variable zurecht legt, in der der Parser 
ablegt: "Juhu, ich bin fertig. Interrupt du darfst!"
Vornehm nennt man sowas eine Semaphore, aber im Prinzip ist es einfach 
nur eine Variable die entweder 0 oder 1 sein kann. ist sie zb 0, darf 
die Interrupt Routien keinen Swap machen, ist sie 1 dann ist der Weg 
frei (oder umgekehrt, was dir lieber ist).

> Sprich, was ist, wenn der Parser mal länger
> braucht, als die Interruptroutine zum Sammeln eines Datensatzes?

Dann hast du sowieso ein Problem. Wenn der Chef dir laufend mehr Arbeit 
auf dem Schreibtisch anhäuft als du bearbeiten kannst, dann wirst du 
irgendwann zusammenbrechen oder einfach irgendwelche Aufträge 
unbearbeitet in den Müll schmeissen müssen. Oder du bremst deinen Chef 
ein.

von STK500-Besitzer (Gast)


Lesenswert?

Ralf Weinert schrieb:
> Damit ich in der Interrupt-Routine Daten sammlen und im Hauptprogramm
> parallel in Ruhe parsen kann, brauche ich für jeden USART zwei Puffer,
> also insgesamt vier.

Guck mal nach Ringpuffer.
Damit (jeweils einer pro Receiver) sollte es auch gehen.
Ansonsten wäre es sinnvoller, jeweils ein zweifach indiziertes Array zu 
nehmen, bei dem zum Wechseln zwischen Parsen und nur der Index geändert 
werden muss.

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.