Forum: Mikrocontroller und Digitale Elektronik uwTick STM32 HAL überlaufsicher?


von Donald (tick1234)


Lesenswert?

Per default ist uwTick eine 32bit variable?!? Mit 1ms tick time wird 
diese zwangsläufig nach 49.7 Tagen überlaufen. Im HAL sehe ich keine 
Vorkehrungen diesbezüglich (z.b. in der HAL delay funktion).

Folgende Fragen:
1. WTF ST?!?
2. Giebts irgendwo eine Einstellung, dass diese per default als 64bit 
variable ausgeführt wird?

Falls dies nicht möglich:
3. Wenn ich HAL_IncTick sowie HAL_GetTick im usercode überschreibe, was 
muss ich alles beachten, damits weiterhin kompatibel ist mit dem HAL?
4. Wie kann ich sicherstellen, dass das HAL nicht nach 49.7 Tagen 
crasht?

von Harald A. (embedded)


Lesenswert?

Wieso “crasht” der deiner Meinung nach?
Solange Du keine Zeitspannen größer als 49 Tage messen willst ist das ja 
kein Problem. Solange Du den alten Vergleichswert im gleichen UINT32 
speicherst kannst Du die ohne weiteres voneinander abziehen. Kannst ja 
mal zwei UINT32 definieren und 0x00000010-0xFFFFFFF0 ausrechnen lassen.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Donald schrieb:
> WTF

Wieso WTF? Was wäre dir denn lieber, dass der Mikrocontroller vorher 
angehalten wird und streikt?

Donald schrieb:
> Giebts irgendwo eine Einstellung, dass diese per default als 64bit
> variable ausgeführt wird?

WTF? Die 64 Bit laufen auch irgendwann über. Damit verschiebst du das 
Problem nur auf später (ja ich weiß, bis dahin sind wir eh alle tot). 
Außerdem sind dann alle Zugriffe nicht mehr Atomar, brauchen also 
zusätzlich Semaphoren. Bei so kleinen Intervallen ist das keine gute 
Idee. Der Mikrocontroller soll schließlich noch etwas anderes machen 
können, als nur Millisekunden zu zählen.

von Donald (tick1234)


Lesenswert?

Harald A. schrieb:
> Wieso “crasht” der deiner Meinung nach?

nun die hal delay funktion dauert dann halt anstelle einiger ms 49 Tage. 
Dies darf man wohl als crash bezeichnen:P.

Stefan F. schrieb:
> Die 64 Bit laufen auch irgendwann über.

ja genau, aber nicht mehr in unserem Sonnensystem (also wo die sonne 
noch brennt :P)

von Stefan F. (Gast)


Lesenswert?

Donald schrieb:
> nun die hal delay funktion dauert dann halt anstelle einiger ms 49 Tage.

Nein, das stimmt nicht. Auch während eines Überlaufs kannst du 
Intervalle bis 49 Tage korrekt messen bzw. pausieren.
1
uint32_t start, duration;
2
start = HAL_GetTick();
3
tu etwas...
4
duration = HAL_GetTick();

oder:
1
uint32_t start;
2
while (HAL_GetTick() - start < 10000);  // 10s warten

Die "duration" ist richtig, auch wenn der Timer zwischendurchn einmal 
überläuft.

Wichtig ist dabei die Subtraktion. Mit einer Addition funktioniert es 
nicht korrekt:
1
uint32_t until;
2
until = HAL_GetTick() + 10000;
3
while (HAL_GetTick() < until); // 10s warten

von pegel (Gast)


Lesenswert?

Es handelt sich hier um ms.
Wenn es zum Überlauf kommt, einfach einen Rundenzähler bei Bedarf 
erhöhen.
Das reicht dann bis zur Ewigkeit und darüber hinaus. :)

von pegel (Gast)


Lesenswert?

So kann man auch leicht eine 64bit Variable basteln.

von Stefan F. (Gast)


Lesenswert?

Korrektur:
1
uint32_t start, duration;
2
start = HAL_GetTick();
3
tu etwas...
4
duration = HAL_GetTick() - start;

von Guest (Gast)


Lesenswert?

Ich würde sagen WTF lern grundlagen.

Such mal bei Goolge oder einer anderen Suchmaschine deiner Wahl nach 
"Arduino millis() überlauf", vielleicht ist das mehr auf deinem Niveau 
erklärt.

von Donald (tick1234)


Lesenswert?

Stefan F. schrieb:
> Nein, das stimmt nicht.

Stefan F. schrieb:
> Wichtig ist dabei die Subtraktion. Mit einer Addition funktioniert es
> nicht korrekt:

stimmt, genau mein denkfehler, danke

edit: quatsch: subtraktion hat das gleiche Problem, wenn der Zählerwert 
tief ist...

: Bearbeitet durch User
von Harald A. (embedded)


Lesenswert?

Donald schrieb:
> edit: quatsch: subtraktion hat das gleiche Problem, wenn der Zählerwert
> tief ist...

Mach doch mal ein Beispiel mit Zahlen bitte.

von Bauform B. (bauformb)


Lesenswert?

Vielleicht so? Dann scheint es zu funktionieren. Wir nehmen mal an, dass 
der Zähler nur 3 Bit breit ist und dass die Subtraktion intern als 
Addition mit dem negativen Wert ausgeführt wird.
zum Beispiel 2 minus 1:
2 ist 010;
das Komplement von 1 ist 110, plus 1 ergibt 111;
010 plus 111 ergibt 1001, das wird bei 3 Bit abgeschnitten, ergibt 001
1
angenommen, start ist 011, das Komplement davon 100, plus 1 macht 101.
2
Zähler -start  Zähler+(-start)  3 Bit
3
 100     101       1001          001    // 4 - 3 = 1
4
 101     101       1010          010
5
 110     101       1011          011
6
 111     101       1100          100    // 7 - 3 = 4
7
 000     101        101          101    // 0 - 3 = 5
8
 001     101        110          110    // 1 - 3 = 6
Aber auf einem Cortex-M4 ist nicht einmal ein 32-Zähler garantiert 
atomar, wenn nämlich die Variable nicht word aligned ist. Oder ist sie 
das immer? Ehrlich? Umgekehrt kann auch ein 64-Bit Zähler funktionieren, 
wenn man zum Lesen LDRD nimmt und die Timer-Interupt-Routine nicht 
unterbrochen werden kann. Oder?

: Bearbeitet durch User
von Kaj (Gast)


Lesenswert?

Bauform B. schrieb:
> wenn nämlich die Variable nicht word aligned ist. Oder ist sie
> das immer?
Wenn man dem Compiler nichts anderes Mitteilt, würde ich mich wundern, 
wenn die Variablen nicht aligned sind.

von Steve van de Grens (roehrmond)


Lesenswert?

Bauform B. schrieb:
> Aber auf einem Cortex-M4 ist nicht einmal ein 32-Zähler garantiert
> atomar, wenn nämlich die Variable nicht word aligned ist. Oder ist sie
> das immer?

Mit den Standardeinstellungen ist sie das. Und ja, wenn man unbedingt 
will, kann man sein eigenes Programm sabotieren.

Bauform B. schrieb:
> Umgekehrt kann auch ein 64-Bit Zähler funktionieren,
> wenn man zum Lesen LDRD nimmt und die Timer-Interupt-Routine nicht
> unterbrochen werden kann. Oder?

Es geht nicht nur um die Timer ISR, sondern um die Konsumenten des 
Zählerstandes. Da musst du immer mit Unterbrechungen rechnen, es sei 
denn, du blockierst sie absichtlich.

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

Steve van de Grens schrieb:
> Bauform B. schrieb:
>> Umgekehrt kann auch ein 64-Bit Zähler funktionieren,
>> wenn man zum Lesen LDRD nimmt und die Timer-Interupt-Routine nicht
>> unterbrochen werden kann. Oder?
>
> Es geht nicht nur um die Timer ISR, sondern um die Konsumenten des
> Zählerstandes. Da musst du immer mit Unterbrechungen rechnen, es sei
> denn, du blockierst sie absichtlich.

Ja, genau. Der LDRD Befehl kann unterbrochen werden, aber er wird danach 
neu gestartet. Ob sich der Zählerstand während der Unterbrechung ändert, 
ist egal. Erst wenn beide Hälften des 64-Bit-Zähler geladen wurden, kann 
der Konsument weiter laufen. Oder wie soll ich das Handbuch¹ verstehen:
1
A3.5.3 Atomicity in the ARM architecture
2
In ARMv7-M, the single-copy atomic processor accesses are:
3
 • All byte accesses.
4
 • All halfword accesses to halfword-aligned locations.
5
 • All word accesses to word-aligned locations.
6
LDM, LDC, LDC2, LDRD, STM, STC, STC2, STRD, PUSH, POP, VLDR,
7
VSTR, VLDM, VSTM, VPUSH, and VPOP instructions are executed
8
as a sequence of word-aligned word accesses. Each 32-bit
9
word access is guaranteed to be single-copy atomic.
10
A subsequence of two or more word accesses from the sequence
11
might not exhibit single-copy atomicity. When an access is
12
not single-copy atomic, it is executed as a sequence of
13
smaller accesses, each of which is single-copy atomic, at
14
least at the byte level. If an instruction is executed as
15
a sequence of accesses according to these rules, some
16
exceptions can be taken in the sequence and cause execution
17
of the instruction to be abandoned. On exception return,
18
the instruction that generated the sequence of accesses
19
is re-executed and so any accesses that had already been
20
performed before the exception was taken might be repeated.

[1] ARM v7-M Architecture ® Reference Manual, ARM DDI 0403E.d

von Steve van de Grens (roehrmond)


Lesenswert?

Bauform B. schrieb:
> aber er wird danach neu gestartet

Ah, gut zu wissen. Danke dass du darauf hingewiesen hast. Damit hätte 
ich gar nicht gerechnet, mit so einem Feature hatte ich noch nie zu tun.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Donald schrieb:
> Per default ist uwTick eine 32bit variable?!? Mit 1ms tick time wird
> diese zwangsläufig nach 49.7 Tagen überlaufen. Im HAL sehe ich keine
> Vorkehrungen diesbezüglich

Ich werde dich bei passender Gelegenheit deswegen mal gebührend 
bedauern.

Aber wozu so eine blöde Überlegung?

Normalerweise sollte man für eine Anwendung auch die Funktionalität (die 
man sich SELBER erarbeitet) planen. Und wenn du Verzögerungszeiten von 
50 Tagen oder mehr benötigst, dann brauchst du ganz gewiß nicht die 
Auflösung in Millisekunden.

Ganz generell: einfach nur stur zu brüllen "ich brauche mehr Bitbreite" 
ist das Gegenteil von klugem Programmieren. Jede Variable, die nicht 
unendlich viele Bit breit ist, läuft irgendwann mal über. Und der Ansatz 
"wenn's nur weit genug von jetzt ist, dann ist's mir egal - nach mir die 
Sintflut" mag praktikabel sein, ist aber im Kern unschön.

Ich habe sowas anders gelöst, hab das auch hier mal gepostet, falls du 
Bedarf haben solltest, dann suche einfach danach.

W.S.

von Stefan F. (Gast)


Lesenswert?

W.S. schrieb:
> der Ansatz
> "wenn's nur weit genug von jetzt ist, dann ist's mir egal - nach mir die
> Sintflut" mag praktikabel sein, ist aber im Kern unschön.

Ich erinnere nur an den Jahr 2000 Bug. Das nächste Problem steht bereits 
für Januar 2038 an, weil dann die 32 Bit Systemzeit (in Sekunden seit 
1.1.1970) überläuft.

Wer damals "Nach mir die Sinntflut" dachte, den hasse ich jetzt schon 
dafür.

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.