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.
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
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
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
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.
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."
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.
@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 ;-)
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"?
Wie wartet wohl ein schlafender μC auf einen seiner Timer? Man kann es mit dem Mißverstehen auch übertreiben ;-)
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.
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.
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.
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.
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...
>..... 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.
@ 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.
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.
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.
Rolf Magnus schrieb: > Jedesmal, wenn jemand eine Warteschleife in eine ISR einbaut, stirbt > irgendwo ein kleines Hasenbaby. Schön gesprochen ;-)
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 :-(
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?
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.