Interrupts und blockierende Prozesse

Gast #4131141
Hey,

ich bin ein relativer Neuanfänger, und habe ein Problem mit einer 
Spezifikation. Der Grundaufbau ist folgendermaßen:

Ein Mikrocontroller und ein Sensor: Der Sensor sendet mit 10 kHz ein 
signed 32 bit Signal, und diese Signale sollen über einen blockierten 
Interrupt interpretiert werden. So weit so gut.

Jedoch steht ein zweiter blockierender Prozess im Hintergrund (z.B. 
print() serielle Ausgabe über UART - bedeutet keine Eintrittsinvarianz), 
dieser Prozess ist wesentlich langsamer als der Interrupt des Signales.

Wie kann ich die Signale des Sensors verarbeiten ohne sie während der 
Zeit des blockierenden Prozesses zu verlieren?

Technische Daten:
Sensor: Alle 100µs
Blockierender Prozess: Jede Sekunde

Momentane Idee ist: Ein Timer und Interrupt für den Sensor, und die 
Daten verarbeiten, allerdings denke ich mir dass die (blockierende) 
Ausgabe über die UART-Schnittstelle die Interrupts des Sensors 
blockierend wird, wodurch ich Daten verlieren würde.

Um jegliche Hilfe wäre ich äußerst dankbar.
Persönliche Seite
Chris Schäufer schrieb:
> diese Signale sollen über einen blockierten
> Interrupt interpretiert werden. So weit so gut.

Warum? Wer sagt das? Das macht doch keinen Sinn!

Chris Schäufer schrieb:
> Jedoch steht ein zweiter blockierender Prozess im Hintergrund …

Warum? Das macht doch auch keinen Sinn!

Setze Flags in den ISRs und mache alles in der Main-Loop.
Gast
Danke für deine Antwort Torsten C.,

das ist nunmal die Spezifikation an der ich nichts ändern kann, und wie 
gesagt bin ich ein Anfänger welcher sich versucht darin einzuarbeiten.

Wenn ich den blockierenden Prozess in die "Main-Loop" einsetze wird das 
Programm dann trotzdem in der Lage sein die Daten des Sensors zu 
verarbeiten? Obwohl der blockierenden Prozess wesentlich länger braucht 
als der Interrupt des Sensors?

Entschuldige es mir falls ich nicht deiner Terminologie entsprechend 
geantwortet habe
Chris Schäufer schrieb:

>
> Wenn ich den blockierenden Prozess in die "Main-Loop" einsetze wird das
> Programm dann trotzdem in der Lage sein die Daten des Sensors zu
> verarbeiten? Obwohl der blockierenden Prozess wesentlich länger braucht
> als der Interrupt des Sensors?
>
Definiere mal "blockierender Prozess" und beantworte Dir selbst folgende 
Frage:
Wie kann der MC irgendetwas anderes machen wenn er von einem Prozess im 
IRQ blockiert wird?
Anders sieht es aus, wenn der blockierende Prozess die Mainloop aus (da 
unterscheidet sich Dein erster von Deinem 2.Beitrag). Dort kann ein IRQ 
natürlich den Prozess unterbrechen.
Man kan auch einen IRQ durch eine anderen unterbrechen. Dann wird es 
aber komplizierter und ich würde diese Vorgehensweise bei Deinem 
Kenntnisstand nicht empfehlen.
Grunsätzlich schreibt man Programme (insbesondere IRQ) bei einem 
Mikroprozessor so, daß sie eben nicht blockieren. (Stichwort: State 
machine)
Wenn also bei Deinem Programm irgendwelche Delays vorkommen, hast Du 
grundsätzlich schon etwas falsch gemacht.

Gruß
Andreas
Gast
Also erst mal eine Klarstellung: Dein "blockierender Prozess"
bedeutet wohl, dass der Prozessor/µC während der Erfassungs-
Routine (Sensor), oder der Ausgabe-Routine nicht unterbrochen
werden darf. Die "Eintrittsinvarianz" klingt schön gebildet,
erläutert dein Problem aber auch nicht so richtig:

Die print()-Ausgabe über UART kann jedenfalls ohne weiteres
unterbrochen werden, wenn man eine Hardware-UART zur Vefügung
hat (z.B. AT-Mega). Dabei schaut der µC, wenn er gerade mal
Zeit hat nach, ob der Sendepuffer frei ist und setzt ggfs. das
nächste Byte ab - um den Rest kümmert sich die µC-Hardware.

Ohne Hardware-UART hast du wohl den falschen µC gewählt,
wenn du nicht auf einige Sensorwerte verzichten willst,
darfst, oder kannst.

In vielen Fällen reichen aber auch ein bis 10 Sensorwerte pro
Sekunde - die mit ihrem 100 µs Takt auch schnell genug
übermittelt sind, um in der restlichen Zeit noch VIELE
Sachen zu erledigen.

Mach dir doch erst mal ein paar konzeptionelle Gedanken!
Kurt schrieb:
> Also erst mal eine Klarstellung: Dein "blockierender Prozess"
> bedeutet wohl, dass der Prozessor/µC während der Erfassungs-
> Routine (Sensor), oder der Ausgabe-Routine nicht unterbrochen
> werden darf.

Wobei ich selbst das in Frage stellen würde. Wenn da alle 100 µs ein Bit 
abgefragt werden muss, kann man auch einen Timer stellen, dessen 
Interrupt das tut. Damit wäre der Prozessor nicht 3,2 ms lang zu 100%, 
sondern nur zu vielleicht 5% ausgelastet. 100 µs entsprechen 
schliesslich selbst bei gemütlichen 10 MHz CPU-Takt immer noch 1000 
Instruktionen.

Und dann sind da u.U. noch Chancen, den Hardware-SPI das Signal lesen zu 
lassen. Dann hat die CPU fast gar nichts mehr zu tun.
Gast
Bastler schrieb:
> Das würde man dann aber als "kreativ" bezeichnen, oder ;-)

Für nicht genutzt Hardware gibt es beim µC kein Geld zurück. Dann kann 
sie auch etwas sinnvolles tun und dem Prozessor für kreativere Dinge als 
regelmäßiges Abtasten den Rücken frei halten.
Chris Schäufer schrieb:
> und diese Signale sollen über einen blockierten
> Interrupt interpretiert werden.

Warum soll ein Interrupt etwas blockieren?
Er macht sein Ding und kehrt sofort wieder zum Main zurück.
Müssen darin zeitverzögerte Sachen gemacht werden, startet er dazu einen 
Timerinterrupt und der macht dann den Rest.

Chris Schäufer schrieb:
> (blockierende)
> Ausgabe über die UART-Schnittstelle

UART im Pollingmode blockiert keine Interrupts, der Interrupt merkt die 
UART garnicht.
UART im Interruptmode blockiert auch nichts. Der schreibt nur das 
nächste Byte in das Datenregister und das braucht nur wenige CPU-Takte.
Gast
@Praktiker: offenbar war meine Ironie mißverständlich. Ich bin sehr 
dafür Probleme mit den Mittel zu lösen, die die Hardware bietet. 
Interrupts sind da mit das Wichtigste. Wie heute schonmal in anderem 
Thread geschrieben: PeDa-Entprellung auf Tiny24 in C++ formuliert, 
braucht Rechenzeit im Promillebereich. Der Rest ist Schlafen und warten 
auf Timer0. "kreativ" bezog sich mehr darauf, daß dies eigentlich nichts 
Neues sein sollte. Dinge, die für Ältere wie mich normal sind und 
Greenhorns "exciten". Und deren Aufregung ob dem vermeintlich Neuem wird 
dann als Kreativität mißverstanden ;-)
Gast
Bastler schrieb:
> dafür Probleme mit den Mittel zu lösen, die die Hardware bietet.
> Interrupts sind da mit das Wichtigste. Wie heute schonmal in anderem

Ich würde die Timer an erster Stelle nennen.

> Thread geschrieben: PeDa-Entprellung auf Tiny24 in C++ formuliert,
> braucht Rechenzeit im Promillebereich. Der Rest ist Schlafen und warten
> auf Timer0. ...

Warten auf Timer0? Den Text solltest du auch nochmal überarbeiten, wenn 
du das nicht so meinst, wie es rüberkommt.

> Dinge, die für Ältere wie mich normal sind und
> Greenhorns "exciten". Und deren Aufregung ob dem vermeintlich Neuem wird
> dann als Kreativität mißverstanden ;-)

Kann dich denn noch was "exciten"?
Gast
Chris Schäufer schrieb:
> ich bin ein relativer Neuanfänger, und habe ein Problem mit einer
> Spezifikation. Der Grundaufbau ist folgendermaßen:
>
> Ein Mikrocontroller und ein Sensor: Der Sensor sendet mit 10 kHz ein
> signed 32 bit Signal, und diese Signale sollen über einen blockierten
> Interrupt interpretiert werden. So weit so gut.

Erstmal eines: Was ist "einen blockierten Interrupt" ?

Ist der Intettupt nun blockiert oder nicht?

Dann zu einem sinnvollen Verfahren:
1. Regel: Du kannst nicht mehr Traffic hereinholen, als du an von diesem 
Traffic verursachtem Output herausbringen kannst. Mißachtest du das, 
kommt es grundsätzlich zum Überlauf.

2. Arbeite mit Puffern. Also hole deine Input-Werte in einer ISR herein 
und stopfe sie in einen Input-Ringpuffer. Verarbeite die Werte aus dem 
Ringpuffer in der Grundschleife oder einer Funktion, die du aus der 
Grundschleife heraus aufrufst. Stopfe die dort anfallenden Erebnisse in 
einen zweiten Ringpuffer. Gib die in dem zweiten Ringpuffer anstehenden 
Ergebnisse per Interrupt an den Ausgabe-Kanal aus.

3. Benutze zu solchen Zwecken NIE NIE NIEMALS sowas wie printf und 
Konsorten, sofern du den dadurch entstehenden Datenstrom nicht selbst in 
den genannten zweiten Ringpuffer leiten und per Interrupt ausgeben 
kannst.

W.S.
> 3. Benutze zu solchen Zwecken NIE NIE NIEMALS sowas wie printf und
> Konsorten, sofern du den dadurch entstehenden Datenstrom nicht selbst in
> den genannten zweiten Ringpuffer leiten und per Interrupt ausgeben
> kannst.

Blöde Frage: Warum nicht? Sind die vom Timing so unvorhersehbar?
@ S. R. (svenska)

>> 3. Benutze zu solchen Zwecken NIE NIE NIEMALS sowas wie printf und
>> Konsorten,

Unsinnige Verallgemeinerung. Man kann das durchaus verwenden, wenn der 
Interrupt sich nicht zu schnell wiederholt.

> sofern du den dadurch entstehenden Datenstrom nicht selbst in
> den genannten zweiten Ringpuffer leiten und per Interrupt ausgeben
> kannst.

>Blöde Frage: Warum nicht?

Man kann.

> Sind die vom Timing so unvorhersehbar?

Nein, das ist eher revht gut vorheragbar, kann aber bisweilen lang sein. 
Ein printf() in einem 10kHz Timer-Interrupt ist eher deplatziert, in 
einem 5 Hz Interrupt kein Problem.
Gast
Falk Brunner schrieb:
> Ein printf() in einem 10kHz Timer-Interrupt ist eher deplatziert, in
> einem 5 Hz Interrupt kein Problem.

Das ist haarsträubender Unsinn, es geht darum wie LANGE eine ISR 
blockiert und nicht wie OFT. So etwas Irreführendes dürfte hier niemals 
veröffentlicht werden, das ist unverantwortlich!

In ISRs darf es keine Warteschleifen geben, die mehr als vorhersehbar 
wenige µs brauchen. Z.B. serielles Senden: die ISR sendet ein Byte, wenn 
das UART frei ist, und wenn nicht kehrt sie sofort zurück - warten in 
der ISR darauf, dass eine Peripherie frei wird, ist ein unentschuldbarer 
Kunstfehler.

Man kann daher so etwas wie printf in einer ISR nur verwenden, wenn man 
das Timing in der Hand hat, weil man die zeichenweise Ausgabe selbst 
durch ISRs ersetzt hat (und das Zeitverhalten überblickt!), oder wenn es 
mit absoluter Garantie keine Verzögerungen gibt, z.B. wenn man ins 
Memory schreibt statt auf einen Drucker o.ä.

Georg
> Man kann daher so etwas wie printf in einer ISR nur verwenden, wenn man
> das Timing in der Hand hat, [...]
...oder wenn es in der Anwendung keine Bedeutung hat.

Und das ist in erstaunlich vielen Fällen der Fall.
Gast
S. R. schrieb:

> ...oder wenn es in der Anwendung keine Bedeutung hat.
>
> Und das ist in erstaunlich vielen Fällen der Fall.

Nur dann, wenn der µC für die zu erfüllende Aufgabe massiv 
überdimensioniert ist und damit unnötig viel Strom verbraucht und 
unnötig viel Abwärme produziert.

Das ist, als wenn man jeden Tag mit einem 40Tonnen-Truck zur Arbeit 
fährt. Klar, dann braucht man sich auch niemals Sorgen darum zu machen, 
ob man die Lunchbox und die Einkäufe auf der Heimfahrt im Fahrzeug 
unterkriegt...

Aber trotzdem machen das erstaunlich wenige Leute. Die können vermutlich 
alle rechnen...
@ Georg (Gast)

>Das ist haarsträubender Unsinn, es geht darum wie LANGE eine ISR
>blockiert und nicht wie OFT. So etwas Irreführendes dürfte hier niemals
>veröffentlicht werden, das ist unverantwortlich!

Ohje. Beschwerd dich doch beim internationalen Gerichtshof in Den Haag.
Natülich darf die langsame 5 Hz Timer ISR mit riesigen print(f) Ausgaben 
nicht ANDERE ISR, welche deutlich öfter aktiv werden, nicht soweit 
ausbremsen, dass dort ISRs verschluckt werden. OK, mein Fehler dass ich 
das nicht so explizit geschrieben habe.

Dass man zwar meistens gut damit fährt, printf(9 & Co in ISRs eher nicht 
zu vermeiden heißt eben nicht, dass es absolut unmöglich bzw. verboten 
ist.
Man muss wie immer wissen was man tut.

>In ISRs darf es keine Warteschleifen geben, die mehr als vorhersehbar
>wenige µs brauchen.

Blödsinn! Das ist ein SONDERFALL! Allgemein gilt das überhaupt nicht.
Eine ISR darf sich im Einzelfall auch mal 100ms Zeit gönnnen.

> Z.B. serielles Senden: die ISR sendet ein Byte, wenn
>das UART frei ist, und wenn nicht kehrt sie sofort zurück - warten in
>der ISR darauf, dass eine Peripherie frei wird, ist ein unentschuldbarer
>Kunstfehler.

Davon redet gar keiner.

>Man kann daher so etwas wie printf in einer ISR nur verwenden, wenn man
>das Timing in der Hand hat, weil man die zeichenweise Ausgabe selbst
>durch ISRs ersetzt hat (und das Zeitverhalten überblickt!),

Das muss man bei ISRs immer.
Falk Brunner schrieb:
> Ein printf() in einem 10kHz Timer-Interrupt ist eher deplatziert, in
> einem 5 Hz Interrupt kein Problem.

Printf kann man generell nicht in Interrupts verwenden, sonst gibt es 
Zeichensalat, da die UART nicht reentrant ist!

Bzw. nur in dem Sonderfall, daß dieser Interrupt die einzige Instanz 
ist, die printf aufruft.
Gast
Also die Aufgabenstellung tönt sehr abenteuerlich. Vielleicht solltest 
du zuerst ein paar Tutorials zum Thema Mikrokontroller durcharbeiten.

So wie ich das verstanden erhältst du 32Bit Daten, alle 100us soll ein 
neues Bit eingelesen werden. Dafür brauchst du eigentlich nur ein Timer 
Interrupt, im Interrupt selbst wird nur der Status des Sensors gelesen 
und danach in einem Zwischenspeicher abgelegt. Die Daten kannst du dann 
in der main() Routine verarbeiten. Der Timer Interrupt wird deine 
restliche Software nicht tangieren.
Im Interrupt sollte keine grosse Datenverarbeitung statt finden, 
irgendwelche delays haben dort ebenfalls nichts zu suchen.

Gruss
Falk Brunner schrieb:
>>In ISRs darf es keine Warteschleifen geben, die mehr als vorhersehbar
>>wenige µs brauchen.
>
> Blödsinn! Das ist ein SONDERFALL! Allgemein gilt das überhaupt nicht.
> Eine ISR darf sich im Einzelfall auch mal 100ms Zeit gönnnen.

Es gibt natürlich Fälle, in denen auch Murks funktioniert. Ändert aber 
nichts daran, daß es Murks ist. Wäre es vernünftig implementiert, würde 
sich die Fragestellung des TE gar nicht erst ergeben. Ihm kann man das 
nicht vorwerfen, da er nach eigenem Bekunden Anfänger ist.
Nun kann man das irgendwie so zurechtfrickeln, daß es trotzdem 
funktioniert, oder man kann es gleich richtig machen, also die ISRs so 
gestalten, daß sie (laufzeitmäßig) möglichst kurz sind und nur das 
selbst machen, was absolut nötig ist.
Jedesmal, wenn jemand eine Warteschleife in eine ISR einbaut, stirbt 
irgendwo ein kleines Hasenbaby.
Gast
Oh, da hab ich bisher wohl etwas falsch gemacht:
Ich habe mir ehrlich gesagt überhaupt nichts dabei gedacht, als ich 
printf() so implementiert hat, dass es in einen Ringpuffer schreibt, 
welcher dann per UART-Interrupt ausgegeben wird.

Mist, jetzt muss ich das alles wieder rausmachen und es per Polling und 
Warteschleifen machen :-(
Rolf Magnus schrieb:
> Was soll daran falsch sein?

Das Main schreibt gerade was in den Puffer, zufällig will der Interrupt 
auch was schreiben und es entsteht ein Mischtext:
"MMMMMMIIIIIIIII\nMMMMMM\n".

Generelle Interruptsperre ist keine gute Idee, wenn der Puffer zu voll 
ist und der UART-Interrupt ihn nicht leeren kann.

Man müßte für den Interrupt einen extra Puffer anlegen, der dann vom 
Main mit eingereiht wird.
Peter Dannegger schrieb:
> Rolf Magnus schrieb:
>> Was soll daran falsch sein?
>
> Das Main schreibt gerade was in den Puffer, zufällig will der Interrupt
> auch was schreiben und es entsteht ein Mischtext:
> "MMMMMMIIIIIIIII\nMMMMMM\n".

Davon stand in Broncos Posting aber nichts. Das was er beschrieben hat, 
nämlich für die Ausgabe von printf() einen Rinpuffer und den 
TX-Interrupt zu benutzen, ist erstmal völlig in Ordnung. Ich sehe auch 
nicht, warum sich das in irgendeiner Form mit dem von mir geschriebenen 
beißen sollte.
Das was du beschreibst, also printf() selbst wiederum aus einer ISR 
heraus aufzurufen, ist aber nochmal was anderes. Das ist dann eben der 
Murks, von dem ich geschrieben hab. Da spielt es aber auch keine große 
Rolle, ob das Backend nun Polling oder Interrupts für die Ausgabe nutzt.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 11 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.