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 ...
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
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.
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.
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
Naja, der Fetzen hat schon gereicht... Leere Whileschleife soll auf
Variable warten. Kann daher nur aus nem Interrupt geändert werden.
=> volatile vergessen.
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 ...
>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".
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.
Eine eigene Frage?
Dieser Thread ist über 18 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.