Forum: Mikrocontroller und Digitale Elektronik Sehr komisches Problem mit while-Schleife


von Jan (Gast)


Lesenswert?

Also ich habe ein kleines Protokoll zur Datenübertragung mit dem PC 
implementiert, welches beim Empfang eines gültigen (nach CRC Prüfung 
usw) Steuercodes die globale Variable "usart_cmd_recv" auf das 
empfangene Kommando setzt, der Empfang ist Interrupt-gesteuert. Ich 
hatte bisher gar keine Probleme. Im Hauptprogramm wird in einer while(1) 
Schleife unter anderem überprüft ob ein Kommando angekommen ist 
(usart_cmd_recv != 0) und dann wird eine switch-case Abfrage gemacht und 
je nach dem welches Kommando empfangen wurde die ein oder andere 
Funktionen ausgeführt.
Eine Funktion dient dazu Daten vom PC ins EEPROM zu schreiben. Diese 
Funktion wird auch aufgerufen und ein ACK wird zurückgesendet danach 
kommt folgende while schleife:

while(usart_cmd_recv != EEPROM_DATA_START) {
  // Implement TIME OUT
}

Diese Schleife soll einfach nur darauf warten, dass der PC das Kommando 
EEPROM_DATA_START sendet, aber wenn das passiert wird die Schleife 
einfach nicht beendet, woran kann das liegen. Ich kann mit sicherheit 
sagen, dass das programm zugriff auf die Variable hat, weil wenn ich die 
Schleife folgendermaßen konstruiere:

while(usart_cmd_recv != WRITE_EEPROM_DATA) {
  // Implement TIME OUT
}

wird die Schleife nicht ausgeführt, da WRITE_EEPROM_DATA das Kommando 
ist um die Funktion aufzurufen ...

von Severino R. (severino)


Lesenswert?

Hast Du usart_cmd_recv als volatile deklariert?

von Gunb (Gast)


Lesenswert?

Hello,

also so richtig verstehen tue ich den genauen Ablauf deines Programms 
nicht, hab' aber auch nur flüchtig gelesen.

Aber vielleicht ziehst du mal folgenden Ansatz in Betracht: Wenn das 
EEPROM mit Schreibvorgängen beschäftigt ist, kann/wird eventuell selbst 
ein per Interrupt empfangenes Zeichen verloren gehen. Der Controller 
verhindert nämlich währenddessen ein korrumpiertes Schreiben ins EEPROM 
durch Ignorieren anderer Events.

Ich hatte das Problem bei mehreren Geräten, die seit Jahren zuverlässig 
über RS232 kommunizierten. Nach Einsatz von USB-Konvertern ging dann am 
Ende der Übertragung immer ein Byte verloren. Die Untersuchung des 
Problems hatte dann ergeben, dass durch leichte Änderung des Timings 
durch den Einsatz des USB-Seriell-Konverters, das verlorene Byte immer 
beim Zugriff auf's EEPROM des Controllers (Atmel M128) ankam.

Da kann man sich eventuell den Wolf suchen, bis man das findet! Schau 
doch mal, ob du einen ähnlichen Konstrukt bei dir vorliegen hast und 
spiel mal mit verzögerten Transfers.


Gruss
Gunb

von Jan (Gast)


Lesenswert?

Also zu dem Zeitpunkt wird noch gar nichts geschrieben. Die Variable ist 
in der Datei usart.c als
unsigned char usart_cmd_recv = 0;
am Dateianfang außerhalb jeder Funktion deklariert. In der Datei 
eeprom.c wird sie am Anfang mit
extern unsigned char usart_cmd_recv;
eingebunden, genauso wie in der Datei welche die main Funktion enthält 
und dort läuft alles ohne Probleme.

von Jan (Gast)


Lesenswert?

Die aufgerufene Funktion erwartet auch erst später die zu schreibenden 
Daten weil mit der Funktion der ganze EEPROM beschrieben werden kann. 
Erst kommt das bereits gennante START Kommando was der Funktion 
eigentlich nur sagt das nächste Kommando enthält Daten uns soll ins 
EEPROM geschrieben werden und dann könnten nochmal Daten kommen solange 
bis das Kommando EEPROM_WRITE_END gesendet wird. Die Daten werden in 
32Byte Blöcken gesendet.

von schon wieder ein gast (Gast)


Lesenswert?

Severino hat den wesentlichen Hinweis gegeben: volatile

von Gunb (Gast)


Lesenswert?

so,

habe mir die Zeit genommen, noch mal genau zu lesen (sorry, hatte vorher 
ne Baustelle vor der Tür).

Schliesse mich den beiden Vorgängern an. Wäre aber interessant zu 
wissen, ob du Erfolg mit 'volatile' hattest?!

Gruss
Gunb

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Immer den ganzen wesentlichen Quelltext posten, nicht nur Fetzen. Sonst 
kann keiner was dazu sagen, nur raten.

von Εrnst B. (ernst)


Lesenswert?

Naja, der Fetzen hat schon gereicht... Leere Whileschleife soll auf 
Variable warten. Kann daher nur aus nem Interrupt geändert werden.
=> volatile vergessen.

von Jan (Gast)


Lesenswert?

Jo, also mit volatile funktioniert das, besten Dank. Jedoch versteh ich 
den Grund ehrlich gesgat nicht so genau. Hab nochmal mein C Buch 
rausgekramt, (The C Programming Language von Brain W. Kernighan und 
Dennis M. Ritchie) selbst da steht nur sehr wenig zu volatile ...

von STK500-Besitzer (Gast)


Lesenswert?

>volatile

weist den Compiler an, diese Variable bzw. einen Zugriff darauf nicht 
wegzuoptimieren, wenn er der "Meinung" ist, dass er sie wegoptimieren 
könnte.
Aus seiner Sicht wird sie nicht geändert und ist deswegen "über"...
Dass sie in einer ISR geändert wird (Regelfall für die Verwendung von 
"volatile"), kann er bei der Übersetzung eines anderen Programmteils 
nicht "sehen".

von Falk B. (falk)


Lesenswert?


von Entwickler (Gast)


Lesenswert?

In der Tat ist es so, dass der Compiler zur Compilierzeit den Inhalt der 
Variable noch nicht kennt. Der Zugriff kann also nicht komplett 
wegoptimiert werden. Letztendlich schaut der erzeugte Assemblercode so 
aus, dass das Programm die Variable einmal (wegen Optimierung) in ein 
Register lädt. Anschließend (in der while-Schleife) wartet das Programm 
nur noch auf eine Änderung des Registerinhalts, der natürlich nie 
eintritt, anstatt immer wieder den tatsächlichen Variablenwert zu lesen. 
Das schafft dann aber der Zusatz volatile.

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.