Forum: Compiler & IDEs von uint16 nach uint32 und wieder zurück.


von Tom M. (tomm) Benutzerseite


Lesenswert?

Hi Leute


Ich brüte gerade über einem Problem bei diesem Code, bei der 
return-Anweisung:
1
int16_t timer0_stop() {
2
3
   uint16_t ticks;
4
5
   ticks = TCNT0;    // stilles Aufruesten auf 16bit
6
   if (ticks < timer0.wstart) ticks += 256;  // wrap-around?
7
   ticks -= timer0.wstart;    // vergangene Ticks
8
9
   return ((uint32_t) ticks * timer0.tick_ns)/1000;  // Mikrosekunden zurueckgeben
10
   //return ticks;
11
}

Ich möchte ticks auf 32 bit aufpumpen, damit das Produkt nicht 
überläuft. /timer0.tick_ns/ ist ein uint16_t und momentan auf 4000 
gesetzt (timer tick intervall ist 4000 Nanosekunden, bei F_CPU 16Mhz und 
Prescaler 64).

Sollte doch so klappen, oder? Tut es aber nicht, die Werte die ich 
rauskriege sind bogus, ich vermute ein Problem mit den Wertebereichen, 
aber wo?. Das direkte Zurückgeben des ticks liefert mir aber 
erwartungsgemässe Ergebnisse, nur eben in timer ticks und nicht in 
Sekunden(bruchteilen)... Was mache ich falsch oder hab ich übersehen?

von Dirk (Gast)


Lesenswert?

So vielleicht?
1
int16_t timer0_stop() {
2
3
   uint32_t ticks;
4
5
   ticks = (uint32_t)TCNT0;    // stilles Aufruesten auf 32bit
6
7
   if (ticks < timer0.wstart)
8
      ticks += 256;  // wrap-around?
9
10
   ticks -= timer0.wstart;    // vergangene Ticks
11
12
   return (uint16_t)(ticks * timer0.tick_ns/1000);  // Mikrosekunden zurueckgeben
13
   //return ticks;
14
}

TCNT0 max. ist 255.
Plus evtl. 256 = 511.
Minus 0 = 511.
Mal 4000 = 2044000
Durch 1000 = 2044

2044000 passt nicht in uint16_t.

Gruß Dirk

von Rolf M. (rmagnus)


Lesenswert?

Tom M. schrieb:
> Sollte doch so klappen, oder?

Ja. Bist du denn sicher, daß in timer0.tick_ns das richtige drinsteht?

Dirk schrieb:
> So vielleicht?
>    return (uint16_t)(ticks * timer0.tick_ns/1000);  // Mikrosekunden

Gerade so nicht.

Dirk schrieb:
> 2044000 passt nicht in uint16_t.

Bei Toms Version muß es das auch gar nicht, aber bei deiner.

von Tom M. (tomm) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:
>> Sollte doch so klappen, oder?
>
> Ja. Bist du denn sicher, daß in timer0.tick_ns das richtige drinsteht?

Werd noch etwas debugging-code ergänzen. Gebe diesen Wert einmalig nach 
der Initialisierung beim Programmstart auf die UART aus, zu diesem 
Zeitpunkt zumindest passt's noch...

von Gelöscht (kami89)


Lesenswert?

Ich bin mir nicht sicher, aber muss man den uint32 nicht wieder auf ein 
uint16 zurückcasten?

also so:
1
return (uint16_t)(((uint32_t) ticks * timer0.tick_ns)/1000);

von Florian P. (db1pf)


Lesenswert?

Hallo,

ich bin mir jetzt nicht sicher, wie der Compiler die Priorität zwischen 
dem Cast und der Multiplikation regelt. Versuch mal:
1
int16_t timer0_stop() {
2
3
   uint16_t ticks;
4
5
   ticks = TCNT0;    // stilles Aufruesten auf 16bit
6
   if (ticks < timer0.wstart) ticks += 256;  // wrap-around?
7
   ticks -= timer0.wstart;    // vergangene Ticks
8
9
   return ( ((uint32_t) ticks) * timer0.tick_ns)/1000;  // Mikrosekunden zurueckgeben
10
   //return ticks;
11
}


Grüße,
Florian

von Gelöscht (kami89)


Lesenswert?

Vergiss mein Post. Von Int32 auf Int16 muss man natürlich nicht casten 
;-)

von Tom M. (tomm) Benutzerseite


Lesenswert?

1
return timer0.tick_ns;
2
// bzw.
3
return ticks*4;
liefert zwar erwartungsgemäss 4000 bzw. 0x4C/0x7C (Zeiten um 80 bzw. 120 
us), aber rechnen will's ned wie ich will. grummel tutet alles nix, 
sitze wohl schon zu lange an der Kiste... 8)

von Karl H. (kbuchegg)


Lesenswert?

Florian Pfanner schrieb:
> Hallo,
>
> ich bin mir jetzt nicht sicher, wie der Compiler die Priorität zwischen
> dem Cast und der Multiplikation regelt.

Ein Cast hat fast die höchste Priortät, die es gibt.
Weit höher als Multiplikation oder die restlichen Arithmetik Sachen.

von Karl H. (kbuchegg)


Lesenswert?

Tom M. schrieb:

> liefert zwar erwartungsgemäss 4000 bzw. 0x4C/0x7C (Zeiten um 80 bzw. 120
> us), aber rechnen will's ned wie ich will.

An deiner Berechnung aus dem ersten Post gibt es nichts auszusetzen. Das 
Problem muss in den Codebereichen stecken, die du nicht gezeigt hast.

von Tom M. (tomm) Benutzerseite


Lesenswert?

Danke für eure Beiträge. Ich glaub' ich hab's gefunden: Ich verwende in 
der Routine 32 bit Variablen. Im Listing sehe ich calls zu Routinen wie 
__udivmodsi4 und __mulsi3. Das gehört wohl irgendwie zur avr-libc (oder 
ist es war avr-gcc spezifisches)? für die avr-libc zumindest gilt:

"Unless otherwise noted, functions of this library are not guaranteed to 
be reentrant."

Meine timer_stop() Funktion rufe ich via callback aus einem Interrupt 
auf. Ich hab die Funktion lang und breit aus main() raus getestet, da 
funzt sie wunderbar. Im Interrupt-Kontext sind die Ergebnisse wild.

Muss mir mal überlegen, ob ich auch mit 16 bit klar komme, auf Kosten 
der Genauigkeit...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tom M. schrieb:
> Danke für eure Beiträge. Ich glaub' ich hab's gefunden: Ich verwende in
> der Routine 32 bit Variablen. Im Listing sehe ich calls zu Routinen wie
> __udivmodsi4 und __mulsi3. Das gehört wohl irgendwie zur avr-libc (oder
> ist es war avr-gcc spezifisches)?

Die Funktionsnamen folgen einer GCC-Nomenklatur, und diese Routinen sind 
in der libgcc implementiert. Diese beiden Routinen (32-bit 
Multiplikation und unsigned Division) stehen in Assembler und sind 
reentrant, wie alle anderen Arithmetik-Routinen in der libgcc auch. 
Ansonsten taugte so eine Bibliothek bestenfalls für die Tonne.

Neben reentrant-Fähigkeit muss der Zugriff auch atomar erfolgen.

von Tom M. (tomm) Benutzerseite


Lesenswert?

Johann L. schrieb:

> sind reentrant, wie alle anderen Arithmetik-Routinen in der libgcc

Gut zu wissen, danke. Sorry für mein FUD. Ich hab die Probleme mit bzw. 
in meinem Code mittlerweile eliminiert (da war auch eine race condition 
drin, dein Stichwort "atomare Zugriffe" trifft ins schwarze). :)

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.