Hallo, Leute!
Ich habe ein komisches Problem und zwar: ich schreibe ein komplexes
Programm für den ATMega128 um meinen Roboter zu steuern.
Das Programm muß Befehle vom RS232 bekommen und, über den gleichen Weg,
Antworten schicken.
Die Kommunikation µC => PC funktioniert problemlos, aber in der andere
Richtung (PC => µC) habe ich oft Probleme.
Also, ich habe ein Datenpaket so gemacht:
struct dataFromRS232
{
uint8_t version;
uint8_t deviceFrom;
uint8_t deviceTo;
uint8_t packetSize;
char data[100];
uint8_t parity;
};
Das Protokoll funktioniert wie folgendes:
die erste 4 Bytes werden geschickt, dann werden X Bytes (packetSize)
empfangen (in data) und zum Schluß wird ein Byte für die Parität
geschickt.
Der Empfänger prüft, ob alles stimmt (gleiche Version des Protokolls,
Parität, usw.) und schickt ein Byte als ACK/NACK.
Das ganze wird auf dem µC mit dem UART-Library vom Fleury implementiert.
Hier ist der Abschnitt des Codes, der mir Probleme verursacht:
...
unsigned int c;
uint8_t l;
...
c = u_getc();
if(c & UART_NO_DATA)
return;
else
{
if(isWaitingACK())
{
... Verwaltung der ACK/NACK. Das löscht das Packet vom Queue.
Funktioniert einwandfrei!
}
else
{
receivedData.version = (uint8_t) (c & 0xFF);
do { c = u_getc(); } while(c & UART_NO_DATA);
receivedData.deviceFrom = (uint8_t) (c & 0xFF);
do { c = u_getc(); } while(c & UART_NO_DATA);
receivedData.deviceTo = (uint8_t) (c & 0xFF);
do { c = u_getc(); } while(c & UART_NO_DATA);
receivedData.packetSize = (uint8_t) (c & 0xFF);
for(l = 0; l < receivedData.packetSize; l++)
{
do { c = u_getc(); } while(c & UART_NO_DATA);
receivedData.data[l] = (char) (c & 0xFF);
}
receivedData.data[l] = 0;
do { c = u_getc(); } while(c & UART_NO_DATA);
receivedData.parity = (uint8_t) (c & 0xFF);
if(receivedData.version != MYPROTOCOLVERSION)
sendNACK();
else if(calculateParity(receivedData) != receivedData.parity)
sendPRMismatch();
else
sendACK();
hasDataToProcess = TRUE;
}
}
Das Problem ist, das ab und zu, leider total zufällig!, die Routine
hängt.
Mit einem Debugger sehe ich, daß es genau an der Schleife mit u_getc
(Alias für uart_getc, bzw. uart1_getc je nach Konfiguration) hängt.
Warum denn? Die Daten werden vom PC geschickt, dann sollten auch vom µC
empfangen werden, oder?
Hat jemand eine Ahnung, warum die Routine nicht geht? Oder, besser
gesagt, warum ab und zu hängt?
Ich werde langsam verrückt...
Danke euch!
Luca Bertoncello
Der Codefetzen ist IMHO nicht ausreichend, um den sporatischen Fehler zu
finden.
Der Empfängercode hat auch einige Probleme. So wird der Eingangspuffer
zuerst mit Daten überschrieben, dann wird auf Fehler geprüft und u.U.
trotz entdeckter Fehler im Programmablauf weitergemacht
(hasDataToProcess = TRUE;). Das Füllen von receivedData.data hat bei
fehlerhaft empfangenem receivedData.packetSize das Potenzial zum
Pufferüberlauf.
Stefan B. schrieb:
> Der Codefetzen ist IMHO nicht ausreichend, um den sporatischen Fehler zu
> finden.
Wenn du mir noch sagst, was fehlt, kann ich gern schicken...
> Der Empfängercode hat auch einige Probleme. So wird der Eingangspuffer
> zuerst mit Daten überschrieben, dann wird auf Fehler geprüft und u.U.
> trotz entdeckter Fehler im Programmablauf weitergemacht
Weil ich beim kopieren ein paar Klammer vergessen habe...
Eigentlich hasDataToProcess = TRUE wird nur nach sendACK() aufgerufen...
> (hasDataToProcess = TRUE;). Das Füllen von receivedData.data hat bei
> fehlerhaft empfangenem receivedData.packetSize das Potenzial zum
> Pufferüberlauf.
Sicherheitsprobleme habe ich im den Fall nicht... receivedData.data ist
100 char groß und der größte Befehl, den ich schicke ich vielleicht 15
Bytes...
Jedenfalls, werde ich später noch eine Prüfung schreiben, daß ein NACK
schickt, wenn packetSize > 100 ist. Und selbstverständlich werden
maximal 100 Zeichen gelesen.
Aber eine Sache ist jetzt sehr komisch...
Heute früh habe ich ein kleines Programm geschrieben, das ich als ZIP
mitschicke.
Es liest die Daten vom RS232 mit dem obengenannten Protokoll, und
schickt sie zurück.
An der anderen Seite (Laptop) habe ich das Kommunikationsprogramm, das
genau das gleiche Protokoll implementiert.
Ich schicke alle Sekunden ein Paket seit kurz nach 9 Uhr, und jetzt
läuft immer noch stabil.
Die einzige Änderung ist, anstatt:
1 | if(c & UART_NO_DATA)
| 2 | return;
| 3 | else
| 4 | {
| 5 | ....
| 6 | }
|
habe ich geschrieben:
1 | if((c & 0xFF00) == 0)
| 2 | {
| 3 | ...
| 4 | }
|
Kann es sein, daß das das Problem ist?
Danke!
Luca Bertoncello
Luca Bertoncello schrieb:
> Die einzige Änderung ist, anstatt:
>
> 1 | > if(c & UART_NO_DATA)
| 2 | > return;
| 3 | > else
| 4 | > {
| 5 | > ....
| 6 | > }
| 7 | >
|
>
> habe ich geschrieben:
>
> 1 | > if((c & 0xFF00) == 0)
| 2 | > {
| 3 | > ...
| 4 | > }
| 5 | >
|
>
> Kann es sein, daß das das Problem ist?
Möglich.
Beide Codefetzen machen verschiedene Dinge.
Der erste returned nur im Fall, dass die Fleury Lib nichts vorliegen
hat. Der andere wertet nur dann aus, wenn die Fleury Lib keinen Fehler
gemeldet hat.
Im ersten Fall wiederrum wertest du auch dann aus, wenn die Fleury Lib
einen Fehler mitteilen will.
Es gibt in der Fleury Lib auch noch andere Return-Codes im Highbyte als
nur NO_DATA
Karl heinz Buchegger schrieb:
>> Kann es sein, daß das das Problem ist?
>
> Möglich.
> Beide Codefetzen machen verschiedene Dinge.
>
> Der erste returned nur im Fall, dass die Fleury Lib nichts vorliegen
> hat. Der andere wertet nur dann aus, wenn die Fleury Lib keinen Fehler
> gemeldet hat.
> Im ersten Fall wiederrum wertest du auch dann aus, wenn die Fleury Lib
> einen Fehler mitteilen will.
>
> Es gibt in der Fleury Lib auch noch andere Return-Codes im Highbyte als
> nur NO_DATA
Ich habe heute nur zufällig diese andere Return-Codes gesehen...
Vorher habe ich immer der erste Code benutzt, weil es mir so gegeben
worden ist (Asche auf meinem Kopf!).
Also, ich probiere heute Abend den Code so zu ändern, wie bei diesem
Testprogramm, dann mal sehen.
Ich danke euch!
Luca Bertoncello
Luca Bertoncello schrieb:
> Wenn du mir noch sagst, was fehlt, kann ich gern schicken...
Das ZIP ist ausreichend.
>> (hasDataToProcess = TRUE;). Das Füllen von receivedData.data hat bei
>> fehlerhaft empfangenem receivedData.packetSize das Potenzial zum
>> Pufferüberlauf.
>
> Sicherheitsprobleme habe ich im den Fall nicht... receivedData.data ist
> 100 char groß und der größte Befehl, den ich schicke ich vielleicht 15
> Bytes...
Das meine ich nicht. Probleme treten auf, wenn das Telegramm unsynchron
wird und irgendein Byte als receivedData.packetSize interpretiert wird.
Wenn es >99 ist, schreibst du in der for-Schleife hinter das
receivedData.data Feld...
> Jedenfalls, werde ich später noch eine Prüfung schreiben, daß ein NACK
> schickt, wenn packetSize > 100 ist. Und selbstverständlich werden
> maximal 100 Zeichen gelesen.
Das wird dieses Problem anpacken und ist notwendig. Noch besser wäre es,
den Start eines Paketes sauber zu erkennen.
> Aber eine Sache ist jetzt sehr komisch...
Dein neuer Code verwirft alle Zeichen, bei denen ein UART-Fehler (FE1,
DOR1, UART_BUFFER_OVERFLOW, UART_NO_DATA) aufgetreten ist. Der alte Code
verwirft explizit nur die Zeichen, bei denen das Bit UART_NO_DATA
gesetzt ist.
1. Finde den genauen Fehlercode raus
2. Setze mal #define UART_RX_BUFFER_SIZE 32 vom Default weg nach oben!
Stefan B. schrieb:
>> Sicherheitsprobleme habe ich im den Fall nicht... receivedData.data ist
>> 100 char groß und der größte Befehl, den ich schicke ich vielleicht 15
>> Bytes...
>
> Das meine ich nicht. Probleme treten auf, wenn das Telegramm unsynchron
> wird und irgendein Byte als receivedData.packetSize interpretiert wird.
> Wenn es >99 ist, schreibst du in der for-Schleife hinter das
> receivedData.data Feld...
Ich verstehe nicht was diese "Wenn es >99 ist" bedeutet...
Ein Byte ist nicht 8bit (0-255)?
Jedenfalls, wie gesagt, es wird die Kontrolle hinzugefügt, obwohl es
sicher nicht passieren kann, daß ein Paket länger als 15-20 Bytes ist...
> Das wird dieses Problem anpacken und ist notwendig. Noch besser wäre es,
> den Start eines Paketes sauber zu erkennen.
Vorschläge? Als Definition, der erste Byte ist die Versionsnummer, also
immer ein "2".
Aber wie gesagt, die Probleme kamen dann später, bei auslesen der
receivedData.data...
>> Aber eine Sache ist jetzt sehr komisch...
>
> Dein neuer Code verwirft alle Zeichen, bei denen ein UART-Fehler (FE1,
> DOR1, UART_BUFFER_OVERFLOW, UART_NO_DATA) aufgetreten ist. Der alte Code
> verwirft explizit nur die Zeichen, bei denen das Bit UART_NO_DATA
> gesetzt ist.
>
> 1. Finde den genauen Fehlercode raus
Das werde ich machen
> 2. Setze mal #define UART_RX_BUFFER_SIZE 32 vom Default weg nach oben!
Was meinst du?
Soll ich die Buffergröße vergrößern? Was schlägst du vor? 100 Byte?
Oder, besser gesagt, 105 (maximale Größe eines Pakets)?
Danke
Luca Bertoncello
Luca Bertoncello schrieb:
> Stefan B. schrieb:
>
>>> Sicherheitsprobleme habe ich im den Fall nicht... receivedData.data ist
>>> 100 char groß und der größte Befehl, den ich schicke ich vielleicht 15
>>> Bytes...
>>
>> Das meine ich nicht. Probleme treten auf, wenn das Telegramm unsynchron
>> wird und irgendein Byte als receivedData.packetSize interpretiert wird.
>> Wenn es >99 ist, schreibst du in der for-Schleife hinter das
>> receivedData.data Feld...
>
> Ich verstehe nicht was diese "Wenn es >99 ist" bedeutet...
Sorry 99 ist der max. Index. Das erste kritische Zeichen bzgl. der
folgenden for-Schleife ist der Wert 101.
Angenommen hier
1 | do { c = u_getc(); } while(c & UART_NO_DATA);
| 2 | receivedData.packetSize = (uint8_t) (c & 0xFF);
| 3 |
| 4 | for(l = 0; l < receivedData.packetSize; l++)
| 5 | {
| 6 | do { c = u_getc(); } while(c & UART_NO_DATA);
| 7 | receivedData.data[l] = (char) (c & 0xFF);
| 8 | }
|
ist das Telegramm unsynchron oder gestört und für
receivedData.packetSize wird z.B. c = 101 eingelesen. Dann wird in
receivedData.data[l==100] = (char) (c & 0xFF); hinter die Feldgrenzen
geschrieben!
for(l = 0; l < ((receivedData.packetSize < MAXDATALENGTH) ? :
MAXDATALENGTH); l++)
>> 2. Setze mal #define UART_RX_BUFFER_SIZE 32 vom Default weg nach oben!
>
> Was meinst du?
> Soll ich die Buffergröße vergrößern? Was schlägst du vor? 100 Byte?
> Oder, besser gesagt, 105 (maximale Größe eines Pakets)?
Laut Fleury-Library soll es eine Potenz von 2 sein. Wenn das RAM es noch
her gibt, würde ich 128 nehmen, ansonsten 64
Stefan B. schrieb:
> Sorry 99 ist der max. Index. Das erste kritische Zeichen bzgl. der
> folgenden for-Schleife ist der Wert 101.
>
> Angenommen hier
>
> 1 | > do { c = u_getc(); } while(c & UART_NO_DATA);
| 2 | > receivedData.packetSize = (uint8_t) (c & 0xFF);
| 3 | >
| 4 | > for(l = 0; l < receivedData.packetSize; l++)
| 5 | > {
| 6 | > do { c = u_getc(); } while(c & UART_NO_DATA);
| 7 | > receivedData.data[l] = (char) (c & 0xFF);
| 8 | > }
| 9 | >
|
>
> ist das Telegramm unsynchron oder gestört und für
> receivedData.packetSize wird z.B. c = 101 eingelesen. Dann wird in
> receivedData.data[l==100] = (char) (c & 0xFF); hinter die Feldgrenzen
> geschrieben!
Verstanden!
>>> 2. Setze mal #define UART_RX_BUFFER_SIZE 32 vom Default weg nach oben!
>>
>> Was meinst du?
>> Soll ich die Buffergröße vergrößern? Was schlägst du vor? 100 Byte?
>> Oder, besser gesagt, 105 (maximale Größe eines Pakets)?
>
> Laut Fleury-Library soll es eine Potenz von 2 sein. Wenn das RAM es noch
> her gibt, würde ich 128 nehmen, ansonsten 64
Aha! OK, ich sollte genugend Speicher noch zur Verfügung haben, ich
probiere also ein Wert von 128.
Danke!
Luca Bertoncello
Stefan B. schrieb:
> for(l = 0; l < ((receivedData.packetSize < MAXDATALENGTH) ? :
> MAXDATALENGTH); l++)
Ähm, Korrektur - du schreibst ja nach dem for... noch ein Nullbyte ins
Feld und l ist dann ggf. schon gleich MAXDATALENGTH. Das muss auch
noch berücksichtigt werden! Also statt MAXDATALENGTH 2x eintragen
MAXDATALENGTH-1
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|