Was übersehe ich hier? If mit/ohne temporäre Variable

#3345365
Lesenswert?

Hallo zusammen,

ich fange langsam an, an mir selbst zu zweifeln... In meiner 
Hauptschleife habe ich die Abfrage
1
if (serialReceivedDataWaiting()) {serialPutC (serialGetC ());}

(Ein kleines Echo zum Testen des USARTs beim ATmega 8, eigentlich nichts 
dolles...). serialReceivedDataWaiting() ist definiert als
1
 unsigned char serialReceivedDataWaiting () {
2
  return (rxBufferNextPut != rxBufferNextGet);
3
}

rxBufferNextPut und rxBufferNextGet sind Indizes in einen Ringpuffer.

Bevor serialReceivedDataWaiting () das erste mal eine 1 zurücmkgibt, 
funktioniert alles wie erwartet. War das Ergebnis jedoch einmal 1, wird 
der then-Block bei jedem Durchlauf ausgeführt. Behelfe ich mir jedoch 
mit einer temporären Variable
1
unsigned char temp2;
2
[...]
3
temp2 = serialReceivedDataWaiting();
4
if (temp2) {serialPutC (serialGetC ());}

funktioniert alles, wie es soll. Was übersehe ich hier?

Gruß & Dank,
Michael
#3345388
Lesenswert?

versuche es mal mit if (Bedingung)

also in der Form


zahl = serialReceivedDataWaiting();
if (zahl<3) { ;};

Dann wird klarer was passiert, vor allem wenn das Funktionsergebnis 
vorher in eine Variable abgespeichert wird, kann besser der 
Programmablauf verfolgt werden.
#3345392
Lesenswert?

Ähm... Wenn das Funktionsergebnis vorher in einer Variable abgespeichert 
wird, funktioniert es, wenn nicht, nicht. Das schrieb ich oben...

Dieses Verhalten tritt bei -O0 genauso auf wie bei -Os, ist also kein 
Optimierungsartefakt. In meiner Verzweiflung habe ich tatsächlich sogar 
mal mit
1
 if (serialReceivedDataWaiting() != 0)

probiert, dies macht keinen Unterchied (und sollte es ja auch nicht).
Gast #3345400
Lesenswert?

Rein von der Logik her müsste es eigentlich gehen.
Möglicherweise solltest Du mal mit der Optimierung "spielen". Vielleicht 
haut die irgendwas raus.
Alternativ kannst Du auch eine .lss Datei erzeugen lassen und Dir die 
Stelle, die spinnt, aus der Nähe anschauen.
Das Wegoptimieren von: serialGetC () wäre so ein Kandidat. Dann geht’s 
dauernd rund.
#3345403
Lesenswert?

A. K. schrieb:
> Hat nichts mit deinem Problem zu tun: Der Test auf die race condition in
> serialPutC funktioniert so nicht. Wenn UDR mit cli leer läuft, der
> Puffer aber nicht leer ist, dann sendest du in verkehrter Reihenfolge.

Stimmt, danke!
1
if (  (UCSRA & (1<<UDRE))                   // USART data register empty
2
   && (txBufferNextPut == txBufferNextGet)) // queue empty

müsste dann aber funktionieren - oder?

Gruß & Dank,
Michael
#3345413
Lesenswert?

Amateur schrieb:

> Alternativ kannst Du auch eine .lss Datei erzeugen lassen und Dir die
> Stelle, die spinnt, aus der Nähe anschauen.

Die wichtigen stellen in der LSS-Datei sehen so aus:

 288:  3b d1         rcall  .+630      ; 0x500 
<serialReceivedDataWaiting>
 28a:  00 97         sbiw  r24, 0x00  ; 0
 28c:  09 f4         brne  .+2        ; 0x290 <main+0x232>
 28e:  7f cf         rjmp  .-258      ; 0x18e <main+0x130>
 290:  13 d1         rcall  .+550      ; 0x4b8 <serialGetC>
 292:  23 d0         rcall  .+70       ; 0x2da <serialPutC>
 294:  7d cf         rjmp  .-262      ; 0x190 <main+0x132>
    }

00000500 <serialReceivedDataWaiting>:
 500:  df 93         push  r29
 502:  cf 93         push  r28
 504:  cd b7         in  r28, 0x3d  ; 61
 506:  de b7         in  r29, 0x3e  ; 62
 508:  20 91 76 00   lds  r18, 0x0076
 50c:  90 91 77 00   lds  r25, 0x0077
 510:  81 e0         ldi  r24, 0x01  ; 1
 512:  29 17         cp  r18, r25
 514:  09 f4         brne  .+2        ; 0x518 
<serialReceivedDataWaiting+0x18>
 516:  80 e0         ldi  r24, 0x00  ; 0
 518:  cf 91         pop  r28
 51a:  df 91         pop  r29
 51c:  08 95         ret


Blöderweise habe ich in Assembler das letzte Mal vor 20+ Jahren auf 
einem C-64 programmiert. Zum groben Lesen reicht's noch, aber den Fehler 
kann ich hier nicht entdecken.

Anyone?

> Das Wegoptimieren von: serialGetC () wäre so ein Kandidat. Dann geht’s
> dauernd rund.

Inwiefern?
Angehängte Dateien:
#3345416
Lesenswert?

A. K. schrieb:

> Spar dir den Zirkus mit der Optimierung darin, schreib den Kram stets in
> den Puffer und schalte den Interrupt ein. cli/sei ist dann völlig
> überflüssig. Worst case ist ein unnötiger Interrupt.

Hast Recht. Als ich den Mechanismus eingebaut habe, dachte ich noch, der 
UDRE-Interrupt würde durch den Übergang von 0 nach 1 ausgelöst, nicht 
davon, dass UDRE 1 ist, so dass ich das erste Byte immer manuell 
schreiben müsste... Danach habe ich ihn nicht mehr ausgebaut.
Gast #3345421
Lesenswert?

> Das Wegoptimieren von: serialGetC () wäre so ein Kandidat. Dann geht’s
> dauernd rund.

Ich habe mir den Sourcecode noch nicht reingezogen, aber zu einem 
Empfang gehört auch das Löschen (wie auch immer) des abgeholten 
Zeichens.
Sagt die Routine serialReceivedDataWaiting(): jemand ist zuhause - so 
lange das nicht der Fall ist, geht's ja gut und erfolgt ein Aufruf von: 
serialPutC () ohne das eingefügte serialGetC (), so wird auch der 
Empfangspuffer nicht aktualisiert und die Abfrage liefert somit auch 
beim nächsten Durchlauf true. Usw.
#3345424
Lesenswert?

Hier wird die Funktion   serialReceivedDataWaiting() 2x aufgerufen
    temp2 = serialReceivedDataWaiting();
//    serialPutC (temp2+0x30);
    if (serialReceivedDataWaiting()




Möglicherweise sind beim 2. mal die Daten schon als nicht mehr als 
Waiting
registriert, weil keine neuen Daten empfangen wurden, und angenommen 
wird das die Daten abgeholt werden, wenn die Funktion 
serialReceivedDataWaiting() aufgerufen wird ? Deshalb liefert diese ein 
anderes Ergebnis.

Kenne leider die Funktionsbeschreibung nicht.
#3345429
Lesenswert?

lutz h. schrieb:
> Hier wird die Funktion   serialReceivedDataWaiting() 2x aufgerufen

> Möglicherweise sind beim 2. mal die Daten schon als nicht mehr als
> Waiting
> registriert, weil keine neuen Daten empfangen wurden, und angenommen
> wird das die Daten abgeholt werden, wenn die Funktion
> serialReceivedDataWaiting() aufgerufen wird ? Deshalb liefert diese ein
> anderes Ergebnis.
>
> Kenne leider die Funktionsbeschreibung nicht.

Die steht im ersten Post (und später im angehängten Quelltext). 
serialReceivedDataWaiting() greift nur lesend auf die Indizes zu.
#3345436
Lesenswert?

Hast du mal die Warnungen eingeschaltet oder gar gelesen? Mir fehlt in 
AVRGCC2.c ein #include "mjgSerial.h" oder so, mit der Deklaration der 
entsprechenden Funktionen. Weshalb der Return-Typ von 
serialReceivedDataWaiting in alter K&R-Tradition als int angenommen 
wird.

Ist er aber nicht, und so steht in der oberen Hälfte des vom Aufrufer 
angenommenen 16-Bit Werts zufällig einer der Indizes drin. Und der ist 
nach dem ersten Byte erst einmal ein Weilchen != 0.
#3345448
Lesenswert?

A. K. schrieb:

Danke, das war's!

> Hast du mal die Warnungen eingeschaltet oder gar gelesen?

Doch, aber ich hatte die "implicit declaration" nur für einen 
Schönheitsfehler gehalten, und angenommen, dass wenn der Linker die 
Funktion findet, es schon irgendwie passen wird.

> Weshalb der Return-Typ von
> serialReceivedDataWaiting in alter K&R-Tradition als int angenommen
> wird.

> Ist er aber nicht, und so steht in der oberen Hälfte des vom Aufrufer
> angenommenen 16-Bit Werts zufällig einer der Indizes drin. Und der ist
> nach dem ersten Byte erst einmal ein Weilchen != 0.

Danke, dass Du mir das Brett vom Kopf genommen hast. Rückblickend hätte 
es mir klar sein sollen...

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