Mahlzeit!
Ein Fundstück mit allen Datentypen die es gibt:
1
voiddelay_us(uint8_tus)
2
{
3
uint32_tt0;
4
5
t0=TIM6->CNT;// 1MHz, 16 Bit
6
while((uint16_t)(TIM6->CNT-t0)<us){};
7
return;
8
}
Gibt es ein Argument für die seltene Kombination von 8, 16 und 32 Bit?
Oder evt. sogar einen vernünftigen Grund? Ja, intern wird meistens mit
32 Bit gerechnet, da muss man aufpassen, aber warum die Beschränkung auf
uint8_t?
Da kann man nur spekulieren. unit8_t mag daher kommen das wirklich keine
Verzögerungen > 255 µs benötigt werden. Oder weil eine vorhandene
Schnittstelle nachgebaut wurde.
unit32_t für den 16-Bit Timer und das Gehampel mit dem Cast der
Differenz auf uint16_t sieht mir nach einem verzweifelten, aber
gescheiterten Versuch aus den Timer-Wraparound unter Kontrolle zu
bekommen.
Hannes J. schrieb:> Da kann man nur spekulieren. unit8_t mag daher kommen das wirklich> keine Verzögerungen > 255 µs benötigt werden. Oder weil eine vorhandene> Schnittstelle nachgebaut wurde.> unit32_t für den 16-Bit Timer und das Gehampel mit dem Cast der> Differenz auf uint16_t sieht mir nach einem verzweifelten, aber> gescheiterten Versuch aus den Timer-Wraparound unter Kontrolle zu> bekommen.
Timer-Wraparound, und zu garantieren dass delay_us(255) auch
funktioniert.
LG, Sebastian
Hannes J. schrieb:> unit32_t für den 16-Bit Timer und das Gehampel mit dem Cast der> Differenz auf uint16_t sieht mir nach einem verzweifelten, aber> gescheiterten Versuch aus den Timer-Wraparound unter Kontrolle zu> bekommen.
Gescheitert ist da nichts. Der cast nach uint16_t ist genau dafür da,
den Wrap around im Ergebnis zu maskieren. Nur t0 hätte auch ein uint16_t
sein können. Dann würde die Subtraktion zwar als int gerechnet, und
nicht als unsigned, der cast fängt das aber wieder ein.
Oliver
Sebastian schrieb:> Timer-Wraparound, und zu garantieren dass delay_us(255) auch> funktioniert.
Das Argument zu delay_us() ist dafür egal. Eine Differenz von 255 (und
mehr) kannst du problemlos mit einem uint16_t abbilden - der natürlichen
Größe dieses 16-Bit Timers. Dafür braucht du kein uint32_t.
Nach den neuesten Forschungsergebnissen stammen die uint32_t aus dem
offiziellen STM-Header. Weil es auch 32-Bit Timer gibt und man nur eine
einheitliche struct möchte. "t0 = TIM6->CNT" ist also 32 Bit breit, auch
wenn die Hardware nur halb so breit ist.
Weil die CPU und C immer mit 32 Bit rechnen, wäre uint16_t fast schon
unnatürlich. So ist es zwar unübersehbar, dass der Timer nur 16 Bit hat,
aber es kostet einen Maschinenbefehl mehr:
1
voiddelay_us(uint16_tus)
2
{
3
uint16_tt0;
4
t0=(uint16_t)TIM6->CNT;
5
while(((uint16_t)TIM6->CNT-t0)<us){};
6
return;
7
}
Edit: das eigentliche Problem mit dem delay_us war ein ganz anderes: der
Timer hatte effektiv nur 11½ Bit. Jemand hatte ihn für Experimente
missbraucht und bei 3333 überlaufen lassen :)
Ich wage zu bezweifeln, daß der Ansatz sonderlich gut ist. Wenn es um
Mikrosekunden geht, und man die auch ansatzweise genau haben will, will
man
nicht einfach C-Code, auch nicht mit einem Timer und auch nicht als
normale Funktion. Sondern da nimmt man ein ASM-Macro, das kriegt man
fast taktgenau hin. Das braucht auch keinen Timer, nur die Kenntnis der
CPU-Frequenz.
Falk B. schrieb:> Sondern da nimmt man ein ASM-Macro, das kriegt man fast taktgenau hin.> Das braucht auch keinen Timer, nur die Kenntnis der CPU-Frequenz.
Nur können solche Schleifen sehr von Randbedingungen wie Waitstates und
Alignment abhängig sein. Wenn der Prozessor deutlich komplexer ist als
AVR. Empfehlenswert ist also eine Kalibrierung exakt jener Schleife per
Timer beim Start. Weshalb eine Funktion auch besser ist als inline Code,
dessen Alignment variieren kann.
(prx) A. K. schrieb:> Empfehlenswert ist also eine Kalibrierung exakt jener Schleife per Timer> beim Start.
Es geht um us. Klar kann da jemand mit einem 3 MHz-Quarz arbeiten, aber
wenn selbst sowas zu Dissertation verkommt, dann versteht das irgendwann
keiner mehr.
Ein delay mit 1us Auflösung liefert irgendwas zwischen 0 und 2us +
Aufruf wenn man mit 1 aufruft. Das tut es ab ein paar Mhz.
Und an den TO: die uint8 für die Zeit sind der beste Weg, das
idiotensicher auf kleine Werte zu begrenzen.
Falk B. schrieb:> Sondern da nimmt man ein ASM-Macro, das kriegt man fast taktgenau hin. Das> braucht auch keinen Timer, nur die Kenntnis der CPU-Frequenz.
Bei dem STM32 wird das in der Regel nicht mehr so einfach klappen. Das
funktioniert nur bei sehr einfachen Prozessoren.
A. S. schrieb:> (prx) A. K. schrieb:>> Empfehlenswert ist also eine Kalibrierung exakt jener Schleife per Timer>> beim Start.>> Es geht um us. Klar kann da jemand mit einem 3 MHz-Quarz arbeiten, aber> wenn selbst sowas zu Dissertation verkommt, dann versteht das irgendwann> keiner mehr.
Wir wissen nicht, mit welchem Takt der Prozessor läuft. Können auch 400
Mhz sein, dann ist eine µs 400 Taktzyklen lang.
A. S. schrieb:> Und an den TO: die uint8 für die Zeit sind der beste Weg, das> idiotensicher auf kleine Werte zu begrenzen.
Wegen Sitte und Moral, technisch wären 16 Bit doch auch kein Problem. In
irgendeiner Initialisierung warte ich auf den Sekundentakt einer RTC, da
wäre ein delay_us(eine-halbe-Sekunde) passend.
Wie oft braucht man denn ein so genaues delay, dass sich eine
Kalibrierung lohnt? Immerhin müsste man in so einem Fall auch die
Interrupts abschalten. Meistens(?) reicht es doch, wenn man mindestens
x us wartet. Ansonsten hilft sowieso nur DMA oder Assembler. Aber das
ist von der Natur schon klug eingerichtet: bei Chips ohne DMA
funktioniert Zyklen zählen.
Falk B. schrieb:> Sondern da nimmt man ein ASM-Macro, das kriegt man> fast taktgenau hin.
Jeder Interrupt verlängert das Delay zusätzlich. Bei der Timernutzung
entsteht zwar auch ein Jitter, aber keine Fehlerakkumulation.
Bauform B. schrieb:> Wegen Sitte und Moral, technisch wären 16 Bit doch auch kein Problem.
Wenn man es mit 30.000 aufrufen kann, dann tut es jemand, auch im
Interrupt.
Bei 255 kommt wenigstens der ms-Scheduler noch zwischendurch dran ;-)
A. S. schrieb:> Wenn man es mit 30.000 aufrufen kann, dann tut es jemand, auch im> Interrupt.
When you make something fool proof, someone will invent a better fool.
chris_ schrieb:> Hier die artverwandte Routine nur mit uint8:> Beitrag "Re: rollover save timer in c"
Das kann zwar:
Sebastian schrieb:> garantieren dass delay_us(255) auch funktioniert.
aber nicht bei delay_us(0).