von uint16 nach uint32 und wieder zurück.

Persönliche Seite #2480228
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?
Gast #2480241
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
#2480273
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
Persönliche Seite #2481863
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...
Persönliche Seite #2484110
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.

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