Forum: Mikrocontroller und Digitale Elektronik Interrupts und blockierende Prozesse


von Chris S. (Gast)


Lesenswert?

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.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch User
von Purzel H. (hacky)


Lesenswert?

Ja. man sollte sich vom blockierend arbeiten loesen.

von Chris S. (Gast)


Lesenswert?

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

von Andreas B. (bitverdreher)


Lesenswert?

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

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Chris Schäufer schrieb:
> Wenn ich den blockierenden Prozess in die "Main-Loop" einsetze
… dann blockiert der Prozess nicht mehr:

Du fragst mit 'if', ob das Flag (z.B. "volatile bool") gesetzt ist, und 
falls nicht, macht die MCU halt was anderes, blockiert also nicht.

: Bearbeitet durch User
von Kurt (Gast)


Lesenswert?

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!

von Markus H. (traumflug)


Lesenswert?

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.

von Bastler (Gast)


Lesenswert?

Das würde man dann aber als "kreativ" bezeichnen, oder ;-)

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Chris Schäufer schrieb:
> das ist nunmal die Spezifikation an der ich nichts ändern kann

  "Qualität heißt nicht nur genau das zu liefern, was der Kunde wollte,
   sondern auch das, was er gewollt hätte, wenn er richtig beraten
   worden wäre."

von Praktiker (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Bastler (Gast)


Lesenswert?

@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 ;-)

von excitus (Gast)


Lesenswert?

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"?

von Bastler (Gast)


Lesenswert?

Wie wartet wohl ein schlafender μC auf einen seiner Timer? Man kann es 
mit dem Mißverstehen auch übertreiben ;-)

von W.S. (Gast)


Lesenswert?

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.

von S. R. (svenska)


Lesenswert?

> 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?

von Falk B. (falk)


Lesenswert?

@ 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.

von Helmut S. (helmuts)


Lesenswert?

Mit Interruptlevels wäre das Problem leicht zu lösen. Wahrscheinlich 
verwendest du eine AVR oder ähnliches. Die kennen keine Interruptlevels.
Nimm einen anderen Prozessor der Interruptlevels hat, z. B. ARM.

von S. R. (svenska)


Lesenswert?

Falk Brunner schrieb:
>>Blöde Frage: Warum nicht?
> Man kann.

Danke, das wollte ich wissen. :-)

Ich nutze gerne und oft printf(), auch auf AVRs.
Solange es eine Möglichkeit für Textausgabe gibt, und sei es Debugging, 
finde ich die 1-2 KB Flash eigentlich immer gut investiert.

von Georg (Gast)


Lesenswert?

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

von S. R. (svenska)


Lesenswert?

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

von c-hater (Gast)


Lesenswert?

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

von Pandur S. (jetztnicht)


Lesenswert?

>..... printf()

ist eine krasse Wollmilchsau. Zu klotzig im code, und dauert zu lange. 
Falls eine zu lesende Zahl ausgegeben wird, dass ist es eine Hexzahl. 
Fuer der Benutzer eine Rationalzahl. Eine float gibt's eigentlich nicht.

von Falk B. (falk)


Lesenswert?

@ 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.

von Peter D. (peda)


Lesenswert?

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.

von Markus H. (traumflug)


Lesenswert?

Jetzt Nicht schrieb:
> ist eine krasse Wollmilchsau.

Es gibt auch sparsamere Implementierungen, z.B. diese hier: 
https://github.com/Traumflug/Teacup_Firmware/blob/master/sersendf.c

Für die ARMs hat MBED eine Implementierung gewählt, bei der man floats 
extra per Compiler-Flag aktivieren muss. Alleine der Float-Teil kostet 
wohl etwa so viel wie der ganze Rest.

von Max Weber (Gast)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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.

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


Lesenswert?

Rolf Magnus schrieb:
> Jedesmal, wenn jemand eine Warteschleife in eine ISR einbaut, stirbt
> irgendwo ein kleines Hasenbaby.

Schön gesprochen ;-)

von Bronco (Gast)


Lesenswert?

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 :-(

von Rolf M. (rmagnus)


Lesenswert?

Bronco schrieb:
> 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.

Was soll daran falsch sein?

von Peter D. (peda)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

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.