Forum: Mikrocontroller und Digitale Elektronik AVR DB - oder doch ein Compiler-Fehler?


von Timo (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
ich habe timing-Probleme bei einem Programm für den AVR128DB64 (Atmel 
Studio, GCC)
Mit einem 1ms-Timer-Interrupt zähle ich einen Millisekunden-Counter 
hoch.
Alle 1000 ms zähle ich in der Main-Loop einen Sekunden-Counter hoch.

Das Problem: Manche der gezählten Sekunden sind kürzer!
Ein externer Logic-Analyzer zählt alle etwa 16s nur 768ms.
Der anghängte Code enthält folgendes Snippet, das eine LED blinken 
lässt, wenn der Fehler auftritt.

 [c]       if (ms_counter_ticker > 999)
        {
            if (ms_counter_ticker < 999)
            {
        LED_red_on();        <- Dieser Abschnitt sollte niemals 
ausgeführt werden
        LED_red_off();
            }
            ms_counter_ticker = 0;
            ms_counter++;
        }
[\c]

        if (ms_counter >= 1)
        {
            LED_red_on();
            ms_counter = 0;
            LED_red_off();
        }

Mit dem Logic-Analyzer sieht man also bei der roten LED einen Puls, wenn 
alles richtig läuft
und 2 Pulse, wenn der "unmögliche" Code-Abschnitt ausgeführt wird.
In der Zeile "grüne LED" wird angezeigt, wann der Interrupt für die ms 
ausgeführt wird.
Ergänzend habe ich den Logic-Analyzer auch die ms-Pulse zählen lassen.
Es wirkt, als würde der Wert der Variable ms_counter_ticker zwischen den 
beiden if-Anweisungen geändert.
In dieser Zeit wird aber anscheinend kein Interrupt oder ähnliches 
ausgeführt (keine grüne LED)

Der angehängte Code ist vollständig.

Hat jemand eine Idee, wie ich da weiterkommen könnte?

von Ralf (Gast)


Lesenswert?

Timo schrieb:
> Der angehängte Code ist vollständig.

Welcher Code?

von Εrnst B. (ernst)


Lesenswert?

Glaskugel:
16 oder 32-Bit Variable, mglw. volatile, wird in der ISR hochgezählt und 
in der main() ohne ATOMIC_BLOCK o.Ä. gelesen.

von Ralf (Gast)


Lesenswert?

Ohne irgendwas vom Code zu kennen, kann es sein daß hier ein Watchdog 
Reset regelmäßig zuschlägt?

von Jems (Firma: oA) (timobomm)



Lesenswert?

Sorry, hatte unangemeldet Probleme mit den Anhängen

von Adam P. (adamap)


Lesenswert?

Zwischen deinen Abfragen if <> 999 kann gut möglich der Interrupt 
kommen, das siehst du nicht, weil du erst danach LED rot schaltest.

Versuch mal ein atomic Zugriff auf deine Variable:

Bsp.:
1
volatile uint32_t sys_tick_ms;
2
3
uint32_t sys_tick_get_ms(void)
4
{
5
  uint32_t ms;
6
  
7
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
8
  {
9
    ms = sys_tick_ms;
10
  }
11
  
12
  return ms;
13
}

@Jems (Firma: oA) (timobomm)
Oder benötigst du mehr Info? Hast du den Zusammenhang verstanden?

: Bearbeitet durch User
von Εrnst B. (ernst)


Lesenswert?

Adam P. schrieb:
> Versuch mal ein atomic Zugriff auf deine Variable:

Kleine Kosmetik-Verschönerung:
Der ATOMIC_BLOCK funktioniert auch, wenn man ihn mit return verlässt:
1
uint32_t sys_tick_get_ms(void) {
2
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
3
    return sys_tick_ms;
4
  }
5
}
(erzeugt aber denselben Code, insofern: Wirklich reine Kosmetik)

zweite Verschönerung:
1
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
2
      if (ms_counter_ticker > 999) {
3
            ms_counter_ticker -= 1000;
4
            ms_counter++;
5
      }
6
   }

==> wenn die Schleife erst z.B. bei ms 1010 vorbeikommt, gehen die 10 ms 
nicht verloren, die Sekunden bleiben gleich lang.

von Jems (Firma: oA) (timobomm)


Lesenswert?

Hallo Adam, Hallo Ernst,
Vielen Dank erstmal!

Adam P. schrieb:
> Zwischen deinen Abfragen if <> 999 kann gut möglich der Interrupt
Müsste ich das nicht anhand der "grünen LED" im Logic Analyzer sehen?!
(es gibt ja nur diesen einen Interrupt)

Ich habe mal die erste Funktion von Ernst bei mir eingefügt.
Verschönerungen gibt es später ;-)
1
        uint16_t tick = sys_tick_get_ms();
2
        if (tick > 999)
3
        {
4
            if (tick < 999)
5
            {
6
                LED_red_on();
7
                LED_red_off();
8
            }
9
            ms_counter_ticker = 0;
10
            ms_counter++;
11
        }
12
        
13
        if (ms_counter >= 1)
14
        {
15
            LED_red_on();
16
            ms_counter = 0;
17
            LED_red_off();
18
        }

Die Variable tick sollte ja jetzt "von außen" nicht mehr verändert 
werden können. Verschiedene Optimierungsstufe ausprobiert. Der 
"unmögliche" Teil des Codes wird nicht mehr angesprungen.

Das ist allerdings auch der Fall, wenn ich den Wert ms_counter_ticker 
vorher einer Variable zuweise, anstatt direkt zu vergleichen.
1
        uint16_t tick = ms_counter_ticker;
2
        if (tick > 999)
3
        {...
Aber es läuft in beiden Versionen immer noch nicht wie gedacht, einige 
Sekunden sind weiterhin nur 768ms lang.
Warum gilt manchmal angeblich auch in dieser Konstellation "768 > 999 = 
true" ?

von Flo (Gast)


Lesenswert?

Dein tick ist 16bit und dein ms_counter 32bit.
Beim Draufspeichern schmeißt du die oberen Bits weg.
Mach mal testweise eine 32bit tick Variable und schau obs noch vorkommt.

von Wendels B. (wendelsberg)


Lesenswert?

Jems schrieb:
> einige Sekunden sind weiterhin nur 768ms lang.

Meine Vermutung:
768 = 2^16 - (32 * 1000)

von Adam P. (adamap)


Angehängte Dateien:

Lesenswert?

Jems schrieb:
> Aber es läuft in beiden Versionen immer noch nicht wie gedacht

Irgendwie hast du da jetzt einiges durcheinander gewürfelt, was die 
verwendeten Variablen betrifft.

Schau mal die Datei im Anhang und probier die aus,
hab sie nur zusammengetippt, nicht getestet.

von Peter D. (peda)


Lesenswert?

Jems schrieb:
> ms_counter_ticker = 0;

Das Löschen muß natürlich auch atomar erfolgen.

von Julian R. (julianrott)


Lesenswert?

Peter D. schrieb:
> Jems schrieb:
>
>> ms_counter_ticker = 0;
>
> Das Löschen muß natürlich auch atomar erfolgen.

Junge Junge. Was für Umstände in Hochsprache. In Asm wär die Sache 
schnell klar, viel kürzer und ohne Atomarbimbamborium erledigt gewesen 🙊

von Ralf (Gast)


Lesenswert?

Ich würd ja lachen wenns sich doch noch als Compilerfehler rausstellt

von Peter D. (peda)


Lesenswert?

Julian R. schrieb:
> Was für Umstände in Hochsprache.

Nö, man muß es nur verstehen, was da passiert.
In ASM muß Du auch atomar klammern, nur heißt es dann "cli, st, st, 
sei".
Ich finde das keineswegs besser lesbar.

von Ralf (Gast)


Lesenswert?

Peter D. schrieb:
> In ASM muß Du auch atomar klammer

Unfug. Man muß es nur richtig anstellen. Hochsprache macht sich viele 
Probleme selber.

von EAF (Gast)


Lesenswert?

Ralf schrieb:
> Unfug. Man muß es nur richtig anstellen.

Dann zeige mal....

"Unfug" kann man leicht rufen.
Der Nachweis ist da schon schwieriger!
Kannst du ihn führen?

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Man muß es nur richtig anstellen.

Dann zeig doch mal. 16-Bit Zähler in ISR, Auswertung im Hauptprogramm, 
"cli" (und dessen SREG-Bitpfriemel-Äquivalent)  ist verboten.

von S. Landolt (Gast)


Lesenswert?

> Dann zeig doch mal. 16-Bit Zähler in ISR ...

Vielleicht meint Ralf etwas mit 'adiw' bei reservierten Registern 
r24&25.

von EAF (Gast)


Lesenswert?

S. Landolt schrieb:
> Vielleicht meint

Kann sein...
Damit endet es aber fix, wenn z.B. 5 solcher Zähler verwaltet werden 
sollen.
Oder diese Zähler 32Bit breit werden sollen, oder man genau diese 
Register für andere Zwecke benötigt.

von S. Landolt (Gast)


Lesenswert?

Nun, es stehen ja 32 Arbeitsregister zur Verfügung - irgendetwas wird 
sich da immer deichseln lassen.

Übrigens vergaß ich 'movw', das wird wohl auch benötigt.

von Adam P. (adamap)


Lesenswert?

Nur so als Idee,

vllt. sollten wir den TO nicht mit asm und all dem verwirren,
auch wenn es dem Verständnis hilft (aber nicht so)

Anscheinend hat er noch nicht verstanden das einzelne C Befehle, mehrere 
Takte benötigen und somit "Trennbar" sind. So das da ein Interrupt 
zwuschendrin einschlagen kann.

"Längenvergleich" ist hier irgendwie nicht angebracht.

von S. Landolt (Gast)


Lesenswert?

> ... Verständnis ...

Okay, dann wollen wir aber präzise formulieren:
> einzelne C Befehle, mehrere Takte benötigen und somit "Trennbar" sind
Es sind nicht die Takte - es liegt daran, dass sich ein C-Befehl aus 
mehreren Assembler-Instruktionen zusammensetzen kann.

von Adam P. (adamap)


Lesenswert?

S. Landolt schrieb:
> Okay, dann wollen wir aber präzise formulieren:
>> einzelne C Befehle, mehrere Takte benötigen und somit "Trennbar" sind
> Es sind nicht die Takte - es liegt daran, dass sich ein C-Befehl aus
> mehreren Assembler-Instruktionen zusammensetzen kann.

Genau das meine ich
und zwischen 2 Assembler-Instruktionen kann nun mal ein Interrupt 
entstehen.

Falls der TO aber keine Ahnung von asm hat,
kann es auch einfacher veranschaulicht werden, als nur um asm 
Optimierung zu diskutieren, oder?

von Adam P. (adamap)


Lesenswert?

S. Landolt schrieb:
> Es sind nicht die Takte - es liegt daran, dass sich ein C-Befehl aus
> mehreren Assembler-Instruktionen zusammensetzen kann.

Ach und was sind mehrere Assembler-Instruktionen...genau mehr Takte, 
siehe Takte je ASM Befehl im Datenblatt.

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

> ... einfacher veranschaulicht ...

Dann beschreiben Sie die Problematik anschaulich, ohne auf Assembler 
zurückzugreifen. Das vermisse ich bislang, und Jerns offenbar auch.

Und auf Ihren letzten Beitrag gehe ich lieber nicht ein: der ist zwar 
richtig, geht aber am entscheidenden Punkt vorbei - und dann wären wir 
schon wieder bei Assembler.

von Adam P. (adamap)


Lesenswert?

S. Landolt schrieb:
>> ... einfacher veranschaulicht ...
>
> Dann beschreiben Sie die Problematik anschaulich, ohne auf Assembler
> zurückzugreifen. Das vermisse ich bislang, und Jerns offenbar auch.
>
> Und auf Ihren letzten Beitrag gehe ich lieber nicht ein: der ist zwar
> richtig, geht aber am entscheidenden Punkt vorbei - und dann wären wir
> schon wieder bei Assembler.

Bin ich grad dran...
dauert halt ein wenig.

edit:
falls der TO das überhaupt noch braucht?

: Bearbeitet durch User
von Jems (Firma: oA) (timobomm)


Lesenswert?

Ich habe durch Eure Ratschläge viel gelernt!

Durch sehr kurzzeitige Unterdrückung der Interrupts während ich mir den 
benötigten Wert aus der Variable hole und in einer anderen speichere, 
kann diese nicht mehr zwischendurch verändert werden.

Ich habe das in dieser Form beherzigt: (schien mir einfach und ich kann 
es mir für das nächste Mal merken, ohne dass ich danach suchen muss)
1
cli();
2
  uint16_t tick = ms_counter_ticker;
3
sei();
4
if (tick > 999)
5
{...
6
cli();
7
ms_ticker = 0;
8
sei();
9
...}
Scheint zu funktionieren :-)
(Ich hatte aber nur sehr kurz Zeit das anzutesten)

Die Macros aus der ATOMIC lib werde ich mir natürlich auch mal genauer 
angucken.

Ganz herzlichen Dank an alle für die vielen Erklärungen!

von Forist (Gast)


Lesenswert?

Adam P. schrieb:
> Ach und was sind mehrere Assembler-Instruktionen...genau mehr Takte,
> siehe Takte je ASM Befehl im Datenblatt.

Nicht jeder Assembler-Befehl wird in einem Takt abgearbeitet.
Bei asm-Befehlen, die mehrere Takte benötigen, kann, obwohl sie mehrere 
Takte benötigen, trotzdem niemand dazwischen grätschen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Die Nutzung von volatile für ms_counter_ticker ist hier unnötig, das 
verhindert unnötigerweise Optimierungen. volatile sollte nur für 
Memory-Mapped-I/O eingesetzt werden, also hier für die HW-Register des 
AVR (s.a. mitgelieferte Header). Denn die Zugriffe auf die HW-Register 
dürfen nicht durch Optimierungen verändert (e.g. zusammengefasst) 
werden.

Was für eine gemeinsam genutzte Datenstruktur wie ms_counter_ticker 
benötigt wird ist:

- Atomarität für rmw-Operationen, und
- Verhinderung von Optimierungen über die Grenzen von kritischen 
Bereichen (atomarer Block) hinaus.

Die einzige Form von Nebenläufigkeit, die es auf AVR gibt, ist die 
Ausführung von ISRs. Damit kann Atomarität durch Abschalten der 
Interrupts erfolgen.

Eine Verhinderung von Optimierungen über die Grenzen eines kritischen 
Bereiches erreicht man durch eine memory-barrier.

Beides erledigt das ATOMIC_BLOCK Macro. Wie vorgeschlagen ist dies also 
in main() zu verwenden.

Allerdings ist beim AVR-DB zu beachten, dass die Interrupts in einer ISR 
nicht via SREG abgeschaltet werden. Daher kann eine ISR weiterhin durch 
eine andere ISR höherer Prio (oder NMI) unterbrochen werden. Gibt es 
also solche weiteren ISRs dafür, müssen die nieder-prioren ISRs 
ebenfalls als ATOMIC_BLOCK für den Zugriff auf die gemeinsam genutzten 
Datenstrukturen verwenden. Anderfalls reicht dort eine memory-barrier. 
Dafür gibt es das Macro _MemoryBarrier() in <avr/cpufunc.h>.

Auf das volatile sollte für die gemeinsam genutzte Datenstruktur 
verzichtet werden. Es ist zwar nicht falsch im dem Sinne, dass es zu 
Fehlern führt, aber es verursacht zuviel Aufwand im Maschinencode, da 
Optimierungen unterdrückt werden können.

von MaWin (Gast)


Lesenswert?

Forist schrieb:
> Bei asm-Befehlen, die mehrere Takte benötigen, kann, obwohl sie mehrere
> Takte benötigen, trotzdem niemand dazwischen grätschen.

Das ist falsch.
Der ARM Multiregister-push/pop ist unterbrechbar.

von Ralf (Gast)


Lesenswert?

Am besten ist doch man verzichtet auf gegenseitige Abhängigkeiten 
Main<>Interrupt indem man das Wesentliche (hier: die Sekunden zählen) 
gleich mit im Interrupt erledigt! Oder zweite Möglichkeit ist der 
Informationsaustausch über Nachrichten (ein Bit, ein Byte, ein 
Register-Flag, ein Register). Bei Schwierigkeiten wie den diesen sollte 
man den Hebel an der grundsätzlichen Programmstruktur ansetzen und nicht 
mit Atomar-Aktionen rumdoktern die letztlich nur den Programmfluss 
aufhalten.

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Das ist falsch.
> Der ARM Multiregister-push/pop ist unterbrechbar.

Das ist falsch. Wir sind nämlich hier beim unvergleichlichen AVR und 
nicht bei ARM.

von Peter D. (peda)


Lesenswert?

Ralf schrieb:
> Bei Schwierigkeiten wie den diesen sollte
> man den Hebel an der grundsätzlichen Programmstruktur ansetzen und nicht
> mit Atomar-Aktionen rumdoktern die letztlich nur den Programmfluss
> aufhalten.

Wenn 0,35µs Interruptpause den Programmfluß aufhalten, dann hast Du die 
völlig falsche CPU gewählt.
Das Atomar-Macro wurde erstellt, um die Programmstruktur übersichtlich 
zu halten und nicht selber was mit cli/sei basteln zu müssen.

Es ist ja gerade der Vorteil von Interrupts, daß sie eine weitere 
Ausführungsinstanz erstellen. Willst Du das nicht, mußt Du Interrupts 
generell verbieten.
MCs ohne Interrupts kommen bei mir nicht auf den Tisch. Gibt es die 
überhaupt noch?

von Ralf (Gast)


Lesenswert?

Peter D. schrieb:
> Wenn 0,35µs Interruptpause den Programmfluß aufhalten

Dazu fällt mir nur noch ein: Kleinvieh macht auch Mist.

> Das Atomar-Macro

bläst nur sinnlos das Programm auf wenn es auch anders geht.

> Es ist ja gerade der Vorteil von Interrupts, daß sie eine weitere
> Ausführungsinstanz erstellen.

Wer hat hier was gegen Interrupts?
Manch ein Programm besteht nur daraus. Im Hauptprogramm wird dann 
gepflegt geschlafen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:

>> Das Atomar-Macro
>
> bläst nur sinnlos das Programm auf wenn es auch anders geht.

Dann zeig doch einfach mal Deine Lösung ;-) Wir wollen alle lernen.

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Auf das volatile sollte für die gemeinsam genutzte Datenstruktur
> verzichtet werden. Es ist zwar nicht falsch im dem Sinne, dass es zu
> Fehlern führt, aber es verursacht zuviel Aufwand im Maschinencode, da
> Optimierungen unterdrückt werden können.

Weißt Du was? Ich verzichte bei solchen Simpel-Programmen gleich ganz 
auf Hochsprache. Da braucht man u.a. auf solche Befindlichkeiten keine 
Rücksicht nehmen und schreibt exakt das was für den Zweck wirklich 
erforderlich ist (im Beispiel des TO sogar mit wesentlich weniger 
getippten Zeichen).

Wilhelm M. schrieb:
> Dann zeig doch einfach mal Deine Lösung ;-)

Was hast Du an der beschriebenen Alternativ- Strategie nicht 
verstanden???
Mikrosekunden/Sekundenzählen reiche ich aber gerne nach. Obs dem TO und 
diesem C- Thema in Asm aber nützt?

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Auf das volatile sollte für die gemeinsam genutzte Datenstruktur
>> verzichtet werden. Es ist zwar nicht falsch im dem Sinne, dass es zu
>> Fehlern führt, aber es verursacht zuviel Aufwand im Maschinencode, da
>> Optimierungen unterdrückt werden können.
>
> Weißt Du was? Ich verzichte bei solchen Simpel-Programmen gleich ganz
> auf Hochsprache.

1. Ist das Beispiel des TO ein Beispiel, was sicher aus einem größeren 
Kontext entstammt.

2. Geht es hier um C/C++ und nicht um AVR-Assembler

> Wilhelm M. schrieb:
>> Dann zeig doch einfach mal Deine Lösung ;-)
>
> Was hast Du an der beschriebenen Alternativ- Strategie nicht
> verstanden???

Nichts.

> Mikrosekunden/Sekundenzählen reiche ich aber gerne nach. Obs dem TO und
> diesem C- Thema in Asm aber nützt?

S.o., gefragt ist hier C/C++ und nicht Assembler.

: Bearbeitet durch User
Beitrag #7252892 wurde von einem Moderator gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

Platin-Thermometer-Nutzer schrieb im Beitrag #7252892:
> Wilhelm M. schrieb:
>> Dann zeig doch einfach mal Deine Lösung ;-) Wir wollen alle lernen.
>
> Du nicht. Das lügst Du.

Danke ;-)
Ich lerne sehr gerne, aber nur, wenn es etwas zu lernen gibt ;-) Schau'n 
wir mal was so kommt ...

von Nop (Gast)


Lesenswert?

Ich nehme bei sowas lieber ein sequential lock (zum Lesen) als die 
Interrupts auszuschalten. Also die Variable solange lesen, bis zweimal 
nacheinander derselbe Wert rauskommt, und das in einer Getter-Funktion 
kapseln.

Ein Rücksetzen des Counters hat IMO gar nichts in der main verloren, 
sondern der Counter sollte im Interrupt mit Überlauf einfach immer 
weiter hochgezählt werden. Zeitvergleiche dann wie üblich mit 
Subtraktion.

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

Was mich bei der ganzen Diskussion wundert: warum wurde dem TO bislang 
noch nicht die Verwendung des RTC-Timers vorgeschlagen? Dank dessen 
TEMP-Registers kann der 16-Bit-Timerwert jederzeit auch bei aktiven 
Interrupts gelesen werden.

Grüßle,
Volker

von Wilhelm M. (wimalopaan)


Lesenswert?

Volker B. schrieb:
> Was mich bei der ganzen Diskussion wundert: warum wurde dem TO bislang
> noch nicht die Verwendung des RTC-Timers vorgeschlagen? Dank dessen
> TEMP-Registers kann der 16-Bit-Timerwert jederzeit auch bei aktiven
> Interrupts gelesen werden.

Weil das nicht das Problem des TOs ist: er hatte nicht verstanden, dass 
es bei nebenläufigem Zugriff auf eine gemeinsam genutzte Datenstruktur 
zu Wettlaufsituationen kommen kann.

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

Wilhelm M. schrieb:

> Weil das nicht das Problem des TOs ist: er hatte nicht verstanden, dass
> es bei nebenläufigem Zugriff auf eine gemeinsam genutzte Datenstruktur
> zu Wettlaufsituationen kommen kann.

Das Problem des TO ist m.E. dass seine Verzögerungszeit unregelmäßig 
ist.

Ich zitiere: "Das Problem: Manche der gezählten Sekunden sind kürzer!"

Genauso kann argumentiert werden, dass der TO nicht verstanden hat, dass 
der RTC-Timer genau für diese Aufgabe, die der TO sucht, implementiert 
wurde.

Grüßle,
Volker

von Wilhelm M. (wimalopaan)


Lesenswert?

Volker B. schrieb:
> Wilhelm M. schrieb:
>
>> Weil das nicht das Problem des TOs ist: er hatte nicht verstanden, dass
>> es bei nebenläufigem Zugriff auf eine gemeinsam genutzte Datenstruktur
>> zu Wettlaufsituationen kommen kann.
>
> Das Problem des TO ist m.E. dass seine Verzögerungszeit unregelmäßig
> ist.
>
> Ich zitiere: "Das Problem: Manche der gezählten Sekunden sind kürzer!"

Allerdings schreibt er dann:

Timo schrieb:
> Es wirkt, als würde der Wert der Variable ms_counter_ticker zwischen den
> beiden if-Anweisungen geändert.

Und genau da lag sein Problem.

Statt die RTC im AVR-DB zu nutzen, könnte man ihm auch vorschlagen, ganz 
auf Interrupts zu verzichten, oder einen anderen µC zu nutzen. Doch 
hätte das seinem Verständnis für das Problem hier nicht gedient.

: Bearbeitet durch User
von EAF (Gast)


Lesenswert?

Volker B. schrieb:
> dass seine Verzögerungszeit unregelmäßig
> ist.

Und genau das deutet auf konkurrierende Zugriffe hin.
Denn ein Quarz/Timer/Counter mag ein paar Takte daneben liegen, aber 
dann stabil.

Klar kann man die RTC Baustelle auch aufmachen.
Aber dennoch muss auch dieses Thema abgearbeitet werden, sonst hakts 
beizeiten woanders.
Und dann soll wieder der Compiler kaputt sein.

von Oliver S. (oliverso)


Lesenswert?

Volker B. schrieb:
> Genauso kann argumentiert werden, dass der TO nicht verstanden hat, dass
> der RTC-Timer genau für diese Aufgabe, die der TO sucht, implementiert
> wurde.

Nein, wurde er nicht. Auch wenn es hier zufällig um ganze Sekunden geht, 
di zufällig auch per RTC abgehandelt werden könnten, sind die Timer 
(u.a.) genau für die Aufgabe eines in regelmäßigen Zeitabständen 
feuernden Interrupts gedacht. Und das Problem, was der TO hat, ist ja 
unabhängig vom Zeitintervall.

Oliver

von Veit D. (devil-elec)


Lesenswert?

Hallo,

@ Wilhelm:
Warum soll eine Variable die außerhalb des normalen Programmablaufes 
geändert wird nicht als volatile deklariert werden? Die Optimierung muss 
doch genau deswegen aktiv verhindert werden, eben mit volatile. So mein 
Kenntnisstand.

: Bearbeitet durch User
von EAF (Gast)


Lesenswert?

Veit D. schrieb:
> Die Optimierung muss
> doch genau deswegen aktiv verhindert werden,

Nicht unbedingt verhindert!
Es muss zudem eine garantierte Abfolge sichergestellt werden.

DAS sind 2 Probleme, mindestens 2.
1. Dass die richtigen aktuellen Values verwendend werden,
2. und dass der Optimizer nicht die Statements (in diesem Fall 
unerwünscht) verwürfelt (was er in der Regel ja durchaus darf, das 
würfeln).

https://en.wikipedia.org/wiki/Memory_barrier

von Εrnst B. (ernst)


Lesenswert?

Veit D. schrieb:
> Warum soll eine Variable die außerhalb des normalen Programmablaufes
> geändert wird nicht als volatile deklariert werden? Die Optimierung muss
> doch genau deswegen aktiv verhindert werden, eben mit volatile. So mein
> Kenntnisstand.

Das mit dem "volatile" ist halt das was man Anfängern erstmal mit auf 
den Weg gibt.
Ist nicht falsch und funktioniert, und man hat wieder Ruhe vor nervigen 
Nachfragen.
Mit Erfahrung kommt dann das Wissen, was mit dem volatile erreicht wird, 
warum es eigentlich nicht ganz das richtige Sprachkonstrukt an der 
Stelle ist, und wie man es besser&eleganter machen kann.
Oder auch nicht. Ist egal, volatile tut ja.

Außer wenn, wie hier, die Variablen > 8 Bit werden... Dann muss man eben 
früher ins kalte Wasser.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> @ Wilhelm:
> Warum soll eine Variable die außerhalb des normalen Programmablaufes
> geändert wird nicht als volatile deklariert werden? Die Optimierung muss
> doch genau deswegen aktiv verhindert werden, eben mit volatile. So mein
> Kenntnisstand.

Das habe ich oben schon geschrieben.

Hier (etwas) ausführlicher:

volatile verhindert (fast) jede Art von Optimierung, denn es muss jedes 
load/store tatsächlich so ausgeführt werden, wie es im C/C++-Code steht. 
Dies ist für HW-Register erforderlich, da hier jedes load/store einen 
erwünschten Seiteneffekt auslöst. Für reine Datenstrukturen wie etwa 
einen integralen Zähler oder ähnliches ist dies aber nicht erforderlich.

Beispiel:
1
namespace {
2
    uint8_t g;
3
    volatile uint8_t h;
4
}
5
void foo() { // kann auch eine ISR sein
6
    g = 1;
7
    g = 2;
8
    h = 1;
9
    h = 2;
10
}

Hier werden tatsächlich die beiden Zuweisungen an g zu einer 
zusammengefasst, was nach der as-if Regel erlaubt ist. Das ist eine der 
simpelsten Optimierungen. Bei h wird hingegen jedes store ausgeführt 
(obwohl nicht notwendig).

Das volatile macht den Code nicht falsch, aber eben wenig effizient.

Man beachte hier, dass foo() nicht-static ist, so dass der Zugriff auf g 
nicht ganz wegoptimiert werden darf, obwohl g in einem anonymen 
namespace steht.

Um nun zu verhindern, dass ggf. der Compiler doch noch weitere 
Optimierungen durchführt, die ggf. dazu führen könnten, dass für g evtl. 
gar kein store mehr ausgeführt wird (nicht in diesem Beispiel), kann man 
dann noch eine memory-barrier - wie eben oben schon geschrieben - (mit 
dem Macro _MemoryBarrier()) eingebaut werden. Das kostet keine 
Instruktion, da das ja nur eine Anweisung an den Compiler ist, das 
load/store tatsächlich auszuführen, wie es (mit Optimierung) notwendig 
ist. Um es deutlich zu sagen: die memory-barrier kostet keine unnötige 
Performance!

Das Thema Atomarität habe ich hier jetzt erstmal ausgeklammert, aber das 
steht ja auch schon in meinem Beitrag von oben.

von Nop (Gast)


Lesenswert?

Wilhelm M. schrieb:
> die memory-barrier kostet keine unnötige Performance!

MB sind aber doch tatsächliche Instruktionen?

Das, was keine Instruktion bewirkt, ist eine Compiler-Barrier, die 
lediglich den Compiler im Zaum hält, etwa mit dem üblichen "asm 
volatile".

Übrigens ist das übliche Idiom für volatile-Variablen in der ISR ja, die 
in eine lokale Variable zu laden, auf der zu arbeiten und am Ende wieder 
zurückzuschreiben. Das kann der Compiler optimieren.

von Wilhelm M. (wimalopaan)


Lesenswert?

Nop schrieb:
> Wilhelm M. schrieb:
>> die memory-barrier kostet keine unnötige Performance!
>
> MB sind aber doch tatsächliche Instruktionen?

Nicht bei einer simpelst CPU wir AVR, um die es hier geht.

Nop schrieb:
> Das, was keine Instruktion bewirkt, ist eine Compiler-Barrier,

Ich bin mir nicht sicher, aber ich denke, der Begriff memory-barrier ist 
ein Oberbegriff für Techniken, ein Compile-time-reorder und/oder ein 
Runtime-reorder (CPU) zu unterdrücken. Für CPUs, die ein 
Instruction-Reorder machen (die AVR wie hier gehört nicht dazu) muss 
natürlich auch eine Instruktion emittiert werden.

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

Bevor sich der TO diese Vorträge anhört kann man ihm nur schleunigst 
raten bei den Grundlagen und mit Asm zu beginnen um schlicht ein 
Verständnis der ablaufenden Vorgänge zu entwickeln. An diesem Beispiel 
zeigen sich die Versäumnisse die entstehen wenn gleich mit Hochsprache 
eingestiegen wird wieder einmal besonders drastisch.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Bevor sich der TO diese Vorträge anhört kann man ihm nur schleunigst
> raten bei den Grundlagen und mit Asm zu beginnen um schlicht ein
> Verständnis der ablaufenden Vorgänge zu entwickeln.

Wie ein super sinnvoller Beitrag von Dir ;-)

Wilhelm M. schrieb:
> Ralf schrieb:
>
>>> Das Atomar-Macro
>>
>> bläst nur sinnlos das Programm auf wenn es auch anders geht.
>
> Dann zeig doch einfach mal Deine Lösung ;-) Wir wollen alle lernen.

Und?

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Wie ein super sinnvoller Beitrag von Dir ;-)

Sinnvoller für den TO als Deine fachlichen Erläuterungen allemal.

Wilhelm M. schrieb:
> Wilhelm M. schrieb:
>> Ralf schrieb:
>>
>>>> Das Atomar-Macro
>>>
>>> bläst nur sinnlos das Programm auf wenn es auch anders geht.
>>
>> Dann zeig doch einfach mal Deine Lösung ;-) Wir wollen alle lernen.
>
> Und?

Wenn es der TO ausdrücklich wünscht was

Ralf schrieb:
> Am besten ist doch man verzichtet auf gegenseitige Abhängigkeiten
> Main<>Interrupt indem man das Wesentliche (hier: die Sekunden zählen)
> gleich mit im Interrupt erledigt! Oder zweite Möglichkeit ist der
> Informationsaustausch über Nachrichten (ein Bit, ein Byte, ein
> Register-Flag, ein Register). Bei Schwierigkeiten wie den diesen sollte
> man den Hebel an der grundsätzlichen Programmstruktur ansetzen und nicht
> mit Atomar-Aktionen rumdoktern die letztlich nur den Programmfluss
> aufhalten.

konkret in Asm bedeutet gerne.
Mich speziell für Dich hinzusetzen wäre doch die Zeit zu schade, da 
stimmst Du sicher zu :)

von gam01hr (Gast)


Angehängte Dateien:

Lesenswert?

Please find attached is working code from Arduino world. The advantage 
here is you do not need reset the variable to zero. Just let it 
overflow.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
>
> konkret in Asm bedeutet gerne.

Das interessiert den TO (und andere) nicht wirklich.

> Mich speziell für Dich hinzusetzen wäre doch die Zeit zu schade, da
> stimmst Du sicher zu :)

Ja, da geb ich Dir Recht. Du hast gar nichts zu bieten, was sich lohnen 
würde, sich damit zu beschäftigen. Nur Geschwafel.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

Danke für eure Antworten an mich. Ich weiß leider immer noch nicht warum 
ich kein volatile verwenden soll. Volatile macht load/store zum Zwang. 
Okay ist ja Absicht. Nur wird das Macro _MemoryBarrier()) ja genauso 
erklärt mit zwangsweise load/store. Was ist jetzt der Unterschied 
zwischen volatile und dem Macro? Ich drehe mich irgendwie im Kreis.

Sind mit dem Load / Store die Macros gemeint die man bei volatile 
Variablen ganz frisch modern verwenden soll, die statt der 
Kurzschreibweisen-Operationen/Zuweisung (+=, -= usw.) verwendet werden 
sollen? Oder hau ich jetzt was komplett durcheinander?

von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
> Was ist jetzt der Unterschied
> zwischen volatile und dem Macro?

Eine MB lässt dem Compiler mehr Freiheiten zur Optimierung.
Da volatile keine ordering-Semantik zwischen volatile und nicht-volatile 
hat, muss man oft alle globalen Variablen, auf die dort zugegriffen 
wird, volatile machen.
Die MB ist ein Synchronizationspunkt vor und nach dem der Compiler 
wieder beliebig (as-if) optimieren kann.

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Das interessiert den TO (und andere) nicht wirklich.

> Du hast gar nichts zu bieten, was sich lohnen würde, sich damit zu
> beschäftigen. Nur Geschwafel.

Stehn Dir nicht wirklich gut solche Äußerungen. Sehr schade.

gam01hr schrieb:
> Just let it overflow.

Eine Lösung mehr, Atomar-Operationen überflüssig zu machen. Wenn es auch 
manch großem Experten überhaupt nicht passt die Dinge einfach zu halten 
:)

von Veit D. (devil-elec)


Lesenswert?

gam01hr schrieb:
> Please find attached is working code from Arduino world. The advantage
> here is you do not need reset the variable to zero. Just let it
> overflow.

Das ist etwas von hinten durch die Brust ins Auge. Ein Reset auf 0 macht 
man sowieso nicht. Der Überlauf korrigiert sich selbst. Vorrausgesetzt 
die Speichervariable hat den gleichen Datentyp wie der Rückgabewert von 
millis. uint32_t.

Der seit Jahren bewährte Standard ist:
1
unsigned long lastMillis {0};
2
const unsigned int intervall {1000};
3
...  
4
...
5
  
6
if (millis() - lastMillis >= intervall)
7
{
8
    lastMillis = millis();
9
    // lastMillis += intervall;  alternativ je nach Ausführungseffekt
10
    ...
11
    ...
12
}

von Veit D. (devil-elec)


Lesenswert?

MaWin schrieb:
> Veit D. schrieb:
>> Was ist jetzt der Unterschied
>> zwischen volatile und dem Macro?
>
> Eine MB lässt dem Compiler mehr Freiheiten zur Optimierung.
> Da volatile keine ordering-Semantik zwischen volatile und nicht-volatile
> hat, muss man oft alle globalen Variablen, auf die dort zugegriffen
> wird, volatile machen.
> Die MB ist ein Synchronizationspunkt vor und nach dem der Compiler
> wieder beliebig (as-if) optimieren kann.

Okay. Beim Makro darf irgendwie trotz load/store Zwang irgendwas 
optimiert werden. Ich lasse das erstmal sacken.  ;-)

Danke.

von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
> Okay. Beim Makro darf irgendwie trotz load/store Zwang irgendwas
> optimiert werden. Ich lasse das erstmal sacken.  ;-)

Genau.
1
A;
2
B;
3
memorybarrier;
4
C;
5
D;

A und B können getauscht werden. C und D können getauscht werden. B und 
C aber nicht (und alle anderen Kombinationen über die Barrier hinweg 
auch nicht).

Wenn A, B, C, D volatile sind, kann gar nichts getauscht werden.

von Oliver S. (oliverso)


Lesenswert?

MaWin schrieb:
> Wenn A, B, C, D volatile sind, kann gar nichts getauscht werden.

Das ist leider nur eine der unschönen urban legends in C, bei der man 
sich letztendlich wundert, warum es überhaupt funktionierende Programme 
gibt.

https://gcc.gnu.org/onlinedocs/gcc/Volatiles.html

Oliver

von MaWin (Gast)


Lesenswert?

Oliver S. schrieb:
> Das ist leider nur eine der unschönen urban legends in C, bei der man
> sich letztendlich wundert, warum es überhaupt funktionierende Programme
> gibt.

Ja. offiziell ist da fast gar nichts garantiert. Trotzdem machen 
vernünftige Compiler kein Reordering zwischen volatile. Es ist also 
praktisch implementation defined, was volatile macht. Alleine deshalb 
ist es für die breite Nutzung im Programm abzulehnen.

von Oliver S. (oliverso)


Lesenswert?

MaWin schrieb:
> Alleine deshalb
> ist es für die breite Nutzung im Programm abzulehnen.

Das C++-Standardisierungskomitee hat ja eine massive Einschränkung 
vorgeschlagen, allerdings hat das dann doch zu einigem Aufruhr geführt.

Ist halt alles nicht so einfach.

Oliver

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Okay. Beim Makro darf irgendwie trotz load/store Zwang irgendwas
> optimiert werden. Ich lasse das erstmal sacken.  ;-)

Hast Du Dir mein Beispiel von oben einmal genauer angesehen? Dort ist 
eine Optimierungsmöglichkeit angegeben, die möglich und sinnvoll wäre, 
aber von volatile verhindert wird.

von Wilhelm M. (wimalopaan)


Lesenswert?

Oliver S. schrieb:
> MaWin schrieb:
>> Alleine deshalb
>> ist es für die breite Nutzung im Programm abzulehnen.
>
> Das C++-Standardisierungskomitee hat ja eine massive Einschränkung
> vorgeschlagen, allerdings hat das dann doch zu einigem Aufruhr geführt.

Das betraf vor allem var++, etc. wie auch var += expr, weil eben die 
konkreten Auswirkungen (Anzahl der der Load/Store-Operationen) nicht 
klar (IB) definiert sind.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Das interessiert den TO (und andere) nicht wirklich.
>
>> Du hast gar nichts zu bieten, was sich lohnen würde, sich damit zu
>> beschäftigen. Nur Geschwafel.
>
> Stehn Dir nicht wirklich gut solche Äußerungen. Sehr schade.

Ich habe Deine bisherigen Posts gelesen und sie für mich bewertet. Mit 
dem gesagten Ergebnis.

Dann werde doch mal konkret!


> gam01hr schrieb:
>> Just let it overflow.
>
> Eine Lösung mehr, Atomar-Operationen überflüssig zu machen. Wenn es auch
> manch großem Experten überhaupt nicht passt die Dinge einfach zu halten
> :)

Das beschreibt aber nicht eine Lösung für das Problem des TO. Aber 
wahrscheinlich hast Du das auch nicht verstanden.

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Eine Lösung mehr, Atomar-Operationen überflüssig zu machen. Wenn es auch
> manch großem Experten überhaupt nicht passt die Dinge einfach zu halten

Nur weil es versteckt ist, ist es nicht überflüssig.
Wirf mal einen Blick in die wiring.c, wie "millis()" implementiert ist:
1
unsigned long millis()
2
{
3
  unsigned long m;
4
  uint8_t oldSREG = SREG;
5
6
  // disable interrupts while we read timer0_millis or we might get an
7
  // inconsistent value (e.g. in the middle of a write to timer0_millis)
8
  cli();
9
  m = timer0_millis;
10
  SREG = oldSREG;
11
12
  return m;
13
}

Compiliert exakt zum selben ASM-Code wie die 
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)-Variante.

von Wilhelm M. (wimalopaan)


Lesenswert?

Εrnst B. schrieb:
> Ralf schrieb:
>> Eine Lösung mehr, Atomar-Operationen überflüssig zu machen. Wenn es auch
>> manch großem Experten überhaupt nicht passt die Dinge einfach zu halten
>
> Nur weil es versteckt ist, ist es nicht überflüssig.
> Wirf mal einen Blick in die wiring.c, wie "millis()" implementiert ist:
>
>
1
> unsigned long millis() {
2
> ...
3
>
>
> Compiliert exakt zum selben ASM-Code wie die
> ATOMIC_BLOCK(ATOMIC_RESTORESTATE)-Variante.

Und man sollte dazu sagen, dass natürlich timer0_millis als volatile 
qualifiziert ist (was eigentlich nicht notwendig ist, s.a. mein Beitrag 
von oben).

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Nur weil es versteckt ist, ist es nicht überflüssig.

Dann war es versteckt.
Und bleibt trotzdem nicht minder überflüssig.
Der Zugriff auf Variablen von zwei verschiedenen Ausführungsebenen 
(Main/Interrupt), zumal schreibend, kann und sollte vermieden werden.
Spezifische Aufgaben sind möglichst vollständig auf nur einer Ebene
abzuhandeln.
Es spricht nur dann nichts gegen globalen Zugriff auf globale Variablen 
wenn diese stets gültige Werte annehmen und sich dabei eine 
Programmebene nicht auf ihr eigenes Variablengeschreibsel verlässt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Εrnst B. schrieb:
>> Nur weil es versteckt ist, ist es nicht überflüssig.
>
> Dann war es versteckt.
> Und bleibt trotzdem nicht minder überflüssig.

Dann Aufgabe an Dich: zeige eine Lösung ohne volatile oder ohne 
memory-barrier bzw. ohne Interrupt-Sperre.

: Bearbeitet durch User
von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Es spricht nur dann nichts gegen globalen Zugriff auf globale Variablen
> wenn diese stets gültige Werte annehmen und sich dabei eine

Häh? d.H. in deiner Welt darf man nur 8-Bit-Variablen verwenden, wenn 
man auf einem 8-Bit-AVR unterwegs ist?
Es ist nunmal eine Hardware-Limitierung, dass der AVR nur 8 Bit auf 
einmal schreiben kann. Völlig egal, ob du den in ASM, in C++, oder mit 
handgemeißelten Binärcode fütterst.

Sonst zeig mal deinen magischen Code für einen glitch-freien 16- oder 
32-Bit Zähler ohne atomaren Zugriff.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Es ist nunmal eine Hardware-Limitierung, dass der AVR nur 8 Bit auf
> einmal schreiben kann.

Und weil das so ist verzichtet man in diesem Fall auch drauf.
Wo ist hier eigentlich das Problem? Der TO zählt seine Sekunden 
idealerweise mit im Interrupt- oder dieserjenige signalisiert den Ablauf 
von 1000ms dem Hauptprogramm (was dann aber meist nicht punktgenau 
reagieren können wird).
Alles andere ist in meinen Augen schlicht Pfusch.

von EAF (Gast)


Lesenswert?

Wilhelm M. schrieb:
> was eigentlich nicht notwendig ist

Aber auch an der Stelle keinen einzigen Takt, oder Byte, verschwendet.
Also durchaus völlig ok ist.

gam01hr schrieb:
> Please find attached is working code from Arduino world. The advantage
> here is you do not need reset the variable to zero. Just let it
> overflow.

Aus mehreren Gründen gefällt mir das überhaupt nicht!
Aus diesen Gründen: Nicht empfehlenswert.

Zudem:
Arduino ist C++, in der Hauptsache

von Wilhelm M. (wimalopaan)


Lesenswert?

EAF schrieb:
> Wilhelm M. schrieb:
>> was eigentlich nicht notwendig ist
>
> Aber auch an der Stelle keinen einzigen Takt, oder Byte, verschwendet.
> Also durchaus völlig ok ist.

Ja, so wie es dort steht, ist das Ergebnis mit volatile nicht schlechter 
als mit memory-barrier.
1
#if defined(TIM0_OVF_vect)
2
ISR(TIM0_OVF_vect)
3
#else
4
ISR(TIMER0_OVF_vect)
5
#endif
6
{
7
  // copy these to local variables so they can be stored in registers
8
  // (volatile variables must be read from memory on every access)
9
  unsigned long m = timer0_millis;
10
  unsigned char f = timer0_fract;
11
12
  m += MILLIS_INC;
13
  f += FRACT_INC;
14
  if (f >= FRACT_MAX) {
15
    f -= FRACT_MAX;
16
    m += 1;
17
  }
18
19
  timer0_fract = f;
20
  timer0_millis = m;
21
  timer0_overflow_count++;
22
}

Aber:
mit memory-barrier statt volatile wäre die Erweiterbarkeit des Codes 
wesentlich besser gewesen, denn man hätte auf den Kommentar und auf die 
lokalen Variablen verzichten können. Denn eine unvorsichtige Erweiterung 
des obigen Codes führt dann zu einer nicht-optimalen Performance, etwa 
wenn jemand ein
1
    if (timer0_millis > 42) ...

einfügt.

Dieser Effekt ist umso wahrscheinlicher, als timer0_millis zur 
öffentlichen Schnittstelle (non-static global) des Moduls gehört.

Das Problem an volatile ist eben (wie oben in meinem Beitrag schon 
gesagt), dass es ein Bestandteil der Variablendeklaration ist und nicht 
der Zugriffsoperation. Daher sollte volatile eben ausschließlich 
HW-Registern vorbehalten bleiben, und die Zugriffe auf nebenläufig 
genutzte Datenstrukturen über memory-barrier vor dem Optimizer schützt 
werden (Atomarität natürlich ebenfalls nicht vergessen).

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Εrnst B. schrieb:
>> Es ist nunmal eine Hardware-Limitierung, dass der AVR nur 8 Bit auf
>> einmal schreiben kann.
>
> Und weil das so ist verzichtet man in diesem Fall auch drauf.
> Wo ist hier eigentlich das Problem? Der TO zählt seine Sekunden
> idealerweise mit im Interrupt- oder dieserjenige signalisiert den Ablauf
> von 1000ms dem Hauptprogramm (was dann aber meist nicht punktgenau
> reagieren können wird).

Du setzt als in der ISR ein flag. Dieses flag fragst Du außerhalb der 
ISR ab, und setzt es ggf. zurück?

Ohne memory-barrier / volatile wird die entweder das if-statement 
komplett weg-optimiert oder der Wert des flag wird gecached in einem 
Register und eine Wertänderung wird nie stattfinden.

von EAF (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Dieser Effekt ist umso wahrscheinlicher, als timer0_millis zur
> öffentlichen Schnittstelle (non-static global) des Moduls gehört.

Ist eigentlich nicht sonderlich öffentlich.
Wäre sie öffentlich gedacht, wäre eine extern Deklaration z.B. in 
Arduino.h erfolgt.
Ist aber nicht.
Gegenbeispiel: Serial
Serial ist als extern deklariert, mit der Absicht es öffentlich zu 
machen.

Öffentlich sind millis(), delay() und Konsorten.
Die verhalten sich auf allen (Arduino) Systemen vergleichbar.
Es gibt keine Notwendigkeit, dass es auf allen Systemen  eine Variable 
namens  timer0_millis gibt. Ehr ist das Gegenteil zu erwarten.
timer0_millis dient also zur internen Verwaltung der Zeiten, auf AVR 
Arduinos.

von Wilhelm M. (wimalopaan)


Lesenswert?

EAF schrieb:
> Ist eigentlich nicht sonderlich öffentlich.

Natürlich ist das öffentlich: jeder kann darauf zugreifen!

Arduino-Framework ist C++, daher verstehe ich nicht, warum man dann die 
Möglichkeiten nicht nutzt - oder zumindest die Möglichkeiten, die auch C 
bietet.

: Bearbeitet durch User
von EAF (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Natürlich ist das öffentlich: jeder kann darauf zugreifen!

Wie gesagt:
Es mag erreichbar sein, ist aber dennoch nicht für die öffentliche 
Verwendung vorgesehen.
Steht nicht auf jedem System zur Verführung, im Gegensatz zu millis()

Wilhelm M. schrieb:
> oder zumindest die Möglichkeiten, die auch C
> bietet.
Ich vermute mal, dass am Anfang nicht abzusehen war, wie doll das ganze 
aufblüht.
Die Bedingungen unter dem es entstanden ist, haben sich über die Zeit 
verändert.
Heutzutage, wäre man sicherlich an vielen Stellen "sorgfältiger" 
vorgegangen.


Oder anders:
Nicht jeder/jede kann so klug/genial/perfekt/sorgfältig wie du sein.
Dir würde das natürlich nicht passieren, irgendwas unabsichtlich 
öffentlich zu halten.

von Wilhelm M. (wimalopaan)


Lesenswert?

EAF schrieb:
> Ich vermute mal, dass am Anfang nicht abzusehen war, wie doll das ganze
> aufblüht.
> Die Bedingungen unter dem es entstanden ist, haben sich über die Zeit
> verändert.
> Heutzutage, wäre man sicherlich an vielen Stellen "sorgfältiger"
> vorgegangen.

Dann sollte man es eben ändern.
Wenn Du der Meinung bist, dass die volatiles nicht öffentlich sein 
sollten, kann man das ja ohne weiters korrigieren. Die Klienten, die 
dann darauf zugegriffen haben, hätten dann einen Bug des Arduino-FW 
ausgenutzt, und müssten mit dem breaking-change leben.

von EAF (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Dann sollte man es eben ändern.
Mach doch.....
Wird sich dann zeigen, ob du damit durch kommst.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich habe das Gefühl wir reden aneinandervorbei. Die memory order bezieht 
sich doch auf die Verwendung von atomic. Das verwendet man um eine 
Variable ungestört zu lesen / zu schreiben ohne das bspw. ein Interrupt 
dazwischen funkt. Soweit war das schon lange klar. Das hat jedoch nichts 
mit volatile zu tun. Volatile verbietet dem Compiler das er die Variable 
wegoptimiert, was er wegen ISR nicht darf, weil Änderungen außerhalb des 
normalen Programmflusses stattfinden können. Damit bin ich wieder am 
Anfang und kein Stück schlauer. Ich kann doch volatile nicht weglassen 
und mich auf atomic bei der Variablenverwendung verlassen. Das reicht 
doch nicht aus. Der Compiler muss doch irgendwie wissen das er den 
Variableninhalt immer frisch lesen muss und nicht aus irgendeinem 
veralteten Cache holt. Ansonsten wäre es nicht falsch wenn jemand einen 
Code zeigt der alles ohne volatile richtig macht. Erklären und verstehen 
muss zusammenpassen.

von EAF (Gast)


Lesenswert?

Veit D. schrieb:
> ich habe das Gefühl wir reden aneinandervorbei.
Punkt 1:
Wenn du einfache Antworten erwartest, solltest du nicht nach 
komplizierten Dingen fragen.

Punkt 2:
Sowohl sei() als auch cli() haben Memory Barrieren im Bauch.
Und die Atomic Macros auch.
Kann man in den betreffenden *.h Dateien nachlesen.

Punkt 3:
......

von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
> Die memory order bezieht
> sich doch auf die Verwendung von atomic.

Nein.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

jetzt brauch ich wirklich gedanklichen Abstand. Ich gehe das später 
nochmal an. Danke für eure Mühen, scheinbar bei mir der falsche 
Zeitpunkt oder so ähnlich.

von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
> Ich gehe das später nochmal an.

Lies doch einfach mal die gegebenen Antworten.
Ich habe in einem einfachen Beispiel gezeigt was eine einfache memory 
barrier ist und wie sie sich aufs Ordering auswirkt.
Mit Atomics hat das überhaupt nichts zu tun.
Um Atomic und Ordering muss man sich separat kümmern. Auch bei volatile! 
Volatile macht praktisch überhaupt nichts, was atomic angeht. 
(Vielleicht verhindert es maximal write-tearing oder sowas)

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> ich habe das Gefühl wir reden aneinandervorbei. Die memory order bezieht
> sich doch auf die Verwendung von atomic.

Nein, völlig andere Baustelle.

> Das verwendet man um eine
> Variable ungestört zu lesen / zu schreiben ohne das bspw. ein Interrupt
> dazwischen funkt. Soweit war das schon lange klar.

Atomare Operationen sind unteilbare Operationen. Eine Folge von 
Anweisungen, die nicht unterbrochen werden soll, bezeichnet man so. Das 
benötigt man für einen konsistenten, nebenläufigen Zugriff auf 
Datenstrukturen, die von unterschiedlichen Aktivitätsträgern genutzt 
werden sollen.

Stellt Dir eine verkettete Liste vor. Wenn dort ein Knoten eingefügt 
werden soll, sind ein paar Zeigermanipulationen an den Listenknoten 
notwendig. Wenn Du Dir vorstellst, dass Du diese Operationen mittendrin 
unterbrichst, und ein anderer Aktivitätsträger in diesem Moment versucht 
die Liste zu traversieren, wird es wahrscheinlich zu Problemen kommen, 
da die Zeigermanipulationen an den Listenknoten einfach nich 
abgeschlossen sind: die Traversion bricht ggf. vorzeitig ab oder 
referenziert einen ungültigen Zeiger.

Diese Anweisungsfolge um einen Listenknoten einzufügen nennt man auch 
kritischen Abschnitt, und diese Anweisungsfolge darf nicht unterbrochen 
werden (auf AVR ist die einzige Art von Nebenläufigkeit das Ausführen 
von ISRs, echte Parallelität durch mehrere Cores oder Quasi-Parallelität 
durch ein OS haben wir hier nicht). Auf den AVRs reicht es daher, den 
kritischen Bereich durch das Abschalten der Interrupts vor einer 
Unterbrechung zu schützen.

Auf AVR reicht also cli/sei als Maßnahmen. Echte Schloßvariablen (mutual 
exclusion lock) haben wir beim AVR nicht (nötig).

> Das hat jedoch nichts
> mit volatile zu tun.

Genau.

> Volatile verbietet dem Compiler das er die Variable
> wegoptimiert,

Jein. Nicht die Variable wird ggf. wegoptimiert (die nur dann, wenn sie 
definitiv nicht benutzt wird), sondern der Compiler darf ggf. 
Operationen auf einer non-volatile Variable (memory-location) weglassen, 
zusammen fassen.
1
uint8_t g;
2
3
void foo() {
4
   g = 1;
5
   g = 2;
6
}

In der obigen Funktion wird nur g = 2 ausgeführt, denn g = 1 hat keinen 
beobachtbaren Effekt (as-if Regel).

Wird die Variable g mit volatile qualifiziert, so werden beide(!) 
Zuweisungen ausgeführt. So etwas will man (normalerweise) nur mit 
MCU-Registern, weil eine Zuweisung (oder auch Lesen) einen Seiteneffekt 
hat.

> was er wegen ISR nicht darf, weil Änderungen außerhalb des
> normalen Programmflusses stattfinden können.

ISR ist auf AVR die einzige Form der Nebenläufigkeit, deswegen "ja"

> Damit bin ich wieder am
> Anfang und kein Stück schlauer. Ich kann doch volatile nicht weglassen
> und mich auf atomic bei der Variablenverwendung verlassen. Das reicht
> doch nicht aus.

Genau.
Auch bei einem volatile kann der Zugriff nicht-atomar sein:
1
volatile uint16_t g;
2
3
void foo() {
4
    g = 1;
5
    g = 2;
6
}

Jede Zuweisung wir bei AVR auf ggf. zwei Maschinen-Instruktionen 
aufgeteilt, also nicht atomar (obwohl volatile).

> Der Compiler muss doch irgendwie wissen das er den
> Variableninhalt immer frisch lesen muss und nicht aus irgendeinem
> veralteten Cache holt.

Genau. Und das ist die Aufgabe einer memory-barrier: sie weist den 
Compiler an, alle ge-cache-ten Inhalte (etwa in Registern der CPU) 
zurückzuschreiben und bei Lese-Operationen frisch aus dem RAM zu lesen.

> Ansonsten wäre es nicht falsch wenn jemand einen
> Code zeigt der alles ohne volatile richtig macht. Erklären und verstehen
> muss zusammenpassen.

Nä. Post ...

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Ansonsten wäre es nicht falsch wenn jemand einen
> Code zeigt der alles ohne volatile richtig macht. Erklären und verstehen
> muss zusammenpassen.

Ich habe mal was zusammengestellt:
1
#include <avr/cpufunc.h>
2
#include <util/atomic.h>
3
#include <stdint.h>
4
5
namespace Memory {
6
    struct Barrier final {
7
        inline Barrier() {
8
            _MemoryBarrier();
9
        }
10
        inline ~Barrier() {
11
            _MemoryBarrier();
12
        }
13
    };
14
    void barrier(const auto f) {
15
        Barrier b;
16
        f();
17
    }
18
}
19
20
namespace Atomic {
21
    struct DisableInterruptsRestore final {
22
        inline DisableInterruptsRestore() {
23
            cli();
24
        }
25
        inline ~DisableInterruptsRestore() {
26
            SREG = save;
27
        }
28
    private:
29
        uint8_t save{SREG};
30
    };
31
    
32
    void access(const auto f) {
33
        DisableInterruptsRestore di;
34
        Memory::barrier([&]{
35
            f();
36
        });
37
    }
38
}
39
40
volatile uint8_t mcuRegister;
41
42
namespace {
43
    uint8_t g;
44
    bool flag;
45
}
46
47
ISR(TCA1_CMP0_vect) {
48
    Memory::barrier([]{
49
        ++g;
50
        if (g > 100) flag = true;
51
    });
52
}
53
54
int main(void) {
55
    while (true) {
56
        Atomic::access([]{
57
            if (flag) {
58
                flag = false;
59
                mcuRegister = 0x01;            
60
            }
61
        });
62
    }
63
}

Vielleicht hilft es zum Verständnis.

von Wilhelm M. (wimalopaan)


Lesenswert?

MaWin schrieb:
> Lies doch einfach mal die gegebenen Antworten.

Oder ein Buch wie den Tanenbaum ;-)

Beitrag #7254796 wurde vom Autor gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

EAF schrieb:
> Wilhelm M. schrieb:
>> Dann sollte man es eben ändern.
> Mach doch.....
> Wird sich dann zeigen, ob du damit durch kommst.

Nö, warum? Ich nutze doch gar kein Arduino-FW. Mir liegt nichts ferner 
als das Arduino-FW, für mich ist das broken-by-design.

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Ohne memory-barrier / volatile wird die entweder das if-statement
> komplett weg-optimiert oder der Wert des flag wird gecached in einem
> Register und eine Wertänderung wird nie stattfinden.

In Asm wird weder weg-optimiert noch gecached. Selbstverständlich 
arbeitet da auch eine Flag-Lösung. Wenn die in Hochsprache verhindert 
würde (traurig genug) bleibt aber immer noch die optimale Lösung, alles 
in der ISR abzuhandeln, wie ich es nun schon mehrfach begründet habe. 
Das sollte doch nun wirklich auch in C gehen. Wer aber hier mit Gewalt 
Probleme konstruiert damit er sich intellektuell drin verbeißen kann hat 
andere Ziele,

Wilhelm M. schrieb:
> Mir liegt nichts ferner als das Arduino-FW, für mich ist das
> broken-by-design.

Wilhelm M. schrieb:
> Nicht bei einer simpelst CPU wir AVR

vor allem aber darf es nicht zu einfach sein :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Ohne memory-barrier / volatile wird die entweder das if-statement
>> komplett weg-optimiert oder der Wert des flag wird gecached in einem
>> Register und eine Wertänderung wird nie stattfinden.
>
> In Asm wird weder weg-optimiert noch gecached.

Irgendwie kapierst Du es nicht: niemand in diesem Thread bezweifelt, 
dass das in ASM nicht wegoptimiert wird. Wie auch ...
Aber: es ist in diesem Thread niemand an Deinem ASM Code interessiert. 
Um es nochmal deutlich zu sagen: es geht um C/C++ und das abstrakte 
Speichermodell darin.

> *Selbstverständlich*
> arbeitet da auch eine Flag-Lösung. Wenn die in Hochsprache verhindert
> würde (traurig genug) bleibt aber immer noch die optimale Lösung, alles
> in der ISR abzuhandeln, wie ich es nun schon mehrfach begründet habe.

Das ist sicher nicht die optimale Lösung.

> Das sollte doch nun wirklich auch in C gehen.

Geht ja auch. Siehe all die Beiträge oben, die Du wohl nicht verstanden 
hast.

>
> Wilhelm M. schrieb:
>> Mir liegt nichts ferner als das Arduino-FW, für mich ist das
>> broken-by-design.
>
> Wilhelm M. schrieb:
>> Nicht bei einer simpelst CPU wir AVR
>
> vor allem aber darf es nicht zu einfach sein :)

Wenn man es verstanden hat, ist es einfach.

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Das ist sicher nicht die optimale Lösung.

Guten Morgen! Dann entfalte doch bitte Deine Kapazitäten das hier nicht 
bloß zu behaupten sondern im Detail zu begründen.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

@ Wilhelm (und natürlich alle anderen) Danke für die nochmalige 
Erklärung(en). Ist schon verständlicher für mich formuliert. Muss mir 
auch nochmal die anderen Antworten durchlesen und gedanklich 
zusammenbringen. Das Bsp. gehe ich noch durch. Eine Frage gibts aber 
schon. Warum ist mcuRegister volatile? Ich kann keinen Grund erkennen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> @ Wilhelm (und natürlich alle anderen) Danke für die nochmalige
> Erklärung(en). Ist schon verständlicher für mich formuliert. Muss mir
> auch nochmal die anderen Antworten durchlesen und gedanklich
> zusammenbringen. Das Bsp. gehe ich noch durch. Eine Frage gibts aber
> schon. Warum ist mcuRegister volatile? Ich kann keinen Grund erkennen.

In dem Beispiel soll eben mcuRegister ein tatsächlcihes HW-Register der 
MCU darstellen, als Beispiel. Ich hätte auch z.B. GPIOR0 schreiben 
können.

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Guten Morgen! Dann entfalte doch bitte Deine Kapazitäten das hier nicht
> bloß zu behaupten sondern im Detail zu begründen.

Es geht hier nicht um Asm. Und es geht auch nicht darum die optimalste 
Lösung zu finden. Begründung Ende.

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Und es geht auch nicht darum die optimalste Lösung zu finden.

Es heißt die 'optimale' MaWin.
Und ja, das stand ohnehin zu vermuten.
Warum einfach wenn's auch kompliziert geht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> MaWin schrieb:
>> Und es geht auch nicht darum die optimalste Lösung zu finden.
>
> Es heißt die 'optimale' MaWin.
> Und ja, das stand ohnehin zu vermuten.
> Warum einfach wenn's auch kompliziert geht.

Und warum zeigst Du uns nicht die bzw. Deine optimale Lösung in C / C++?

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Es heißt die 'optimale' MaWin.

Ach?
Schon einmal daran gedacht, dass ich das extra so geschrieben habe?

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Und warum zeigst Du uns nicht die bzw. Deine optimale Lösung in C / C++?

Sag bloß das verhindert jetzt eine ordentliche Begründung :)

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Und warum zeigst Du uns nicht die bzw. Deine optimale Lösung in C / C++?
>
> Sag bloß das verhindert jetzt eine ordentliche Begründung :)

Ziemlich. Ja.
Und natürlich, dass es vollkommen offtopic ist.

Niemand ist an deiner optimalstesten Lösung interessiert.
Schon einmal daran gedacht, dass es nicht nur ein Optimumse gibt?

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Niemand ist an deiner optimalstesten Lösung interessiert.
> Schon einmal daran gedacht, dass es nicht nur ein Optimumse gibt?

Ihr beide seid mir schon ein paar Spezialisten, selbst wenn ihr woanders 
vielleicht konstruktivere Rollen spielen mögt. Ich will Euch aber hier 
nicht weiter an Schwachstellen (auch von C)  piesacken solange der TO 
nicht ausdrücklich zustimmt :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> MaWin schrieb:
>> Niemand ist an deiner optimalstesten Lösung interessiert.
>> Schon einmal daran gedacht, dass es nicht nur ein Optimumse gibt?
>
> Ihr beide seid mir schon ein paar Spezialisten, selbst wenn ihr woanders
> vielleicht konstruktivere Rollen spielen mögt.

Danke für die Blumen.
In meinen Augen bist Du hier der Oberspezialist, schwafelst die ganze 
Zeit rum ohne irgendwie konkret zu werden. Der TO wollte eine Erklärung 
und eine Lösung für sein Problem in C / C++. Du redest die ganze Zeit 
rum, dass das alles Quatsch sei und Du eine viel bessere Lösung hast. 
Auf Nachfragen dazu kommt von Dir überhaupt gar nichts. Das nenne ich 
wirklich mal "konstruktiv". Solche Kollegen, die einem nur ein Ohr 
abkauen, ohne irgendwie etwas sinnvolles beizutragen wünscht man sich 
wirklich. Im echten Leben fliegen die aus dem Team. Hier können leider 
Gäste immer wieder herum trollen.

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> das alles Quatsch sei

Nein. Aber in diesem Fall suboptimal, unnötig und überflüssig weil es 
eine bessere Lösung gibt: Einfach die Sekunden mit in der ISR zählen!
Das kannst Du nun gerne zum x.Mal nicht zur Kenntnis nehmen oder endlich 
die Begründung liefern warum es so einfach nicht geht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> das alles Quatsch sei
>
> Nein. Aber in diesem Fall suboptimal, unnötig und überflüssig weil es
> eine bessere Lösung gibt: Einfach die Sekunden mit in der ISR zählen!

Damit hast Du dann dasselbe Problem.
Und damit wir nicht aneinander vorbei reden: zeige uns den Code, und 
nimmt gerne das Minimalbeispiel, was ich oben schon geschrieben habe. 
Aber bleibe in der Struktur vom TO: die ISR zählt und der non-ISR-Code 
wertet aus (bspw. alle 4711 Sekunden ein Ausgabe oder irgendein 
MCU-Register setzen reicht auch).

von Markus F. (mfro)


Lesenswert?

Wilhelm M. schrieb:
> Ich habe mal was zusammengestellt:

Das mag meist funktionieren, scheint mir aber nicht 100%ig wasserdicht 
zu sein.
Wenn ich die AVR-Dokumentation 
(https://www.nongnu.org/avr-libc/user-manual/group__avr__cpufunc.html) 
von _MemoryBarrier() lese, sehe ich einen expliziten Hinweis (Link 
"Problems with reordering code") darauf, dass die _MemoryBarrier() 
lediglich Zugriffe auf volatile Variablen vor dem (u.U. durch 
Optimierungen vom Compiler "beschlossenen") Reordering schützt.

Ich würde daraus schliessen, dass lediglich die Kombination von 
_MemoryBarrier() und volatile Variablenzugriffen 100%ig "wasserdicht" 
ist?

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Damit hast Du dann dasselbe Problem.

Bitte erzähle doch keinen Blödsinn.
Weshalb denn?

Wilhelm M. schrieb:
> Aber bleibe in der Struktur vom TO: die ISR zählt und der non-ISR-Code
> wertet aus

Die ist ja hier das Problem.
Begreifst Du das nicht?

von EAF (Gast)


Lesenswert?

Markus F. schrieb:
> dass die _MemoryBarrier()
> lediglich Zugriffe auf volatile Variablen vor dem (u.U. durch
> Optimierungen vom Compiler "beschlossenen") Reordering schützt.

Falsch übersetzt!

Die Google Transe macht daraus:
Implementieren Sie eine Lese-/Schreibspeicherbarriere. Eine 
Speicherbarriere weist den Compiler an, keine Speicherdaten in Registern 
jenseits der Barriere zwischenzuspeichern. Dies kann manchmal effektiver 
sein, als bestimmte Optimierungen zu blockieren, indem ein Objekt mit 
einem flüchtigen Qualifizierer deklariert wird.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:

> Die ist ja hier das Problem.

Genau, und das ist die Vorgabe.

> Begreifst Du das nicht?

Natürlich. Und ich verstehe auch, dass Du ein LED-Blinki komplett in der 
ISR laufen lassen willst und der non-ISR Code macht nur die 
Initialisierungen. Nur kommst Du damit eben im echten Leben nicht weit. 
Deswegen hat es sich etabliert, einen sys-tick zu haben, der bspw. eben 
Sekunden zählt.

Das war die Anforderung des TO. Jetzt bist Du drann. Aber mit Code ...

von Markus F. (mfro)


Lesenswert?

EAF schrieb:
> Falsch übersetzt!

Huh? Hast Du dir den "Problems with reordering code"-Link durchgelesen?

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Genau, und das ist die Vorgabe.

Falsch. Der TO möchte seine Sekunden richtig gezählt bekommen. Was 
"Vorgabe" ist legst sicher nicht Du fest.

Wilhelm M. schrieb:
> Nur kommst Du damit eben im echten Leben nicht weit.

Klasse Begründung. Hut ab.

> Deswegen hat es sich etabliert, einen sys-tick zu haben, der bspw. eben
> Sekunden zählt.

So ist das auch richtig.
Nichts anderes bezeichne ich hier als richtige Lösung: Vollständige 
Verwaltung einer Aufgabe auf einer Programmebene- Hier im Systick 
Interrupt.

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> So ist das auch richtig.

Und warum willst du diese richtige Lösung dann auf Biegen und brechen 
verhindern?

Wenn der Systick mehr als 8 Bit breit ist, braucht es eben atomaren 
Zugriff darauf. Auch wenn es eine Sekunden-Variable ist, die in der ISR 
hochgezählt wird.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Nichts anderes bezeichne ich hier als richtige Lösung: Vollständige
> Verwaltung einer Aufgabe auf einer Programmebene- Hier im Systick
> Interrupt.

Da es immer noch kein Code ist, den Du zeigst, denke ich mal, dass Du 
von C / C++ oder ASM überhaupt keine Ahnung hast. Du hast noch nie eine 
Zeile Code geschrieben und liest Computer-Bild. Daraus kennst Du nur ein 
paar Buzzwords.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Auch wenn es eine Sekunden-Variable ist, die in der ISR hochgezählt
> wird.

Die aber jetzt stets konstant zählt, das ist der Unterschied. Die in 
diesem Fall übrigens auch 8bittig bleibt.
Da beißt die Maus keinen Faden dran ab: >8bittige Schreibzugriffe von 
Main auf Interrupt-Variablen sind Pfusch und daher zu vermeiden, wenn 
das Programm nicht komplizierter werden soll als nötig.

von Ralf (Gast)


Lesenswert?

Ralf schrieb:
> Εrnst B. schrieb:
>
>> Auch wenn es eine Sekunden-Variable ist, die in der ISR hochgezählt
>> wird.
>
> Die aber jetzt stets konstant zählt, das ist der Unterschied. Die in
> diesem Fall übrigens auch 8bittig bleibt.
> Da beißt die Maus keinen Faden dran ab: >8bittige Schreibzugriffe von
> Main auf Interrupt-Variablen sind Pfusch und daher zu vermeiden, wenn
> das Programm nicht komplizierter werden soll als nötig.

Wilhelm M. schrieb:
> Du hast noch nie eine Zeile Code geschrieben und liest Computer-Bild.
> Daraus kennst Du nur ein paar Buzzwords.

Mehr als solche unsachlichen Aussagen erwarte ich von Dir leider nicht 
mehr. Verständlich wenn man fachlich so in der Sackgasse steckt.

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Die in
> diesem Fall übrigens auch 8bittig bleibt.

d.H. Alle Anwendungen die Zeitintervalle > 255 Sekunden benötigen sind 
Pfusch?
Seltsame Einstellung.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Alle Anwendungen die Zeitintervalle > 255 Sekunden benötigen sind
> Pfusch?
> Seltsame Einstellung.

Man muss es nur richtig machen Ernst B.
Die Zeitintervalle nämlich vollständig im Interrupt verwalten.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Εrnst B. schrieb:
>> Alle Anwendungen die Zeitintervalle > 255 Sekunden benötigen sind
>> Pfusch?
>> Seltsame Einstellung.
>
> Man muss es nur richtig machen Ernst B.
> Die Zeitintervalle nämlich vollständig im Interrupt verwalten.

Code?

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Man muss es nur richtig machen

(tm)

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Die Zeitintervalle nämlich vollständig im Interrupt verwalten.

Super. Wenn ich haufenweise unterschiedliche Zeitintervalle brauche, die 
evtl. sogar noch online konfiguriert werden sollen, dann muss ich jedes 
mal das Programm neu Kompilieren, damit die ISR die richtigen 
Zeitintervalle enthält?
Statt einfach sekunden hochzuzählen, und meine Tasks daran Auszurichten?

Was ist da wohl komplizierter?

Ralf schrieb:
> wenn
> das Programm nicht komplizierter werden soll als nötig.

Echt? Beispiel, aus einem Projekt mit Stromspar-AVR + Uhrenquarz:
1
static uint32_t seconds;
2
3
static uint32_t getSeconds() {
4
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
5
        return seconds;
6
    }
7
    return 0;  // Unreachable, Silence Compiler warning
8
}
9
10
ISR(TIMER2_OVF_vect) {
11
    seconds += 1;
12
}

Und das findest du jetzt so extrem unfassbar kompliziert?

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Wenn ich haufenweise unterschiedliche Zeitintervalle brauche, die evtl.
> sogar noch online konfiguriert werden sollen, dann muss ich jedes mal
> das Programm neu Kompilieren, damit die ISR die richtigen Zeitintervalle
> enthält

Variable ISR-Zeitintervalle stehen hier gar nicht zur Debatte. Wenn es 
sie aber braucht und diese vom Programmierer nicht vorhersehbar sind 
kann man immer noch auf kompliziertere Übergabeverfahren zurückgreifen.

Εrnst B. schrieb:
> extrem unfassbar kompliziert

Wer redet von "unfassbar"?
Ich rede von

Ralf schrieb:
> suboptimal, unnötig und überflüssig

So, ich bin dann mal bei der "electronica"... :)

von der_eine (Gast)


Lesenswert?

Ralf schrieb:

> Da beißt die Maus keinen Faden dran ab: >8bittige Schreibzugriffe von
> Main auf Interrupt-Variablen sind Pfusch und daher zu vermeiden, wenn
> das Programm nicht komplizierter werden soll als nötig.

Aha. 4 kleine unbedeutende Anmerkungen.

1. halbwegs Moderne AVR´s haben auch durchaus atomare 16-Bit Operationen 
(z.B. movw). Wenn diese gezielt genutzt werden, dann muß man auch bei 
gemischter Verwendung ISR/main keine Klimmzüge machen.

2. Lesezugriffe sind nicht mehr oder weniger gefährdet als 
Schreibzugriffe

3. Pfusch ist der falsche Begriff. Man muß wissen, was man tut. Aber das 
haben schon viele vorher getan, und es gibt haufenweise HowTos.

4. Auch 8-Bit kann fehlschlagen. (z.B. Bitmanipulationen).

Gruß

Robert

von Ralf G. (ralg)


Lesenswert?

Ralf schrieb:
> Unfug. Man muß es nur richtig anstellen. Hochsprache macht sich viele
> Probleme selber.

Äähmm ... Moby? Bist du's?

von Oliver S. (oliverso)


Lesenswert?

Ralf G. schrieb:
> Äähmm ... Moby? Bist du's?

Natürlich ist er das. Das war doch schon lange klar.

Oliver

von MaWin (Gast)


Lesenswert?

So, jetzt habe ich mir das hier mal angeschaut:

https://www.nongnu.org/avr-libc/user-manual/optimization.html#optim_code_reorder

>However, memory barrier works well in ensuring that all volatile accesses
> before and after the barrier occur in the given order with respect to the
> barrier. However, it does not ensure the compiler moving
> non-volatile-related statements across the barrier.
> Peter Dannegger provided a nice example of this effect:

Dieser Absatz ist leider kompletter Blödsinn.
Tut mir leid Peter, aber du hast Barriers nicht verstanden.

In dem Beispiel wandert eine lokale Variable über die Barrier hinweg.
Was natürlich erlaubt ist.

Bei *memory*-Barriers geht es natürlich um *memory*-Zugriffe.
Und *memory*-Zugriffe, auch nicht-volatile, werden natürlich nicht 
über die Barrier hinweg verschoben.

Lokale Variablen können per Definition keine Data-Races oder 
Orderingprobleme mit ISRs oder anderen CPUs erzeugen, weil sie eben 
lokal sind. (Solange es keinen globalen Zeiger darauf gibt. Aber dann 
greift die Memory Barrier wieder)

von Ralf (Gast)


Lesenswert?

der_eine schrieb:
> Wenn diese gezielt genutzt werden, dann muß man auch bei gemischter
> Verwendung ISR/main keine Klimmzüge machen.

Kann man, muß man aber hier nicht.

> Lesezugriffe sind nicht mehr oder weniger gefährdet als Schreibzugriffe

Lesezugriffe ändern nichts an einer schreibverwalteten Variable der ISR.
Man kann sie auch ggf. zu einem unbedenklichen Zeitpunkt ausführen wenn 
kein Überlauf zu erwarten ist und hinterher auf Plausibilität prüfen.

> Man muß wissen, was man tut.

Sehr diplomatisch weil immer zutreffend.

> Auch 8-Bit kann fehlschlagen. (z.B. Bitmanipulationen).

Nicht beim Schreiben von tatsächlich 8 Bits.

MaWin schrieb:
> Lokale Variablen können per Definition keine Data-Races oder
> Orderingprobleme mit ISRs oder anderen CPUs erzeugen,

Gut erkannt. Die Regel dann bitte hier nur noch praktisch anwenden und 
schon sind wir uns einig :)

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
>> Auch 8-Bit kann fehlschlagen. (z.B. Bitmanipulationen).
>
> Nicht beim Schreiben von tatsächlich 8 Bits.

Ach?
1
uint8_t var;
2
3
void main_func(void)
4
{
5
   var = var ^ 0x03;
6
}
7
8
void ISR(void)
9
{
10
   var = var ^ 0x30;
11
}

Nur 8-Bit Schreib- und Lesezugriffe. Trotzdem nicht atomisch.

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Gut erkannt. Die Regel dann bitte hier nur noch praktisch anwenden und
> schon sind wir uns einig :)

Und wozu? Wenn ich es gerne anders machen möchte oder anders machen 
muss, dann mache ich es halt anders.
Du darfst gerne mir die Bewertung überlassen, was besser und was 
schlechter ist.
Deine Lösung ist eine Lösung. Aber ob sie besser ist, das bewertest 
nicht du für andere.

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Lesezugriffe [..]
> zu einem unbedenklichen Zeitpunkt ausführen wenn
> kein Überlauf zu erwarten ist und hinterher auf Plausibilität prüfen.

Und das soll besser sein, als einen "unbedenklichen Zeitpunkt" einfach 
per CLI/SEI zu erzwingen, und dann ohne extra Plausibilitätsprüfung 
immer garantiert valide Daten zu lesen?

Kriegst du Geld zurück, wenn du die CLI-Instruktion ungenutzt lässt?

Hat dir CLI irgendwann mal was Böses angetan, dass du jetzt soviel Angst 
davor hast?

Glaubst du die Grünen schmeißen dich aus der Partei, weil du 
"ATOMIC_BLOCK" in deinem Quelltext stehen hast?

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Nur 8-Bit Schreib- und Lesezugriffe. Trotzdem nicht atomisch.

Richtig, wegen der unklaren Reihenfolge.
Ein Grund mehr, die Variable VAR schreibend entweder in Main ODER in der 
ISR zu verwalten.

> Aber ob sie besser ist, das bewertest nicht du für andere.

Das ist ganz rational entscheidbar: Sie konstruiert keine Gründe um 
diese hinterher wieder ausbügeln zu müssen.
Einfacher ist besser. Das sollte hinter jedem Programmierer- Ohr 
geschrieben stehen!

Εrnst B. schrieb:
> Und das soll besser sein, als einen "unbedenklichen Zeitpunkt" einfach
> per CLI/SEI zu erzwingen

Es ging um die Behauptung

der_eine schrieb:
> Lesezugriffe sind nicht mehr oder weniger gefährdet als Schreibzugriffe

Das macht nämlich durchaus einen Unterschied.

Εrnst B. schrieb:
> Glaubst du die Grünen schmeißen dich aus der Partei, weil du
> "ATOMIC_BLOCK" in deinem Quelltext stehen hast?

Was sich durch durch anderes Herangehen an ein Problem vermeiden lässt 
muss nicht hinterher mit zusätzlicher Bürokratie bekämpft werden.
Aber letztere mögen wir Deutsche ja so sehr, vielleicht weht daher der 
Wind.

von EAF (Gast)


Lesenswert?

Alles klar, du verstehst es wirklich gut, deine ASM Begeisterung 
vorzüglich rüber zu bringen.
Mit deinen Argumenten wirst du sicherlich 80% aller C++ Schreiber hier 
überzeugen. (natürlich auch die C Helden)

Alternativ:
Möchtest du nicht einen Youtubekanal eröffnen um als gottgleicher 
Influencer die Welt von deinen Ansichten zu überzeugen?
Dann hast du was zu tun, und wir sind dich los.

von Ralf (Gast)


Lesenswert?

EAF schrieb:
> ASM Begeisterung
> C++ Schreiber hier überzeugen

Falls Du es noch nicht mitbekommen hast: Es geht hier nicht primär um 
die Programmiersprache. Aber natürlich hat eine jede ihr Licht und ihren 
Schatten und ihren sinnvollen Anwendungsbereich.
Wenn ich hier auf Asm zu sprechen kam dann weil der TO auf dieser Ebene 
sein Problem viel besser durchschaut hätte.

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Aber natürlich hat eine jede ihr Licht und ihren
> Schatten und ihren sinnvollen Anwendungsbereich.
> Wenn ich hier auf Asm zu sprechen kam dann weil der TO auf dieser Ebene
> sein Problem viel besser durchschaut hätte.

Richtig.
Und in einer modernen Sprache wie Rust sind solche Data-Races, wie die 
vom TO, gar nicht erst formulierbar. Dort wäre er gezwungen worden es zu 
durchschauen, weil das Programm nicht compilierbar gewesen wäre.

Und nun? Asm scheiße? C scheiße? Alles verbrennen?
Sicher nicht.

Die Übergänge und Entscheidungen sind praktisch nie so schwarz/weiß, wie 
du sie hier darstellst.

Ich stimme dir ja durchaus zu, dass Einfachheit oft besser ist. Aber 
halt nicht immer. Einfachheit kann auch dazu führen, dass das Programm 
in der späteren Weiterentwicklung nicht mehr skaliert. Dein Vorschlag 
funktioniert schließlich nicht weit über das Trivialbeispiel hinaus.

von Nop (Gast)


Lesenswert?

MaWin schrieb:

> Und in einer modernen Sprache wie Rust sind solche Data-Races, wie die
> vom TO, gar nicht erst formulierbar.

Geht Datentausch zwischen Interrupt und Application in Rust ohne 
"unsafe"? Wenn ja, was ist die zugrundeliegende Logik, auf die das 
hinausläuft? Interrupt in der Application sperren?

von MaWin (Gast)


Lesenswert?

Nop schrieb:
> Geht Datentausch zwischen Interrupt und Application in Rust ohne
> "unsafe"?

Selbstverständlich.

> Wenn ja, was ist die zugrundeliegende Logik, auf die das
> hinausläuft?

Kein Aliasing.
Nur ein Schreibzugriff auf Variablen wird erzwungen.
Synchronisation oder atomic zwischen Threads und/oder ISRs wird statisch 
erzwungen.

Also praktisch alles das, was man in C sowieso einhalten muss, wird 
erzwungen.

> Interrupt in der Application sperren?

Natürlich. Oder atomic.
Und zwar statisch erzwungen.


Aber ich glaube das ist hier definitiv offtopic :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> EAF schrieb:
>> ASM Begeisterung
>> C++ Schreiber hier überzeugen
>
> Falls Du es noch nicht mitbekommen hast: Es geht hier nicht primär um
> die Programmiersprache. Aber natürlich hat eine jede ihr Licht und ihren
> Schatten und ihren sinnvollen Anwendungsbereich.
> Wenn ich hier auf Asm zu sprechen kam dann weil der TO auf dieser Ebene
> sein Problem viel besser durchschaut hätte.

Bla bla bla ...

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Dein Vorschlag
> funktioniert schließlich nicht weit über das Trivialbeispiel hinaus.

Was erstmal zu beweisen wäre. Die Behauptung steht mir zu einsam im 
Raum.

Selbst für variabele Zeitperioden und für die zeitliche Synchronisation 
von Prozessen bin ich bei AVR bislang sehr gut mit der Verwaltung in 
einem zentralen Systick-Interrupt gefahren der eine benötigte Anzahl von 
zweckgebundenen 32-Bit Variablen zum Beispiel mit 100Hz schlicht immer 
nur stur auf Null herunterzählt. Zugehörige Prozesse stellen nun einen 
beliebigen Byte-Anteil ihres Zählers auf das was sie brauchen und 
überwachen beliebige Byte-Anteile die sie brauchen. Auf schön einfache 
eindeutig-atomare Weise ohne irgendwelche Interrupts aufzuhalten oder 
sonstiges Management. Das macht sich natürlich besonders schön  & 
transparent in Asm.

Diese Vorgehensweise hat mir bislang noch jedes zeitliche 
Steuerungsproblem in Anwendungen erschlagen - auch wenn sie mit einer 
gewissen Ungenauigkeit behaftet ist. Für noch genauere Messungen stehen 
dann die diversen AVRxDx Hardwaretimer exklusiv zur Verfügung.

Und für noch höhere Ansprüche nimmt man ohnehin andere Controller.
Dass wir hier (etwas sehr von oben herab) von einer "Simpelst" MCU für 
einfachere Aufgaben sprechen sollte schon noch im Hinterkopf bleiben.

von EAF (Gast)


Lesenswert?

Ralf schrieb:
> Und für noch höhere Ansprüche nimmt man ohnehin andere Controller.
> Dass wir hier (etwas sehr von oben herab) von einer "Simpelst" MCU für
> einfachere Aufgaben sprechen sollte schon noch im Hinterkopf bleiben.

Jetzt fängt  der ASM Priester auch noch über die glänzende Portabilität 
von seinem unsichtbaren Code an zu schwafeln. Portabel zwischen 
verschiedensten Systemen...
Ein Genie in Tüten.

Viele Grüße aus Absurdistan.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Selbst für variabele Zeitperioden und für die zeitliche Synchronisation
> von Prozessen bin ich bei AVR bislang sehr gut mit der Verwaltung in
> einem zentralen Systick-Interrupt gefahren der eine benötigte Anzahl von
> zweckgebundenen 32-Bit Variablen zum Beispiel mit 100Hz schlicht immer
> nur stur auf Null herunterzählt. Zugehörige Prozesse stellen nun einen
> beliebigen Byte-Anteil ihres Zählers auf das was sie brauchen und
> überwachen beliebige Byte-Anteile die sie brauchen. Auf schön einfache
> eindeutig-atomare Weise ohne irgendwelche Interrupts aufzuhalten oder
> sonstiges Management.

Das ist zwar kein Code, aber irgendwie der Ansatz eines Algorithmus.

Verstehe ich das richtig:
Du hast für jedes benötigte Intervall einen eigenen 32Bit-Zähler, der 
von der periodischen ISR@100Hz dekrementiert wird. Die Startwerte dieser 
Zähler entstehen durch einen 8Bit-Wert, der entsprechend geschoben wird, 
also etwa um 1Bit, dann kannst Du Intervalle von 0,02...5,1s mit 
Quantisierung 0,2s abbilden, oder etwa um 9bit, dann kannst Du 
Intervalle von 5,12...1305,6s mit Quantisierung 5,12s abbilden. In der 
main()-loop machst Du dann nun ein polling? Von was?

von Ralf (Gast)


Lesenswert?

EAF schrieb:
> Viele Grüße aus Absurdistan

Mit solchen "Beiträgen" ganz sicher.

Wilhelm M. schrieb:
> Das ist zwar kein Code, aber irgendwie der Ansatz eines Algorithmus

Das war zwar wieder nicht die geforderte Begründung, aber irgendwie der 
Ansatz einer Rückkehr zur Sache.

> Verstehe ich das richtig

Ich hab noch nicht den Eindruck. Ihr denkt per default zu kompliziert.

Bei 100Hz zählt das niederwertigste Byte1 bis 256* 10ms = 2,56 Sek
das zweite deckt einen Bereich von 2,56Sek *256 Sek= 10,92min ab,
das dritte 10,92min *256= 46,6 Stu, das vierte Byte bis 497 Tage ab.
Die angesprochene Ungenauigkeit ergibt sich bei 100Hz zu +-10ms startend 
beim ersten Byte, sollte das nicht langen tut dem AVR meist auch die 
10fache Zählfrequenz nicht weh, was ich aber noch nie gebraucht habe. 1 
Tag abzubilden bedeutet also z.B. einen Zähler von 83D600H, und da ist 
dann das nicht-atomare Stellen UND Abfragen auch herzlich wurscht. 
Main-Programme prüfen einfach auf Null oder jeden anderen gewünschten 
Zählerwert ihres zugeordneten Zählers, idealerweise nur eines der 4 
Zälerbytes.

Zusätzlich zählen 100Hz Timer-Interrupt oder auch ein Sekunden-Interrupt 
der RTC einen Byte- oder Wordzähler aufwärts, um dem Programm eine 
globale Zeit-Rasterung zur Abstimmung unterschiedlichster Prozesse 
anzubieten.

Prophylaktisch sei noch ganz gelassen gesagt: Wichtig ist, daß dieses 
Timingprocedere funktioniert, weniger wichtig, hier die Zustimmung noch 
des letzten Experten (oder gar Trolls) zu erhalten :)

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> und da ist
> dann das nicht-atomare Stellen UND Abfragen auch herzlich wurscht.

Ach.
Du ignorierst das Problem also einfach nur.
Das ist ja mal innovativ.

von Igor (Gast)


Lesenswert?

MaWin schrieb:
> Du ignorierst das Problem also einfach nur.

Da gibts beim Stellen kein Problem solange das erste Byte ungleich Null 
bleibt (maximal ein ZählerInterrupt dazwischen, besagte Ungenauigkeit 
10ms) und beim Nulltesten genauso wenig: Einfach mit dem höchsten Byte 
anfangen.
Je nach Genauigkeitsanspruch (der in aller Regel mit längeren Zeiträumen 
über Minuten, Stunden, Tage sinkt) langt aber meist, nur ein einzelnes 
der 4 Zählerbytes dem Zeitraum entsprechend in den Blick zu nehmen.

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Du ignorierst das Problem also einfach nur.
> Das ist ja mal innovativ.

Ich stelle hier ein allgemeines Zeitmanagement- System vor MaWin.
Die Lösung für den TO bleibt deshalb dieselbe: Sekunden in der ISR 
zählen!

von MaWin (Gast)


Lesenswert?

Igor schrieb:
> Da gibts beim Stellen kein Problem solange das erste Byte ungleich Null
> bleibt (maximal ein ZählerInterrupt dazwischen, besagte Ungenauigkeit
> 10ms) und beim Nulltesten genauso wenig: Einfach mit dem höchsten Byte
> anfangen.

Die Reihenfolge, in der die Bytes geschrieben werden, ist implementation 
defined und damit nicht portabel. Super "Lösung".

Zähler ist 0.
main stellt Zähler auf 0x100. Erst MSB, dann LSB, weil der Compiler das 
halt so entschieden hat.
Unterbrechung zwischen MSB- und LSB-Schreiben. ISR dekrementiert zu 0xFF
main schreibt LSB.
Zähler ist 0 statt der erwarteten Werte 0x100 oder 0xFF. Das ist ein 
Fehler von nahezu 100%.

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> weil der Compiler das halt so entschieden hat

Tja das wäre mit Asm nicht passiert :)
Die Lösung für den TO bleibt trotzdem die Gleiche.

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Tja das wäre mit Asm nicht passiert :)

Ach. Echt?
Dann lass uns mal einen umgekehrten Schreibzugriff betrachten.

Zähler ist 0x300.
main stellt Zähler auf 0xF00. Erst LSB, dann MSB.
Unterbrechung zwischen LSB- und MSB-Schreiben. ISR dekrementiert zu 
0x2FF
main schreibt MSB.
Zähler ist 0xFFF statt der erwarteten Werte 0xF00 oder 0xEFF.

Echt super Verfahren. Funktioniert in keiner Schreibreihenfolge korrekt.

von Igor (Gast)


Lesenswert?

MaWin schrieb:
> Zähler ist 0x300.
> main stellt Zähler auf 0xF00. Erst LSB, dann MSB.
> Unterbrechung zwischen LSB- und MSB-Schreiben

Igor schrieb:
> Da gibts beim Stellen kein Problem solange das erste Byte ungleich Null
> bleibt (maximal ein ZählerInterrupt dazwischen, besagte Ungenauigkeit
> 10ms)

von MaWin (Gast)


Lesenswert?

Igor schrieb:
> solange das erste Byte ungleich Null

Ja genau. Und wenn doch, dann knallt es eben massiv.

Diese "Lösung" ist maximal eine Speziallösung, die in ganz bestimmten 
Anwendungsfällen, wo man wirklich die zwei Takte für die Interruptsperre 
sparen muss, Anwendung finden kann. Einmal nicht "aufgepasst" und den 
Timer vor Ablauf neugestartet und schon knallt es.
Oder es knallt halt ständig, weil der Compiler die Schreibreihenfolge 
selbst festlegt.
Da muss man also selbst von Hand herumfrickeln.
Alles unschön und unelegant.

von Ralf (Gast)


Lesenswert?

Es ist keine gute Lösung wenn man unter den Beschränkungen von C zu 
leiden hat, zugegeben. Die meisten Timingaufgaben sind aber erstens mit 
nur einem, dem ersten Zählerbyte in der Spanne bis 2,56 Sek erledigt und 
bei seltener verwendeten, längeren Zeiträumen sind die Ansprüche an die 
Genauigkeit geringer daß man meist doch nur mit einem betrachteten Byte 
des Zählers auskommt. Die Lösung, seine Sekunden gleich mit in der ISR 
zu zählen bleibt trotzdem die bessere und ist ebenso in C realisierbar.

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Es ist keine gute Lösung

Na da bin ich ja froh, dass du doch noch einsichtig bist.

Ralf schrieb:
> Die Lösung, seine Sekunden gleich mit in der ISR
> zu zählen bleibt trotzdem die bessere

Die Bessere (tm).
In Jedem Fall (tm).
Ultimativ Beste (tm).

von Igor (Gast)


Lesenswert?

MaWin schrieb:
> Interruptsperre
=
> unschön und unelegant!

Würde ich gleich hinter dumpfen Polling-Schleifen im Hauptprogramm 
einordnen.

von MaWin (Gast)


Lesenswert?

Igor schrieb:
> Würde ich gleich hinter dumpfen Polling-Schleifen im Hauptprogramm
> einordnen.

Möglichst komplexe und möglichst trickreiche Programme mit vielen 
verborgenen Bedingungen (z.B. laufenden Zähler niemals neustarten) ist 
für dich also elegant?

Was spricht gegen eine "dumpfe Polling-Schleife", wenn damit das Problem 
auf einfache und gut nachvollziehbare Art und Weise vollständig gelöst 
wird.

Hängt es vielleicht von der Situation ab, was elegant ist?

von Igor (Gast)


Lesenswert?

MaWin schrieb:
> Interruptsperre

Die Un-schönheit von Notbremsen liegt nicht nur im Auge des Betrachters.
Sollten halt für den Notfall dienen und nicht zum Fahren auf der 
Autobahn.

> Hängt es vielleicht von der Situation ab, was elegant ist?

Was ein System ohne Not aufhält ist objektiv messbar.

von Εrnst B. (ernst)


Lesenswert?

Hat denn schon jemand den magischen Zauber-Code von Ralph oder Igor 
gesehen, der ohne Interrupt-Sperre auskommt?
Egal in welcher Programmiersprache?

Oder existiert der nur in deren Phantasie?

So als reine Behauptung, dass es irgendwie möglich sein könnte, ist das 
ja nicht mehr wert als die Behauptung, dass Einhörner Regenbogen kotzen.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Hat denn schon jemand den magischen Zauber-Code von Ralph

Du siehst Dich also außerstande das Zählen der Sekunden der ISR 
hinzuzufügen?
Was hast Du denn daran noch nicht verstanden?

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Du siehst Dich also außerstande das Zählen der Sekunden der ISR
> hinzuzufügen?
> Was hast Du denn daran noch nicht verstanden?

d.H. du bist nicht in der Lage, die paar Zeilen für die ISR 
hinzuschreiben?

Ist es, weil du überhaupt nicht programmieren kannst sondern nur 
trollst, oder ist es, weil dir beim ersten Versuch aufgefallen ist, dass 
du da in einer Sackgasse steckst?

Beitrag #7257641 wurde von einem Moderator gelöscht.
von Ralf (Gast)


Lesenswert?

Elektrischer Reiter schrieb im Beitrag #7257641:
> Ralf schrieb:
>> Du siehst Dich also außerstande das Zählen der Sekunden der ISR
>> hinzuzufügen?
>
> Willst Du Dich wirklich mit solchen Leuten weiter unterhalten? Das ist
> nicht Dein Ernst...

Stimmt. Viel Sinn macht es wohl nicht wenn der Angesprochene nicht 
verstehen sondern nur polemisieren will.

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Stimmt. Viel Sinn macht es wohl nicht wenn der Angesprochene nicht
> verstehen sondern nur polemisieren will.

Einsicht ist der erste Schritt zur Besserung.
Gute Besserung, Ralf.

von Ralf (Gast)


Lesenswert?

Ich möchte Dir ja Deine wartenden Pollingschleifen und globalen 
Internetblockaden gar nicht wegnehmen Mawin! Jeder wie er kann!

von Εrnst B. (ernst)


Lesenswert?

Ach, jetzt hast du's mit

Ralf schrieb:
> zu einem unbedenklichen Zeitpunkt ausführen wenn
> kein Überlauf zu erwarten ist und hinterher auf Plausibilität prüfen.

so spannend gemacht. Das würde ich echt gern sehen, wie du den Zeitpunkt 
bestimmst (ohne Polling? oder mit?) und wie du die Plausibilitätsprüfung 
implementierst.

Aber war wohl nur heiße Luft.

von MaWin (Gast)


Lesenswert?

Εrnst B. schrieb:
> Das würde ich echt gern sehen, wie du den Zeitpunkt
> bestimmst (ohne Polling? oder mit?) und wie du die Plausibilitätsprüfung
> implementierst.

Ich vermute, dass Magie bei der Implementierung involviert ist.

Aber genaueres kann wohl nur Ralf sagen, wenn er endlich seinen Code 
zeigt.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:

> Das würde ich echt gern sehen, wie du den Zeitpunkt
> bestimmst

Der Zeitpunkt ist recht genau mit 1000ms definiert lieber Ernst.

Aber das wolltest Du vermutlich jetzt nicht hören :)

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Der Zeitpunkt ist recht genau mit 1000ms definiert lieber Ernst.

1000 ms ist eine Zeitspanne. Ein Intervall. Aber kein Zeitpunkt.

Also: An welchem Zeitpunkt findet deine Abfrage statt? Gerne auch mit 
Beispielcode.

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Der Zeitpunkt ist recht genau mit 1000ms definiert lieber Ernst.
>
> Aber das wolltest Du vermutlich jetzt nicht hören :)

d.H. du hast eine ISR, die einmal pro Sekunde läuft, und im 
Hauptprogramm nochmal eine Polling-Schleife, die ebenfalls exakt eine 
Sekunde Zeit vertrödelt, damit du im Hauptprogramm exakt weißt wann die 
ISR durch ist, und du gefahrlos deine Variable auslesen kannst?

Ok. Ist eine Lösung.

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Ralf schrieb:
>> Der Zeitpunkt ist recht genau mit 1000ms definiert lieber Ernst.
>
> 1000 ms ist eine Zeitspanne. Ein Intervall. Aber kein Zeitpunkt.
>
> Also: An welchem Zeitpunkt findet deine Abfrage statt? Gerne auch mit
> Beispielcode.

Der Zeitpunkt ist nach 1000ms erreicht, Mawin.
Das zu erkennen hätte ich Dir schon zugetraut.
Und auch auf die Gefahr hin daß es beim 115. Mal
nicht begriffen wird: Bei 1000ms wird noch in der
ISR die Sekunde weitergezählt (und meinetwegen ein
Signal zum Messgerät des TO gegeben).
Gerne können wir an exakt dieser Stelle weiter diskutieren.
Die Idee ist so bestechend einfach, das schafft Ihr in der
Programmiersprache Euer Wahl! Wer es freilich nicht bis zu
dieser Stelle schafft hat meine Zeit nicht verdient :)

von Εrnst B. (ernst)


Lesenswert?

Der Vollständigkeit halber:
Bei dem Code, den ich oben gepostet hatte

Εrnst B. schrieb:
> static uint32_t getSeconds() {
...

Könnte ich tatsächlich auf den ATOMIC_BLOCK verzichten. Einfach weil der 
µC immer im Sleep steckt, und nur von exakt der ISR aufgeweckt wird, die 
auch den Sekunden-Zähler inkrementiert.
Da dann ein main-Schleifendurchlauf immer weniger als eine Sekunde 
braucht bevor der µC wieder schlafen geht, wäre die Bedingung vom 
"unbedenklichen Zeitpunkt" durchgängig erfüllt.

Aber: Warum sich auf solche Nebenbedingungen verlassen, wenn man's auch 
einfach "robust" programmieren kann?

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Der Zeitpunkt ist nach 1000ms erreicht, Mawin.

Und wie erfährt das Hauptprogramm davon?
Gerne mit Beispielcode.

Ralf schrieb:
> Die Idee ist so bestechend einfach, das schafft Ihr in der
> Programmiersprache Euer Wahl!

Dann schaffst du es ja sicher auch hier Beispielcode zu posten.

Εrnst B. schrieb:
> Aber: Warum sich auf solche Nebenbedingungen verlassen, wenn man's auch
> einfach "robust" programmieren kann?

Weil man auf Krampf zwei Takte sparen muss, die man eh nicht anderweitig 
brauchen kann.
Jedenfalls habe ich Ralf so verstanden.
Oder damit das Programm garantiert kaputt geht, wenn man es in 6 Jahren 
noch einmal anfasst und die ganzen Randbedingungen nicht mehr kennt.
Nur so findet Ralf das spannend, nehme ich an.

von Igor (Gast)


Lesenswert?

MaWin schrieb:
> Und wie erfährt das Hauptprogramm davon?

Wozu im Beispiel des TO?
Bei Bedarf könnte es den 8-bittigen Sekundenzähler ja problemlos 
auslesen.
Die Strategie ist richtig: Alles an Ort und Stelle zu erledigen spart 
ggf. problematischen Datenaustausch.
Das würde ich "robust" nennen.

von Nop (Gast)


Lesenswert?

Εrnst B. schrieb:
> Hat denn schon jemand den magischen Zauber-Code [...]
> gesehen, der ohne Interrupt-Sperre auskommt?

Ist sehr einfach mit dem sequential lock machbar, das ich schon vor vier 
Tagen vorgeschlagen habe: 
Beitrag "Re: AVR DB - oder doch ein Compiler-Fehler?"

von MaWin (Gast)


Lesenswert?

Nop schrieb:
> Ist sehr einfach mit dem sequential lock machbar, das ich schon vor vier
> Tagen vorgeschlagen habe:

Und das ist dann einfacher und besser als kurz IRQs abzuschalten?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich finde es zwar schon traurig wenn Palph immer nur um den heiße Brei 
redet, sowas macht man nicht, aber ...

Wenn ich Ralph richtig verstehe, dann ist seine gesamte Zählerverwaltung 
in der ISR und nirgends woanders.
Wenn er verschiedene "Zähler" benötigt stehen die alle in der ISR.
Am Ende wird Ralph ein 'bool' für jeden Zähler zurückgeben und in der 
Main auswerten und ggf. auch in der Main zurücksetzen.
Da bool 8Bit/1Byte sind ist das automatisch atomar und Bedarf keiner 
weiteren Behandlung.
Korrekt?
Nur falls Ralph Zählerwerte größer 1 Byte in die Main zurückgibt Bedarf 
es atomarer Behandlung. Wenn er das nicht macht hat er ein Problem.

von Εrnst B. (ernst)


Lesenswert?

MaWin schrieb:
> Nop schrieb:
>> Ist sehr einfach mit dem sequential lock machbar, das ich schon vor vier
>> Tagen vorgeschlagen habe:
>
> Und das ist dann einfacher und besser als kurz IRQs abzuschalten?

Nö. Das ist komplizierter, langsamer, und bietet nochmal Fallstricke, 
z.B. bzgl. Compiler-Optimierung.
Stattdessen könnte man es auch einfach richtig machen, und sich 100%ig 
sicher sein, dass man immer und jederzeit einen gültigen Wert lesen 
kann.

Aber da geht das Abenteuer verloren. Muss ja spannend bleiben.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Könnte ich tatsächlich auf den ATOMIC_BLOCK verzichten.

Hab einen Luftsprung gemacht.

Εrnst B. schrieb:
> Da dann ein main-Schleifendurchlauf immer weniger als eine Sekunde
> braucht bevor der µC wieder schlafen geht, wäre die Bedingung vom
> "unbedenklichen Zeitpunkt" durchgängig erfüllt.

Ich frage Dich und alle hier:
Wenn das "Sekundenpuls" Beispiel des TO schon eine vollständige 
Anwendung wär: Wie könnte man diese einfacher und eleganter und robuster 
implementieren als in Main energie- und komplexitätssparend zu schlafen 
(sprich auf eine Programmebene ganz zu verzichten) und die 
übersichtliche Aufgabe in einem einzigen Interrupt zu erledigen?

Veit D. schrieb:
> Korrekt?

Korrekt!

Veit D. schrieb:
> Nur falls Ralph Zählerwerte größer 1 Byte in die Main zurückgibt Bedarf
> es atomarer Behandlung.

In Asm weniger, in C viel mehr. Siehe weiter oben.

von MaWin (Gast)


Lesenswert?

Εrnst B. schrieb:
> Nö. Das ist komplizierter, langsamer, und bietet nochmal Fallstricke,
> z.B. bzgl. Compiler-Optimierung.

Dachte ich es mir doch ;)

> Stattdessen könnte man es auch einfach richtig machen, und sich 100%ig
> sicher sein, dass man immer und jederzeit einen gültigen Wert lesen
> kann.

Ich habe auch schon trickreiche Konstrukte wie z.B. seqlocking 
verwendet.
Aber nicht ohne Not.

Wenn das mit normalen atomic-blocks lösbar ist, dann nehme ich die. Ist 
viel einfacher und wartbarer.

Ralf hat bis heute keine Begründung und keinen Beispielcode liefern 
können, der belegt, dass es besser und schlauer ist grundsätzlich auf 
atomic-blocks zu verzichten.
Das bestätigt mich nur.

> Aber da geht das Abenteuer verloren. Muss ja spannend bleiben.

Aus dem Alter bin ich raus :)

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Ich frage Dich und alle hier:
> Wenn das "Sekundenpuls" Beispiel des TO schon eine vollständige
> Anwendung wär: Wie könnte man diese einfacher und eleganter und robuster
> implementieren als in Main energie- und komplexitätssparend zu schlafen
> (sprich auf eine Programmebene ganz zu verzichten) und die
> übersichtliche Aufgabe in einem einzigen Interrupt zu erledigen?

Völlig richtig.
Leider sind die wenigsten Programme so trivial, dass sie nur Sekunden 
zählen.

von Nop (Gast)


Lesenswert?

MaWin schrieb:

> Und das ist dann einfacher und besser als kurz IRQs abzuschalten?

Ja. Zumal ein sequential lock nicht die worst-case-Latenz der Interrupts 
erhöht. Außerdem hält es den Kontrollfluß sauber, aber das ist wohl auch 
Geschmackssache. Deswegen ist es meine zweitliebste Lösung - nach 
atomarem Zugriff (sofern möglich), also auf diesem µC mit 
8-Bit-Variablen.

Interrupts sperren würde ich allerdings, wenn Interrupt-Settings 
verändert werden sollen, oder wenn etwas gemacht wird, wo keine 
Interrupts kommen sollen, z.B. Flashprogrammierung.

von MaWin (Gast)


Lesenswert?

Nop schrieb:
> Ja. Zumal ein sequential lock nicht die worst-case-Latenz der Interrupts
> erhöht.

Was, wenn mir die worst-case-Latenz des Interrupts (es geht hier um 2, 
3, vielleicht 4 Takte) in der Größenordnung egal ist?

Was, wenn mir die erhöhte Latenz durch das seqlock in der Hauptschleife 
nicht egal ist?

> Außerdem hält es den Kontrollfluß sauber,

Ein seqlock hält den Kontrollfluss sauber?
Hast du ein neues Wort gelernt und versuchst es jetzt auf Krampf zu 
verwenden?

von Nop (Gast)


Lesenswert?

MaWin schrieb:

> Was, wenn mir die worst-case-Latenz des Interrupts (es geht hier um 2,
> 3, vielleicht 4 Takte) in der Größenordnung egal ist?

Es spielt keine Rolle, ob es Dir egal ist.

> Was, wenn mir die erhöhte Latenz durch das seqlock in der Hauptschleife
> nicht egal ist?

Dann ist der Punkt erreicht, an dem Du über ein RTOS nachdenken 
solltest.

> Hast du ein neues Wort gelernt und versuchst es jetzt auf Krampf zu
> verwenden?

Du mich auch.

von MaWin (Gast)


Lesenswert?

Nop schrieb:
> Dann ist der Punkt erreicht, an dem Du über ein RTOS nachdenken
> solltest.

Ja genau.
Um atomic-blocks zu vermeiden ein RTOS verwenden.
Hast du wieder getrunken? Kein Bier vor vier.

von Nop (Gast)


Lesenswert?

MaWin schrieb:

> Um atomic-blocks zu vermeiden ein RTOS verwenden.

Nope. Du hast auch diesen Punkt nicht verstanden.

> Kein Bier vor vier.

Bezeichnend, was so alles in Deinem Kopf vorgeht. Merkt man Deinen 
Beiträgen gerade auch an.

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Ich frage Dich und alle hier:
> Wenn das "Sekundenpuls" Beispiel des TO schon eine vollständige
> Anwendung wär:

dann könnte man das ganze Programm weglassen, weil es ja nix "nach 
Außen" sichtbares mehr macht, außer Strom zu verbrauchen.

Ralf schrieb:
> und die
> übersichtliche Aufgabe in einem einzigen Interrupt zu erledigen

da stößt man schnell an Grenzen, oder muss noch mehr komische Handstände 
machen.
z.B. in dem Programm in dem ich den oben gezeigten Sekunden-Zähler 
verwende: Da wird auch der ADC verwendet, und zwar mit dessen 
Sleep/Noise Reduction Mode. Schon hast du zwei Ebenen an IRQs, und musst 
noch mehr mit CLI/SEI rumbasteln, als es das simple ATOMIC_BLOCK beim 
Auslesen einer Variable macht...

Nop schrieb:
> Zumal ein sequential lock nicht die worst-case-Latenz der Interrupts
> erhöht.

Nur weil es denkbar ist, dass es in 1-von-1Mio Anwendungen vielleicht 
nötig ist, die Interruptlatenz um die paar Instruktionen zu optimieren: 
Das ist nicht allgemeingültig. In >99% der Anwendungen ist es völlig 
egal, ob der Sekunden- oder millis-Interrupt mal fünf Taktzyklen später 
kommt. Er geht deswegen ja nicht verloren.

Nop schrieb:
> Außerdem hält es den Kontrollfluß sauber,

Genau das Gegenteil ist der Fall. Statt einfach den Timer-Wert zu nehmen 
musst du überall den Programmfluss mit zusätzlichen Abfragen und 
Schleifen zumüllen.

von MaWin O. (mawin_original)


Lesenswert?

Nop schrieb:
> Nope. Du hast auch diesen Punkt nicht verstanden.

Willst du ihn mir erklären?
Wir kamen von atomic-blocks. Du schlugst seqlocks als Alternative vor. 
Und dann schlugst du ein RTOS als Problemlösung für die Probleme des 
seqlocks vor.

Warum also keine atomic-blocks?

von Nop (Gast)


Lesenswert?

Εrnst B. schrieb:

> Genau das Gegenteil ist der Fall. Statt einfach den Timer-Wert zu nehmen
> musst du überall den Programmfluss mit zusätzlichen Abfragen und
> Schleifen zumüllen.

Unsinn. Siehe mein Originalposting von vor vier Tagen. Das wird mit nem 
Getter gekapselt.


MaWin O. schrieb:
> Und dann schlugst du ein RTOS als Problemlösung für die Probleme des
> seqlocks vor.

Nope. Du kamst mit "Latenzen in der Hauptschleife", und wenn das ein 
Problem ist, dann bist Du eben im Bereich, wo ein RTOS Sinn ergibt.

> Warum also keine atomic-blocks?

Habe ich bereits geschrieben, siehe oben. Lesen. Ich wiederhole mich 
ungerne.

von MaWin O. (mawin_original)


Lesenswert?

Nop schrieb:
> Unsinn. Siehe mein Originalposting von vor vier Tagen. Das wird mit nem
> Getter gekapselt.

Was am Programmfluss rein gar nichts ändert.

> Nope. Du kamst mit "Latenzen in der Hauptschleife", und wenn das ein
> Problem ist,

Kannst du überhaupt sinnerfassend lesen?
Warum "kam ich" denn damit?
Denk mal darüber nach.

> Lesen

Gute Idee.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Bei 100Hz zählt das niederwertigste Byte1 bis 256* 10ms = 2,56 Sek
> das zweite deckt einen Bereich von 2,56Sek *256 Sek= 10,92min ab,
> das dritte 10,92min *256= 46,6 Stu, das vierte Byte bis 497 Tage ab.

Das ist genau das, was ich oben beschrieben habe, allerdings beschrankst 
Du Dich eben auf Shifts von 8-Bit, weil Du nur die ganzen Bytes des 
uint32_t nimmst.

Da Du beim polling die N Bytes (N € [1,4]) nicht atomar abfragst, 
"verlierst" Du im worst case immer (N-1) niederwertigere Bytes bzw. die 
dazugehörige Zeitspanne wird das Intervall länger. Das ist Deine 
beschriebene Ungenauigkeit.
Das kann man genauso natürlich auch in C / C++ machen. Dazu benötigst Du 
kein ASM. Und in C++ kann man das natürlich auch elegant kapseln und 
elegant erweitern. Wie das geht, schreibe ich natürlich nicht, lieber 
Ralph ;-)

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Das ist zwar kein Code, aber irgendwie der Ansatz eines Algorithmus
>
> Das war zwar wieder nicht die geforderte Begründung, aber irgendwie der
> Ansatz einer Rückkehr zur Sache.

Du bist nicht in der Lage, eine Begründung von mir für was auch immer zu 
fordern. Im Gegensatz zu Dir habe ich oben sehr detailliert für den TO 
und andere erläutert, wo das Problem ist. Und zwar inkl. 
Code-Beispielen.

Und genau das tust Du seit Anbeginn nicht, stattdessen müssen wir raten, 
was Du meinst. Ich habe oben auch mir als einziger hier die Mühe 
gemacht, Dein Geschwafel mal in verständliche Worte zu fassen. Das 
kriegst Du nicht hin bzw. Du willst es nicht, weil Du hier einfach nur 
trollen willst. Und Du bist nicht in der Lage bzw. Du willst es offenbar 
nicht, irgendeinen konkreten Code zu zeigen. Nach dem ganzen Gelaber 
bleibt nur ein einziger Schluss: Du hast solchen Code gar nicht, oder 
willst ihn gar nicht zeigen, weil Du die Schwachstellen kennst aber 
nicht zugeben willst.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Ich hab noch nicht den Eindruck. Ihr denkt per default zu kompliziert.

Du kannst Deinen Ansatz sogar noch verbessern, indem Du so ähnlich 
vorgehst, wie ich oben geschildert habe, allerdings einfach nur einen 
uint32_t Zähler hast und daraus per Shift den entsprechenden 
quantisierten Zähler als uint8_t (atomar) für Deine Task ableitest. Und 
das kann man in C++ wunderbar und allgemeingültig, plattformneutral 
abbilden.

von c-hater (Gast)


Lesenswert?

Veit D. schrieb:

> Wenn ich Ralph richtig verstehe, dann ist seine gesamte Zählerverwaltung
> in der ISR und nirgends woanders.

Das kann gut sein.

> Wenn er verschiedene "Zähler" benötigt stehen die alle in der ISR.

Auch das kann gut sein.

> Am Ende wird Ralph ein 'bool' für jeden Zähler zurückgeben und in der
> Main auswerten und ggf. auch in der Main zurücksetzen.

Das allerdings muss wirklich nicht sein, das ist wieder dieser fiese 
C-only-Dummy-Blick, wo eigentlich alles in main() passiert, weil da die 
Kontrollstrukturen einfach zu lesen sind. Und wo unendlich Zeit damit 
verballert wird, die Ereignisse zu pollen. Statt zu schlafen...

Nimm also bitte zur Kenntnis, dass Anwendungen auch vollständig 
ereignisgesteuert implementiert werden können, wobei "Ereignisse" immer 
auf die Auslösung irgendeines Interrupts zurückgehen und die dafür 
nötige Aktion vollständig im Kontext der jeweiligen ISR abgearbeitet 
werden.

In solchen Anwendungen hat main() nur noch genau eine Aufgabe: den 
entsprechend der Gesamtsituation der Anwendung aktuell tiefstmöglichen 
Schlafzustand zu aktivieren.

Ja, das sind Sachen, die dem generischen C-ler nicht so richtig 
schmecken, aber: solche Anwendungen kann man durchaus auch in C 
programmieren!

Man muss halt einfach nur wissen, was man tut.

von MaWin O. (mawin_original)


Lesenswert?

c-hater schrieb:
> Nimm also bitte zur Kenntnis, dass Anwendungen auch vollständig
> ereignisgesteuert implementiert werden können, wobei "Ereignisse" immer
> auf die Auslösung irgendeines Interrupts zurückgehen und die dafür
> nötige Aktion vollständig im Kontext der jeweiligen ISR abgearbeitet
> werden.

Niemand hat das hier jemals bestritten.

von 900ss (900ss)


Lesenswert?

Wilhelm M. schrieb:
> Und zwar inkl. Code-Beispielen.

Frag mal den TO ob er deinen Code versteht. Es gibt hier leider im Forum 
genauso C++ Missionare wie es Ralf ein ASM Missionar ist. :(
Beides war hier wahrscheinlich
nicht gefragt.
Das Problem lässt sich in vielen Sprachen lösen. Der TO hat 
vermutlich(!) eher auf C gesetzt.

von Wilhelm M. (wimalopaan)


Lesenswert?

900ss D. schrieb:
> Wilhelm M. schrieb:
>> Und zwar inkl. Code-Beispielen.
>
> Frag mal den TO ob er deinen Code versteht. Es gibt hier leider im Forum
> genauso C++ Missionare wie es Ralf ein ASM Missionar ist. :(
> Beides war hier wahrscheinlich
> nicht gefragt.
> Das Problem lässt sich in vielen Sprachen lösen. Der TO hat
> vermutlich(!) eher auf C gesetzt.

Es gab auch C Beispiele

von Ralf (Gast)


Lesenswert?

900ss D. schrieb:
> wie es Ralf ein ASM Missionar ist

Das Ansprechen von Problemen unter einer Programmier-Sprache macht noch 
niemanden zum Missionar.

MaWin schrieb:
> Ralf hat bis heute keine Begründung und keinen Beispielcode liefern
> können, der belegt, dass es besser und schlauer ist grundsätzlich auf
> atomic-blocks zu verzichten.

Was heißt hier "grundsätzlich"? Es ist eine schnelle, ziemlich unsaubere 
Lösung. Gleich sämtliche Interrupts sperren zu müssen würde ich schon 
als Versagen und Niederlage einstufen- die des unerfahrenen 
Programmierers.
Gerade in größeren Programmen mit vielen zeitnah zu beantwortenden 
Interrupts führt der Weg solcherlei Politik von unnötiger 
Ressourcenbelastung über zunehmende Intransparenz bis hin zu immer 
schwerer ortbaren Fehlerbildern.

MaWin schrieb:
> Völlig richtig.
> Leider sind die wenigsten Programme so trivial, dass sie nur Sekunden
> zählen.

Wunderbar daß Du zustimmst.
Es ging zunächst ums Beispiel des TO.
Und die grundsätzliche Lösungs-Strategie die ich nun von allen Seiten 
versucht habe zu beleuchten lässt sich auch darüber hinaus anwenden.
Mit der Einstellung daß der Zweck stets alle Mittel heiligt und alle 
Software derselben Qualität sei darfst Du ja gerne ans Werk gehen.
Mein Anspruch ist ein anderer.

Εrnst B. schrieb:
> Ralf schrieb:
>> und die
>> übersichtliche Aufgabe in einem einzigen Interrupt zu erledigen
>
> da stößt man schnell an Grenzen, oder muss noch mehr komische Handstände
> machen.
> z.B. in dem Programm in dem ich den oben gezeigten Sekunden-Zähler
> verwende: Da wird auch der ADC verwendet, und zwar mit dessen
> Sleep/Noise Reduction Mode. Schon hast du zwei Ebenen an IRQs, und musst
> noch mehr mit CLI/SEI rumbasteln, als es das simple ATOMIC_BLOCK beim
> Auslesen einer Variable macht...

Mit CLI/SEI bastelt man möglichst überhaupt nicht rum. Die Notwendigkeit 
mußt Du mir schon genauer begründen. Mehrere Ebenen an IRQs (der AVRxDx 
hat derer zwei) sind jedenfalls kein Grund dazu. Meine Programme 
enthalten genau 1x SEI: Nämlich um die Grundinitialisierung ungestört 
vornehmen zu können und dann alle Interrupts die darauf aufbauen 
endgültig freizuschalten.

Wilhelm M. schrieb:
> Das kann man genauso natürlich auch in C / C++ machen. Dazu benötigst Du
> kein ASM. Und in C++ kann man das natürlich auch elegant kapseln und
> elegant erweitern. Wie das geht, schreibe ich natürlich nicht, lieber
> Ralph ;-)

Ja. Vermutlich ist es noch komplizierter und ziemlich unansehnlich.
Wenn ich dagegen die wenigen Zeilen Asm Code stelle mit denen ich eine 
große Anzahl Zähler verwalten kann dürfte das ziemlich blamabel für C 
ausfallen.
Immerhin, Punkt für Dich, kannst Du immer noch mit "Portabilität" 
protzen. Nur muß man die erstens wirklich benötigen und zweitens geht 
die eben aufs Konto von Leistung und Codetransparenz- und das behaupte 
ich bis zum Beweis des Gegenteils.

Wilhelm M. schrieb:
> Im Gegensatz zu Dir habe ich oben sehr detailliert für den TO
> und andere erläutert, wo das Problem ist.

Deine Begründung warum es nicht besser sein soll die Sekunden des TO 
gleich in der ISR zu zählen steht bis zur aktuellen Sekunde aus. Du 
redest um den heißen Brei und versuchst den Anschein zu erwecken, daß 
diese Lösung nur mit C-Code zu belegen wäre. Ziemlich albern.

Wilhelm M. schrieb:
> allerdings einfach nur einen
> uint32_t Zähler hast und daraus per Shift den entsprechenden
> quantisierten Zähler als uint8_t (atomar) für Deine Task ableitest.
> verständliche Worte

Verständliche Worte sind eher Deinen Schilderungen aus abstrakter 
Theorie anzuraten.

c-hater schrieb:
> C-only-Dummy-Blick

So drastisch wollte ich es nicht ausdrücken.
Immerhin hat C auch seine Verdienste.
Wenn es aber dazu führt daß Grundlagen unverstanden bleiben führt das 
u.a. hier zu vielen überflüssigen Beiträgen.

von MaWin (Gast)


Lesenswert?

Naja, ich bin dann mal weg. War ganz lustig, aber der Troll wiederholt 
sich.

von 900ss (900ss)


Lesenswert?

Ralf schrieb:
> 900ss D. schrieb:
>
>> wie es Ralf ein ASM Missionar ist
>
> Das Ansprechen von Problemen unter einer Programmier-Sprache macht noch
> niemanden zum Missionar

In der Art, wie du krampfhaft versuchst die vermeintlichen Vorteile 
einer Assembler-Lösung gegen über C oder eine Hochsprache in den 
Vordergrund zu stellen hat durchaus etwas Missionarisches.

Dann weiter die Geheimniskrämerei, kein konkretes ASM-Beispiel zu 
liefern an dem man einen Vorteil erkennen könnte. Das verstärkt schon 
den Eindruck, dass du nur so ungefähr weißt, wovon du redest. Aber was 
sollst... DU darfst gerne alles in Assembler lösen. Und wenn der Tag 
kommt, wo du auf eine MCU wechselst, die kein AVR Assembler versteht, da 
machst halt alles nochmal. Ja, das ist klug, Hut ab.

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Naja, ich bin dann mal weg. War ganz lustig, aber der Troll
> wiederholt
> sich.

Was solltest Du bei dieser recht eindeutigen Sachlage auch noch 
vorbringen können? Was bleibt ist Frust auf persönlicher Schiene 
abzulassen. Was auch für meinen unmittelbaren Vorredner gilt.

Beitrag #7258564 wurde vom Autor gelöscht.
von EAF (Gast)


Lesenswert?

Mich erinnert die Diskussion an Kurt Bindl.
1. Ein Priester, der meint den heiligen Gral, oder so, gefunden zu 
haben.
2. Alle anderen sind doof
3. Zeigt nichts, keine einziger Nachweis wird geführt
4. Gegenanzeigen werden komplett ausgeblendet, z.B. hier Portabilität

von Ralf (Gast)


Lesenswert?

Für Dich gilt das Gleiche. Bleib beim Thema.
Wer portablen Code braucht soll C oder was anderes nehmen.
Lt. Aussage von Wilhelm M. bestehen angeblich keinerlei Einschränkungen.
Dann kann er Euch bestimmt auch weiterhelfen.

von EAF (Gast)


Lesenswert?

Ralf schrieb:
> Für Dich gilt das Gleiche.
Meine Verfahren habe ich hier schon einige male im Forum ausgebreitet. 
Natürlich mit konkreten Beispielen.

Damit bist du der Lüge überführt.

von Ralf (Gast)


Lesenswert?

EAF schrieb:
> Damit bist du der Lüge überführt.

Daß Du genau wüsstest welcher wär auch gelogen :))
Freut mich daß Du Dich an anderer Stelle schon eingebracht hast. Davon 
lebt das Forum schließlich.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Das kann man genauso natürlich auch in C / C++ machen. Dazu benötigst Du
>> kein ASM. Und in C++ kann man das natürlich auch elegant kapseln und
>> elegant erweitern. Wie das geht, schreibe ich natürlich nicht, lieber
>> Ralph ;-)
>
> Ja. Vermutlich ist es noch komplizierter und ziemlich unansehnlich.
> Wenn ich dagegen die wenigen Zeilen Asm Code stelle mit denen ich eine
> große Anzahl Zähler verwalten kann dürfte das ziemlich blamabel für C
> ausfallen.

Wohl kaum. Ich bevorzuge Code, der deterministisch arbeitet, was bei 
Deinem Geschwafel nicht der Fall ist.

> Immerhin, Punkt für Dich, kannst Du immer noch mit "Portabilität"
> protzen. Nur muß man die erstens wirklich benötigen und zweitens geht
> die eben aufs Konto von Leistung und Codetransparenz- und das behaupte
> ich bis zum Beweis des Gegenteils.

Eben nicht, wenn man es richtig macht.

> Wilhelm M. schrieb:
>> Im Gegensatz zu Dir habe ich oben sehr detailliert für den TO
>> und andere erläutert, wo das Problem ist.
>
> Deine Begründung warum es nicht besser sein soll die Sekunden des TO
> gleich in der ISR zu zählen steht bis zur aktuellen Sekunde aus. Du
> redest um den heißen Brei und versuchst den Anschein zu erwecken, daß
> diese Lösung nur mit C-Code zu belegen wäre. Ziemlich albern.

Was nicht stimmt. Ich habe oben gesagt, dass es in ASM genauso trivial 
ist wie in C / C++, wenn man es richtig macht. Um das zu widerledegn, 
müsstest Du schon mal Deinen nicht existenten Code zeigen.


> Wilhelm M. schrieb:
>> allerdings einfach nur einen
>> uint32_t Zähler hast und daraus per Shift den entsprechenden
>> quantisierten Zähler als uint8_t (atomar) für Deine Task ableitest.
>> verständliche Worte
>
> Verständliche Worte sind eher Deinen Schilderungen aus abstrakter
> Theorie anzuraten.

Mit was hast denn ein Problem? Weißt Du nicht, was atomar ist?

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:

> Wer portablen Code braucht soll C oder was anderes nehmen.

Wer deterministisches Verhalten haben möchte, sollte nicht Ralphs 
Geschwafel nehmen.

von Ralf (Gast)


Lesenswert?

Zur Debatte stand meine Forderung, Sekunden statt in Main gleich nach 
Ablauf der 1000ms in der ISR zu zählen um jedem Problem mit gemeinsam 
genutzen Variablen inklusive den nötigen Interruptsperrungen aus dem 
Wege zu gehen.
Wenn DU diese simple Idee nur mit entsprechendem Code nachvollziehen 
kannst tust Du mir als angeblich so erfahrener C Experte wirklich leid.
Wer nach eigener Definition alles richtig macht mit dem besteht eher 
kein weiterer Diskussionsbedarf. Wofür ich mich aber bedanken möchte ist 
die unfreiwillige Offenbarung einiger weiterer Beschränkungen mit denen 
man beim Umstieg auf C rechnen müsste. Allen gegenteiligen Bemühungen 
inklusive vieler Nebelkerzen zum Trotz. Da musst Du noch etwas am 
Determinismus Deiner Argumentationskette arbeiten :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Zur Debatte stand meine Forderung, Sekunden statt in Main gleich nach
> Ablauf der 1000ms in der ISR zu zählen um jedem Problem mit gemeinsam
> genutzen Variablen inklusive den nötigen Interruptsperrungen aus dem
> Wege zu gehen.

Nö, mittlerweile steht Dein Zauber-Code aka Geschwafel zur Diskussion, 
beliebige Intervalle abbilden zu können und diese in der main-loop zu 
verwenden.

> Wenn DU diese simple Idee nur mit entsprechendem Code nachvollziehen
> kannst tust Du mir als angeblich so erfahrener C Experte wirklich leid.

Ich kann nicht nur das, sondern ich kann auch noch Deinem Geschwafel 
entlocken, das es nicht funktioniert.

> Da musst Du noch etwas am
> Determinismus Deiner Argumentationskette arbeiten :)

Und Du musst Dir irgendwo noch etwas Code klauen, den Du hier zeugen 
kannst.

von Ralf (Gast)


Lesenswert?

Leeres Geschwätz Wilhelm M.
Was ich mich aber frage, weshalb investiert hier jemand Zeit mit 
persönlichen Angriffen von dem man meinen könnte er hätte sinnvolleres 
zu tun? Irgendwas kann da wohl nicht stimmen. Frustrieren die 
Möglichkeiten anderer Sprachen? Was ist es was Dich deprimiert?

von Εrnst B. (ernst)


Lesenswert?

Andererseits ist es ja ganz gut, dass Ralph keinen Code postet.
Sonst könnte noch jemand versucht sein, das zu kopieren...

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Andererseits ist es ja ganz gut, dass Ralph keinen Code postet.
> Sonst könnte noch jemand versucht sein, das zu kopieren...

Unbedingt.
Eine simple Idee ist ohnehin besser in Worten beschrieben.
Dann versteht sie nämlich jeder. Oder tappst Du ohne Code
so wie Wilhelm M. auch noch im Dunklen?

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Unbedingt.

Ach, du gibst also zu, dass deine Idee in Code gegossen so abgrundtief 
grottenschlecht ist, dass du das selbst niemandem zumuten willst?

Gibt Bonuspunkte für Selbstreflektion.

von Ralf (Gast)


Lesenswert?

Aber dermaßen Ernst.
Und ich hab mich schon immer gewundert warum nix richtig funktioniert :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Εrnst B. schrieb:
> Andererseits ist es ja ganz gut, dass Ralph keinen Code postet.
> Sonst könnte noch jemand versucht sein, das zu kopieren...

Ja, das stimmt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Εrnst B. schrieb:

> Gibt Bonuspunkte für Selbstreflektion.

Ich denke, dass er dazu nicht fähig ist.

Er hat keinen Code, den er zeigen kann. Er weiß auch gerade nicht, wo er 
sowas kopieren soll. Alles nur Gelaber.

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Εrnst B. schrieb:
>
>> Gibt Bonuspunkte für Selbstreflektion.
>
> Ich denke, dass er dazu nicht fähig ist.
>
> Er hat keinen Code, den er zeigen kann. Er weiß auch gerade nicht, wo er
> sowas kopieren soll. Alles nur Gelaber.

Mach was Sinnvolleres Wilhelm M. anstatt Dir hier ständig was aus den 
Fingern zu saugen. Code gibts keinen, es langt wenn Du das 1mal 
feststellst. Vermutlich weißt Du selber längst nicht mehr worum es darin 
gehen sollte...

@Ernst: Wolltest Du nicht noch begründen welchem Zweck nun genau Deine 
CLI/SEI Stümpereien, sorry Basteleien genau dienen?

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Εrnst B. schrieb:
>>
>>> Gibt Bonuspunkte für Selbstreflektion.
>>
>> Ich denke, dass er dazu nicht fähig ist.
>>
>> Er hat keinen Code, den er zeigen kann. Er weiß auch gerade nicht, wo er
>> sowas kopieren soll. Alles nur Gelaber.
>
> Mach was Sinnvolleres Wilhelm M. anstatt Dir hier ständig was aus den
> Fingern zu saugen. Code gibts keinen, es langt wenn Du das 1mal
> feststellst.

Alles klar: es gibt keinen, weil Du keinen hast.

von 900ss (900ss)


Lesenswert?

Mobi ist back :)

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Alles klar

Hoffentlich.

von Ralf (Gast)


Lesenswert?

Was ebenso klar geworden sein sollte:
Globale Interruptsperren sind meistens durch schlaueren Methoden 
ersetzbar.
Das Beispiel des TO gehört auf jeden Fall dazu.

von Sebastian (Gast)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>
>> Alles klar
>
> Hoffentlich.

Die Idee, für Zeitabfragen aus einem 32-Bit-Zähler immer nur ein Byte 
atomar auszulesen und so Interuptsperren und ATOMAR-Konstrukte zu 
vermeiden, ist ja recht interessant. Wenn Wertebereiche und Auflösung 
ausreichen.

Dem TO vom ATOMAR-Konstrukt, von Specherbarrieren, und allgemein von 
allem ausser Assembler abzuraten halte ich für eine Einzelmeinung (sagt 
man doch so, auch wenn es mindestens schon zwei Foristen gibt die sie 
vertreten).

Eine Softwarekonstruktion die fast alles in Interrupts abhandelt und bei 
der das Hauptprogramm "gepflegt schläft" scheint mir nur in wenigen 
Fällen geeignet. Ich würde es eher nicht so machen. Aber auf alle 
Anforderungen der Hardware rechtzeitig zu reagieren erfordert eh eine 
Analyse maximaler Reaktionszeiten und davon abgeleitet maximaler 
Sperrzeiten, und des Abklopfens aller benutzter Bibliotheken darauf, 
dagegen ist dann die Aufteilung zwischen regulärem Kontext und 
Interrupt-Kontext eher ein Streit um des Kaisers Bart.

YMMV.

LG, Sebastian

von Veit D. (devil-elec)


Lesenswert?

Hallo,

habe mir das natürlich angeschaut. Ich habe nur die namespace Verwirrung 
entfernt. :-)
Vorweg, ich habe keine Ahnug was der Syntax wie barrier([&] ... macht. 
Oder access([]{ ... . Ein Array? wo es kein Array gibt noch dazu mit & 
Symbol. Absolut Null Schimmer was das ist. Ich kann mir jedoch davon 
abgesehen den Code erklären was da abläuft.

'flag' wird mit MemoryBarrier in der ISR und main() Zwangsweise frisch 
gelesen bzw. geschrieben. Das wird mittels Barrier Klasse 
Konstruktoraufruf und Zerstörung automatisch 2x aufgerufen. Das läuft 
über mehrer "Funktionsaufrufe". Soweit ist mir der Ablauf klar. im 
Detail gibts aber mehr Fragen wie Antworten.


In der barrier Funktion wird eine Instanz b erstellt aber nie vewendet. 
???
Dann wird eine Funktion f() aufgerufen die es gar nicht gibt. Ähmm 
'grübel'
1
void barrier(const auto f) {
2
  Barrier b;
3
  f();
4
}


Auch in der Access Funktion wird eine 'di' Instanz erzeugt aber nie 
verwendet? Und der unbekannte Syntax ([&]{ und wieder die nicht 
existierende Funktion f(). 'grübel'
1
void access(const auto f)
2
{
3
  DisableInterruptsRestore di;
4
  barrier([&] {
5
    f();
6
  });
7
}


Jetzt muss ich nochmal auf den Vergeich mit volatile zurückkommen. Mit 
der MemoryBarrier wird ja der frische Lese/Schreibzugriff erzwungen. 
Also das was auch mit volatile erzwungen wird. Nur das ohne volatile die 
Variable woanders an anderen Stellen vom Compiler optimiert werden 
könnte. Könnte! Soweit sollte das nun von mir stimmen. Nun kommt meine 
Praxisseite raus wegen dem Könnte! Wenn man eine Variable hat die 
außerhalb von normalen Programmfluss geändert wird und man deswegen 
frischen Lese/Schreibzugriff benötigt, dann ist es ja meistens so das 
man sowieso immer den frischen Wert haben möchte und der Compiler 
sowieso nicht optimieren kann/darf. Zudem werden solche 'volatile' 
Variablen ja nicht verstreut im gesamten Programm verwendet sondern 
üblich nur an ganz bestimmten Stellen, was ja beim Zeitzähler der Fall 
ist. Man fragt den ja nicht an verschiedenen Stellen ab sondern alles 
was nach Zeitablauf erfolgen soll passiert nach dessen gültigen 
Ereigniseintritt. Das heißt die vom Compiler mögliche non volatile 
Optimierung irgendwo anders kommt sowieso nicht zum Zuge. Also warum 
soll man sich in der Praxis das verkomplizierende Konstrukt mit 
MemoryBarrier überhaupt antun? Denn der gezeigte Code macht ja nichts 
anderes was man auch mit volatile machen könnte mit viel weniger 
Programmzeilen. Hier und da kann der Compiler an 'flag' nichts 
optimieren. Jeder Zugriff wird überall frisch benötigt und erzwungen. 
Genau wie mit volatile.

Ich habe verstanden was MemoryBarrier ist und macht. Vielen Dank. Aber 
der Nutzen ist mir nicht klar. Wann mit Optimierungsnutzen für den 
Compiler ist das statt volatile wirklich sinnvoll? Also selbst wenn ich 
100 Rechenkerne habe die alle mit der MemoryBarrier Variable arbeiten 
benötigen alle Rechenkerne den aktuellen Wert. Wo soll dabei eine 
Optimierung für den Compiler möglich sein? Mein Gedanke sollte 
verständlich sein worauf ich hinaus möchte. Ich würde es ja zukünftig 
verwenden wenn mir der Vorteil klar wäre. Wir reden nicht von der 
möglichen Optimierungsmöglichkeit. Wir reden davon in welchen Fällen der 
Compiler überhaupt die Chance zum optimieren wahrnehmen kann. Wenn er 
Compiler seine Trumpfkarte nie ausspielen kann, wie ich denke, dann ist 
der ganze Aufwand für die Katz.

Ich hätte aus Nutzersicht noch ein Problem mit _MemoryBarrier(). Es ist 
kein Anfang und Ende erkennbar. Code der dazwischen steht wird 
"erzwungen". Soweit so gut. Nur man bräuchte ein Anfang und Ende ähnlich 
wie cli/sei vom Namen her oder meinetwegen wie AtomicBlock mit Klammer { 
... } woraus jederzeit ersichtlich wird für den Codeleser was jetzt 
'gekapselt' ist. Denn folgen mehrere im Wechsel ist spätestens nach dem 
2. Aufruf unklar welche Codezeilen dazwischen liegen. Das wird wohl auch 
der Grund sein für die Klassen mit expliziten Dekonstruktor. Weil sonst 
blickt niemand mehr durch.

Darum ging es:
1
#include <avr/cpufunc.h>
2
#include <util/atomic.h>
3
#include <stdint.h>
4
5
6
struct Barrier final {
7
  inline Barrier() {
8
    _MemoryBarrier();
9
  }
10
  inline ~Barrier() {
11
    _MemoryBarrier();
12
  }
13
};
14
15
void barrier(const auto f) {
16
  Barrier b;
17
  f();
18
}
19
20
struct DisableInterruptsRestore final {
21
  inline DisableInterruptsRestore() {
22
    cli();
23
  }
24
  inline ~DisableInterruptsRestore() {
25
    SREG = save;
26
  }
27
  private:
28
    uint8_t save{SREG};
29
};
30
31
void access(const auto f) {
32
  DisableInterruptsRestore di;
33
  barrier([&] {
34
    f();
35
  });
36
}
37
38
volatile uint8_t mcuRegister;
39
uint8_t g;
40
bool flag;
41
42
43
ISR(TCA1_CMP0_vect) {
44
  barrier([] {
45
    ++g;
46
    if (g > 100) flag = true;
47
  });
48
}
49
50
int main(void) {
51
  while (true) {
52
    access([]{
53
      if (flag) {
54
        flag = false;
55
        mcuRegister = 0x01;
56
      }
57
    });
58
  }
59
}

von 900ss (900ss)


Lesenswert?

Veit D. schrieb:
> Jetzt muss ich nochmal auf den Vergeich mit volatile zurückkommen.

Ich stimme dir voll zu. Es sollte schon lesbar bleiben. Das Beispiel mit 
der memory barrier ist deutlich unübersichtlicher als eine Lösung mit 
volatile. Und wenn einem die paar Takte wegen der schlechteren 
Optimierung fehlen, dann man eher ein anderes Problem und es fliegt 
einem das Zeugs an einer anderen Stelle auch um die Ohren.

Das Problem der fehlenden Optimierung mit volatile ist mir im 
Berufsleben noch nie begegnet. Es ist eher theoretischer Natur. Man kann 
es nicht ausschließen aber wie schon geschrieben, dann hat man woanders 
auch Probleme. Dann ist eher das Systemdesign fragwürdig (Auswahl der 
geeigneten MCU) wenn es so eng wird dass die paar nicht optimierten 
Stellen ins Gewicht fallen.

Ja klar, in Assembler wird das alles besser und vor allem trotzdem 
übersichtlich und wartbarer. ;) Man hätte diese Probleme nicht.
Und nein, ich nehme trotzdem kein Assembler, habe ich auch mal ca. 10 
Jahre machen dürfen. :) Hat auch was ja. Aber heute? Nur wenn es ohne 
nicht geht ein paar Zeilen.

: Bearbeitet durch User
von EAF (Gast)


Lesenswert?

Veit D. schrieb:
> Vorweg, ich habe keine Ahnug was der Syntax wie barrier([&] ... macht.
> Oder access([]{ ... . Ein Array? wo es kein Array gibt noch dazu mit &
> Symbol. Absolut Null Schimmer was das ist.
Eine Lambda Funktion, der alle Instanzeigenschaften als Referenz zur 
Verfügung stehen.

von Ralf (Gast)


Lesenswert?

Sebastian schrieb:
> Die Idee, für Zeitabfragen aus einem 32-Bit-Zähler immer nur ein Byte
> atomar auszulesen und so Interuptsperren und ATOMAR-Konstrukte zu
> vermeiden, ist ja recht interessant. Wenn Wertebereiche und Auflösung
> ausreichen.

Main>Interrupt atomar Lesen/Schreiben wird mit C Pflicht, sonst gehts 
wie schon beschrieben auch "quasi-atomar" in richtiger 
Zugriffs-Reihenfolge mit mehreren Bytes des Zählers. Mit nur 1 Byte 
kommt man aber auch schon weit da für immer längere Zeiträume meist auch 
immer größere Ungenauigkeiten tolerabel sind.
Ich wüsste nicht, welche gebräuchlichen Zeitperioden mal mindestens ab 
1ms bis beliebig lange mit der Methode nicht abgedeckt werden könnten.

> von allem ausser Assembler abzuraten

Kann keine Rede von sein. Fakt bleibt: Asm ist am flexibelsten aber eben 
meist nur für kleinere Programme sinnvoll. Für nicht unbedingt wenige.

> Eine Softwarekonstruktion die fast alles in Interrupts abhandelt und bei
> der das Hauptprogramm "gepflegt schläft" scheint mir nur in wenigen
> Fällen geeignet.

In allen Fällen bei denen der Programm-Funktionsumfang und die 
Interrupt-Belastung überschaubar bleiben. Für nicht unbedingt wenige.

> Analyse maximaler Reaktionszeiten und davon abgeleitet maximaler
> Sperrzeiten, und des Abklopfens aller benutzter Bibliotheken darauf

Auf Sperrzeiten ganz zu verzichten schafft gerade bei hoher 
Interruptfrequenz maximalen Spielraum und erleichtert Entwicklung und 
Debugging ungemein.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

@ 900ss:
Das ich bei Programmierdiskussionen mal Zustimmung bekomme ist auch neu. 
:-)  Mal abwarten ob Wilhelm noch eine Bsp. hat wo der Compiler diese 
Variable optimieren kann.

@ EAF:
Danke. Mit dem Begriff Lambda kann ich arbeiten bzw. nachlesen. Habe 
Lambda bis heute noch nicht benötigt.

von 900ss (900ss)


Lesenswert?

Veit D. schrieb:
> Das ich bei Programmierdiskussionen mal Zustimmung bekomme ist auch neu.

Ich fürchte du verwechselst da etwas.

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Vorweg, ich habe keine Ahnug was der Syntax wie barrier([&] ... macht.
> Oder access([]{ ... . Ein Array? wo es kein Array gibt noch dazu mit &
> Symbol. Absolut Null Schimmer was das ist. Ich kann mir jedoch davon
> abgesehen den Code erklären was da abläuft.

Den Funktionen wird ein Funktionsobjekt übergeben, in dem Fall ein 
Closure erzeugt durch einen Lambda-Ausdruck -> Funktionales 
Programmieren in C++. Wer Lambda-Ausdrücke verstanden hat, hat C++ 
verstanden ;-)

> In der barrier Funktion wird eine Instanz b erstellt aber nie vewendet.
> ???

Das Idiom nennt sich RAII. Ist eines der einfachten C++-Idiome und 
sollte jedem bekannt sein.

> Dann wird eine Funktion f() aufgerufen die es gar nicht gibt. Ähmm
> 'grübel'

Ist das Funktionsobjekt in der Parametervariablen f: kann eine Funktion, 
ein Funktor oder Closure sein.

>
> Auch in der Access Funktion wird eine 'di' Instanz erzeugt aber nie
> verwendet? Und der unbekannte Syntax ([&]{ und wieder die nicht
> existierende Funktion f(). 'grübel'

RAII

> Jetzt muss ich nochmal auf den Vergeich mit volatile zurückkommen. Mit
> der MemoryBarrier wird ja der frische Lese/Schreibzugriff erzwungen.
> Also das was auch mit volatile erzwungen wird. Nur das ohne volatile die
> Variable woanders an anderen Stellen vom Compiler optimiert werden
> könnte.

Ja. Eine Variable als volatile zu deklarieren ist eigentlich sinnlos, es 
sei denn es ist ein HW-Register, wo jeder Zugriff einen Seiteneffekt 
auslösen soll.

Ansonsten sollte die Zugriffsart ggf. "volatile" sein, und nicht die 
Variable. Und das erreicht man mit einer memory-barrier. Wobei natürlich 
eine wie hier verwendete globale memory-barrier alle(!) ge-cache-ten 
Register zurückschreibt, also auch noch zu viel ist.

Wenn man das noch besser machen will, kann man z.B. explizit einen 
"volatile"-acces machen.

> Jeder Zugriff wird überall frisch benötigt und erzwungen.
> Genau wie mit volatile.

Mach mal einen Test: nimmt eine x-beliebiges, etwas größeres Artefakt, 
einmal mit als volatile qualifizierte Datenstrukturen und andererseits 
einen Zugriff mit memory-barrier.

> Ich habe verstanden was MemoryBarrier ist und macht. Vielen Dank. Aber
> der Nutzen ist mir nicht klar.

Dann hast Du es nicht verstanden.

> Wann mit Optimierungsnutzen für den
> Compiler ist das statt volatile wirklich sinnvoll? Also selbst wenn ich
> 100 Rechenkerne habe die alle mit der MemoryBarrier Variable arbeiten
> benötigen alle Rechenkerne den aktuellen Wert.

Du musst bedenken, dass es bei komplexeren CPUs als die simplen AVR 
neben den Compiler-memory-barriern (Compile-zeit) auch noch die 
CPU-memory-barrier (Laufzeit) gibt.

> Wo soll dabei eine
> Optimierung für den Compiler möglich sein? Mein Gedanke sollte
> verständlich sein worauf ich hinaus möchte. Ich würde es ja zukünftig
> verwenden wenn mir der Vorteil klar wäre. Wir reden nicht von der
> möglichen Optimierungsmöglichkeit. Wir reden davon in welchen Fällen der
> Compiler überhaupt die Chance zum optimieren wahrnehmen kann.

Mach einfach mal in einer ISR:
1
volatile uint8_t g;
2
ISR(...) {
3
    ++g;
4
    if (g > 10) {
5
         ...
6
    }

Dann erkennst Du es: g kann nicht in einem register ge-cahe-ed werden 
wegen volatile.
[/c]

> Ich hätte aus Nutzersicht noch ein Problem mit _MemoryBarrier(). Es ist
> kein Anfang und Ende erkennbar. Code der dazwischen steht wird
> "erzwungen".

Nein. Es werden alle ge-cached-ten Inhalte Zrückgeschrieben und die 
Register-Inhalte invalidiert, müssen also nachgeladen werden.

> Das wird wohl auch
> der Grund sein für die Klassen mit expliziten Dekonstruktor. Weil sonst
> blickt niemand mehr durch.

Wie gesagt: jeder(!) der C++ einsetzt sollte RAII kennen.
Was ich dort geschrieben habe, ist nicht mehr als ein Schulbeispiel, wo 
man explizit den Einsatz eines Kritischen Bereiches und den Einsatz 
einer memory-barrier explizit sehen kann. Ich fand das besser, als den 
ATOMIC_BLOCK, wo genau dasselbe im C-Stil stattfindet, eber m.E. weniger 
sichtbar ist. Also didaktische Gründe.

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Du musst bedenken, dass es bei komplexeren CPUs als die simplen AVR

Wir sind hier aber beim dankenswerterweise simplen AVR.
Hast Du Dir diesen Thread als Vehikel ausgesucht graue C++ Theorie zu 
diskutieren?

> Dann hast Du es nicht verstanden!


Das mag ja alles seine Anwendung und Bedeutung in größeren IT-Kisten 
haben- für das Thread-Thema aber sicher nicht. Möge jeder meiner simplen 
AVRs von der Belastung durch C++ verschont bleiben- und schlicht nur 
seine Aufgabe erledigen.

von EAF (Gast)


Lesenswert?

Ralf schrieb:
> C++

Was ist das?
Wo sind die Vor- und Nachteile?

von Peter D. (peda)


Lesenswert?

Ralf schrieb:
> Auf Sperrzeiten ganz zu verzichten schafft gerade bei hoher
> Interruptfrequenz maximalen Spielraum und erleichtert Entwicklung und
> Debugging ungemein.

Nun, beim AVR gibt es keine Interruptlevel. Du mußt daher jederzeit 
damit rechnen, daß der längste Interrupthandler gerade in Ausführung ist 
und für seine eigene Laufzeit sämtliche anderen Interrupts sperrt. Mit 
Einsprung, Aussprung, Prolog, Epilog, Register retten usw. kommt man 
kaum unter 50 CPU-Zyklen Interruptsperre. Dagegen ist ein atomarer 
Zugriff auf 2 oder 4 Byte einfach nur lächerlich.

Es ist daher auch extrem kontraproduktiv, statt einer globalen Sperre 
nur den speziellen Interrupt zu sperren, mit dem der atomare 
Datenaustausch erfolgen soll. Denn dann hat man wieder das Problem mit 
dem längsten Interrupthandler, der dazwischen grätschen kann. Bzw. bei 
CPUs mit Interruptlevel hat man dann sogar eine mögliche 
Prioritätsinversion.

von Wilhelm M. (wimalopaan)


Lesenswert?

Peter D. schrieb:
> Nun, beim AVR gibt es keine Interruptlevel.

Bei den etwas neueren schon: NMI, Level1, Level0. Außerdem werden 
Interrupts in der ISR nicht automatisch deaktiviert. Wenn man sie also 
zulässt (kein cli/sei/SREG), hat man ggf. wieder dasselbe Problem ...

von Ralf (Gast)


Lesenswert?

Peter D. schrieb:
> Nun, beim AVR gibt es keine Interruptlevel. Du mußt daher jederzeit
> damit rechnen, daß der längste Interrupthandler gerade in Ausführung ist
> und für seine eigene Laufzeit sämtliche anderen Interrupts sperrt. Mit
> Einsprung, Aussprung, Prolog, Epilog, Register retten usw. kommt man
> kaum unter 50 CPU-Zyklen Interruptsperre. Dagegen ist ein atomarer
> Zugriff auf 2 oder 4 Byte einfach nur lächerlich.

Nun, der hier diskutierte AVR hat erstens zwei 
Anwendungs-Interruptlevel.
Mit 50 CPU- Zyklen für einen Interrupt hast Du wahrscheinlich C mit 
seiner umfangreicheren Register-Sicherung im Hinterkopf. So muß das aber 
ganz und gar nicht sein wenn man flexibler ist. Kurzfristige Sperren für 
atomare Zugriffe können je nach Belastung in der Tat lächerlich sein. 
Sie bleiben dennoch überflüssig, erfordern extra Bürokratie in Form von 
AtomicBlocks, die eine extra Ecke sind um die man denken muß und über 
die man wie der TO stolpern kann. Dieser Kritikpunkt ist fast noch 
wichtiger...

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> erfordern extra Bürokratie in Form von
> AtomicBlocks, die eine extra Ecke sind um die man denken muß

Ach, und bei deiner Lösung ist das besser? Wenn man bei jedem Zugriff 
erstmal überlegen muss, wie man da eine Plausibilitätsprüfung einbaut, 
und was diese alles prüfen und beachten muss?

Das Argument mit "Das ist in einen Getter gekapselt" zählt nicht, da 
kann ich nämlich auch den Atomic-Block drin kapseln.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Ach, und bei deiner Lösung ist das besser? Wenn man bei jedem Zugriff
> erstmal überlegen muss, wie man da eine Plausibilitätsprüfung einbaut,
> und was diese alles prüfen und beachten muss?

Thema war das Problem des TO.
Es ist so simpel wie hier tausendmal beschrieben zu lösen.

Du beziehst Dich jetzt auf das Timing-Management in meinen Programmen 
das ich kurz erläutert hatte. Irgendeine Plausibilitäts-Prüfung wäre 
dort nur dann erforderlich wenn mehrere Prozesse auf denselben Zähler 
schreiben würden. Kann man machen, in aller Regel sind die Zähler aber 
wie beschrieben nur einer bestimmten Aufgabe zugeordnet. Via Asm kann 
dann jede Zählerbyte-Teilmenge problemlos beschrieben und gelesen 
werden. Hier ist die Regel dann meist nur ein Null-Test eines bestimmten 
Zählerbytes vom Hauptprogramm aus. Alternativ ließe sich, für maximal 
Speed, auch ein im Timer-Interrupt gestelltes GPR_GPRx IO-Registerbit 
als Kommunikationsmedium dafür einspannen.

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Thema war das Problem des TO.

Und genau für das Problem ist die millionenfach bewährte Standard-Lösung 
eben eine kurze Interrupt-Sperre.
Egal ob man das in Assembler schreibt (CLI/SEI) oder in C mit 
cli()/sei() oder mit dem ATOMIC_BLOCK syntactic-sugar, oder in C++ mit 
einer auto-Variable, die das im Konstruktor+Destruktor verpackt.
Und wenn man wiederverwertbaren Code will und einem ein paar Bytes mehr 
im Flash nicht stören, nimmt man statt SEI eben ein Save&Restore vom 
SREG.

Und nein, das Argument mit der gesteigerten Interrupt-Latenz zählt auch 
nicht. Deine Lösung verlängert die Timer-ISR mehr als es eine kurze 
Sperre beim Auslesen tun würde, insofern ist deine Lösung da auch 
schlechter.

Beitrag #7260385 wurde von einem Moderator gelöscht.
von Εrnst B. (ernst)


Lesenswert?

Mehmet T. schrieb im Beitrag #7260385:
> Hallo zusammen,
> Kann man mir auch helfen?
> Ich möchte eine GPS UHR mit einem Arduino UNO bauen.

Beib doch bei deinem Thread:

https://www.mikrocontroller.net/topic/546402#

von Nop (Gast)


Lesenswert?

Wilhelm M. schrieb:

> Also didaktische Gründe.

Daß man mit C++ einfachste Probleme solange verkomplizieren kann, bis 
man sie ausführlich erklären muß, hat keiner bezweifelt. Ist ansonsten 
aber überflüssig, kann also weg.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Und genau für das Problem ist die millionenfach bewährte Standard-Lösung
> eben eine kurze Interrupt-Sperre.

Klar. Man hat das immer schon so gemacht. Dann machs doch weiter so.

Εrnst B. schrieb:
> Deine Lösung verlängert die Timer-ISR mehr als es eine kurze
> Sperre beim Auslesen tun würde

Die Lösung für den TO kommt mit dem Sekundenzählen im Interrupt in Summe 
kürzer und einfacher.

Redest Du von meinem Zähler-Zeitmanagement hast Du vermutlich Recht.
Nur ist dessen Zielrichtung gar nicht maximale Performance sondern 
bequem-übersichtliches, problemfreies Zeitmanagement für's Hauptprogramm 
und dessen einzelne Bestandteile. Für ein Hauptprogramm, welches für 
seine Zwecke niemals in die globale Interruptsperrung/freigabe 
eingreift. Das hat in gewissem Sinne was von Kapselung und Trennung 
selbstständiger Programmebenen. Auf diese Weise lassen sich gewisse 
Interrupt-Vorlagen mit einem bestimmten Portfolio an Diensten 
(Zeit-Management fürs Hauptprogramm ist nur eine Aufgabe) für viele 
Projekte wiederverwenden.

Nop schrieb:
> Daß man mit C++ einfachste Probleme solange verkomplizieren kann, bis
> man sie ausführlich erklären muß, hat keiner bezweifelt. Ist ansonsten
> aber überflüssig, kann also weg.

Das hätte man nicht besser ausdrücken können :)

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Die Lösung für den TO kommt mit dem Sekundenzählen im Interrupt in Summe
> kürzer und einfacher.

Was zu beweisen wäre. Du hast keinen Code geliefert, sondern nur eine 
grobe Umschreibung als Fließtext. Nach der wäre das Gegenteil der Fall.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Was zu beweisen wäre.

Mach Dich doch nicht lächerlich.
Derselbe Code der die Sekunden in Main zählt kann sie auch in der ISR 
zählen. Damit ist Dein extra AtomicBlock schonmal hinfällig.
An anderer Stelle dieses Threads warst Du schon mal weiter!

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> An anderer Stelle dieses Threads warst Du schon mal weiter!

Echt jetzt?
Mein Code zählt die Sekunden in der ISR.
Du wolltest es anders machen.
Also: Zeig mal.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Mein Code zählt die Sekunden in der ISR.

Wenn es so wäre passt es doch. Genau die Idee hab ich vertreten.
Wozu dann noch AtomicBlocks im Hauptprogramm? Wozu Interrupts sperren?

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Wozu dann noch AtomicBlocks im Hauptprogramm?

na zum Auslesen des sekunden-Zählers, gekapselt in einem Getter, zum 
x-ten mal...

Mag manchmal nicht nötig sein, aber so funktioniert der Code immer & 
garantiert, auch wenn ich ihn in einem anderen Projekt mit anderen 
Rahmenbedingungen recycle.

Darum geht es mir: Sauberen Code zu schreiben, der reproduzierbar 
funktioniert.

Nicht irgendwas planlos zusammenschustern, und dann ewig dran rumdoktorn 
bis es vielleicht meistens gut funktioniert, solange bis sich irgendwas 
ändert.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> na zum Auslesen des sekunden-Zählers

Wozu denn? Um den Puls zur Messung vom Hauptprogramm auszugeben?
Das erledigt man im Interrupt selbstredend mit.

> Darum geht es mir: Sauberen Code zu schreiben, der reproduzierbar
> funktioniert.

Das schaffe ich genauso. Ohne sinnlose Interrupt-Sperren.

> Nicht irgendwas planlos zusammenschustern, und dann ewig dran rumdoktorn
> bis es vielleicht meistens gut funktioniert, solange bis sich irgendwas
> ändert.

Meinen Plan hab ich beschrieben. Und beantworte Nachfragen dazu gerne.

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> Wozu denn? Um den Puls zur Messung vom Hauptprogramm auszugeben?
> Das erledigt man im Interrupt selbstredend mit.

> Das schaffe ich genauso. Ohne sinnlose Interrupt-Sperren.

> Meinen Plan hab ich beschrieben. Und beantworte Nachfragen dazu gerne.

->
1
goto Threadanfang;


Hiiiilllffeeeeeee! Wir sind gefangen!

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Hiiiilllffeeeeeee! Wir sind gefangen!

Da haben wir direkt mal den gleichen Eindruck :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Weil Ralph ja keinen Code liefert, schreibe ich seinen ASM-Code hier mal 
als C++. Und der Compiler macht daraus dasselbe, wie er per Hand machen 
würde, wenn der Ralph das denn könnte.
1
template<uint8_t N>
2
struct Timer {
3
    static void isr() {
4
        ++c;
5
    }
6
    template<uint8_t B>
7
    static void whenByteIsZero(auto f) {
8
        Memory::barrier([&]{
9
            if (etl::nth_byte<B>(c) == 0_B) {
10
                f();
11
            }
12
        });
13
    }
14
private:
15
    inline static uint32_t c;
16
};
17
18
using timer0 = Timer<0>;
19
20
ISR(TCA0_CMP0_vect) {
21
    timer0::isr();
22
}
23
24
int main() {
25
    while (true) {
26
        timer0::whenByteIsZero<1>([]{
27
            VPORTA_OUT = 0x01;
28
        });
29
    }
30
}

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Und damit Ralph noch etwas lernen kann, hier der ASM-Code aus dem 
vorigen Post:
1
__RAMPZ__ = 0x3b
2
__CCP__ = 0x34
3
.text
4
.type   __vector_9, @function
5
__vector_9:
6
__gcc_isr 1      ;
7
push r25                 ;
8
push r26                 ;
9
push r27                 ;
10
lds r24,Timer<(unsigned char)0>::c       ;  c, c
11
lds r25,Timer<(unsigned char)0>::c+1     ;  c, c
12
lds r26,Timer<(unsigned char)0>::c+2     ;  c, c
13
lds r27,Timer<(unsigned char)0>::c+3     ;  c, c
14
adiw r24,1       ;  tmp45,
15
adc r26,__zero_reg__     ;
16
adc r27,__zero_reg__     ;
17
sts Timer<(unsigned char)0>::c,r24       ;  c, tmp45
18
sts Timer<(unsigned char)0>::c+1,r25     ;  c, tmp45
19
sts Timer<(unsigned char)0>::c+2,r26     ;  c, tmp45
20
sts Timer<(unsigned char)0>::c+3,r27     ;  c, tmp45
21
pop r27          ;
22
pop r26          ;
23
pop r25          ;
24
__gcc_isr 2      ;
25
reti
26
__gcc_isr 0,r24
27
.size   __vector_9, .-__vector_9
28
.section        .text.startup,"ax",@progbits
29
.type   main, @function
30
main:
31
ldi r24,lo8(1)   ;  tmp52,
32
.L4:
33
lds r25,Timer<(unsigned char)0>::c+1     ;  tmp49, c
34
cpse r25,__zero_reg__    ;  tmp49,
35
rjmp .L3         ;
36
out 0x1,r24      ;  MEM[(volatile uint8_t *)1B], tmp52
37
.L3:
38
rjmp .L4                 ;

von MaWin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> hier mal als C++.

Du scheinst Spaß daran zu haben triviale Probleme möglichst kompliziert 
zu schreiben.

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Das schaffe ich genauso.
Dann zeig es.

> Meinen Plan hab ich beschrieben.
"Rummurksen, bis es nicht mehr ganz so oft abstürzt?"

Oder war dein Plan:
"den TE mit einer Spezial-Sonderlösung verwirren, die zwar in diesem 
Einzelfall erstmal funktioniert, ihm aber im nächsten Projekt dermaßen 
auf die Füße fällt, dass er noch Wochen danach Kopfschmerzen hat?

> Und beantworte Nachfragen dazu gerne.

Nachfrage: wie schaut der Quelltext aus?

von Veit D. (devil-elec)



Lesenswert?

Hallo,

ich weiß zwar nicht worauf genau ich testen soll, habe jedoch einmal ein 
asmdump erstellt. Ich kann da jetzt keinen Unterschied in der ISR und 
dem flag Zugriff in der main erkennen. Alles der gleiche Code. Was mich 
ehrlich gesagt nicht wundert, denn der Compiler kann ja hier nichts 
optimieren. Wo soll er optimieren? An welcher Stelle? Es wird wie schon 
gesagt an allen Stellen ein frischer Zugriff benötigt.

>> Ich hätte aus Nutzersicht noch ein Problem mit _MemoryBarrier(). Es ist
>> kein Anfang und Ende erkennbar. Code der dazwischen steht wird
>> "erzwungen".

> Nein. Es werden alle ge-cached-ten Inhalte Zrückgeschrieben und die
> Register-Inhalte invalidiert, müssen also nachgeladen werden.

Hier hast du meine Frage falsch verstanden. Alles was mit MemoryBarrier 
erfolgen soll muss doch zwischen zwei Aufrufen stehen.
 _MemoryBarrier();
...
...
 _MemoryBarrier();

Wenn das jetzt mehrfach erfolgen muss wie etwa

 _MemoryBarrier();
...
 _MemoryBarrier();
...
 _MemoryBarrier();
...
 _MemoryBarrier();
...
 _MemoryBarrier();
...
 _MemoryBarrier();

Wie soll man dann noch erkennen welche Codezeilen mit und welche ohne 
MemoryBarrier erfolgen?

von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
> Alles was mit MemoryBarrier
> erfolgen soll muss doch zwischen zwei Aufrufen stehen

Nein. Meistens nicht.
Meistens haben die zwei Threads-of-execution jeweils eine Barrier.

von Veit D. (devil-elec)


Lesenswert?

MaWin schrieb:
> Veit D. schrieb:
>> Alles was mit MemoryBarrier
>> erfolgen soll muss doch zwischen zwei Aufrufen stehen
>
> Nein. Meistens nicht.
> Meistens haben die zwei Threads-of-execution jeweils eine Barrier.

Irgendwie raff ich das nicht oder mein Gedankenproblem wird nicht 
verstanden. Wenn im Code nur einmal der Aufruf MemoryBarrier() steht, 
woher  weiß der Compiler welche Variablen er frisch einlesen/schreiben 
soll? Alle davor? Alle danach? Wo zieht der Aufruf seine Grenze? Im 
AtomicBlock gibts eine Klammer damit ist der Fall klar. Zwischen den 
Klammern ist AtomicBlock gültig. Mit cli und sei ist der Fall auch klar. 
Dazwischen erfolgt keine Interruptunterbrechung. Was ist mit Einen 
MemoryBarrier() Aufruf?
Wilhelm ruft in seiner Klasse automatisch 2x MemoryBarrier() auf. 2x.

von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
> Wenn im Code nur einmal der Aufruf MemoryBarrier() steht,
> woher  weiß der Compiler welche Variablen er frisch einlesen/schreiben
> soll? Alle davor? Alle danach?

Selbstverständlich die davor. Das ist doch triviale Logik.
Die danach kann er nicht frisch einlesen, weil die noch gar nicht 
eingelesen wurden.
Die werden dann eben nach der Barriere eingelesen.

> Im AtomicBlock gibts eine Klammer damit ist der Fall klar.

Mit Klammern ist überhaupt nichts klar. Die haben überhaupt keine 
Barrierenfunktion.

> Wilhelm ruft in seiner Klasse automatisch 2x MemoryBarrier() auf. 2x.

Wilhelms Code ist auch ziemlicher Käse.
Der verkompliziert das ohnehin schon nicht ganz triviale Problem der 
memory barriers ohne Grund weiter.

von Nop (Gast)


Lesenswert?

MaWin schrieb:

> Meistens haben die zwei Threads-of-execution jeweils eine Barrier.

Und zwar eine nach dem Schreiben (auf der Producer-Seite) und eine vor 
dem Lesen (auf der Consumer-Seite).

von MaWin (Gast)


Lesenswert?

@Veit D. (devil-elec)

Ich würde auch einmal diese Lektüre empfehlen:

https://en.cppreference.com/w/c/atomic/memory_order

Dort werden generelle Prinzipien und Ordering-Strategien besprochen.
Barriers sind nur Mittel zum Zweck, um diese Strategien umzusetzen.
Man sollte die Prinzipien und Strategien also vorher verstehen, bevor 
man sie mit Barriers anwendet.
Deine Frage, wie viele Barriers man braucht, deutet eindeutig darauf 
hin, dass du diese Grundlagen nicht verstanden hast.

Wenn man ein Bild aufhängen will, dann beschäftigt man sich auch nicht 
als erstes mit dem Durchmesser des Bohrers.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ist denn hier wirklich niemand im Stande eine einfache Frage zu 
beantworten?

Ich frage nach wo die Abgrenzung ist und bekomme alles davor als 
Antwort. Ganz prima. Kann doch nicht sein.
Ich mach das Bsp. mit AtomicBlock und bekomme die Antwort hat keine 
Barrierfunktion.
Menno. Will man nicht oder kann man nicht?
Natürlich hat AtomicBlock nichts mit Barrier zu tun. Es geht um die 
Klammern. Um die klare Abgrenzung worauf sich AtomicBlock bezieht.
Mit MemoryBarrier sehe ich keinen klaren abgegrenzten Anweisungsblock. 
Wenn man mir sagt alles davor ist das keine Antwort auf meine Frage. Auf 
wieviel Variablenzugriffe davor gilt denn dann ein MemoryBarrier Aufruf? 
Wenn der für alle davor gilt wäre das ja vollkommen sinnfrei. Man will 
es ja nur auf bestimmte Variablen anwenden.

von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
> ist denn hier wirklich niemand im Stande eine einfache Frage zu
> beantworten?

Gerne, danke.

> Ich frage nach wo die Abgrenzung ist

Die Abgrenzung ist an der Barriere. Was verstehst du daran denn nicht?

> und bekomme alles davor als Antwort.

Hilfe hilfe, die helfen mir und geben mir Informationen!!

> Es geht um die Klammern

Nein. Klammern haben nichts mit dem Konzept von Barriers zu tun. Vergiss 
das komplizierte C++-Beispiel.
Das verwirrt nur.

> Auf
> wieviel Variablenzugriffe davor gilt denn dann ein MemoryBarrier Aufruf?

Auf alle.

> Wenn der für alle davor gilt wäre das ja vollkommen sinnfrei.

Nein. Warum?

> Man will
> es ja nur auf bestimmte Variablen anwenden.

Ja. Aber "bestimmte" ist eine Untermenge von "alle".

Und ja, es gibt auch Barrieren, die nur auf bestimmte Variablen wirken.
Siehe: https://en.cppreference.com/w/c/atomic/memory_order
Es ist aber nicht so, dass diese Variablen dann an ihren Namen irgendwie 
benannt werden. Sondern die Barrier hat bestimmte Eigenschaften (z.B. 
Load-Acquire-Semantik) und wirkt deshalb nur auf bestimmte 
Zugriffsarten, aber nicht auf alle.

Lies dich doch bitte ein. Das ist kein triviales Thema, was man eben mal 
in einem Forum lernt.

von Nop (Gast)


Lesenswert?

Veit D. schrieb:

> Wenn der für alle davor gilt wäre das ja vollkommen sinnfrei. Man will
> es ja nur auf bestimmte Variablen anwenden.

Der Trick an der Sache ist, daß Du die Barrier beim Schreiben direkt 
danach anwendest und beim Lesen direkt davor. Im sehr einfachen Beispiel 
von Wikipedia [1]:

Thread #1 Core #1:
1
 while (f == 0);
2
 // Memory fence required here
3
 print x;

Thread #2 Core #2:
1
 x = 42;
2
 // Memory fence required here
3
 f = 1;

Also in Thread 2 nach dem Schreiben von x, weil f erst geschrieben 
werden darf, wenn x auf 42 steht. Und in Thread 1 vor dem Lesen von x, 
weil x erst gelesen werden soll, wenn die Kontrollogik mit der 
while-Schleife durch ist.

Es gibt da keinen Barrier-Block, sondern ein Paar, das an zwei ganz 
verschiedenen Stellen steht. Hier in zwei Threads, geht aber mit 
Interrupt vs. Anwendung ähnlich. Dieses Paar wirkt zusammen.

[1] https://en.wikipedia.org/wiki/Memory_barrier

von EAF (Gast)


Lesenswert?

Veit D. schrieb:
> ist denn hier wirklich niemand im Stande eine einfache Frage zu
> beantworten?

Bist du denn in der Lage eine einfache Frage zu einem komplexen Problem 
zu stellen?
Offensichtlich ist doch wohl, dass der Compiler zwecks Optimierung, 
Variablen in Register hält.
Damit ist die eigentlich fundamentale Notwendigkeit der Datenkonsistenz 
gebrochen. Was nicht schlimm ist, solange nicht einer "heimlich" die 
Variablen im Speicher manipuliert.
z.B. in einer ISR

Die Memory Barriere soll genau die Konsistenz wieder herstellen. Also 
muss sie natürlich VOR dem kritischen Zugriff gesetzt werden.
Und natürlich nochmal, bevor die ISR wieder auf die Variable zugreifen 
muss/kann, wenn das Hauptprogramm auch die Variable manipuliert.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

> Bist du denn in der Lage eine einfache Frage zu einem komplexen Problem
> zu stellen?

Bist du in der Lage eine einfache Frage zu verstehen? Anders gefragt. 
Bist du in der Lage eine einfache Frage zu erkennen?

Ich kann auch so pampig antworten.

Ihr steckt wahrscheinlich so tief im Detail das niemand meine Frage 
versteht. Kann doch nicht sein. 'Nop' kommt dem jetzt sehr nahe. Mal 
sehen was sich daraus machen lässt.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
> Ich kann auch so pampig antworten.

Das haben wir bereits gemerkt.

> Ihr steckt wahrscheinlich so tief im Detail das niemand meine Frage
> versteht.

Wenn jemand eine Frage nicht versteht, dann trägt niemals der Gefragte 
die Schuld daran. Solltest du dir allgemein merken.

> Kann doch nicht sein.

Genau.

von EAF (Gast)


Lesenswert?

Veit D. schrieb:
> Bist du in der Lage eine einfache Frage zu verstehen? Anders gefragt.
> Bist du in der Lage eine einfache Frage zu erkennen?
>
> Ich kann auch so pampig antworten.

Ich bin nicht für deine Denkblockaden verantwortlich, auch wenn du dir 
das noch so gerne wünscht!

Veit D. schrieb:
> Ich mach das Bsp. mit AtomicBlock und bekomme die Antwort hat keine
> Barrierfunktion.
> Menno. Will man nicht oder kann man nicht?
> Natürlich hat AtomicBlock nichts mit Barrier zu tun.

Natürlich implementieren die Macros aus util/atomic.h auch Memory 
Barrieren!
Das lässt sich leicht im QuellCode nachweisen.
Auch die Macros in interrupts.h tun das, zumindest cli() und sei() 
welche in atomic.h verwendet werden.

von EAF (Gast)


Lesenswert?

Veit D. schrieb:
> Es geht um die Klammern.
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) braucht keine Klammern.

Veit D. schrieb:
> Mit MemoryBarrier sehe ich keinen klaren abgegrenzten Anweisungsblock.
Das ist richtig!
Weil es keinen Anweisungsblock hat.
Die Barriere stellt die Datenkonsistenz wieder her.
Mehr nicht.

Veit D. schrieb:
> Auf
> wieviel Variablenzugriffe davor gilt denn dann ein MemoryBarrier Aufruf?
> Wenn der für alle davor gilt wäre das ja vollkommen sinnfrei. Man will
> es ja nur auf bestimmte Variablen anwenden.

Die Barriere wirkt auf ALLE Variablen, welche gerade in Registern 
gehalten werden und noch nicht im Speicher gesichert wurden.
Was jetzt günstiger ist, wird man wohl im Einzelfall entscheiden dürfen

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Natürlich hat AtomicBlock nichts mit Barrier zu tun.

Doch: das Macro beinhaltet zwei memory-barrier, eine am Block-Anfang und 
eine am -Ende. Genau wie ich es in der C++-Alternative geschrieben 
haben.

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Du scheinst Spaß daran zu haben triviale Probleme möglichst kompliziert
> zu schreiben.

Bingo. Wir teilen tatsächlich wieder denselben Eindruck.

Εrnst B. schrieb:
> Oder war dein Plan:
> "den TE mit einer Spezial-Sonderlösung verwirren, die zwar in diesem
> Einzelfall erstmal funktioniert, ihm aber im nächsten Projekt dermaßen
> auf die Füße fällt, dass er noch Wochen danach Kopfschmerzen hat?

Bis zur Vorstellung meines Timer-Managements war das Problem des TO ja 
längst gelöst, es sollte verdeutlichen wie einfach, intuitiv und 
übersichtlich Timing-Aufgaben generell angegangen werden können. Ohne 
AtomicBlockMemoryBarriereWissenschaften.

Wilhelm M. schrieb:
> Weil Ralph ja keinen Code liefert, schreibe ich seinen ASM-Code
> hier mal
> als C++. Und der Compiler macht daraus dasselbe, wie er per Hand machen
> würde, wenn der Ralph das denn könnte.
> template<uint8_t N>
> struct Timer {
>     static void isr() {
>         ++c;
>     }
>     template<uint8_t B>
>     static void whenByteIsZero(auto f) {
>         Memory::barrier([&]{
>             if (etl::nth_byte<B>(c) == 0_B) {
>                 f();
>             }
>         });
>     }
> private:
>     inline static uint32_t c;
> };
> using timer0 = Timer<0>;
> ISR(TCA0_CMP0_vect) {
>     timer0::isr();
> }
> int main() {
>     while (true) {
>         timer0::whenByteIsZero<1>([]{
>             VPORTA_OUT = 0x01;
>         });
>     }
> }

Meine Güte, was für ein Irrgarten.
Der Assembler-Code schaut noch schlimmer aus.

Eine Anzahl von bis 255 32-Bit Timern 0-dekrementieren lässt sich in Asm 
z.B. für 4 Stück recht knapp und übersichtlich wie folgt formulieren:
1
;TDC    TIMER-DOWNCOUNTER (*4)
2
;               (x= DoubleWord 0-7: zählt alle HSEK/2.56Sek/10.92Min/46.6Stu)
3
;               (HSEK/xSEK/xMIN/xSTU)
4
;    1Sek= 64/00/00/00, 1Min= 70/17/00/00, 1Stu= 40/7E/05/00
5
;    1Tag= 00/D6/83/00, 1Wo= 00/DA/9A/03
6
 
7
tdc:    ldi  ZL,low(DC0HSEK)
8
    ldi  ZH,high(DC0HSEK)
9
    ldi  YL,4      ;4 DOWNCOUNTER
10
tdc1:    ldd  XL,Z+0
11
    ldd  XH,Z+1
12
    sbiw  XH:XL,1
13
    brsh  tdc2
14
    ldd  XL,Z+2
15
    ldd  XH,Z+3
16
    sbiw  XH:XL,1
17
    brlo  tdc3
18
    std  Z+2,XL
19
    std  Z+3,XH
20
    ser  XL
21
    ser  XH
22
tdc2:    std  Z+0,XL
23
    std  Z+1,XH
24
tdc3:    adiw  ZH:ZL,4
25
    dec  YL
26
    brne  tdc1
27
                ret
28
29
DC0HSEK:        .BYTE 1         ;[4010H] not available
30
DC0SEK:    .BYTE 1    ;[4011H] STARTTIMER
31
DC0MIN:    .BYTE 1    ;[4012H] not available
32
DC0STU:    .BYTE 1    ;[4013H] not available
33
DC1HSEK:        .BYTE 1         ;[4014H] not available
34
DC1SEK:    .BYTE 1    ;[4015H] PRESENCE CONTROL
35
DC1MIN:    .BYTE 1    ;[4016H] not available
36
DC1STU:    .BYTE 1    ;[4017H] not available
37
DC2HSEK:        .BYTE 1         ;[4018H] not available
38
DC2SEK:    .BYTE 1    ;[4019H] VALIDDATA TIMEOUT
39
DC2MIN:    .BYTE 1    ;[401AH] not available
40
DC2STU:    .BYTE 1    ;[401BH] not available
41
DC3HSEK:        .BYTE 1         ;[401CH] not used
42
DC3SEK:    .BYTE 1    ;[401DH] not used
43
DC3MIN:    .BYTE 1    ;[401EH] not used
44
DC3STU:    .BYTE 1    ;[401FH] not used

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:

> Irgendwie raff ich das nicht oder mein Gedankenproblem wird nicht
> verstanden. Wenn im Code nur einmal der Aufruf MemoryBarrier() steht,
> woher  weiß der Compiler welche Variablen er frisch einlesen/schreiben
> soll? Alle davor? Alle danach? Wo zieht der Aufruf seine Grenze? Im
> AtomicBlock gibts eine Klammer damit ist der Fall klar. Zwischen den
> Klammern ist AtomicBlock gültig. Mit cli und sei ist der Fall auch klar.
> Dazwischen erfolgt keine Interruptunterbrechung. Was ist mit Einen
> MemoryBarrier() Aufruf?
> Wilhelm ruft in seiner Klasse automatisch 2x MemoryBarrier() auf. 2x.

Genau, es ist das direkte Äquivalent zu ATOMIC_BLOCK. Schau Dir das 
Macro an. Der CPP ersetzt den init-Ausdruck der for-Schleife durch ein 
cli(), das ist wiederum ein cli in asm und memory-barrier. Und am Ende 
im restore-Ausdruch der out-of-scope gehenden sreg_save Variablen kommt 
auch eine memory-barrier. Damit ist dieser Block universell einsetzbar. 
Zwei unmittelbar aufeinanderfolgende memory-bariier kollabieren 
natürlich zu einer, denn dazwischen git es keine Register, die evtl. 
dirty sein könnten.

von MaWin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Doch: das Macro beinhaltet zwei memory-barrier, eine am Block-Anfang und
> eine am -Ende. Genau wie ich es in der C++-Alternative geschrieben
> haben.

Für 99% aller Anwendungsfälle als Ablaufsynchronisation ist eine von den 
beiden Barriers überflüssig.
Deine Lösung ist unnötig kompliziert.

Ralf schrieb:
> Ohne AtomicBlockMemoryBarriereWissenschaften.

Das geht nicht.
Auch nicht in asm.

von MaWin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Zwei unmittelbar aufeinanderfolgende memory-bariier kollabieren
> natürlich zu einer, denn dazwischen git es keine Register, die evtl.
> dirty sein könnten.

Das ist natürlich nur auf dieser Trivialarchitektur namens AVR der Fall.

von Wilhelm M. (wimalopaan)


Lesenswert?

MaWin schrieb:
> Wilhelm M. schrieb:
>> Doch: das Macro beinhaltet zwei memory-barrier, eine am Block-Anfang und
>> eine am -Ende. Genau wie ich es in der C++-Alternative geschrieben
>> haben.
>
> Für 99% aller Anwendungsfälle als Ablaufsynchronisation ist eine von den
> beiden Barriers überflüssig.
> Deine Lösung ist unnötig kompliziert.

Und nochmal: es ist einfach das direkte Äquivalent zu ATOMIC_BLOCK, 
sonst nichts. Mit dem Vorteil, das alle Operationen nun sichtbar sind. 
Auch Beit D. hat das nun gesehen, das hatte er bei ATOMIC_BLOCK so nicht 
bemerkt.

von MaWin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Und nochmal: es ist einfach das direkte Äquivalent zu ATOMIC_BLOCK,
> sonst nichts.

Ja. Habe ich verstanden. Es ergibt aber trotzdem keinen Sinn.
Eine Barrier, ohne lock/mutex oder cli/sei, ist halt kein Block.
Das Konzept eines Blocks ergibt dort überhaupt gar keinen Sinn.

> Mit dem Vorteil, das alle Operationen nun sichtbar sind.

Nö. Es verbirgt die Barriere.

von Wilhelm M. (wimalopaan)


Lesenswert?

MaWin schrieb:
> Ja. Habe ich verstanden. Es ergibt aber trotzdem keinen Sinn.
> Eine Barrier, ohne lock/mutex oder cli/sei, ist halt kein Block.
> Das Konzept eines Blocks ergibt dort überhaupt gar keinen Sinn.

Der Block von ATOMIC_BLOCK ist begrenzt durch cli() bzw. SREG restore 
und zwei memory-barrier (Anfang / Ende).

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Der Block von ATOMIC_BLOCK ist begrenzt durch cli() bzw. SREG restore
> und zwei memory-barrier (Anfang / Ende).

korrekt.

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> Ralf schrieb:
>> Ohne AtomicBlockMemoryBarriereWissenschaften.
>
> Das geht nicht.
> Auch nicht in asm.

Für besagtes Zeitmanagement mal mindestens.
Erzähl doch keinen Unsinn.
Einfach herrlich diese "Trivialarchitektur"!
Warum kompliziert wenn es auch einfach geht!
Mögen uns diese Chips noch lange erhalten bleiben!

von Wilhelm M. (wimalopaan)


Lesenswert?

MaWin schrieb:
> Das geht nicht.
> Auch nicht in asm.

Siehe mein letztes Beispiel aus

Beitrag "Re: AVR DB - oder doch ein Compiler-Fehler?"

Das ist genau das was Ralph ohne Code mit Geschwafel beschrieben hat. In 
diesem Spezialfall (nur 8-Bit atomare Lese/Schreibvorgänge, "Timer" mit 
zunehmender Quantisierung) geht es auch in C / C++ ohne cli/sei. 
Natürlich sollte man das mit entsprechende static_asserts absichern, 
dass diese Annahmen zutreffen, damit es später nicht irgendwo knallt.
Natürlich muss man in C / C++ hier eine memory-barrier einbauen. Diese 
kleine Maßnahme ist notwendig, damit man sich trotzdem auf die 
Optimierungen des Compilers verlassen kann, ohne über irgendwelchen ASM 
Murks nachdenken zu müssen.

von Ralf (Gast)


Lesenswert?

Bei manchem Zeitgenossen kann einfach nicht sein was nicht sein darf.
Dabei muss man sich eigentlich nicht wundern, wenn sich fette Bulldozer 
in gerade mal 8 Bit breiten Nischen etwas schwerer tun.

P.S. Wie nennt man ein neues C++ Feature? Verschlimmbesserung!

von MaWin (Gast)


Lesenswert?

Ralf schrieb:
> wenn sich fette Bulldozer
> in gerade mal 8 Bit breiten Nischen etwas schwerer tun.
>
> P.S. Wie nennt man ein neues C++ Feature? Verschlimmbesserung!

Nur weil etwas im Quellcode gesprächig ist, heißt das noch lange nicht, 
dass es im Binary groß ist.
C++ und viele andere Sprachen arbeiten nach dem Konzept der 
zero-cost-abstraction.

Und grundsätzlich halte ich das für eine gute Sache.
Man darf es halt nicht übertreiben und Abstraktionen nicht nur zum 
Selbstzweck einfügen.

von EAF (Gast)


Lesenswert?

MaWin schrieb:
> zero-cost-abstraction

MaWin schrieb:
> Abstraktionen

Vorsicht!
ASM Priester verstehen unter Abstraktion häufig was anderes. Die halten 
gerne ihre Sprache, für die, mit den meisten/besten 
Abstraktionsmöglichkeiten.

von Ralf (Gast)


Lesenswert?

MaWin schrieb:
> dass es im Binary groß ist

Das bekäme man mit hinreichend guten Spezial-Kenntnissen ja noch hin- 
sprich klein und schnell genug. Bulldozer meint eher die mangelnde 
Flexibilität dabei (siehe: atomarer Zählerzugriff) und den großen zu 
beherrschenden Sprachumfang- ohne gleichzeitig und zwingend den "Kontakt 
zur Realität da ganz unten" vermittelt zu bekommen. Abstrakt ist und 
bleibt abstrakt.

MaWin schrieb:
> Und grundsätzlich halte ich das für eine gute Sache.
> Man darf es halt nicht übertreiben und Abstraktionen nicht nur zum
> Selbstzweck einfügen.

Da sind wir sogar einer Meinung. Aber nur dort wo es wirklich Sinn 
macht- und das heißt bei größeren Architekturen und nicht bei 
Simply-AVR. Wobei- wer selbst diese mit Bulldozern bearbeiten will und 
Spaß dran hat warum nicht. Er oder Sie darf sich bloß nicht wundern wenn 
in diesem Fall so manches mit einfacheren Methoden flexibler zu 
bewerkstelligen ist.

von Ralf (Gast)


Lesenswert?

EAF schrieb:
> ASM Priester verstehen unter Abstraktion häufig was anderes. Die halten
> gerne ihre Sprache, für die, mit den meisten/besten
> Abstraktionsmöglichkeiten

Was für ein Unfug.
AVR ist so einfach, da brauchts schlicht keine Abstraktion. Und 
Priestertum schon gar nicht.

von EAF (Gast)


Lesenswert?

Ralf schrieb:
> Abstrakt ist und bleibt abstrakt.
Nein!
Ein Compiler formt aus Abstraktionen (Klassen, Templates, usw) ganz 
konkrete Anwendungen.

Ralf schrieb:
> und nicht bei Simply-AVR.
Und du bist ganz offensichtlich der unbestechliche "Experte", welcher 
die ganze Welt von solch einem Blödsinn überzeugen will.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Das bekäme man mit hinreichend guten Spezial-Kenntnissen ja noch hin-
> sprich klein und schnell genug. Bulldozer meint eher die mangelnde
> Flexibilität dabei (siehe: atomarer Zählerzugriff) und den großen zu
> beherrschenden Sprachumfang- ohne gleichzeitig und zwingend den "Kontakt
> zur Realität da ganz unten" vermittelt zu bekommen.

Schau Dir meinen Code und das Assembler-Listing nochmal an: es ist genau 
Dein Prinzip (soweit ich das aus Deinem Geschwafel entnehmen konnte) und 
verwendet keine Interrupt-Sperre und ist trotzdem korrekt.

Leider hast Du dann danach etwas später Dein ASM-Code Schnipsel gezeigt, 
was Du wohl in der ISR einsetzen würdest. Aber das ist natürlich noch 
keine vollständige ISR geschweige denn ein komplettes Programm.
Also: zeige alles!

>Abstrakt ist und
> bleibt abstrakt.

Manche Leute können abstrakt denken, andere eben nicht.

von Ralf (Gast)


Lesenswert?

EAF schrieb:
> Ein Compiler formt aus Abstraktionen (Klassen, Templates, usw) ganz
> konkrete Anwendungen.

Wen interessiert was der Compiler "formt"?
Selbstredend den gleichen Maschinencode.
Interessant ist natürlich das Interface,
die Abstraktionen mit denen der Programmierer
arbeitet.

EAF schrieb:
> Und du bist ganz offensichtlich der unbestechliche "Experte", welcher
> die ganze Welt von solch einem Blödsinn überzeugen will.

Komm einfach von der persönlichen Schiene runter und konzentriere Dich 
auf die Fakten welche die Technik vorgibt.

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Manche Leute können abstrakt denken, andere eben nicht.

Abstraktionen ist dann eine gute Sache wenn sie wirklich nötig und 
hilfreich sind. Im übrigen wurden sie ja gerade erschaffen um dem 
Verständnis auf die Sprünge zu helfen. Nur hat das Schatten-Seiten und 
einen Preis. Und man kann es dabei arg übertreiben.

von EAF (Gast)


Lesenswert?

Ralf schrieb:
> Im übrigen wurden sie ja gerade erschaffen um dem
> Verständnis auf die Sprünge zu helfen.

Hier sage ich mal: Nein!

Der wohl wichtigste Zweck/Ziel ist:
Einmal schreiben, tausendfach wiederverwenden, egal auf welcher 
Hardware.

von Ralf (Gast)


Lesenswert?

EAF schrieb:
> Hier sage ich mal: Nein!

Ach, dann schau Dir mal die Vorworte und Einleitungen dicker OOP Wälzer 
oder der tausenden anderen Lernbücher an :)

> Einmal schreiben, tausendfach wiederverwenden, egal auf welcher
> Hardware.

Ja, die liebe Portabilität.
Die man zunächst mal brauchen muß.
Also ich brauche sie nicht weil mir AVRs für alle Zwecke ausreichen.
Mit den richtigen Konzepten kann man innerhalb einer Architektur auch 
vieles wiederverwenden.

Und dann gibts da bei Hochsprache und bei maschinennahen Programmteilen 
so manch kleine aber feine nötige Anpassung. Ganz so einfach ist das 
nämlich nicht. Schließlich kommt das facettenreiche Gesicht eines 
Ungetüms wie C++ in vielerlei Programmierstilen daher. Mal eben was vom 
unbekannten Kollegen wiederweiterverwenden kann auch schwierig werden. 
Dennoch: Portabilität, oder sagen wir besser maximal alle 
Voraussetzungen dafür bleiben ein Plus von C (Plus Plus). Hatte ich das 
irgendwo bestritten?

von EAF (Gast)


Lesenswert?

Ralf schrieb:
> Also ich brauche sie nicht weil mir AVRs für alle Zwecke ausreichen.
> Mit den richtigen Konzepten kann man innerhalb einer Architektur auch
> vieles wiederverwenden.

Vergleich:
> Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem 
Brunnenrand.
https://german.cri .cn/1833/2011/05/27/1s157501.htm

PS:
> Der Beitrag scheint Spam zu enthalten: ".cn/"
Ein Leerzeichen eingefühgt

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Manche Leute können abstrakt denken, andere eben nicht.
>
> Abstraktionen ist dann eine gute Sache wenn sie wirklich nötig und
> hilfreich sind. Im übrigen wurden sie ja gerade erschaffen um dem
> Verständnis auf die Sprünge zu helfen. Nur hat das Schatten-Seiten und
> einen Preis. Und man kann es dabei arg übertreiben.

Du hast mal wieder "vergessen", Deinen Code für ein vollständiges 
Beispiel zu zeigen, und nicht nur den Teil für ein Inkrement der 4 
Variablen. Nimm einfach mein sehr simples, letztes Beispiel aus 
funktionales Vorlage.

von Ron T. (Gast)


Lesenswert?

EAF schrieb:
> Ralf schrieb:
>> Also ich brauche sie nicht weil mir AVRs für alle Zwecke ausreichen.
>> Mit den richtigen Konzepten kann man innerhalb einer Architektur auch
>> vieles wiederverwenden.
>
> Vergleich:
>> Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem
> Brunnenrand.
> https://german.cri .cn/1833/2011/05/27/1s157501.htm
>
> PS:
>> Der Beitrag scheint Spam zu enthalten: ".cn/"
> Ein Leerzeichen eingefühgt

Bist ja echt ne traurige Gestalt.
Kann den Frust aber verstehen.
Bedenke aber: In der Niederlage zeigt sich die wahre menschliche Größe 
:)

Wilhelm M. schrieb:
> Du hast mal wieder "vergessen"

Irrtum Wilhelm M.
Gesagt ist wohl alles.
Eher schon zu oft.

von EAF (Gast)


Lesenswert?

Ron T. schrieb:
> Bedenke aber: In der Niederlage zeigt sich die wahre menschliche Größe

Vielleicht....
Warum, liebster Moby, hast du schon wieder deinen Namen gewechselt?
Du weißt doch, dass du das nicht darfst.

Übrigens:
Ich gönne dir deinen kleinen Brunnen.
Bevorzuge allergings das Meer.

von Meeresforscher (Gast)


Lesenswert?

EAF schrieb:
> Bevorzuge allergings das Meer.

Das kann so groß nicht sein wenn die sachlichen Argumente so schnell 
ausgehen.

von EAF (Gast)


Lesenswert?

Meeresforscher schrieb:
> Das kann so groß nicht sein

Ach du kleiner AVR - ASM - Brunnenfrosch, woher meinst du denn zu 
wissen, wie groß das Meer ist?

Disclamer:
Ich habe weder irgendwas gegen Frösche, Brunnen, AVR oder ASM. Finde es 
nur recht seltsam, wenn das alles sein soll....
-> Es gibt noch weit mehr! <-

von Meeresforscher (Gast)


Lesenswert?

EAF schrieb:
> woher meinst du denn zu wissen, wie groß das Meer ist

Wenn Du davon sprichst kann es nicht groß sein. Dafür sitzt Du viel zu 
schnell auf dem Trockenen. Vielleicht bist Du ja in Wahrheit der kleine 
Frosch?

von Wilhelm M. (wimalopaan)


Lesenswert?

Ron T. schrieb:
> Wilhelm M. schrieb:
>> Du hast mal wieder "vergessen"
>
> Irrtum Wilhelm M.

Ralph / Ron T. oder welchen Nickname Du gerade benutzt: jetzt hast Du 
irgendeinen geklauten ASM Code gepostet und jetzt bist Du mal wieder 
nicht in der Lage, ein ganzes µC-Programm daraus zu machen.

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> jetzt hast Du irgendeinen geklauten ASM Code gepostet

Nachdem Du nun zum zweiten Mal diese Märchen in die Welt zu setzen 
versuchst scheinen Dir offensichtlich wirklich ein paar Tassen im 
Schrank zu fehlen. Ist das etwa Folge jahrelangen C++ Wahns?

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> jetzt hast Du irgendeinen geklauten ASM Code gepostet
>
> Nachdem Du nun zum zweiten Mal diese Märchen in die Welt zu setzen
> versuchst scheinen Dir offensichtlich wirklich ein paar Tassen im
> Schrank zu fehlen.

Ron / Ralph: Du lässt durch Dein Verhalten keinen anderen Schluss zu.

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Du lässt durch Dein Verhalten keinen anderen Schluss zu

Nimmst Du im Ernst an irgend jemand aus dem Forum wär Dir hier zu 
irgendwas verpflichtet? Hier muß sich niemand niemandem gegenüber 
rechtfertigen.
Zieh Deine Schlüsse wie Du magst.
Wundere Dich nur nicht wenn andere die ihren ziehen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Du lässt durch Dein Verhalten keinen anderen Schluss zu
>
> Nimmst Du im Ernst an irgend jemand aus dem Forum wär Dir hier zu
> irgendwas verpflichtet?

In diesem Form nehme ich gar nichts an. Schon gar nicht von Leuten, die 
seit ca.  200 Beiträgen hier so herum schwafeln wie Du Ron T. / Ralph.

von MaWin (Gast)


Lesenswert?

Och menno! Nein, du!
aufstampf

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> In diesem Form nehme ich gar nichts an.

Das das jemand in der Ferne völlig egal sein kann scheint Dir nicht in 
den Sinn zu gelangen. Wir müssen hier nicht auf einen Nenner kommen wenn 
ein jeder mit seiner Sprache zufrieden ist und das begründet. Allerdings 
hab ich den Eindruck daß damit gewisse Leute partout nicht klarkommen. 
Die sind nämlich die eigentlich missionarischen Eiferer.

MaWin schrieb:
> Och menno! Nein, du!
> aufstampf

In diesem Sinne :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> In diesem Form nehme ich gar nichts an.
>
> Das das jemand in der Ferne völlig egal sein kann scheint Dir nicht in
> den Sinn zu gelangen.

Mit ist es egal, was Du benutzt.

> Wir müssen hier nicht auf einen Nenner kommen wenn
> ein jeder mit seiner Sprache zufrieden ist und das begründet.

Allerdings hast Du hier laut rumgetönt, das Deine Lösung in allen 
Belangen besser sei, jedoch zeigst Du das gar nicht. Auch bist Du nicht 
bereit oder in der Lage, ein Analogon zu meinem Mini-Beispiel zu 
bringen.

> Allerdings
> hab ich den Eindruck daß damit gewisse Leute partout nicht klarkommen.

Darum geht es nicht: wie schon x-mal gesagt: Du tönst rum und lieferst 
nicht.

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Du tönst rum und lieferst nicht

Wenn Dich mein "Geschwafel" nicht überzeugt dann überzeugt es halt 
nicht. Da bin ich völlig schmerzlos. Ich habe meine Erfahrungen gemacht, 
Du die Deinen. So wie ein jeder die seinen machen muß...

Und was heißt schon in allen Belangen besser? Das ist Asm ganz sicher 
nicht, das ist C++ ganz sicher nicht. C ist portabler- also kann Asm 
schon mal nicht in allen Belangen besser sein. Mit Unterstellungen 
bist Du aber allzu fix ganz vorn dabei. Behaupte ruhig weiter ich würde 
Code klauen, wenn Du Dein Gemüt nicht anders zügeln kannst. Das wird 
allerdings ganz sicher nicht dazu führen daß Du weiteren wunschgemäß zu 
Gesicht bekommst.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

habe mich versucht einzulesen. Wäre das hier äquivalent zu Wilhelms 
Code? Ist auf dem PC und CodeBlocks getestet. Deswegen die Limitierung 
auf 100 Zeilen und die 10ms Bremse. Ohne Bremse gibts Lücken in der 
Konsole, der Rechner ist zu schnell.
1
#include <chrono>
2
#include <thread>
3
#include <atomic>
4
#include <iostream>
5
6
using namespace std::this_thread;    
7
using namespace std::chrono_literals;
8
using std::chrono::system_clock;
9
10
int counter;
11
12
std::atomic<int> g;
13
std::atomic<bool> flag;
14
15
void otherThread (void)
16
{
17
  auto tempG = g.load();              // g einlesen
18
  auto tempFlag = flag.load();        // flag einlesen
19
  ++tempG;
20
  if (tempG > 9) {
21
    tempFlag = true;
22
    tempG = 0;
23
  }
24
  g.store(tempG);                     // g zurückschreiben
25
  flag.store(tempFlag);               // flag zurückschreiben
26
}
27
28
int main()
29
{
30
  std::cout << "Reset\n";
31
32
  while(1)
33
  {
34
    if (counter < 100)                  // willkürliche Ausgabenlimitierung
35
    {
36
      otherThread();
37
38
      ++counter;
39
      std::cout << "counter " << counter << " flag " << flag;
40
41
      auto tempFlag = flag.load();      // flag einlesen
42
      if (tempFlag)
43
      {
44
        tempFlag = false;
45
        flag.store(tempFlag);           // flag zurückschreiben
46
        std::cout << " Flag true.\n";
47
      }
48
49
      std::cout << "\n";
50
    }
51
52
    sleep_until(system_clock::now() + 10ms);
53
  }
54
}

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Was möchtest Du damit sagen? Du hast ein rein sequentielles Programm, in 
dem keine Nebenläufigkeit enthalten ist. Daher kann Du auf die atomics 
verzichten.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

manchmal weiß ich nicht was dazu sagen soll ...
Worum dreht es sich denn bei mir die ganze Zeit? Das ich auf dem PC 
keinen AVR Interrupt nachbauen kann sollte doch klar sein. Der Name 
"otherThread" sollte Aussagekräftig genug sein für das Prinzip worum es 
geht.
Ich frage anders. Kann atomic.load/store deinen MemoryBarrier Aufruf 
gleichwertig ersetzen?

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> manchmal weiß ich nicht was dazu sagen soll ...

Tja, das weiß ich auch nicht.

> Worum dreht es sich denn bei mir die ganze Zeit?

Keine Ahnung.

> Das ich auf dem PC
> keinen AVR Interrupt nachbauen kann sollte doch klar sein.

Nein, ist es nicht. Ein Signal-Handler kommt dem sehr, sehr nahe.

> Der Name
> "otherThread" sollte Aussagekräftig genug sein für das Prinzip worum es
> geht.

Ja, aber Du startest eben keinen Thread. Es wäre doch ganz einfach 
gewesen,
1
std::thread t{otherThread};

einzufügen (statt otherThread() synchron aufzurufen). Und genau deswegen 
habe ich in der Art geantwortet, wie ich geantwortet habe.

> Ich frage anders. Kann atomic.load/store deinen MemoryBarrier Aufruf
> gleichwertig ersetzen?

Jein.

Am besten liest Du mal:
https://en.cppreference.com/w/cpp/atomic/atomic

Die atomics machen das load/store atomar für Dein int und bool und 
berücksichtigen das Zugriffsmodell entsprechend memory_order bspw. 
"sequential consistent", was einer allg. CPU-memory-barrier (und 
Compiler-barrier) gleichkommt. Auf x86-64 wird daraus im wesentlichen 
ein xchg, wenn die Datentypen weniger als 64Bit umfassen. Bei größeren 
DT wird dann tatsächlich ggf. ein Mutex eingebaut (etwa über einen 
Aufruf von __atomic_store).

Je nachdem was Du erreichen möchtest, wäre in Deinem Beispiel ein
1
struct Shared {
2
    int g;
3
    bool flag;
4
};
5
6
std::atomic<Shared> s;

angebrachtet gewesen. Damit wird der Zugriff auf die gesamte 
Datenstruktur atomar (was dann einem kritischen Abschnitt entspricht).

Der wesentliche Unterschied zu meinem simplen AVR Beispiel ist, dass bei 
meinem Beispiel nur der Code in main() gegen einen nebenläufigen Zugriff 
geschützt war und damit Atomarität gewährleistet hat. Der Code in der 
ISR hat das nicht gemacht / machen müssen, weil das Beispiel davon 
ausging, dass man keine weiteren Interrupt-Level (neuere AVR) benutzt.

In Deinem Beispiel könntest Du weitere Threads starten, und es wäre 
trotzdem noch ok. Sofern - wie oben gesagt - g und flag keinen 
semantischen Zusammenhang haben (nicht dieselbe Datenstruktur bilden) 
und somit der Zugriff auf beide atomar sein soll. Dann käme meine 
Modifikation (s.o.) ins Spiel.

von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
> Kann atomic.load/store deinen MemoryBarrier Aufruf
> gleichwertig ersetzen?

C++ atomics behinhalten (sogar wählbare) Memory Barriers. Ich glaube 
default war, wenn der Programmierer nichts anderes angibt, ein 
Sequence-consistent-ordering. Also das strikteste.

Vielleicht liest du endlich mal die Doku, die hier schon mehrfach 
verlinkt wurde?

https://en.cppreference.com/w/cpp/atomic/atomic

Veit D. schrieb:
> Das ich auf dem PC
> keinen AVR Interrupt nachbauen kann sollte doch klar sein.

Auch dein PC hat Threads.
Damit kann man die meisten Concurrency-Effekte von Interrupts 
hinreichend simulieren. (und noch mehr darüber hinaus)

https://en.cppreference.com/w/cpp/thread/thread

Ach ja und als Schlusswort bleibt noch zu sagen:
Vielleicht liest du endlich mal die Doku?

von Veit D. (devil-elec)


Lesenswert?

MaWin schrieb:
> Vielleicht liest du endlich mal die Doku?

Was denkst du denn wie ich auf atomic load/store gekommen bin?

Ansonsten Danke Wilhelm. Sollte "nur" einen anderen Ansatz mit 
Vergleichbarkeit darstellen, rein zum Verständnis.

von MaWin (Gast)


Lesenswert?

Veit D. schrieb:
>> Vielleicht liest du endlich mal die Doku?
>
> Was denkst du denn wie ich auf atomic load/store gekommen bin?

Du hast es ja ganz offensichtlich nicht gelesen. Denn sonst käme die 
Frage von dir nicht auf.

https://en.cppreference.com/w/cpp/atomic/atomic/store

90% des Textes dort handeln vom Memory-Barrier-Verhalten des stores.

Wichtige Lektüre, zum 100sten mal gepostet und immer noch nicht gelesen:

https://en.cppreference.com/w/cpp/atomic/memory_order

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Ansonsten Danke Wilhelm. Sollte "nur" einen anderen Ansatz mit
> Vergleichbarkeit darstellen, rein zum Verständnis.

Wie gesagt: die Vergleichbarkeit mit dem simplen AVR Beispiel wird eher 
durch einen Signal-Handler anstatt weiterer Aktivitätsträger erreicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

MaWin schrieb:
> Du hast es ja ganz offensichtlich nicht gelesen. Denn sonst käme die
> Frage von dir nicht auf.

Würde ich so nicht sagen: lesen und verstehen sind zwei unterschiedliche 
Dinge.

Und im Gegensatz zu vielen anderen hier, scheint sich Veit D. ja aktiv 
mit dem Stoff auseinander zu setzen. Das ist schon mal viel mehr als die 
meisten anderen hier.

von EAF (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Und im Gegensatz zu vielen anderen hier, scheint sich Veit D. ja aktiv
> mit dem Stoff auseinander zu setzen. Das ist schon mal viel mehr als die
> meisten anderen hier.
Ja!

von Jan V. (janv)


Lesenswert?

Wilhelm M. schrieb:
> aktiv mit dem Stoff auseinander zu setzen

Ob unser TE Timo den "Stoff" überhaupt zur Lösung braucht ist nach Lage 
der Dinge eine ganz andere Frage...

von Wilhelm M. (wimalopaan)


Lesenswert?

Jan V. schrieb:
> Wilhelm M. schrieb:
>> aktiv mit dem Stoff auseinander zu setzen
>
> Ob unser TE Timo den "Stoff" überhaupt zur Lösung braucht ist nach Lage
> der Dinge eine ganz andere Frage...

Es ist wie immer hier: der TO ist mit der einfachen, symptomatischen 
Lösung zufrieden. Der Rest disktutiert weiter.

von Jan V. (janv)


Lesenswert?

Wilhelm M. schrieb:
> mit der einfachen, symptomatischen Lösung zufrieden

Was ist daran auszusetzen?
Braucht es noch eine komplizierte Lösung? Mir scheint Du bist dieser 
Meinung.

von Wilhelm M. (wimalopaan)


Lesenswert?

Jan V. schrieb:
> Wilhelm M. schrieb:
>> mit der einfachen, symptomatischen Lösung zufrieden
>
> Was ist daran auszusetzen?
> Braucht es noch eine komplizierte Lösung? Mir scheint Du bist dieser
> Meinung.

Nein.
Lies Dir die Texte durch. Es ging darum aufzuzeigen, welche Schritte 
ablaufen. Einige haben nicht erkannt, was in dem ATOMIC_BLOCK()-Macro 
ablaufen.
Wenn der TO nicht daran interessiert ist zu erfahren, was die Ursachen 
für sein Problem waren, dann ist das ok für mich. Es gab aber Nachfragen 
und Bemerkungen anderer Teilnehmer.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

Eins werde ich nie verstehen. Das es immer wieder Leute gibt die sich 
über geäußertes Wissen aufregen. Entweder man liest still mit, man 
beteiligt sich aktiv oder man lässt alle ihr Ding machen. Aber sich 
darüber aufregen Wissen zu veröffentlichen ... dann müßte man denjenigen 
Leuten alle Bücher wegnehmen und den Schulbesuch verbieten.

von H.E. (Gast)


Lesenswert?

Veit D. schrieb:
> Das es immer wieder Leute gibt die sich
> über geäußertes Wissen aufregen

Die Aufregung scheint mir hier eher auf zwei andere Dinge zu zielen:
- Leute wollen Dinge unbedingt komplizierter lösen als nötig
- Leute wollen Dinge diskutieren die mit dem Thread-Thema wenig zu tun 
haben
- Leute äußern sich unsachlich und völlig am Thema vorbei

von Wilhelm M. (wimalopaan)


Lesenswert?

H.E. schrieb:
> Veit D. schrieb:
>> Das es immer wieder Leute gibt die sich
>> über geäußertes Wissen aufregen
>
> Die Aufregung scheint mir hier eher auf zwei andere Dinge zu zielen:
> - Leute wollen Dinge unbedingt komplizierter lösen als nötig

Du meinst sicher mich ;-)
Wenn Du meine ersten Beiträge hier gelesen hast, hast Du sicher bemerkt, 
dass ich erstmal das Problem beschrieben habe, damit der TO das 
versteht.

> - Leute wollen Dinge diskutieren die mit dem Thread-Thema wenig zu tun
> haben

Wie gesagt: der TO war höchstens an einer symptomatischen Lösung 
interessiert. Die Gründe für sein Problem haben ihn dann schon wieder 
weniger interessiert.

Und dann stiegen Leute ein, die ihm unbedingt Assembler empfehlen 
wollten ;-)

von EAF (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Und dann stiegen Leute ein, die ihm unbedingt Assembler empfehlen
> wollten ;-)

Das ist gar nicht das Drama.
Das Drama ist, dass genau dieser offensichtlich nichts anderes kann, 
dazu noch fürchterlich penetrant ist.
Und ob ihm ASM wirklich "kann" liegt auch im dunklen.

von Ralf (Gast)


Lesenswert?

EAF schrieb:
> fürchterlich penetrant

Na na na! So kann man es auch umschreiben wenn man nichts anderes als 
unsachliche Beschimpfung zu entgegnen hat :)
Schau, die Beschränkung aufs Erforderliche entlarvt immer auch das 
Umständliche.

EAF schrieb:
> Und ob ihm ASM wirklich "kann" liegt auch im dunklen

Meinetwegen. Ich brauch Deine Bestätigung jetzt nicht wirklich.
Hauptsache mein Code tut (einfacher als bei manch anderem) was er soll.
Alles andere ist erstmal Entertainment.

von Εrnst B. (ernst)


Lesenswert?

Ralf schrieb:
> Hauptsache mein Code tut (einfacher als bei manch anderem) was er soll.

Schau: Das Problem ist seit ~ 60 Jahren bekannt (Dijkstra), und genauso 
lange gibt es eine Standard-Lösung dafür. Egal ob man die in ASM, C, C++ 
oder sonstwas implementiert.

Nur weil du eine abweichende Lösung gefunden hast, die in einem ganz 
speziellen Sonderfall möglicherweise auch funktioniert, wirfst du damit 
nicht Jahrzehnte Informatik-Theorie über den Haufen.

Und wenn ein Anfänger das Problem lösen will, dann gibt man ihm erstmal 
die 08/15 - Lösung. Die funktioniert immer, unter allen Umständen, 
korrekt.

Irgendeine Spezial-Sonderfall-Lösung, mit der er beim nächsten Projekt 
auf die Nase fällt, ist da eher kontraproduktiv.

Wenn er dann den Anfänger-Status hinter sich gelassen hat, kann er 
selber entscheiden, wann er auf die IRQ-Sperre verzichten mag oder muss, 
dann braucht er aber deinen Input auch nicht mehr dafür.

von EAF (Gast)


Lesenswert?

Ach der Frosch, in seinem AVR-ASM Brunnen, er quakt noch!
Wie schön ...
Sing uns dein Leid nochmal... bitte...

von Veit D. (devil-elec)


Lesenswert?

H.E. schrieb:
> Veit D. schrieb:
>> Das es immer wieder Leute gibt die sich
>> über geäußertes Wissen aufregen
>
> Die Aufregung scheint mir hier eher auf zwei andere Dinge zu zielen:
> - Leute wollen Dinge unbedingt komplizierter lösen als nötig
> - Leute wollen Dinge diskutieren die mit dem Thread-Thema wenig zu tun
> haben
> - Leute äußern sich unsachlich und völlig am Thema vorbei

Hallo,

ganz nüchtern betrachtet. Man sollte einen Schritt zurückgehen und die 
Sache neu betrachten. Was ist schlimm daran wenn jemand Wissen übern 
Tellerrand zeigt? Ob einem das persönlich zu kompliziert erscheint oder 
nicht ist immer individuell. Es ist auch erstmal egal ob man es versteht 
oder nicht. Man muss es nicht annehmen, man kann es annehmen, man kann 
es für später im Hinterstübchen behalten.
Ich programmiere Ein Kern AVRs. Andere programmieren Zwei Kern ESP32, 
andere Zwei Kern RP2040. Paar Leute werden sicherlich glücklich sein 
über die "Zusatzinformationen", statt immer nur sturr volatile.

Ich habe mich früher auch über diverse Dinge und Leute aufgeregt. 
Mittlerweile sehe ich das anders. Ich kann mich an der Stelle für mein 
vergangenes Verhalten nur Entschuldigen. War damals nicht nett von mir. 
Ich weiß das heute hoffentlich besser. Sie haben es nur gut gemeint.

von Ralf (Gast)


Lesenswert?

Εrnst B. schrieb:
> Nur weil du eine abweichende Lösung gefunden hast, die in einem ganz
> speziellen Sonderfall möglicherweise auch funktioniert,

Wie amüsant.
Übrigens Ernst, da waren noch ein paar Fragen an Dich offen :)

EAF schrieb:
> Ach der Frosch, in seinem AVR-ASM Brunnen, er quakt noch!
> Wie schön ...

Auf dieses Niveau muss man sich wirklich nicht hinab begeben. Quake 
fröhlich weiter, zu mehr langts offensichtlich nicht mehr :(

Veit D. schrieb:
> Ich kann mich an der Stelle für mein vergangenes Verhalten nur
> Entschuldigen. War damals nicht nett von mir.

Sollte das eine Vorlage für mich sein?
Da kann ich mich aber nur entschuldigen daß ich dazu keinerlei Anlass 
sehe.

MaWin schrieb:
> Du hast es ja ganz offensichtlich nicht gelesen.
> Wichtige Lektüre, zum 100sten mal gepostet und immer noch nicht gelesen

Also Veit D., es warten weit wichtigere Aufgaben auf Dich. Vor dem 
Aufwand, diese Bürokratie in sich reinzuprügeln würde ich aber immer 
empfehlen, zunächst das Problem zu analysieren, ob es nicht einfachere 
Wege gibt?!

von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Ich kann mich an der Stelle für mein
> vergangenes Verhalten nur Entschuldigen.

Alles gut.
Entschuldigen sollten sich allerdings Leute, die hier nur Geschwafel 
abliefern und trollen.

von Ralf (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Entschuldigen sollten sich allerdings Leute

... die hier Personen mit erfundenen Unterstellungen aller Art zu 
diskreditieren versuchen weil die nicht so wollen wie sie es gerne 
hätten. Stimmts, Wilhelm M.?

von DontFeedTheTrolls (Gast)


Lesenswert?

Ralf schrieb:
> ... die hier Personen mit erfundenen Unterstellungen aller Art zu
> diskreditieren versuchen weil die nicht so wollen wie sie es gerne
> hätten.

MegaTroll

Beitrag #7269998 wurde von einem Moderator gelöscht.
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.