Forum: Mikrocontroller und Digitale Elektronik Gefahren bei Interrupts


von me_and_my_µC (Gast)


Lesenswert?

Hallo!

Ich meine einmal irgendwo gelesen zu haben, dass, wenn ein Interrupt 
ausgelöst wird und man beispielsweise gerade mitten in einer Aktion mit 
z.B. 32-bit Integern ist (auf einem 8-bit µC), dass dann Fehler 
auftreten können, weil die Register vermischt werden (können).
Stimmt das?

Und noch eine weitere kleine Frage:
Wenn man am Anfang der Programmschleife mit cli() Interrupts deaktiviert 
und am Ende wieder mit sei() aktiviert, werden dann auch in der 
Zwischenzeit auftretende Interrupts ausgeführt? Oder verfallen die dann?

Danke!

von Sven S. (boldie)


Lesenswert?

Im Interrupt muss man ohnehin immer die Register sichern, die man 
letztendlich auch nutzt und beim Beenden wieder zurück zu spielen. Dann 
macht das nichts mehr aus. Es ist nur darauf zu achten, dass 
gleichzeitig (also Interrupt und außerhalb) benutzte Werte atomar 
zugegriffen werden oder ansonsten muss man Interrupts sperren. Das muss 
man sich vorher genau überlegen, wie die Daten genutzt werden und wie 
der Datenaustausch und wann statt finden sollte. Z.b. ist es in einer 
Rechnung auch nicht gut, wenn sich plötzlich Werte ändern, etc.

Interrupts an sich verfallen nicht, aber es kann sein, das man dann 
einen Überlauf oder Datenverlust bekommt, wenn diese nicht zeitnah 
verarbeitet werden. Dann wird z.B. ein Register überschrieben, sie 
werden nicht gestapelt, also dann 2 mal getriggert o.ä. Evtl. bekommt 
man auch andere Probleme, wenn man versucht über den Interrupt Timings 
zu bestimmen. Normalerweise ist es nicht sinnvoll größere Codeblöcke mit 
cli und sei zu sichern.

: Bearbeitet durch User
von 6a66 (Gast)


Lesenswert?

me_and_my_µC schrieb:
> dass dann Fehler
> auftreten können, weil die Register vermischt werden (können).
> Stimmt das?

JEIN.
Es gibt Architekturen da werden die Register durch die CPU gesichert, 
dann kann der Interrupt machen was er will. Nachteil: Zeit für das 
Sichern geht mit in die Interruptroutine mit ein.
Dann gibt es Architekturen da sichert die CPU von sich aus Garnichts, 
dafür macht der Compiler einer Hochsprache das da er ja weiß, welche 
Register er benötigt.
Und der letzte Fall ist die Architektur die nicht sichert die du mit 
Assembler programmierst, bei der Du selbst das Vergnügen hast über die 
Verwendung Deiner Register und die Sicherung dieser die Übersicht zu 
behalten.

me_and_my_µC schrieb:
> Wenn man am Anfang der Programmschleife mit cli() Interrupts deaktiviert
> und am Ende wieder mit sei() aktiviert, werden dann auch in der
> Zwischenzeit auftretende Interrupts ausgeführt? Oder verfallen die dann?

Auch das hängt ein Bisschen von den Umständen ab.
Die CPU wird normalerweise einen Interrupt auslösen und sich das anhand 
von Flags merken. Wenn du dann die Interrupts wieder zulässt werden die 
in der  bestimmten Priorität abgearbeitet.
ABER: treten Interrupts auf die nicht unterschieden werden können oder 
tritt ein und derselbe Interrupt in der gesperrten Zeit mehrfach auf 
geht das unter.

Und: NEIN, Interrupts sind keine Gefahren nur der nachlässige und nicht 
verstandene Umgang damit :)

rgds

von Falk B. (falk)


Lesenswert?

@ me_and_my_µC (Gast)

>ausgelöst wird und man beispielsweise gerade mitten in einer Aktion mit
>z.B. 32-bit Integern ist (auf einem 8-bit µC), dass dann Fehler
>auftreten können, weil die Register vermischt werden (können).
>Stimmt das?

Nein. Es geht dabei um globale Variablen.

https://www.mikrocontroller.net/articles/Interrupt#Interruptfeste_Programmierung

>Wenn man am Anfang der Programmschleife mit cli() Interrupts deaktiviert
>und am Ende wieder mit sei() aktiviert, werden dann auch in der
>Zwischenzeit auftretende Interrupts ausgeführt?

Natürlich nicht.

> Oder verfallen die dann?

Nur dann, wenn wähend der Sperre mehr als ein Interrupt vom gleichen Typ 
auftritt. Siehe Interrupt.

von Thomas M. (langhaarrocker)


Lesenswert?

Falk B. schrieb:
>>Wenn man am Anfang der Programmschleife mit cli() Interrupts deaktiviert
>>und am Ende wieder mit sei() aktiviert, werden dann auch in der
>>Zwischenzeit auftretende Interrupts ausgeführt?
>
> Natürlich nicht.

Ich wittere ein Missverständnis zwischen dem was der Fragesteller fragen 
wollte, wie er seine Frage formuliert hat und wie der Antwortende die 
Frage verstanden hat.

Tritt nach setzen von cli() eine InterruptANFORDERUNG auf, dann wird 
natürlich der Interrupt nicht sofort ausgeführt, denn das ist wegen cli 
gesperrt. Aber das Flag wird gesetzt. Durch Aufruf von sei() wird die 
Interruptsperre aufgehoben. Jetzt darf die Interrupt Service Routine 
ausgeführt werden.

Also eine Interruptanforderung wird durchaus auch registriert während 
der Prozessor in einem Block zwischen cli und sei ist. Die Behandlung 
dieser Interruptanforderung geschieht aber erst nach Aufruf von sei und 
wird somit verzögert durchgeführt.

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

6a66 schrieb:
> Es gibt Architekturen da werden die Register durch die CPU gesichert,
> dann kann der Interrupt machen was er will.

Das ist nicht der Punkt.

Es geht um den Zugriff auf Variablen, die sowohl von der Interrupt- 
Serviceroutine (ISR) als auch dem Hauptprogramm genutzt werden. Hier muß 
sichergestellt werden, daß der Zugriff atomar erfolgt. Wenn z.B. ein AVR 
eine 16-Bit Variable aus dem RAM liest, dann sind dazu mindestens zwei 
Maschinenbefehle notwendig. Der Zugriff ist nicht atomar, wenn zwischen 
dem Lesen des Low- und des High-Teils ein Interrupt stattfinden könnte. 
Wenn nun die ISR genau diese 16-Bit Variable verändert, dann liest das 
Hauptprogramm die eine Hälfte der Variable vom alten Wert und die zweite 
Hälfte vom neuen Wert. Und dann kann in der Folge alles mögliche schief 
gehen. Ganz abgesehen davon, daß solche Fehler extrem schwer zu finden 
sind.

Innerhalb der ISR besteht das Problem nicht, weil innerhalb einer ISR 
standardmäßig keine weiteren Interrupts erlaubt sind. Außerhalb der ISR 
ist die einfachste Lösung, Interrupts vor dem Lesen der Variable zu 
sperren und danach wieder zu erlauben.

Die AVR-libc hat dafür Makros:
1
#include <util/atomic.h>
2
...
3
volatile uint16_t foo;
4
...
5
uint16_t bar;
6
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
7
  bar= foo;
8
}
9
...

Zu Beginn des ATOMIC_BLOCK werden Interrupts gesperrt, alles was 
innerhalb des Blocks geschieht, kann also nicht unterbrochen werden. 
Beim Verlassen des Blocks wird der alte Zustand der Interrupts 
(erlaubt/gesperrt) wiederhergestellt.

siehe 
http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html

von Curby23523 N. (Gast)


Lesenswert?

Wenn du auf einem AVR eine uint64_t verwendest und während des 
Schreibvorganges dieser variable ein Interrupt auftritt, kann es zu 
Schwulitäten kommen.

Denn eine 64bit Zahl wird durch acht 8Bit Register/Variablen 
ausgedrückt. Nun kann es sein, dass du vier Bytes geschrieben hast, vier 
folgen noch - doch jetzt kommt ein Interrupt.

Wenn du dann im Interrupt diese int64_t verwendest steht da mist drin, 
da genau im Schreibvorgang dieser Variable unterbrochen wurde.

Nach dem Interrupt wird der Schreibvorgang ganz normal fortgesetzt.

Du kannst hier z.B. atomatre Hilfsvariablen verwenden, die 
signalisieren, dass neue Daten in der uint64_t vorhanden sind. Oder eine 
cli() sei() gemisch.

Aber vermischt wird nichts. Nach dem Interrupt arbeitet das Programm 
weiter, als ob nichts war. Es sei denn, du machst im Interrupt selber 
mist.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

Die AVR sichern nicht mal das Flagregister, das muss man zu Fuß retten. 
Der 6502 beispielsweise legte das automatisch auf den Stack und 
restaurierte es beim Return-from-interrupt.

von me_and_my_µC (Gast)


Lesenswert?

Okay, vielen Dank für eure Antworten!

Ich hätte allerdings noch eine andere kleine Frage:
ich habe einen Timer, der im 0.5µs Takt zählt und einen, der im 1s Takt 
zählt.
Allerdings wird in der Interruptroutine von dem 1s-Timer eine Variable 
erhöht, die in der Programmschleife ziemlich oft gelesen und teilweise 
auch neu beschrieben wird. Es ist ein uint32_t.
Was ist der sicherste Weg, nur die Interrupts von dem 1s-Timer zu 
deaktivieren (die Verzweigung dauert sicher keine Sekunde) und danach 
wieder zuzulassen, ohne dass der 0.5µS-Timer dadurch behindert wird?

von m.n. (Gast)


Lesenswert?

Die Interrupt-Freigabe (enable) für den 1 s Timer abzuschalten und 
anschließend wieder einzuschalten. Dadurch werden alle anderen 
Interrupts weiterhin bedient.

von Stefan F. (Gast)


Lesenswert?

Um welchen µC geht es denn?

von Dominik (Gast)


Lesenswert?

me_and_my_µC schrieb:
> Es ist ein uint32_t

ein "volatile" uint32_t ?

von Peter D. (peda)


Lesenswert?

me_and_my_µC schrieb:
> ohne dass der 0.5µS-Timer dadurch behindert wird?

Vergiß es, der AVR kann keinen Interrupt in nur 10 Zyklen (@20MHz) 
ausführen.
Rechne je Interrupt wenigstens 100 Zyklen, damit auch das Main etwas 
Rechenzeit bekommt.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

me_and_my_µC schrieb:
> Was ist der sicherste Weg, nur die Interrupts von dem 1s-Timer zu
> deaktivieren (die Verzweigung dauert sicher keine Sekunde) und danach
> wieder zuzulassen, ohne dass der 0.5µS-Timer dadurch behindert wird?

Auf den 1sec-Timer verzichten und im 0,5µS-Timer den Sekunden-Zähler um 
1 inkrementieren, wenn ein interner Zähler den Stand 2000000 erreicht 
hat.

Blöd nur, dass dadurch der 0,5µS-Timer um ein ganzes Stück länger in der 
Ausführungszeit wird.

m.n. schrieb:
> Die Interrupt-Freigabe (enable) für den 1 s Timer abzuschalten und
> anschließend wieder einzuschalten.

Während eines Interrupts können sowieso standardmäßig erstmal keine 
weiteren ISRs abgefackelt werden. Aber das ist ja auch gar nicht das 
Problem.

Sondern:

Wenn die 1sec-ISR bereits läuft und es wird der 0,5µs-Timer-Interrupt 
ausgelöst, kommt die ISR für den 0,5µs-Timer erst dann dran, wenn die 
1sec-ISR sich beendet hat.

Wenn der (leider ungenannte) µC Interrupt-Prioritäten kennt, ließe sich 
das leicht lösen. Bei einem 8-Bit-AVR wirds eklig, insbesondere dann, 
wenn in der 1-Sek-ISR sowieso nur ein Statement steht, nämlich das 
Inkrementieren des 1-Sekunden-Zählers. Jedes weitere Statement zur 
Interrupt-Priorisierung kann dann das Timer-Verhalten vom 0,5µs-Timer 
noch weiter verzerren.

EDIT:

Nach Peters Beitrag ist dieser jetzt sowieso obsolet, wenn es sich 
tatsächlich um einen AVR handelt. ;-)

: Bearbeitet durch Moderator
von m.n. (Gast)


Lesenswert?

Frank M. schrieb:
> m.n. schrieb:
>> Die Interrupt-Freigabe (enable) für den 1 s Timer abzuschalten und
>> anschließend wieder einzuschalten.
>
> Während eines Interrupts können sowieso standardmäßig erstmal keine
> weiteren ISRs abgefackelt werden. Aber das ist ja auch gar nicht das
> Problem.

Die Frage war, den 1 s Timer Interrupt zu deaktivieren ohne andere 
Interruptquellen zu sperren, wie es mit cli() der Fall wäre.

Frank M. schrieb:
> Nach Peters Beitrag ist dieser jetzt sowieso obsolet, wenn es sich
> tatsächlich um einen AVR handelt. ;-)

Oder es sind einfach nur 0,5 ms gemeint ;-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

m.n. schrieb:
> Die Frage war, den 1 s Timer Interrupt zu deaktivieren ohne andere
> Interruptquellen zu sperren, wie es mit cli() der Fall wäre.

Ja, schon klar. Aber überlege mal: wann und wo, ohne den 0,5µs-Timer 
(oder 0,5ms) zu beeinflussen?

Den 1-Sekunden-Timer generell zu deaktivieren dürfte keine Lösung sein - 
außer Du zählst den 1-Sekunden-Zähler in der 0,5µs-ISR hoch - wie oben 
beschrieben.

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


Lesenswert?

me_and_my_µC schrieb:
> Allerdings wird in der Interruptroutine von dem 1s-Timer eine Variable
> erhöht, die in der Programmschleife ziemlich oft gelesen und teilweise
> auch neu beschrieben wird. Es ist ein uint32_t.
> Was ist der sicherste Weg,...

Also, der sicherste Weg in ALLEN solchen Fällen ist der, erstmal 
generell auf das temporäre Sperren von Interrupst zu verzichten. Also 
kein cli und sei. Da man unter solcher Prämisse eben zu allen Zeiten 
damit rechnen muß, daß einem ein Interrupt dazwischenkommt, besteht die 
Hauptaufgabe eben darin, daß man sich irgend eine saubere 
Synchronisation zwischen Grundprogramm und ISR ausdenkt.

An deiner Stelle würde ich so verfahren:
1. Beide Instanzen (Grundprogramm und ISR) besitzen jeweils ein 
Kennbyte. Am Anfang sind beide Kennbytes gleich, z.B. Null.
2. Wenn nun die ISR dran ist, inkrementiert sie ihr Kennbyte.

3. Das Grundprogramm vergleicht in jedem chleifendurchlauf sein eigenes 
Kennbyte mit dem Kennbyte der ISR und wenn beide ungleich sind, dann 
macht sie folgendes:
3a) sie inkrementiert den besagten 1s-Timer
3b) sie inkrementiert ihr eigenes Kennbyte (ob die Kennbytes überlaufen, 
ist dabei völlig egal)

So, das war's. Beide Instanzen kommen sich niemals gegenseitig ins 
Gehege, weil keine von beiden schreibend auf ne Ressource der anderen 
zugreift. Sicher gegenüber 8 Bit Systemen ist das auch, denn der lesende 
Zugriff auf das Kennbyte der Gegenseite ist atomar. Und das Ganze 
braucht auch nur 2 poplige Bytes RAM. Dafür spart man sich die 32 Bit 
Inkrementierung in der ISR ein.

Nochwas:

me_and_my_µC schrieb:
> ich habe einen Timer, der im 0.5µs Takt zählt..

Einen Timer oder etwas, das alle 500 ns einen Interrupt auslöst? Schreib 
das mal klarer. Für einen µC, der im besten Falle 50 ns pro Befehl 
braucht, halte ich den 500 ns Interrupt für astronomisch.

W.S.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

W.S. schrieb:
> Beide Instanzen kommen sich niemals gegenseitig ins
> Gehege, weil keine von beiden schreibend auf ne Ressource der anderen
> zugreift.

Das ist richtig, aber: Es setzt voraus, dass allerspätestens nach 256 
ISR-Aufrufen das Hauptprogramm zum Zug kommt. Ist das nicht gesichert, 
wirds schon wieder schwierig. 16-bit-Variable? Dann hast erst wieder das 
non-atomic Problem...

von Stefan F. (Gast)


Lesenswert?

Kleiner Hinweis: Dass es um einen AVR geht, ist bislang nur eine 
Vermutung. Also verrennt euch da mal nicht zu weit in die falsche 
Richtung.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Stefan U. schrieb:
> Kleiner Hinweis: Dass es um einen AVR geht, ist bislang nur eine
> Vermutung. Also verrennt euch da mal nicht zu weit in die falsche
> Richtung.

AVR ist Mutmaßung, aber "8-Bit-uC" steht im Eröffnungsposting. Und mir 
wäre kein 8Bitter bekannt, der 16- oder 32-bit-Werte atomar lesen 
könnte...

von me_and_my_µC (Gast)


Lesenswert?

Entschuldigung, ich habe mich tatsächlich ziemlich doof ausgedrückt. Das 
gebe ich zu. Da kam ich leider mit einem anderen Projekt durcheinander, 
bei dem es 0.5ms Sekunden sind.
Der gemeinte Timer löst alle 50µS ein Interruptroutine aus.
Der verwendete µC ist nur ein kleiner ATmega8A.
Und ja, natürlich. Es handelt sich um einen volatile uint32_t.

Aber aus euren Antworten schließe ich, dass sich das wohl nicht so 
einfach umsetzen lässt.

Dann werde ich mir noch einmal etwas überlegen.
Die 50µs Routine würde ich nur ungern erweitern. Die ist für meinen 
Geschmack sowieso schon zu lang.
Ich werde mir noch etwas ausdenken.
Eventuell eine Kopie der Variable während der ich Interrupts verhindere. 
Nicht optimal, aber vermutlich fast das beste. Oder wie seht ihr das?

von Stefan F. (Gast)


Lesenswert?

Manchmal hat man die Möglichkeit, in der ISR nur einen "kleinen" 8bit 
Counter zu benutzen. Dann kann das Hauptprogramm diesen auf 32bit oder 
gar 64bit erweitern. Vorausgesetzt natürlich, dass der 8bit Zähler nicht 
überläuft, bevor das Hauptprogramm ihn ausliest.

von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Also, der sicherste Weg in ALLEN solchen Fällen ist der, erstmal
> generell auf das temporäre Sperren von Interrupst zu verzichten. Also
> kein cli und sei.

Der sicherste Weg ist, genau das zu tun. Man muß ja nur den einen 
Zugriff atomar kapseln, d.h. die Sperre dauert etwa 10 Zyklen und so ein 
kurzes Delay muß jeder Interrupt verkraften können.

Eine spezielle Quelle zu sperren, ist aufwendiger und kann Seiteneffekte 
haben. Z.B. kann sich ein geringer priorisierter Interrupt vordrängeln 
und die Pause wird dann erheblich größer als 10 Zyklen. Ein großer 
Jitter ist aber bei Timerinterrupts oft nicht erwünscht. Das kann z.B. 
eine Multiplexanzeige sichtbar flackern lassen.

von m.n. (Gast)


Lesenswert?

Peter D. schrieb:
> Ein großer
> Jitter ist aber bei Timerinterrupts oft nicht erwünscht. Das kann z.B.
> eine Multiplexanzeige sichtbar flackern lassen.

Dazu muß man sich aber schon sehr ungeschickt anstellen. Falls der 
Jitter tatsächlich einmal stören sollte, nimmt man sowieso einen 
Compare-Ausgang für jitterfreies Timing.

von MaWin O. (Gast)


Lesenswert?

Peter D. schrieb:
> Der sicherste Weg ist, genau das zu tun.

Der sicherste Weg ist zu verstehen, was man tut.
Alles andere ist unsicheres Voodoo.

von Peter D. (peda)


Lesenswert?

m.n. schrieb:
> Falls der
> Jitter tatsächlich einmal stören sollte, nimmt man sowieso einen
> Compare-Ausgang für jitterfreies Timing.

Wie willst Du damit eine Anzeige multiplexen?

von Karl B. (gustav)


Lesenswert?

W.S. schrieb:
> Beide Instanzen (Grundprogramm und ISR) besitzen jeweils ein
> Kennbyte. Am Anfang sind beide Kennbytes gleich, z.B. Null.

Hi,
das nennt man wohl auch "Job-Flag".
Realisierbar mit "Job"-Register.

Beispiel für AVR:
; ISR wird durchlaufen und setzt Job-Flag am Ende:
;....
ldi temp, 0x01
mov job, temp
clr temp
;
ISR_1:    ; ohne ISR-Durchlauf
sbrc job, 0
rjmp no_sync1
rcall  char2lcd
clr job
ret
;
no_sync1:  ; wieder vorbereiten für nächsten ISR-Durchlauf
clr job
ret
;
und im Analogieverfahren andere Bits desselben Registers "Job".

ciao
gustav

P.S.:
Dient zum Beispiel als Umschaltung einer Funkuhr auf "Gangreserve"- 
interne Uhr

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Peter D. schrieb:
> m.n. schrieb:
>> Falls der
>> Jitter tatsächlich einmal stören sollte, nimmt man sowieso einen
>> Compare-Ausgang für jitterfreies Timing.
>
> Wie willst Du damit eine Anzeige multiplexen?

Auf das gestörte Multiplexen von Anzeigen bezog sich, daß man sich sehr 
ungeschickt anstellen muß, um dies zu erreichen: Beispielsweise 
delay_ms() in anderen Interrupts regelmäßig und häufig verwenden.

Das Verwenden von vom Timer synchronisierten Ausgängen ist allgemein 
gemeint, daß man damit Jitter durch vorübergehende Interrupts vermeiden 
kann. Wenn man allerdings seine Anzeigen (spezieller Fall) per 
Schieberegister ansteuert, kann man diese beschreiben und das 
Übernahmesignal (strobe) per Compare-Ausgang erzeugen. Damit läuft die 
Anzeige völlig ungestört.

von W.S. (Gast)


Lesenswert?

Peter D. schrieb:
> Der sicherste Weg ist, genau das zu tun.

Ach wo. Du bist mental gar sehr auf dem AVR-Niveau. Auf anderen 
Architekturen läuft der größte Teil der Firmware im User-Modus und von 
dort aus kannst du nichtmal den geringsten Interrupt sperren, wenn du 
nicht sofort eine Exception auslösen willst, die dich schlichtweg aus 
dem Rennen nimmt. Da gilt solchartiges Programmieren nämlich als 
"Elefant im Porzellanladen".

Nein, es ist wirklich die beste und sauberste Art, erst garnicht auf 
den Gedanken an Generalsperren von Interrupts zu denken, sondern sich 
ein vernünftiges Protokoll zwischen den konkurrierenden Instanzen 
auszudenken.

W.S.

von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Auf anderen
> Architekturen läuft der größte Teil der Firmware im User-Modus und von
> dort aus kannst du nichtmal den geringsten Interrupt sperren, wenn du
> nicht sofort eine Exception auslösen willst, die dich schlichtweg aus
> dem Rennen nimmt.

Ach komm, Du mußt doch keine riesen float Tabellen unter der Sperre 
berechnen, sondern nur für den einen Zugriff auf die Variable sperren.
Wenige Zyklen Verzögerung muß jede Applikation abkönnen.
Natürlich gibt es auf komplexeren CPUs noch andere Methoden, einen 
atomaren Zugriff abzusichern. Die sind auch notwendig, da ja auch noch 
ein Cache mit ins Spiel kommt.

von Thomas E. (picalic)


Lesenswert?

W.S. schrieb:
> Auf anderen
> Architekturen läuft der größte Teil der Firmware im User-Modus und von
> dort aus kannst du nichtmal den geringsten Interrupt sperren,

Welche 8-Bit Architektur (um die geht es hier ja wohl) hat denn sowas?

Und wie sähe Deine Lösung für einen simplen 16-Bit Millisekunden-Zähler 
aus, der in einem Systick-Interrupt hochgezählt wird, d.h. was wäre 
Deine Alternative, um im Hauptprogramm eines 8-Bitters die ms-Systemzeit 
in eine 16-Bit Variable zu lesen?

: Bearbeitet durch User
von me_and_my_µC (Gast)


Lesenswert?

Thomas E. schrieb:
> W.S. schrieb:
>> Auf anderen
>> Architekturen läuft der größte Teil der Firmware im User-Modus und von
>> dort aus kannst du nichtmal den geringsten Interrupt sperren,
>
> Welche 8-Bit Architektur (um die geht es hier ja wohl) hat denn sowas?
>
> Und wie sähe Deine Lösung für einen simplen 16-Bit Millisekunden-Zähler
> aus, der in einem Systick-Interrupt hochgezählt wird, d.h. was wäre
> Deine Alternative, um im Hauptprogramm eines 8-Bitters die ms-Systemzeit
> in eine 16-Bit Variable zu lesen?

Was ich mir eventuell überlegt habe, wäre, so etwas in der Art:
1
#include <stdint.h>
2
3
uint8_t* counter = NULL;
4
uint32_t real_counter;
5
6
int main()
7
{
8
  /* start timer */
9
10
  while(1)
11
  {
12
    if(counter != NULL && *counter > 0)
13
    {
14
      real_counter += *counter;
15
16
      if(*counter >= 255)
17
      {
18
        uint8_t i = 1;
19
        for(; *(counter + i) >= 255; ++i)
20
          real_counter += *(counter + i);
21
        real_counter += *(counter + i);
22
23
        free(counter);
24
      }
25
    }
26
  }
27
}
28
29
ISR(TIMER_INTR_NAME)
30
{
31
  if(counter == NULL)
32
  {
33
    counter = calloc(1, sizeof(uint8_t));
34
  }
35
  else if(*counter >= 255)
36
  {
37
    uint8_t i = 1;
38
    for(; *(counter + i) >= 255; ++i)
39
      ;
40
    counter = realloc(counter, (i + 1) * sizeof(uint8_t));
41
    ++*(counter + i);
42
  }
43
  else
44
  {
45
    *counter += 1;
46
  }
47
}

Habe ich darin irgendeinen Denkfehler oder geht das so in etwa?
(Code ungetestet, nur eben als grobe Skizze geschrieben)

von (prx) A. K. (prx)


Lesenswert?

calloc in der ISR... Au Weia!

von m.n. (Gast)


Lesenswert?

me_and_my_µC schrieb:
> if(counter == NULL)
>   {
>     counter = calloc(1, sizeof(uint8_t));
>   }

Oh, oh, oh!
Das kann man eigentlich nur noch steigern, indem man das Byte bitweise 
anfordert ;-)

von me_and_my_µC (Gast)


Lesenswert?

Just in dem Moment, in dem ich es abgeschickt habe, fällt mir auf, dass 
gar nicht gewährleistet ist, dass in der Schleife nicht die Größe von 
counter verändert wird.
Auch das calloc in der ersten if-Verzweigung in ISR ist natürlich 
Schwachsinn. Muss malloc mit einer folgenden Initalisierung mit 1 sein.

Könnte das jetzt so klappen?
1
#include <stdint.h>
2
3
uint8_t* counter = NULL;
4
uint8_t changed;
5
6
int main()
7
{
8
  uint32_t real_counter = 0;
9
10
  /* start timer */
11
12
  while(1)
13
  {
14
    while(changed)
15
    {
16
      retry = 0;
17
18
      if(counter != NULL && *counter > 0)
19
      {
20
        real_counter += *counter;
21
        if(changed)
22
          continue;
23
        *counter = 0;
24
25
        if(*counter >= 255)
26
        {
27
          uint8_t i = 1;
28
          for(; *(counter + i) >= 255; ++i)
29
            real_counter += *(counter + i);
30
          real_counter += *(counter + i);
31
32
          if(changed)
33
            continue;
34
          free(counter);
35
          counter = NULL;
36
        }
37
      }
38
    }
39
40
    changed = 0;
41
  }
42
}
43
44
ISR(TIMER_INTR_NAME)
45
{
46
  changed = 1;
47
48
  if(counter == NULL)
49
  {
50
    counter = malloc(sizeof(uint8_t));
51
    *counter = 1;
52
  }
53
  else if(*counter >= 255)
54
  {
55
    uint8_t i = 1;
56
    for(; *(counter + i) >= 255; ++i)
57
      ;
58
    counter = realloc(counter, (i + 1) * sizeof(uint8_t));
59
    ++*(counter + i);
60
  }
61
  else
62
  {
63
    *counter += 1;
64
  }
65
}

Verbesserungsvorschläge und Kritik sind ausdrücklich erwünscht.

von me_and_my_µC (Gast)


Lesenswert?

Gerade eure Beiträge gesehen.
Meint ihr dynamische Speicheranforderung allgemein oder nur calloc?
calloc ist natürlich auch Schwachsinn. Ist schließlich nur einer und 
muss dazu noch mit 1 initialisiert werden.
Dass dyn. Speicherverwaltung langsamer ist als der Stack ist klar. Aber 
so langsam sollte das doch auch nicht sein, oder?

von (prx) A. K. (prx)


Lesenswert?

me_and_my_µC schrieb:
> Meint ihr dynamische Speicheranforderung allgemein oder nur calloc?

Generell. ISRs sollte man einfach und kurz halten.

Diese Funktionen sind evtl nicht in Interrupts einsetzbar, wenn sie auch 
ausserhalb davon eingesetzt werden, wenn nicht reentrant.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

me_and_my_µC schrieb:
> Meint ihr dynamische Speicheranforderung allgemein

Ja.
Alles, was man zur Compilezeit abschätzen kann, sollte auch dort 
definiert werden.
Da malloc selber auch Speicher zur Verwaltung benötigt, lohnt es sich 
für Blöcke <16Byte in der Regel nicht.
Auf kleinen MCs hat man oft zur Laufzeitoptimierung nur eine einfache 
Verwaltung (keine Defragmentierung), daher kann realloc schnell gegen 
die Wand laufen.

von me_and_my_µC (Gast)


Lesenswert?

Ansonsten Vorschläge?
Oder soll ich sonst einfach nur einen einzelnen uint8_t hochzählen in 
der Hoffnung, dass spätestens nach 255 Interrupts die Programmschleife 
den richtigen Counter hochgezählt hat?
Also dann:
1
uint8_t temp = timercounter; uint32_t real_counter = temp;
Das müsste sonst ja eigentlich auch recht sicher sein.

von Thomas E. (picalic)


Lesenswert?

Hm, also so ganz blicke ich nicht durch, was Dein Programm da so 
kompliziertes macht und warum.
Frage: was spricht nun eigentlich gegen das direkte Hochzählen des 
32-Bit Counters in der ISR und eine kurze Interrupt-Sperre beim Zugriff 
auf den Counter im Hauptprogramm? Ist die ISR so zeitkritisch, daß es 
nicht für die Verarbeitung von 4 Bytes reicht? Oder sind die 
ISR-Latenzen so kritisch, daß Du die Interrupts nicht für die Zeitdauer 
des Zugriffs auf die 32-Bit Zählervariable sperren kannst? Oder läuft 
Dein ATMega im Supervisor-Modus, weshalb Du keine CLI- und SEI-Befehle 
in Deinem im User-Mode ablaufenden Programm benutzen kannst (ich wusste 
gar nicht, daß der ATMega das kann...)?

P.S.: vergiss nicht, Variablen, die durch die ISR verändert werden und 
auf die auch im Hauptprogramm zugegriffen wird, als "volatile" zu 
deklarieren!

: Bearbeitet durch User
von Walter (Gast)


Lesenswert?

me_and_my_µC schrieb:
> Könnte das jetzt so klappen?

ich verstehe zwar nicht warum das Programm so kompliziert sein muss,
aber schon beim Überfliegen sehe ich:

volatile fehlt

Zugriff auf counter ist nicht atomar!

von Walter (Gast)


Lesenswert?

me_and_my_µC schrieb:
> uint8_t i = 1;
>     for(; *(counter + i) >= 255; ++i)
>       ;

und was ist denn das, du lässt dir ein Byte allozieren und rödelst dann 
fröhlich auf den darauf folgenden Bytes rum?

von Thomas E. (picalic)


Lesenswert?

Mein Vorschlag wäre ungefähr so:
1
volatile uint32_t count;
2
3
uint32_t AtomicRead32 (uint32_t * volatile pt)
4
{
5
  uint32_t retval;
6
7
  cli();  
8
  retval = *pt;
9
  sei();
10
  return retval;
11
}
12
13
void AtomicWrite32 (uint32_t * volatile pt, uint32_t data)
14
{
15
  cli();  
16
  *pt = data;
17
  sei();
18
}
19
20
int main()
21
{
22
  ... Initialisierungen etc. ...
23
24
  while (1)
25
  {
26
    if(AtomicRead32(&count) > 1234567)     // z.B....
27
      AtomicWrite32(&count, 0);
28
  }
29
}
30
31
ISR(TIMER_INTR_NAME)
32
{
33
  count++;
34
}

von Stefan F. (Gast)


Lesenswert?

Anstatt Interrupts zu sperren kann man auch einfach den Counter 2x 
lesen. Wenn diese Beiden Werte nicht gleich sind, liest man noch einmal, 
dann hat man den richtigen Wert.

So macht man das bei der RTC im STM32F1 (allerdings nicht wegen ISR, 
sondern weil der Counter asynchron in HW implementiert ist).

von c-hater (Gast)


Lesenswert?

Thomas E. schrieb:

> Oder läuft
> Dein ATMega im Supervisor-Modus, weshalb Du keine CLI- und SEI-Befehle
> in Deinem im User-Mode ablaufenden Programm benutzen kannst (ich wusste
> gar nicht, daß der ATMega das kann...)?

Kann er auch nicht. Es gibt beim AVR8 nur zwei Instruktionen, für die es 
sowas wie Berechtigungsebenen für die Ausführung gibt. Das sind: lpm und 
spm.

von Thomas E. (picalic)


Lesenswert?

Stefan U. schrieb:
> So macht man das bei der RTC im STM32F1 (allerdings nicht wegen ISR,
> sondern weil der Counter asynchron in HW implementiert ist).

Klar, da würde ja das Sperren der Interrupts auch nichts nützen.
Zweimal lesen und vergleichen gibt wahrscheinlich etwas mehr Code, aber 
man blockiert dafür die interrupts nicht - das muss man halt abwägen, ob 
einem die Codegröße oder die Interrupt-Latenz wichtiger ist.
Wenn sicher ist, daß es um einen simplen Counter geht, reicht es evtl. 
aus, nur das niederwertige Byte zu vergleichen - das müsste etwas 
kürzer/schneller sein.

von me_and_my_µC (Gast)


Lesenswert?

Walter schrieb:
> me_and_my_µC schrieb:
>> Könnte das jetzt so klappen?
>
> ich verstehe zwar nicht warum das Programm so kompliziert sein muss,
> aber schon beim Überfliegen sehe ich:
>
> volatile fehlt
>
> Zugriff auf counter ist nicht atomar!

volatile habe ich vergessen, das stimmt.
counter sind nur mehrere unabhängige uint8_t, auf die doch eigentlich 
atomar zugegriffen werden kann.
Ob sich in der Zwischenzeit die Größe von counter verändert hat wird ja 
auch immer wieder über changed überprüft. Sollte es sich verändert 
haben, beginnt die Schleife von vorne. Der Timer muss dafür natürlich 
ziemlich langsam zählen.
Aber dadurch, dass malloc in ISR wohl nicht zu empfehlen ist, klappt das 
sowieso nicht.

Walter schrieb:
> me_and_my_µC schrieb:
>> uint8_t i = 1;
>>     for(; *(counter + i) >= 255; ++i)
>>       ;
>
> und was ist denn das, du lässt dir ein Byte allozieren und rödelst dann
> fröhlich auf den darauf folgenden Bytes rum?

Es wird gezählt, wie viele Bytes schon voll sind. Die mehreren Bytes 
sind ja nur dafür da, um sicherzustellen, dass, falls die if-Abfrage in 
der Programmschleife nicht nach 255 Interrupts drankam.
Das letzte (noch freie) Byte wird dann hochgezählt.
Wobei das tatsächlich nicht so klappt. Das müsste man noch einmal ein 
wenig umschreiben.
Ist aber ja, wie gesagt, anscheinend sowieso nicht sinnvoll.

Stefan U. schrieb:
> Anstatt Interrupts zu sperren kann man auch einfach den Counter 2x
> lesen. Wenn diese Beiden Werte nicht gleich sind, liest man noch einmal,
> dann hat man den richtigen Wert.
>
> So macht man das bei der RTC im STM32F1 (allerdings nicht wegen ISR,
> sondern weil der Counter asynchron in HW implementiert ist).

Diese Lösung gefällt mir in der Tat am Besten und der Aufwand hält sich 
in Grenzen. Wobei in dem Fall vermutlich auch einfach der uint8_t 
counter reicht, weil es in dem Programm eigentlich keine großen 
Verzögerungen geben kann, die 256 Sekunden lang den Programmfluss 
behindern.
Danke.

von Stefan F. (Gast)


Lesenswert?

> Wobei in dem Fall vermutlich auch einfach der uint8_t counter reicht

Wenn das so ist, dann brauchst Du Dir um die Interrupts gar keinen Kopf 
machen.

von me_and_my_µC (Gast)


Lesenswert?

Ich meine als Zwischenzähler, der dann in der Programmschleife kopiert 
wird. Die Kopie wird dann anschließend zu dem richtien Zähler gezählt, 
der 32-bit groß ist.
Ich meine, dass der Interrupt quasi unmöglich 255 Mal auftreten kann, 
ohne dass er zu dem richtigen Zähler gezählt und anschließend wieder 
zurückgesetzt wurde.

von W.S. (Gast)


Lesenswert?

Peter D. schrieb:
> Ach komm, Du mußt doch keine riesen float Tabellen unter der Sperre
> berechnen,

Ich glaub, ich krieg hier ne Krise...

Versuche du doch bloß endlich, mal nicht alles kleinzureden, was du im 
Moment nicht überschaust. Ich geb dir mal ein Beispiel: Kommunikation 
des µC mit dem PC via USB-VCP. Wenn du da mit Interrupt-Sperren im 
verkehrten Moment daherkommst, klinkt dich der Host ganz einfach 
gnadenlos raus.

Nein, das ist alles 8 Bit AVR-Denke. Wenn man bei diesen µC zu bleiben 
gedenkt, dann kann man das ja lustig so weitermachen, aber wer vom AVR 
in Richtung 32 Bitter guckt (wie der TO), der sollte sowas eben 
bleibenlassen und stattdessen andere Strategien sich aneignen. Jaja, der 
32 Bit Zugriff ist dort atomar, weswegen das hier gekäute Problem 
gegenstandslos wird, aber hier geht's mir um das Wegkommen von der 
archaischen AVR-Denke.

W.S.

von m.n. (Gast)


Lesenswert?

W.S. schrieb:
> AVR-Denke

Was ist das?

von Thomas E. (picalic)


Lesenswert?

W.S. schrieb:
> Wenn du da mit Interrupt-Sperren im
> verkehrten Moment daherkommst, klinkt dich der Host ganz einfach
> gnadenlos raus.

Mit Verlaub - das ist Quatsch! Weil der USB-Interrupt im µC mal 2-3 
Mikrosekunden später bedient wird, schmeißt der Host das Gerät nicht 
'raus. Wir reden hier ja wohl nicht von V-USB oder solchen Krücken (da 
könnte ich mir das sogar vorstellen), sondern von einer "richtigen" 
USB-Hardware im µC?

W.S. schrieb:
> aber wer vom AVR
> in Richtung 32 Bitter guckt (wie der TO),

Ähm - wo guckt er denn in diese Richtung? Ich sehe es nicht...

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Kommunikation
> des µC mit dem PC via USB-VCP. Wenn du da mit Interrupt-Sperren im
> verkehrten Moment daherkommst, klinkt dich der Host ganz einfach
> gnadenlos raus.

Schon beim AVR sind Interfaces (UART, CAN, USB) gepuffert, bzw. das I2C 
kann den Master bremsen. Es besteht also immer genügend Zeit, Interrupts 
abzuarbeiten und das kostet selber ja auch Zeit.
Ich kann mir nicht vorstellen, daß 32Bitter da rückständiger sein 
sollen.

Auch muß jede Interruptquelle damit klarkommen, daß sie durch andere 
Interrupts verzögert wird. Und ein gerade laufender Interrupthandler 
kostet deutlich mehr Zyklen, als nur ein simpler atomarer Zugriff.

In der Praxis bevorzugt man daher die globale Sperre für atomare 
Zugriffe, 1. weil es keine Nachteile hat und 2. weil es keine 
Seiteneffekte hat (wie z.B. Prioritätsinversion).

von (prx) A. K. (prx)


Lesenswert?

Peter D. schrieb:
> Ich kann mir nicht vorstellen, daß 32Bitter da rückständiger sein
> sollen.

Ist auch nicht. Zumal man bei den Cortex M nicht zwingend alle 
Interrupts abschalten muss, sondern über den aktuellen Prio-Level auf 
sehr einfache Art alle höher priorisierten Interrupts weiterhin 
durchlassen kann.

> In der Praxis bevorzugt man daher die globale Sperre für atomare
> Zugriffe, 1. weil es keine Nachteile hat und 2. weil es keine
> Seiteneffekte hat (wie z.B. Prioritätsinversion).

Prioritätsinversion ist eine Eigenheit von RTOS. Einfache verschachtelte 
Interrupts sind davon nicht betroffen, wenn man über den 
Prio-Mechanismus geht, statt über einzelne Int-Enables.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

A. K. schrieb:
> Prioritätsinversion ist eine Eigenheit von RTOS. Einfach verschachtelte
> Interrupts sind davon m.W. nicht betroffen.

Wenn man wie von W.S. postuliert, nur eine Interruptquelle sperrt, kann 
wärend dessen jeder andere Interrupt niederer Priorität ausgeführt 
werden und damit die Sperre unerwartet lange verlängern. Solche 
Seiteneffekte sind gefährlich, da nur schwer zu debuggen.

Die globale Sperre kann aber nicht durch andere Interrupts verlängert 
werden, d.h. sie bleibt immer wie erwartet kurz. Und bei deren Ende 
wirkt immer die eingestellte Prioritätskette. Es kann sich kein 
Interrupt niederer Priorität vordrängeln.

von (prx) A. K. (prx)


Lesenswert?

Peter D. schrieb:
> Wenn man wie von W.S. postuliert, nur eine Interruptquelle sperrt, kann
> wärend dessen jeder andere Interrupt niederer Priorität ausgeführt
> werden und damit die Sperre unerwartet lange verlängern.

Weshalb ich ja auch auf den Prio-Mechanismus rauswollte. Damit sperrt 
man alle Interrupts bis zum betroffenen Level und vermeidet so die 
Prio-Inversion:
1
uint32_t save = __get_BASEPRI();
2
__set_BASEPRI_MAX(level);
3
...
4
__set_BASEPRI(save);

Die Variante über das eigens dafür definierte MSR BASEPRI_MAX ist auch 
dann sicher, wenn sie aus bereits höher priorisiertem Code heraus 
aufgerufen wird.

PS: Das ist übrigens ein ganz alter Hut und bereits in den Frühversionen 
des Unix-Quellcodes zu finden, da die PDP-11 ebenfalls Int-Prios hatte. 
Nur die clevere _MAX Version der Cortex M ist m.E. eine neue Idee.

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


Lesenswert?

Peter D. schrieb:
> Wenn man wie von W.S. postuliert, nur eine Interruptquelle sperrt,

Wie kommst du denn darauf?

Meine Position ist ganz klar:
Interrupts werden überhaupt nicht gesperrt, weder dediziert noch global.

Stattdessen soll man sich sein Zeugs so ausdenken, daß man mit 
Interrupts ohne Probleme zurechtkommt. Das geht, und zwar immer und auf 
allen Architekturen. Auch dort, wo es sowas wie den NMI gibt und wenn 
man diesen in Verwendung hat. Gelle?

W.S.

von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Wie kommst du denn darauf?

Sorry, das war ja  m.n.

von Adapter (Gast)


Lesenswert?

W.S. schrieb:
> Peter D. schrieb:
>> Wenn man wie von W.S. postuliert, nur eine Interruptquelle sperrt,
>
> Wie kommst du denn darauf?
>
> Meine Position ist ganz klar:
> Interrupts werden überhaupt nicht gesperrt, weder dediziert noch global.
>
> Stattdessen soll man sich sein Zeugs so ausdenken, daß man mit
> Interrupts ohne Probleme zurechtkommt. Das geht, und zwar immer und auf
> allen Architekturen. Auch dort, wo es sowas wie den NMI gibt und wenn
> man diesen in Verwendung hat. Gelle?
>
> W.S.

Mal wieder ein typischer W.S.

He, Du Chuck Norris der Embedded Welt - wenn es tatsächlich ohne Sperren 
gehen würde, warum gibt es denn keinen einzigen Controller, der 
Interrupts Ausmaskieren NICHT implementiert? Wäre doch bares Geld, das 
man da herauswirft.

Klar, wenn man in der Nanowelt eines W.S. lebt, in der man jedes 
einzelne Bit mit Namen kennt, kriegt man es vielleicht irgendwie hin. 
Aber das ist ja nicht das Mass der Dinge. Und den daraus resultierenden 
Code möchte ich aber einer gewissen Komplexität nicht mehr sehen 
wollen...

Wenn man sich z.B. mal den Standard 08/15 Code wirklich JEDEN 
Inputtreibers ansieht, sieht man so etwas wie das folgende (Pseudo 
Code):

ISR:
- Vorverarbeitung (z.B. Vorpufferung eines Zeichens)
- Signalisierung einer task, die die Zeichen weniger zeitkritisch 
wegschafft

Task:
- Warten auf das Signal
- Wegschaffen der Zeichen

Das ist Jahrzehntelang bewährte Praxis. Man KANN es Anders machen, aber 
mit dem Kontrollfluss funktionieren gefühlt 90% aller Softwarebasen, und 
das ist m.E. nach der beste Kompromiss zwischen Systemausbremsen und 
keine Zeichen zu verlieren riskieren.

Und nun erzähl uns doch mal, lieber C.N. (alias W.S.), wie man so etwas 
OHNE Ausmaskieren von Interrupts hinkriegen soll. Das Signalisieren und 
Warten auf ein Signal sind nämlich in sich (zumindestens in wenn auch 
nur sehr kurzen Codeabschnitten) gegenseitig ausschliessende 
Operationen. Und da sich ja ISRs nicht suspendieren lassen dürfen, 
bleibt nix Anderes als das Ausmaskieren. In jedem RTOS gibt es deswegen 
des Konzept von Exklusiven Codeabschnitten, die sich darauf verlassen 
müssen, dass sie eben exklusiv ablaufen. Und eben durch das Ausmaskieren 
implementiert sind.

von Thomas E. (picalic)


Lesenswert?

W.S. schrieb:
> Interrupts werden überhaupt nicht gesperrt, weder dediziert noch global.

Ich halte mehr von Pragmatismus, als von Dogmatismus.

von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Meine Position ist ganz klar:
> Interrupts werden überhaupt nicht gesperrt, weder dediziert noch global.
>
> Stattdessen soll man sich sein Zeugs so ausdenken, daß man mit
> Interrupts ohne Probleme zurechtkommt.

Das mag oft möglich sein, aber mit dem Ausdenken ist das so eine Sache. 
Je komplizierter der Code dadurch wird, umso mehr besteht die Gefahr, 
daß man dabei einen Fehler macht. Und Interruptfehler sind extrem schwer 
zu debuggen.

Meine Position ist auch ganz klar:
Die CPU kann immer nur einen Interrupt zur Zeit abarbeiten. Es gibt also 
bei mehreren Interruptquellen immer den Fall, daß ein Interrupt durch 
einen anderen verzögert werden kann. Im Worst-Case sogar um die Summe 
aller Handlerausführungszeiten aller anderen Interrupts. Und das muß das 
Programm abkönnen, sonst hat man falsch geplant.
Dagegen sind wenige Zyklen Sperre durch einen atomaren Zugriff nur 
Pillepalle. Die merkt man garnicht. Also gibt es keinen Grund, etwas 
unnötig zu verkomplizieren.
KISS: Keep it short and simple.

von m.n. (Gast)


Lesenswert?

Als ob es bei Interrupts immer nur um atomare Zugriffe ginge. Das ist 
doch alles nur Theorie.

Thomas E. schrieb:
> W.S. schrieb:
>> Interrupts werden überhaupt nicht gesperrt, weder dediziert noch global.
>
> Ich halte mehr von Pragmatismus, als von Dogmatismus.

So sieht es aus!

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.