Forum: Mikrocontroller und Digitale Elektronik Merkwürdige endlosschleife (STM32; GCC4; C)


von NeoNull (Gast)


Lesenswert?

Hi
Ich möchte eine sleep-funktion implementieren habe dort allerdings ein 
merkwürdiges Problem.
1
void sleep_10us(int times)
2
{
3
 register unsigned long long oldcv;
4
 oldcv  = counter;
5
6
 oldcv += 23; // <- Diese Zeile macht den unterschied
7
8
 while(oldcv > counter);
9
}
counter ist eine globale Variable die alle 10µs inkrementiert wird. Eine 
Ausgabe der Variable bestätigt auch dass dies geschieht.
Datentyp: volatile unsigned long long

Beim Bau der warteschleife bekam ich allerdings merkwürdige Probleme - 
Die schleife wird nicht verlassen.
Nach einigem rumprobieren (vermutete zunächst das der optimizer da 
Probleme macht) stellte sich heraus, das der obige Code funktioniert, 
wenn ich die Addition auskommentiere, tue ich dies nicht hängt sich das 
Programm auf.

Also habe ich mir mal den assembly-code angeguckt den der Compiler 
erzeugt:

Ohne addition
1
0800ab9c <sleep_10us>:
2
 800ab9c:   4905        ldr r1, [pc, #20]   ; (800abb4 <sleep_10us+0x18>)
3
 800ab9e:   b530        push    {r4, r5, lr}
4
 
5
 800aba0:   e9d1 2306   ldrd    r2, r3, [r1, #24] ; counter laden (in oldcv)
6
 800aba4:   460c        mov r4, r1
7
8
 ; schleife
9
  800aba6:   e9d4 0106   ldrd    r0, r1, [r4, #24] ; counter erneut laden
10
  800abaa:   4290        cmp r0, r2  ; counter und oldcv vergleichen
11
  800abac:   eb71 0503   sbcs.w  r5, r1, r3
12
  800abb0:   d3f9        bcc.n   800aba6 <sleep_10us+0xa>
13
 800abb2:   bd30        pop {r4, r5, pc}
14
 800abb4:   20000988    .word   0x20000988
Soweit ist der code verständlich, auch wenn ich nie in arm-asm 
programmiert habe.

Als nächstes habe ich mir dann den Code mit der Addition angesehen
1
0800ab9c <sleep_10us>:
2
 800ab9c:   b530        push    {r4, r5, lr}
3
 800ab9e:   4c07        ldr r4, [pc, #28]   ; (800abbc <sleep_10us+0x20>)
4
5
 800aba0:   2017        movs    r0, #23 ; konstanter summand
6
 800aba2:   e9d4 2306   ldrd    r2, r3, [r4, #24] ; counter in oldcv laden
7
 800aba6:   2100        movs    r1, #0 ; die oberen 32 bit des summanden
8
9
 800aba8:   1812        adds    r2, r2, r0 ; addition der konstanten auf oldcv
10
 800abaa:   eb43 0301   adc.w   r3, r3, r1
11
12
; Schleifen-anfang 
13
  800abae:   e9d4 0106   ldrd    r0, r1, [r4, #24] ; counter laden
14
15
  800abb2:   4290        cmp r0, r2 ; counter mit oldcv vergleichen
16
  800abb4:   eb71 0503   sbcs.w  r5, r1, r3
17
  800abb8:   d3f9        bcc.n   800abae <sleep_10us+0x12>
18
19
 800abba:   bd30        pop {r4, r5, pc}
20
 800abbc:   20000988    .word   0x20000988
Dieser Code sieht ebenfalls 100% korrekt aus, allerdings wird die 
schleife nie verlassen…

Meine Frage nun: Warum? :D

Controllers: ARM Cortex M3 STM32F103RBT6
Compiler: gcc 4.5.2
1
CFLAGS="-Wall -nostdlib -fno-common -fno-builtin -O0 -g -mcpu=cortex-m3 -mthumb -c"

von NeoNull (Gast)


Lesenswert?

Wenn ich die Schleife wie folgt schreibe funktioniert es sporadisch:
1
 while(oldcv > newcv) newcv = counter;
kann es sein dass ich irgend etwas am cache des µCs einstellen muss? 
Habe noch nicht sehr viel Erfahrung mit ARMs

von Zuschauer (Gast)


Lesenswert?

Hallo,

sage mir doch bitte wozu die Variable "times" übergeben wird, wenn sie 
doch nicht in der Funktion verwendet wird. Ist die Funktion wirklich 
komplett?

Gruß

von Peter D. (peda)


Lesenswert?

Timer können überlaufen. Da sind schon Generationen an Programmierern 
dran gescheitert.
Nur Differenzen stimmen auch bei einem Überlauf.
Vergleiche die Differenz:
1
start_time = get_time();
2
while( get_time() - start_time < delay );
Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Die Warteschleife sieht in beiden Fällen doch absolut gleich aus.
Der Grund kann also nur sein, daß "counter" nicht weit genug hochgezählt 
wird, zB vorher wieder zurückgesetzt wird.

von Marcus O. (marcus6100)


Lesenswert?

Die Glaskugel sagt, du rufst die sleep_10us() Funktion auf während 
Interrupts gesperrt sind, deshalb wird counter hier nicht inkrementiert.

Ohne Addition ist die Bedingung in der while Schleife übrigens immer 
falsch.

von NeoNull (Gast)


Lesenswert?

Bei einem unsigned int würde es schon etwa 11h dauern bis zum overflow, 
so lange wird das Programm nie laufen :)
Und inkrementiert wird auch. Ich habe zunächst einfach den aktuellen 
Stand des Counters zurückgegeben und diesen dann per USB an den PC 
geschickt - dieser wurde steht größer.
Das mit den Interrupts könnte aber tatsächlich ein Problem sein, da ich 
die sleep-funktion inmitten einer USB-Kommunikation anwende.

Ich habe das Problem inzwischen ohne timer lösen können, aber Trotzdem 
danke für den Hinweis.

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.
Lade...