uwTick STM32 HAL überlaufsicher?

OP #7312158
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?

#7312171
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.

Gast #7312197
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.

Gast #7312220
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
#7312334
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?

Gast #7312503
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.

#7312647
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

Gast #7313094
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.

Gast #7313129
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.

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