Forum: Mikrocontroller und Digitale Elektronik SysTick (1ms) Uptime Design-Frage


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Adam P. (adamap)


Lesenswert?

Hallo zusammen,

ich bin gerade dabei mein System neu aufzusetzen und mache mir Gedanken 
über grundsätzliche Dinge die mir in der Vergangenheit aufgefallen sind.

µC: Cortex-M4

Wie es bis jetzt war:
Im SysTick Handler (1ms) wurde eine uint32_t Variable inkrementiert.
Die aufgerufenen Module aus meinem Round-Robin Scheduler nutzten den 
System-Tick um Timeouts zu berechnen oder als Zeitstempel für erzeugte 
Datenströme.

Das mit den Timeouts habe ich dann irgendwann geändert, so dass die 
Timeout Variablen vom gewünschten Wert aus dekrementiert und auf 0 
geprüft werden.

Es blieb jedoch noch das Problem des Zeitstempels für erzeugte Daten.
Würde die Hardware länger als 49,71... Tage laufen, käme der Überlauf.

Nun hatte ich die Idee eine Uptime zu nutzen:
1
struct uptime
2
{
3
   uint8_t day;
4
   uint8_t hour;
5
   uint8_t min;
6
   uint8_t sec;
7
   uint16_t ms;
8
};

1)
Wenn ich diese Uptime im SysTick aktualisiere und sie global verfügbar 
mache, hätte ich doch das Problem, dass mir der SysTick dazwischen 
funken könnte, z.B. bei:
1
sprintf(buf, "%02d:%02d:%02d.%03d | ",
2
   sys_uptime.hour, sys_uptime.min, sys_uptime.sec, sys_uptime.ms);

2)
Ich verwende eine get_uptime Funktion in der ich die Interrupts sperre 
und eine Kopie der Uptime zurückgebe.
Was jedoch dazu führen würde, dass ich jedes mal eine struct uptime 
Variable anlegen müsste - überall dort wo ich es verwenden möchte.

Weiterhin ist die Handhabung von einzelnen Variablen in der struct für 
einen Zeitstempel eher unpraktisch.

...das alles stellt mich noch nicht wirklich zufrieden.

3)
ich mache es ganz anders?

Mir fehlt irgendwie der richtige Ansatz.

Habt ihr Ideen / Vorschläge?

von Stefan ⛄ F. (stefanus)


Lesenswert?

So ist das halt, ich denke dass dein Lösungsansatz schon OK ist.

Im Vergleich zu deinem sprintf ist der Zeitaufwand für das Kopieren der 
Struktur verschwindend gering.

Beim Kopieren der Struktur kannst du das Sperren der Interrupts 
einsparen, indem du die ms zweimal liest und miteinander vergleichst. 
Wenn sie sich geändert haben, funkte der Systick Interrupt dazwischen. 
Nur dann liest du noch ein drittes mal. Die anderen Felder (sec, min, 
hour, day) können sich unmittelbar danach nicht mehr ändern, sind also 
ohne Extra-Aufwand zu kopieren.

von A. S. (achs)


Lesenswert?

Adam P. schrieb:
> Das mit den Timeouts habe ich dann irgendwann geändert, so dass die
> Timeout Variablen vom gewünschten Wert aus dekrementiert und auf 0
> geprüft werden.

Das ist eigentlich ein Rückschritt.

Adam P. schrieb:
> Würde die Hardware länger als 49,71... Tage laufen, käme der Überlauf.

Dann mache einen Reset (ist das sicherste) oder inkrementiere eine 
weitere Variable.

Dann hast Du das Problem prinzipiell zwar noch immer, aber nur sehr 
selten :-)

Generell kostet konsistentes lesen: entweder Interrupt so lange sperren, 
oder zweimal lesen und vergleichen

Alternative, wenn Du sicherstellen kannst, dass Du einmal pro 40 Tage 
fragst: die inkremente aufaddieren. Dann brauchst Du keine Interrupts 
sperren, solange systicker konsistent gelesen wird in der Loop.
1
t=Systicker;
2
diff=t-told;
3
told=t;
4
5
Systemzeit um diff updaten

Noch größerer Vorteil: du rechnest die Stunden etc nur, wenn du es 
brauchst, nicht jeden Tick.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Adam P. schrieb:
> Nun hatte ich die Idee eine Uptime zu nutzen:

Ob 49d oder 256d, ist doch kein großer Unterschied.
Was sind das für komische Datenströme, die nach 49d immer noch nicht 
verarbeitet wurden?

Für Zeitabstände <49d nimmt man einfach die Differenz zum Tick. 
Differenzen stimmen immer, auch bei einem Überlauf des Ticks.

von Adam P. (adamap)


Lesenswert?

A. S. schrieb:
> Das ist eigentlich ein Rückschritt.

Warum das?
Wenn ich ein Timeout benötige, dann setz ich den Wert und dieser wird 
durch den SysTick oder durch einen Timer auf 0 dekrementiert.
Besser als sowas:
1
timeout = sys_tick + MY_TIMEOUT;
2
3
if (timeout <= sys_tick)
4
   foo();

A. S. schrieb:
> Dann mache einen Reset (ist das sicherste)

Das mache ich ja auch. Habe mich nur gefragt, ob es auch eine elegantere 
Lösung gibt.

Peter D. schrieb:
> Was sind das für komische Datenströme, die nach 49d immer noch nicht
> verarbeitet wurden?

Ja es betrifft nicht direkt die Datenströme, viel mehr geht es um den 
Überlauf.

Ich versuch es irgendwie "richtig" zu machen, aber ich glaub, es gibt 
gar kein "richtig"-richtig :-)

von Stefan ⛄ F. (stefanus)


Lesenswert?

Adam P. schrieb:
> timeout = sys_tick + MY_TIMEOUT;

Weil Systick irgendwann man kurz vor dem Überlauf steht, und die 
Addition dann ein falsches Ergebnis liefert. Bei der Subtraktion hast du 
das Problem nicht:
1
  uint32_t start = sys_tick;
2
3
  if (sys_tick-start > MY_TIMEOUT) { ... }

sys_tick-start liefert immer den richtigen Wert, auch wenn 
zwischenzeitlich ein Überlauf statt fand.

: Bearbeitet durch User
von Adam P. (adamap)


Lesenswert?

Stefan ⛄ F. schrieb:
> sys_tick-start liefert immer den richtigen Wert, auch wenn
> zwischenzeitlich ein Überlauf statt fand.

Ja ok, das ergibt Sinn.
Aber ist das besser/schöner, als wenn ich in Modul X eine timeout 
Variable anlege, diese am "Timer" anmelde und dann setze und auf 0 
prüfe?
Oder sogar eine Funktion am Timer anmelde, die mir dann aufgerufen wird.

Was ich halt in den letzten Jahren immer festgestellt habe:
Im ersten Moment scheint eine Lösung perfekt, bis mehr und mehr dazu 
kommt und man dann merkt, ohhh neee, hätte ich das Grundsystem mal 
anders aufgebaut.

Deshalb meine jetzigen Gedanken zum grundlegenden Aufbau.

von Peter D. (peda)


Lesenswert?

Ich hatte hier mal meinen Scheduler vorgestellt. Ich benutze ihn sehr 
gerne.

Beitrag "Wartezeiten effektiv (Scheduler)"

von A. S. (achs)


Lesenswert?

Adam P. schrieb:
> Aber ist das besser/schöner, als wenn ich in Modul X eine timeout
> Variable anlege, diese am "Timer" anmelde und dann setze und auf 0
> prüfe?

Hängt von deinem Design ab. Eventgetrieben oder Mainloop (SPSloop).

Die Timer mit Systicker sind brotlos (fressen kein Brot = werden nur zur 
Auswertung geprüft), beliebig viele, lokal ohne anmelden, synchron zur 
Loop, ...

Von daher kann hier keiner einen Ansatz empfehlen ohne Deine Struktur zu 
kennen.

Trotzdem: Timer auf Basis Systicker solltest Du kennen. Sie sind so 
effizient, dass sie sich selbst dann lohnen, wenn Du Deine Timer 
vielfach verwendst.

von Stefan ⛄ F. (stefanus)


Lesenswert?

Es gibt nicht die eine ideale Lösung. Ohne dein gesamtes Projekt zu 
sichten kann ich dir nicht sagen, welche für dich die beste Lösung ist. 
Ich kann nur Alternativen aufzeigen, mit denen ich gut klar komme.

von Adam P. (adamap)


Lesenswert?

A. S. schrieb:
> Von daher kann hier keiner einen Ansatz empfehlen ohne Deine Struktur zu
> kennen.

Stefan ⛄ F. schrieb:
> Es gibt nicht die eine ideale Lösung. Ohne dein gesamtes Projekt zu
> sichten kann ich dir nicht sagen, welche für dich die beste Lösung ist.

Bis jetzt gibt es keinen Ansatz.

In der Vergangenheit sah das System so aus:
- Das Sampling wurde vom Timer jede 1ms aufgerufen, das hat die ADC 
getriggert und Daten in ein FIFO geschoben.
- Alles andere lief in der "Main" und hat entweder auf den SysTick oder 
auf verfügbare Daten reagiert.
Zusätzlich hatten die einzelnen Module noch eigene Timeouts, bzgl. 
Peripherie (USB/UART/I²C/SPI).

Nun wollt ich das alles besser strukturieren und es evtl. effizienter 
gestalten.

: Bearbeitet durch User
von Stefan ⛄ F. (stefanus)


Lesenswert?

Adam P. schrieb:
> Nun wollt ich das alles besser strukturieren und es evtl. effizienter
> gestalten.

Wie gesagt kenne ich dein Projekt nicht. Mein Bauch grummelt, dass du 
dich eventuell zu sehr auf unwichtige Details konzentrierst.

Die Struktur sollte für alle am Projekt beteiligten offensichtlich sein, 
also leicht nachvollziehbar. Dann ist sie gut. Primitive Strukturen sind 
manchmal sogar besser als ausgefuchste akademische Bauwerke.

Zur Effizienz: Solange dein Code sprintf() enthält, erscheint mir das 
Feilschen um einzelne Bytes und Taktzyklen geradezu lächerlich. Zudem 
ist dein Mikrocontroller bereits erheblich schneller als mein erster PC, 
auf dem ich ernsthafte Datenbank-Anwendungen nutzen musste.

Optimiere Effizienz nur da, wo es nötig ist. Solange dein Gerät 
funktioniert, ist es nicht nötig. Verschwende diese Zeit deines Lebens 
lieber damit, einen Sexual-Partner zu finden oder die um die Bedürfnisse 
Familie zu kümmern.

von Johannes S. (jojos)


Lesenswert?

für allgemeine Strukturierung wurden Betriebssysteme entwickelt, die 
enthalten die passende Elemente dafür.
Ein Systick ist keine für alles passende Lösung, bei Batteriebetrieb ist 
es z.B. nicht unbedingt gut das der Prozessor ständig geweckt wird. 
Etwas Tickless zu bauen ist aber auch nicht trivial, ich hätte keine 
Lust das Rad immer wieder neu zu erfinden.

von Adam P. (adamap)


Lesenswert?

Stefan ⛄ F. schrieb:
> Optimiere Effizienz nur da, wo es nötig ist. Solange dein Gerät
> funktioniert, ist es nicht nötig. Verschwende diese Zeit deines Lebens
> lieber damit, einen Sexual-Partner zu finden oder die um die Bedürfnisse
> Familie zu kümmern.

Ja ich glaub das ist diese immer wiederkehrende "Perfektion" die dann 
doch voll unnötig war.

Ich fang jetzt einfach mal mit KISS an und schau was das System mit der 
Zeit an zusätlichen Funktionen benötigt...
Mach mir wohl wieder zuviele Gedanken um Dinge die vllt. nie gebraucht 
werden.

von Peter D. (peda)


Lesenswert?

Adam P. schrieb:
> Ja ich glaub das ist diese immer wiederkehrende "Perfektion" die dann
> doch voll unnötig war.

Es ist schon sinnvoll, für immer wiederkehrende Aufgaben sich ein 
passendes Werkzeug einzurichten.
Mich hat das genervt, für jede Zeitverzögerung erst umständlich eine 
Variable anlegen zu müssen und im Timertick extra zu behandeln.
Die Idee mit der sortierten Liste und dem Callback habe ich in einem 
älteren Steuerprogramm gefunden und ich fand sie so bequem, daß ich sie 
übernommen habe.

von m.n. (Gast)


Lesenswert?

Adam P. schrieb:
> Im SysTick Handler (1ms) wurde eine uint32_t Variable inkrementiert.
> ...
> Würde die Hardware länger als 49,71... Tage laufen, käme der Überlauf.

Auf einem M4 habe ich keine Bedenken, einfach uint64_t zu verwenden.

von Stefan ⛄ F. (stefanus)


Lesenswert?

m.n. schrieb:
> Auf einem M4 habe ich keine Bedenken, einfach uint64_t zu verwenden.

Da die Zugriffe auf uint64 nicht atomar sind, muss man dann aber wieder 
Interrupts sperren. Ist nur schlimm, wenn man es vergisst.

von Adam P. (adamap)


Lesenswert?

m.n. schrieb:
> Auf einem M4 habe ich keine Bedenken, einfach uint64_t zu verwenden.

Ja das habe ich mir auch schon überlegt.

Peter D. schrieb:
> Mich hat das genervt, für jede Zeitverzögerung erst umständlich eine
> Variable anlegen zu müssen und im Timertick extra zu behandeln.
> Die Idee mit der sortierten Liste und dem Callback habe ich in einem
> älteren Steuerprogramm gefunden und ich fand sie so bequem, daß ich sie
> übernommen habe.

Ja schon, ich muss mir nochmal überlegen wie ich meine "Software-Tasks" 
also die Module die vom Scheduler in der main aufgerufen werden, 
behandel - sowie die Timeouts.

Habe da zwar schon die Funktionalität, dass jedes Modul seine 
Zeitscheibe zum Aufruf selbst einstellen kann, jedoch wäre ein Aufruf 
der Eventbezogen geschieht, noch eleganter.
Aber das kommt auch wieder auf den Einsatzzweck drauf an.

: Bearbeitet durch User
von Rechen Künstler (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ist nur schlimm, wenn man es vergisst.

Der Overflow, also der Update der oberen 32 Bit findet ja nur
alle 49,71... Tage statt. Also halb so wild ;-)

von m.n. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Da die Zugriffe auf uint64 nicht atomar sind, muss man dann aber wieder
> Interrupts sperren.

Ach Gott! Interrupts, die nur alle ms bedient werden müssen, kann man 
locker mal um < 50 ns verzögern.

von A. S. (achs)


Lesenswert?

Adam P. schrieb:
> Nun wollt ich das alles besser strukturieren und es evtl. effizienter
> gestalten.

Wenn Mainloop, dann brotlose Timer.

Und einmal mit den Eigenschaften der Überlaufrechnung vertraut machen. 
Wenn Du ein If oder ein % dabei verwendest, ist was falsch. Wenn ein 
Tick verloren gehen kann, ist was falsch. Wenn Du Interrupts sperren 
musst, ist was falsch.

Das Prinzip ist nicht nur bei Timern wichtig, sondern bei allen 
asynchronen Zählern..

Als Übung mach den Systicker z.b. nur 16 Bit groß und alle Zeiten unter 
30s. Wenn dann was falsch ist, fällt es eher auf

von Stefan ⛄ F. (stefanus)


Lesenswert?

m.n. schrieb:
> Ach Gott! Interrupts, die nur alle ms bedient werden müssen, kann man
> locker mal um < 50 ns verzögern.

Eben, deswegen schrieb ich im selben Absatz
> Ist nur schlimm, wenn man es vergisst.

Was wolltest du wirklich sagen?

von Stefan ⛄ F. (stefanus)


Lesenswert?

A. S. schrieb:
> Wenn Mainloop, dann brotlose Timer.

Was meinst du mit "brotlos"? Ich kenne den Begriff nicht.

von A. S. (achs)


Lesenswert?

Stefan ⛄ F. schrieb:
> Was meinst du mit "brotlos"? Ich kenne den Begriff nicht

Fressen kein Brot, kosten nur im Augenblick der Abfrage Rechenzeit. Und 
brauchen keinen feste reservierten Speicher wie ein Array von TIM_MAX.

Davon kannst Du also einen verwenden oder 5000, ohne dass dein 
Tickerinterrupt etwas davon weiß. Du kannst sie im Stack anlegen, 
brauchst sie nirgends anmelden, etc

Und bei einem 4-Byte Systicker braucht es nur 4-10 Byte RAM, je nach 
Funktionalität.

von Stefan ⛄ F. (stefanus)


Lesenswert?

A. S. schrieb:
>> Was meinst du mit "brotlos"? Ich kenne den Begriff nicht
> Fressen kein Brot ...
Danke

von Adam P. (adamap)


Lesenswert?

A. S. schrieb:
> Fressen kein Brot, kosten nur im Augenblick der Abfrage Rechenzeit. Und
> brauchen keinen feste reservierten Speicher wie ein Array von TIM_MAX.
>
> Davon kannst Du also einen verwenden oder 5000, ohne dass dein
> Tickerinterrupt etwas davon weiß. Du kannst sie im Stack anlegen,
> brauchst sie nirgends anmelden, etc

Jetz bin ich ein wenig verwirrt.
Könntest du mir ein kleines Bsp. zeigen?

Das der Interrupt davon nichts wissen muss, kann ich ja noch 
nachvollziehen.
Aber wenn ich mir eine Variable anlege, dann braucht die doch auch 
Speicherplatz.

von A. S. (achs)


Lesenswert?

Adam P. schrieb:
> Aber wenn ich mir eine Variable anlege, dann braucht die doch auch
> Speicherplatz.

Ja, aber nur

A. S. schrieb:
> 4-10 Byte RAM, je nach Funktionalität.

Peter z.b. braucht für seine eine feste Liste, Du musst also wissen, ob 
Du 3 oder 1000 brauchst.

Die einfachste Version besteht aus timStart/Stop/Running/Expired braucht 
2/4byte RAM und ein Dutzend Zeilen Code.

Später am PC gerne ein Beispiel.

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


Lesenswert?

Adam P. schrieb:
> Mir fehlt irgendwie der richtige Ansatz.

Zu allererst mache dir klar, daß du immer mit Überläufen leben mußt - es 
sei denn, du zählst deine Zeitstücke in einer Variablen unendlicher 
Bitbreite - was praktisch nicht zu realisieren ist.

Also ist ein wenig Bescheidenheit angesagt. Die allumfassende 
Generallösung wirst du nicht erreichen. Wähle am sinnvollsten die 
Bitbreite der Variablen für das Zählen deiner Millisekunden so, daß 
deine HW damit am besten klarkommt, zähle damit nur die Zeit innerhalb 
einee Tages - und benutze für das Zählen der Tage ab einem gewählten 
Stichdatum eine andere Variable. Wenn du für beide Variablen long 
nimmst, reicht das für mehr als die nächsten 5 Mio Jahre. Das ist 
vemutlich die beste Lösung deines Problems.

W.S.

von Peter D. (peda)


Lesenswert?

A. S. schrieb:
> Peter z.b. braucht für seine eine feste Liste, Du musst also wissen, ob
> Du 3 oder 1000 brauchst.

Einspruch. Du mußt nur wissen, ob Du 3 oder 1000 gleichzeitig 
brauchst.
Wenn Du 1000 insgesamt, aber nur 100 gleichzeitg brauchst, spart die 
Liste ne Menge Speicherplatz und CPU-Zeit.

von Adam P. (adamap)


Lesenswert?

A. S. schrieb:
> Später am PC gerne ein Beispiel.

Ja das wäre super.
Nur das ich zu 100% verstehe wie du das genau meinst.

von A. S. (achs)


Lesenswert?

1
typedef uint16_t TickType;   /* ob 16 oder 32 Bit*/
2
#define MAX_TICKS (50000)    /* Maximalwert des Timers. Deutlich unter dem Überlauf */ 
3
typedef struct               /* Struktur der Timer, wenn auch nur ein Element */
4
{
5
    TickType ticks;
6
} TimType;
7
extern uint32_T SysTicker;    /* SysTicker muss >= TickType sein */
8
9
/* starten des Timers */
10
void TimerStart(TimType &t, TickType ticks)
11
{
12
    if(ticks>MAX_TICKS) ticks=MAX_TICKS; /* Begrenzen */
13
    t->ticks=SysTicker + ticks;          /* jetzt + ticks */  
14
    if(!t->ticks) t->ticks++;            /* notfalls +1 */ 
15
}
16
17
/* Stoppen */
18
void TimStop(TimType &t)
19
{
20
    t->ticks=0; 
21
}
22
23
/* Gestartet und Zeit ist noch nicht abgelaufen */
24
int TimRunning(TimType &t)
25
{
26
TickType ticks=t->ticks-SysTicker;
27
28
    if(!t->ticks) return 0;          /* 0 wenn nicht gestartet */
29
    if(ticks<=MAX_TICKS+1) return 1; /* 1 wenn noch läuft */
30
    t-ticks=0;                       /* stoppen */
31
    return 0;                        /* 0, läuft nicht mehr */
32
}
33
34
/* Elapsed: Gestartet UND Zeit ist gerade abgelaufen */
35
int TimElapsed(TimType &t)
36
{
37
    if(!t->ticks) return 0;          /* 0 wenn nicht gestartet */
38
    return !TimRunning(t);           /* das Gegenteil von Running */
39
}
40
41
42
/* Verwendung im Modul Lampe, mit Elapsed */
43
44
static TimType TimAn;
45
46
void LampeAn(void)
47
{
48
    TimStart(&TimAn, 1000);
49
    LampeEinschalten();
50
}
51
52
/* zyklische Funktion */
53
void LampeMain(void)
54
{
55
   ...
56
   if(TimElapsed(&TimAn)) LampeAusschalten();
57
   ...
58
}
59
60
/* Verwendung im Modul ADC, BurstMessung für 3 Sekunden */
61
62
static TimType TimBurst;
63
64
void ADCBurstStart(void)
65
{
66
    TimStart(TimBurst, 3000);    
67
}
68
69
void ADCMain(void)
70
{
71
    ...
72
    if(TimRunning(&TimBurst)) ADCBurst(...);
73
    ...
74
}

Achtung: Die Timer müssen zyklisch ausgewertet werden. Genauer: 
innerhalb des "Deutlich" aus Zeile 3, hier also innerhalb 10s.

Bei einem Start und a oder b, da beide den Timer ggf. stoppen.

Man kann das dann sukzessive erweitern: Mit eigenem Bit für Start (dann 
fällt der offset von 1ms bei 0 weg), mit Speichern des Reload-Wertes, 
mit zyklischem Timer, der sich immer wieder neue aufzieht (Tick-Genau 
oder ab jetzt), selbstständig Funktionen startet, ...

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Adam P. schrieb:

> Im SysTick Handler (1ms) wurde eine uint32_t Variable inkrementiert.
> Die aufgerufenen Module aus meinem Round-Robin Scheduler nutzten den
> System-Tick um Timeouts zu berechnen oder als Zeitstempel für erzeugte
> Datenströme.
>
> Das mit den Timeouts habe ich dann irgendwann geändert, so dass die
> Timeout Variablen vom gewünschten Wert aus dekrementiert und auf 0
> geprüft werden.

Das beides hat erstmal nicht direkt miteinander zu tun. Die Timeouts 
kann man also schlicht aus den Betrachtungen eleminieren.

> Es blieb jedoch noch das Problem des Zeitstempels für erzeugte Daten.
> Würde die Hardware länger als 49,71... Tage laufen, käme der Überlauf.

Na und? Dann muss man halt einfach "breiter" zählen. Schon mit einem 
weiteren 32Bit-Wort als Zählererweiterung wirst du ganz sicher keinen 
Überlauf mehr erleben...

Und der Performanceverlust ist minimal, da nur alle ca. 4 Milliarden 
Increments mal die Zählererweiterung auf den Stand der Dinge gebracht 
werden muss.

Ich begreife dein Problem nicht.

von Nop (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:

> Da die Zugriffe auf uint64 nicht atomar sind, muss man dann aber wieder
> Interrupts sperren.

Nein, muß man nicht, und das wurde auch schon gesagt. Erst lesen, dann 
posten: Beitrag "Re: SysTick (1ms) Uptime Design-Frage"

von Stefan ⛄ F. (stefanus)


Lesenswert?

Nop schrieb:
> Nein, muß man nicht

Ja stimmt. Die Alternative mit 2-3 mal lesen hatte ich ja selbst schon 
vorher genannt.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Eine dritte Möglichkeit auf Cortex-M wäre natürlich LDRD. Das sind zwar 
auf dem Bus zwei Speicherzugriffe, aber wenn da ein Interrupt 
reingrätscht, wird danach LDRD komplett von vorne gestartet - was hier 
genau das Verhalten wäre, was man braucht.

Mit etwas Glück macht der Compiler sowieso ein LDRD aus dem Laden eines 
uint64_t, aber das sollte man im Disassembly nachprüfen. Für LDM gilt 
das übrigens gerade nicht, sondern das würde stattdessen an der Stelle 
fortgesetzt, wo der Interrupt passiert ist, so daß eine Inkonsistenz 
möglich wäre.

von m.n. (Gast)


Lesenswert?

Nop schrieb:
> Mit etwas Glück macht der Compiler sowieso ein LDRD aus dem Laden eines
> uint64_t, aber das sollte man im Disassembly nachprüfen.

In einem Programm, wo viel mit uint64_t gearbeitet wird, wimmelt es nur 
so von LDRD und STRD. Das werden wohl alle Compiler verwenden.
Danke für den Hinweis!

von Purzel H. (hacky)


Lesenswert?

Wenn man viele Timer benoetigt, zB bei einem Multitasking System, 
verwendet man Timer Queues, bei denen die Zeiten einsortiert werden. Der 
einsortierte Wert ist dann nur noch die Differenz zum Vorhergehenden. 
Eine Queue muss nicht als dynamische Struktur vorliegen, sondern kann 
auch als festes Array mit Pointern implementiert werden.

: Bearbeitet durch User
von Til S. (Firma: SEGGER) (til_s)


Lesenswert?

Man könnte alternativ auch ein RTOS verwenden das dieses Problem bereits 
gelöst hat:
https://www.segger.com/doc/UM01001_embOS.html#OS_TIME_Getus64

Mikrosekunden Auflösung und kein Überlauf in den nächsten ~584942 Jahren 
;-).

von Nop (Gast)


Lesenswert?

Til S. schrieb:
> Man könnte alternativ auch ein RTOS verwenden das dieses Problem
> bereits gelöst hat:

Man könnte auch einfach mal nicht spammen. Hier offtopic kommerzielle 
eigene Produkte reinzuspammen ist nämlich auch mit Smiley immer noch 
Sch**ße.

von Adam P. (adamap)


Lesenswert?

Nop schrieb:
> Til S. schrieb:
>> Man könnte alternativ auch ein RTOS verwenden das dieses Problem
>> bereits gelöst hat:
>
> Man könnte auch einfach mal nicht spammen.

Hey Til,
danke für deine Info, aber ein RTOS würde in diesem Fall nicht in Frage 
kommen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.