Hallo zusammen,
ich verwende bei meinem ATmega328 mehrere externe und interne
Interruptquellen (timer, SPI, pinchange). Gibt es eine Möglichkeit zu
erkennen, ob manche Interruptanforderungen verloren gehen, weil
vielleicht die CPU nicht schnell genug alle Interruptanforderungen
abarbeiten kann?
Natürlich könnte man eine theoretische worst-case Analyse aufgrund der
Ausführungszeiten und vorraussichtlichen Häufigkeit der Interrupts
machen, aber vielleicht geht es ja auch einfacher?
Dennis Heynlein schrieb:> Beitrag "Interrupts beim ATmega"
Hallo Dennis, ich finde in obigem Beitrag leider nur allgemeines zum
Thema Interrupts. Ich habe auch den Interrupt Abschnitt im AVR-GCC
Tutorial gelsen. Dort steht leider auch nichts dazu, wie man sein
Programm auf mögliche Interruptverluste überprüfen kann.
Hat noch jemand eine Idee?
Martin schrieb:> Kommt ein interrupt während eines interrupts, wird dieser nach der> vorherigen interrupt-routine ausgeführt. Es geht also kein INT verloren
Außer der "Interrupt im Interrupt" kommt noch ein zweites mal, dann geht
die erste Anforderung verloren. Wenn das eintritt hat man aber schon
irgendwo anders ein Problem in seinem ganzen Konzept.
Martin schrieb:> Kommt ein interrupt während eines interrupts, wird dieser nach der> vorherigen interrupt-routine ausgeführt. Es geht also kein INT verloren
Hallo Martin, das ist mir bekannt. Mir geht es um den Fall, dass die CPU
bereits einen Interrupt bearbeitet und dann ein weiterer Interrupt
auftritt und kurze Zeit später noch einer gleichen Typs. Damit ginge
dann der erste wartende Interrupt verloren. Mir geht es darum im
Dauertest abzusichern dass es praktisch nicht vorkommt. Eine theoretisch
worst-case-Betrachtung ersetzt es natürlich nicht, würde mir aber
zusätzliche Sicherheit geben.
test schrieb:> Außer der "Interrupt im Interrupt" kommt noch ein zweites mal, dann geht> die erste Anforderung verloren. Wenn das eintritt hat man aber schon> irgendwo anders ein Problem in seinem ganzen Konzept.
Ich habe wie beschrieben viele unterschiedliche Interruptquellen bei
denen nicht genau bekannt ist, wie häufig sie auslösen. Da das ganze
nicht wirklich kritisch ist würde es mir reichen, wenn nur selten mal
ein Interrupt verloren geht. Das würde ich gerne praktisch absichern.
Mir ist klar, dass der Königsweg darin besteht alle Intteruptroutinen so
kurz wie möglich zu gestalten und mit Flags zu arbeiten.
Mir geht es darum zu erkennen, ob / oder wie häufig praktisch Interrupts
verworfen werden mußten wegen CPU Überlastung durch zu viele
Interruptanforderungen pro Zeit.
Tja.
Egal was du machst, gibt es immer eine Grenze, ab der der µC nicht mehr
mitkommt.
Dein Problem steckt aber hier
> Ich habe wie beschrieben viele unterschiedliche> Interruptquellen bei denen nicht genau bekannt ist,> wie häufig sie auslösen.
solange du da nichts drüber weißt, ist alles andere sinnlose Überlegung.
> Mir geht es darum zu erkennen, ob / oder wie häufig> praktisch Interrupts verworfen werden mußten
Im schlimmsten Fall brauchst du dazu Hardware-Unterstützung.
Im einfachsten Fall kommt das ISR-Jobflag System zum Zug, bei dem du in
der ISR vereinbaren kannst: Tritt der Interrupt auf, und ist das Jobflag
schon (noch immer) gesetzt, dann wird es kritisch.
Falk Brunner schrieb:> http://www.mikrocontroller.net/articles/Multitaski...
Hallo Falk, das ist ein sehr interessanter Link. Dort wird aber erklärt,
wie man die Dauer des Hauptprogrammes über Interrupts im
Millisekundentakt mittels Interrupt absichert und nicht ob sich
Interrupts auftürmen.
Ein voller Eimer Wasser läuft über und das Wasser läuft dann weg.
Da der µC ohnehin immer ein paar Takte braucht, wird dir, wenn die
Interruptquelle schneller ist als der µC, sicher ein gleicher Interrupt
verloren gehen.
Artur schrieb:> Mir geht es um den Fall, dass die CPU> bereits einen Interrupt bearbeitet und dann ein weiterer Interrupt> auftritt und kurze Zeit später noch einer gleichen Typs. Damit ginge> dann der erste wartende Interrupt verloren.
Es gibt im Prozessor keine automatische Möglichkeit, diesen Fall zu
erkennen.
> Mir geht es darum im> Dauertest abzusichern dass es praktisch nicht vorkommt. Eine theoretisch> worst-case-Betrachtung ersetzt es natürlich nicht, würde mir aber> zusätzliche Sicherheit geben.
Du musst sicherstellen, daß deine ISRs kürzer sind, als die kürzeste
vorkommende Interrupt-Wiederholzeit. Kennst du letztere nicht, kannst du
nichts garantieren.
Zu der Analyse gehört aber such die Überlegung, was genau passiert, wenn
du mal eine Interruptanforderung nicht bedienen kannst.
Oliver
Artur schrieb:> Ich habe wie beschrieben viele unterschiedliche Interruptquellen bei> denen nicht genau bekannt ist, wie häufig sie auslösen.
Bei einigen Interrupts ist es bekannt, z.B. Timer, UART.
Bei anderen ist es egal, z.B. I2C, ADC, EEPROM, Master-SPI.
Erzähl dochmal genauer, welcher Interrupt bei Dir kritisch sein könnte.
Karl Heinz schrieb:> Im einfachsten Fall kommt das ISR-Jobflag System zum Zug, bei dem du in> der ISR vereinbaren kannst: Tritt der Interrupt auf, und ist das Jobflag> schon (noch immer) gesetzt, dann wird es kritisch.
Hallo Karl Heiz, wäre super wenn das so ginge. Meinst du mit Jobflag das
Interrupt Flag?
So wie ich das Datenblatt verstanden habe wird doch das Interruptflag,
z.B. bei Pegelwechsel an einem Pin, auf 1 gesetzt (hier im EIFR –
External Interrupt Flag Register), dann sofort der Interrupt
angesprungen, dabei automatisch die 1 wieder gelöscht und dann der Code
des Interrupts ausgeführt.
Währenddessen kann ein weiterer Pegelwechsel gleich nochmal das Flag von
0 auf 1 setzten. Das Flag wird solange nicht 0, bis der Interrupt
bearbeitet wird.
Wenn vor der Bearbeitung dieses wartenden Interrupts noch ein
Pegelwechsel auftritt, wird das Interruptflag nochmals auf 1 gesetzt. Da
es aber bereits auf 1 steht geht die Information verloren, dass jetzt
eigentlich zweimal der Interruptcode ausgeführt werden müsste.
Der Interruptverlust bleibt doch leider unbemerkt, oder?
@ Artur (Gast)
>> http://www.mikrocontroller.net/articles/Multitaski...>Hallo Falk, das ist ein sehr interessanter Link. Dort wird aber erklärt,>wie man die Dauer des Hauptprogrammes über Interrupts im>Millisekundentakt mittels Interrupt absichert und nicht ob sich>Interrupts auftürmen.
Bitte nochmals lesen und NACHDENKEN!
@ Artur (Gast)
>Wenn vor der Bearbeitung dieses wartenden Interrupts noch ein>Pegelwechsel auftritt, wird das Interruptflag nochmals auf 1 gesetzt. Da>es aber bereits auf 1 steht geht die Information verloren, dass jetzt>eigentlich zweimal der Interruptcode ausgeführt werden müsste.>Der Interruptverlust bleibt doch leider unbemerkt, oder?
Ja. Das kann der AVR leider nicht erkennen, das könnte man nur in
Hardware machen.
Artur schrieb:> Wenn vor der Bearbeitung dieses wartenden Interrupts noch ein> Pegelwechsel auftritt, wird das Interruptflag nochmals auf 1 gesetzt. Da> es aber bereits auf 1 steht geht die Information verloren, dass jetzt> eigentlich zweimal der Interruptcode ausgeführt werden müsste.
Die eigentliche Frage ist, muß er das wirklich?
Oder ist es nur ein Prellen oder ein Störimpuls.
Das kann man allgemein nicht beantworten. Dazu muß man schon konkret
wissen, was den Interrupt bewirkt und wie er ausgewertet werden soll.
Man muß sich also erstmal Gedanken machen, welche maximale
Nutzsignal-Interruptrate erwarte ich von der Quelle.
Peter Dannegger schrieb:>>> http://www.mikrocontroller.net/articles/Multitaski...>>Hallo Falk, das ist ein sehr interessanter Link. Dort wird aber erklärt,>>wie man die Dauer des Hauptprogrammes über Interrupts im>>Millisekundentakt mittels Interrupt absichert und nicht ob sich>>Interrupts auftürmen.> Bitte nochmals lesen und NACHDENKEN!
Hallo Falk, ich bin nochmal durchgegangen und ich weiß wirklich nicht wo
du da das Ei des Kolumbus versteckt siehst. In der Datei ACF?
In diesem Abschnitt?
Diese Überprüfung kann an zwei Stellen durchgeführt werden.
* Am Ende der Hauptschleife nach Abarbeitung aller Ausgaben. Wenn
hier die Variable flag_1ms schon wieder aktiv ist, dauerte die
Abarbeitung länger als 1ms. Wenn man ein sehr strenges Timing
sicherstellen möchte, ist das ein Fehler, der erkannt und signalisiert
werden kann.
* In der ISR. Wenn hier die Variable immer noch aktiv ist, wurde sie
von der Hauptschleife noch nicht erkannt und zurück gesetzt. Das ist
definitiv ein Fehler, denn jetzt würde ohne Fehlererkennung ein
Timerdurchlauf von der Hauptschleife verschluckt werden. Diese Prüfung
ist etwas nachgiebiger, weil zwischenzeitlich ein Durchlauf der
Hauptschleife mehr als 1ms, jedoch nicht länger als 2ms dauern darf.
Siehe auch den Abschnitt Interrupt#Zeitverhalten_eines_Timerinterrupts.
Sinnvollerweise nutzt man nur eine der beiden Prüfungen, nicht beide
zusammen.
Artur schrieb:> Karl Heinz schrieb:>> Im einfachsten Fall kommt das ISR-Jobflag System zum Zug, bei dem du in>> der ISR vereinbaren kannst: Tritt der Interrupt auf, und ist das Jobflag>> schon (noch immer) gesetzt, dann wird es kritisch.>> Hallo Karl Heiz, wäre super wenn das so ginge. Meinst du mit Jobflag das> Interrupt Flag?
Nein.
Ich meine die Technik des Jobflags
Vielleicht mal etwas deutlicherer Klartext:
Solange du nicht weißt, in welchen Zeitabständen deine
Interruptanforderungen kommen, und was es bedeutet, wenn du mal eine
verpasst, brauchst du nirgends weiterzulesen. Dann hast du schlicht
keine Chance, das Problem zu lösen. Geht nicht. Fertig.
Wenn du aber die kürzeste Zeit zwischen den Interruptanforderungen
kennst, kannst du versuchen, deine ISR's noch kürzer zu gestalten. Das
geht nicht ohne Zyklen zählen, oder ähnliche Anaylsen. Wenn du innerhalb
der vorgegeben Zeit in der ISR alles abarbeiten kannst, prima.
Wenn nicht, so kannst du versuchen, ein eigenes Flag-System zu bauen,
das z.B. die Interruptanforderung selber und die relevanten Daten dazu
in eine queue schreibt. Die eigentlich Abarbeitung übernimmt dann das
Hauptprogramm. Wenn deine ISR damit kurz genug wird, verlirst du keine
Interrupts, aber die Abarbeitung bzw. Reaktion darauf kann verspätet
erfolgen (eben erst dann, wenn das Hauptprogramm Zeit findet, den
Request abzuarbeiten). Das funktioniert natürlich nur, wenn im Mittel
das Haupprogramm schnell genug ist, alle Request abzuarbeite, ansonsten
läuft deine Queue irgendwann über.
Wenn du es nicht schaffst, das Flag/Queue-System innerhalb der zur
Verfügung stehehden ISR-Zeit abzuarbeiten, dann bist du wieder am
Ausgangspunkt: Zu langsam...
Oliver
Karl Heinz schrieb:> Ich meine die Technik des Jobflags>> uint8_t Job;>> ISR( ... )> {> Job = 1;> }>> int main> {>> ....> while( 1 )> {>> if( Job )> ...
Wenn ich das richtig verstanden habe hilft diese Technik nur
sicherzustellen, dass der Teil unter "if( Job )" nicht mehr Zeit
benötigt als der Interrupt als Takt vorgibt.
Ich möchte aber sicherstellen, dass meine 3 unterschiedlichen Timer die
ich verwende, mehrere Pinchange Interrupts und die SPI Kommunikation
sehr zügig funktioniert und daher im Interrupt abgearbeitet werden soll.
Die Main-Loop ist sehr voll mit Berechnungen, die eine sehr zeitnahe
Ausführung auf Flag-Basis nicht ratsam machen.
Hallo Oliver,
vielen Dank für deine umfangreiche Antwort. Da sind viele gute Ideen
dabei. Ich sehe, es gibt aber anscheinend keinen einfachen Mechanismus
der mir sagen könnte ob das Interruptsystem überläuft.
Es sei denn Falk kann mich noch darauf stoßen.
Um zu verhindern, dass dir keine interrupts verloren gehen, musst du die
ISR so klein wie möglich halten. Bedeutet, serielle kommunikation in
einen puffer zwischen speichern und diesen in der main-Schleife
auswerter (solange der puffer voll ist).
Timer sind kritisch, da diese nicht später im Hauptprogramm ausgeführt
werden dürfen, aber evtl kannst du im Hauptprogramm etwas die Daten
vorbereiten und sie dann anschliesend nur im der ISR ausgeben.
Pin change interrupts kann man auch in einen puffer schreiben und später
im Hauptprogramm auswerten.
Ein Rinspeicher beschreiben ist in unter 20 Takten möglich, wenn deine
Auswertung eines interrupts länger als 20 takte benötigt, die daten in
einen puffer schreiben und in der Hauptschleife auswerten.
Ganz verhindern kann man das "verschlucken" von interrupts nicht, aber
in dem man die ISR so kurz wie möglich gestaltet kann man einiges
erreichen.
Probleme können aber Taster machen, die prellen. Diese müsste man
entweder in Hardware entprellen oder bei auftreten eines interrupts eine
systemzeit mit abspeichern damit man ein prellen ausschliesen kann.
@ Artur (Gast)
>Wenn ich das richtig verstanden habe hilft diese Technik nur>sicherzustellen, dass der Teil unter "if( Job )" nicht mehr Zeit>benötigt als der Interrupt als Takt vorgibt.
Ja.
>Ich möchte aber sicherstellen, dass meine 3 unterschiedlichen Timer die>ich verwende, mehrere Pinchange Interrupts und die SPI Kommunikation>sehr zügig funktioniert und daher im Interrupt abgearbeitet werden soll.
Kann man machen.
>Die Main-Loop ist sehr voll mit Berechnungen, die eine sehr zeitnahe>Ausführung auf Flag-Basis nicht ratsam machen.
Alles eine Frage der Programmierung. Wenn man es will, kann man lange
Berechnungen auf mehrere Schritte aufteilen und mit mehreren Aufrufen
erledigen. Siehe Multitasking.
Aber was hast du denn konkret zu tun? So eine allgemeine Beschreibeung
nützt wenig. Nenn mal ein paar konkrete Zahlen.
@ Artur (Gast)
>dabei. Ich sehe, es gibt aber anscheinend keinen einfachen Mechanismus>der mir sagen könnte ob das Interruptsystem überläuft.
Auf unterstet Ebene, nein. Schrieb ich bereits.
Beitrag "Re: AVR - Erkennen ob Interrupts verloren gehen"
Aber man kann es mal so sehen. Interrupts können nun durch andere,
gerade laufende Interrupts blockiert und damit verschluckt werden, weil
der AVR von hause aus keine Prioritäten für die Interrupts hat. Hält man
aber alle ISRs kurz, kann das nicht passieren, auch nicht im
schlimmsten, definierten Fall (den man ja berechnen/simulieren kann).
Klar, wenn man maximal mit 10kHz rechnet, duch was auch immer ein Pin
aber mit 100kHz toggelt, dann war's das. Aber sowas ist vermeidbar.
Wenn du feststellen willst, ob du Interrupts verlierst, musst du das
Ueberlaufmanagement einfach selbst machen. Am Anfang der
Interruptroutine einen Zaehler hochsetzen. Ist er groesser als 1, laeuft
die Interruptroutine schon und du brichst ab. Ist er 1, gibst du die
Interrupts wieder frei und machst die eigentliche Interruptbearbeitung.
Am Ende der Bearbeitung sperrst du die Interrupts wieder und
dekrementierst den Zaehler wieder. Alles, was groesser als Null ist,
sind verlorene Interrupts. Die kannst du zum Beispiel auf eine andere
Variable aufaddieren und in der Hauptschleife ausgeben. Nicht vergessen,
den Zaehler wieder auf Null zu setzen, sonst war das die letzte
Interruptausfuehrung. Alternativ kann man das Aufaddieren auch am Anfang
der Interruptroutine machen, dann entgehen einem Deadlocks in der
Interruptverarbeitung nicht.
cybmorg schrieb:> Wenn du feststellen willst, ob du Interrupts verlierst, musst du> das> Ueberlaufmanagement einfach selbst machen. Am Anfang der> Interruptroutine einen Zaehler hochsetzen. Ist er groesser als 1, laeuft> die Interruptroutine schon und du brichst ab. Ist er 1, gibst du die> Interrupts wieder frei und machst die eigentliche Interruptbearbeitung.> Am Ende der Bearbeitung sperrst du die Interrupts wieder und> dekrementierst den Zaehler wieder. Alles, was groesser als Null ist,> sind verlorene Interrupts. Die kannst du zum Beispiel auf eine andere> Variable aufaddieren und in der Hauptschleife ausgeben. Nicht vergessen,> den Zaehler wieder auf Null zu setzen, sonst war das die letzte> Interruptausfuehrung. Alternativ kann man das Aufaddieren auch am Anfang> der Interruptroutine machen, dann entgehen einem Deadlocks in der> Interruptverarbeitung nicht.
Hallo cyvmorg,
das hört sich nach einer guten Lösung an. Sie ist nicht einfach, sie
erzeugt overhead, ab sie scheint machbar. Hast du sowas schon praktisch
getestet?
Artur schrieb:> cybmorg schrieb:>> Wenn du feststellen willst, ob du Interrupts verlierst, musst du>> das>> Ueberlaufmanagement einfach selbst machen. Am Anfang der>> Interruptroutine einen Zaehler hochsetzen. Ist er groesser als 1, laeuft>> die Interruptroutine schon und du brichst ab. Ist er 1, gibst du die>> Interrupts wieder frei und machst die eigentliche Interruptbearbeitung.>> Am Ende der Bearbeitung sperrst du die Interrupts wieder und>> dekrementierst den Zaehler wieder. Alles, was groesser als Null ist,>> sind verlorene Interrupts. Die kannst du zum Beispiel auf eine andere>> Variable aufaddieren und in der Hauptschleife ausgeben. Nicht vergessen,>> den Zaehler wieder auf Null zu setzen, sonst war das die letzte>> Interruptausfuehrung. Alternativ kann man das Aufaddieren auch am Anfang>> der Interruptroutine machen, dann entgehen einem Deadlocks in der>> Interruptverarbeitung nicht.>> Hallo cyvmorg,> das hört sich nach einer guten Lösung an. Sie ist nicht einfach, sie> erzeugt overhead, ab sie scheint machbar. Hast du sowas schon praktisch> getestet?
Das funktioniert nicht. Währrend eine ISR läuft, sind die Interrupts
gesperrt. D.h. die ISR wird kein zweites Mal erreicht.
mfg.
Thomas Eckmann schrieb:> Das funktioniert nicht. Währrend eine ISR läuft, sind die Interrupts> gesperrt.
Na ja.
Man kann sie freigeben.
Hier im Forum wird zwar meistens davon abgeraten, solange man aber weiß
was man tut, kann man das natürlich machen.
Thomas Eckmann schrieb:> Das funktioniert nicht. Währrend eine ISR läuft, sind die Interrupts> gesperrt. D.h. die ISR wird kein zweites Mal erreicht.
Die kann man sofort nach Eintritt in die ISR wieder einschalten mit
sei().
Oder den Interrupt gleich richtig ausschalten, wie es hier geschrieben
steht:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Interrupts_mit_avr-gcc
#include <avr/interrupt.h>
ISR(XXX,ISR_NOBLOCK) /* veraltet: INTERRUPT(SIG_OVERFLOW0) */
{
/* Interrupt-Code */
}
Karl Heinz schrieb:> Thomas Eckmann schrieb:>>> Das funktioniert nicht. Währrend eine ISR läuft, sind die Interrupts>> gesperrt.>> Na ja.> Man kann sie freigeben.> Hier im Forum wird zwar meistens davon abgeraten, solange man aber weiß> was man tut, kann man das natürlich machen.
Leider wissen die meisten das aber nicht.
mfg.
Thomas Eckmann schrieb:> Das funktioniert nicht. Währrend eine ISR läuft, sind die Interrupts> gesperrt. D.h. die ISR wird kein zweites Mal erreicht.
Im Text habe ich explizit erklaert, wann die Interrupts freizugeben und
zu sperren sind. Wie man das ueberlesen kann, ist mir unverstaendlich.
Artur schrieb:> Hallo cyvmorg,> das hört sich nach einer guten Lösung an. Sie ist nicht einfach, sie> erzeugt overhead, ab sie scheint machbar. Hast du sowas schon praktisch> getestet?
Das ist eigentlich recht einfach, ich arbeite oft mit mehreren
Interruptebenen und dazu muss ich die manuelle Ueberlaufsteuerung
verwenden, um die Prioritaeten der Interruptebenen zu gewaehrleisten.
Der Ueberlaufzaehler ist eine einfache Erweiterung davon. Overhead
erzeugt die Loesung natuerlich schon - aber wenn du so nah am Limit
deines Kontrollers bist, dass es dafuer nicht mehr reicht, hast du
wahrscheinlich noch andere Probleme.
cybmorg schrieb:> Im Text habe ich explizit erklaert, wann die Interrupts freizugeben und> zu sperren sind. Wie man das ueberlesen kann, ist mir unverstaendlich.>> Am Ende der Bearbeitung sperrst du die Interrupts wieder
Wie das funktionieren soll, ist mir unverständlich.
mfg.
cybmorg schrieb:> Das ist eigentlich recht einfach, ich arbeite oft mit mehreren> Interruptebenen und dazu muss ich die manuelle Ueberlaufsteuerung> verwenden, um die Prioritaeten der Interruptebenen zu gewaehrleisten.
Wer will das wissen?
Ein Atmega 328 hat keine verschiedenen Prioritätsebenen.
Im Ausgangspost hat der TO explizit erklaert, daß er einen Atmega 328
benutzt. Wie man das ueberlesen kann, ist mir unverstaendlich.
mfg.
Thomas Eckmann schrieb:> Ein Atmega 328 hat keine verschiedenen Prioritätsebenen.
Natuerlich hat er das nicht. Sonst muesste ich das ja nicht haendisch
implementieren.
> Im Ausgangspost hat der TO explizit erklaert, daß er einen Atmega 328> benutzt. Wie man das ueberlesen kann, ist mir unverstaendlich.
Das liebe ich so hier am Forum: Wenn man in's Klo gegriffen hat, ist
Zugeben und Schnabel halten die letzte Alternative - lieber aus vollen
Rohren feuern, vielleicht merkt es keiner!
> Wie das funktionieren soll, ist mir unverständlich.
Meinst du den ganzen Ablauf, oder nur das Sperren am Ende der
Bearbeitung? Letzteres macht ein einfaches cli(). Oder ist unklar,
warum? Wenn ich den Interruptzaehler anfasse, muss das gegen
nebenlaeufige Zugriffe gesichert passieren, also werden die Interrupts
vorher wieder gesperrt. Die Freigabe, dass ueberhaupt wieder Interrupts
bearbeitet werden, geschieht danach "automatisch", wie ueblich.
cybmorg schrieb:> Das ist eigentlich recht einfach, ich arbeite oft mit mehreren> Interruptebenen und dazu muss ich die manuelle Ueberlaufsteuerung> verwenden, um die Prioritaeten der Interruptebenen zu gewaehrleisten.> Der Ueberlaufzaehler ist eine einfache Erweiterung davon.
Hallo cybmorg,
schicke Sache. Hast du da mal etwas (Pseudo-)code zur Veranschaulichung?
Mich würde insbesonders der Code am Ende jeder ISR interessieren, der
dann explizit (?) die aufgelaufenen Interrupts niedrigerer Priorität
abarbeitet ...
LG, Sebastian
cybmorg schrieb:> Wenn ich den Interruptzaehler anfasse, muss das gegen> nebenlaeufige Zugriffe gesichert passieren, also werden die Interrupts> vorher wieder gesperrt. Die Freigabe, dass ueberhaupt wieder Interrupts> bearbeitet werden, geschieht danach "automatisch", wie ueblich.
Und wenn in der Zeit zweimal der gleiche Interrupt auftritt, hast du mit
dem Gehampel gar nichts gewonnen. Völliger Humbug das Ganze.
mfg.
Thomas Eckmann schrieb:> Und wenn in der Zeit zweimal der gleiche Interrupt auftritt, hast du mit> dem Gehampel gar nichts gewonnen. Völliger Humbug das Ganze.
Wenn gerade ein Interrupt bearbeitet wird, könnte ein schnell folgender
Interrupt, der ja nur kurz den Zähler erhöht und sich dann selbst
beendet, im ersten Interrupt direkt angehängt werden. Schneller käme ja
ein mit Flag zwischengepeicherter Interrupt auch nicht zum Zug.
Artur schrieb:> Wenn gerade ein Interrupt bearbeitet wird, könnte ein schnell folgender> Interrupt, der ja nur kurz den Zähler erhöht und sich dann selbst> beendet, im ersten Interrupt direkt angehängt werden. Schneller käme ja> ein mit Flag zwischengepeicherter Interrupt auch nicht zum Zug.
Den Interrupt gibt es aber nicht umsonst. Der kostet jede Menge Zeit,
die ja angeblich nicht vorhanden ist. Sonst könnte man sich das ja alles
grundsätzlich sparen. Das Zählergehampel mit Wiederfreigabe kann aber
auch nicht zu 100% garantieren, daß kein Interrupt verloren geht.
Maximal ein Interrupt kann im Flagregister gespeichert werden. Mehr gibt
die AVR-Hardware einfach nicht her.
Tritt allerdings während einer ISR derselbe Interrupt nochmals auf, kann
man diesen auch durch Abfrage des Interrupt-Flags vor Verlassen der ISR
bearbeiten. Wenn es denn unbedingt sein muß.
Man kann aber auch vernünftig programmieren lernen und sich diesen Mist
komplett ersparen.
mfg.
Thomas Eckmann schrieb:> Das Zählergehampel mit Wiederfreigabe kann aber> auch nicht zu 100% garantieren, daß kein Interrupt verloren geht.
Es gibt Ingenieure, die Probleme loesen und Ingenieure, die endlos
darueber referieren koennen, was an Loesungsansaetzen anderer schlecht
ist und wieso das Problem sowieso nicht loesbar ist. Rate mal, welche
von Beiden keiner braucht.
cybmorg schrieb:> Thomas Eckmann schrieb:>> Das Zählergehampel mit Wiederfreigabe kann aber>> auch nicht zu 100% garantieren, daß kein Interrupt verloren geht.>> Es gibt Ingenieure, die Probleme loesen und Ingenieure, die endlos> darueber referieren koennen, was an Loesungsansaetzen anderer schlecht> ist und wieso das Problem sowieso nicht loesbar ist. Rate mal, welche> von Beiden keiner braucht.
Mehr als so ein blödes Gelaber fällt dir jetzt nicht ein?
In der Digitaltechnik gibt es zwei Möglichkeiten. Entweder es
funktioniert zu 100% oder es funktioniert nicht. Dazwischen ist gar
nichts.
mfg.
Thomas Eckmann schrieb:> In der Digitaltechnik gibt es zwei Möglichkeiten. Entweder es> funktioniert zu 100% oder es funktioniert nicht. Dazwischen ist gar> nichts.
Da du von nichts, was du baust/programmierst die Funktion zu 100%
garantieren kannst, reduziert sich bei deiner Sichtweise jeglicher
Output deiner Taetigkeit auf: Gar nichts. Wie du das deinem Arbeitgeber
vermittelst, dass er dich fuer gar nichts bezahlen soll, wuerde mich
interessieren.
cybmorg schrieb:> Thomas Eckmann schrieb:>> In der Digitaltechnik gibt es zwei Möglichkeiten. Entweder es>> funktioniert zu 100% oder es funktioniert nicht. Dazwischen ist gar>> nichts.>> Da du von nichts, was du baust/programmierst die Funktion zu 100%> garantieren kannst, reduziert sich bei deiner Sichtweise jeglicher> Output deiner Taetigkeit auf: Gar nichts. Wie du das deinem Arbeitgeber> vermittelst, dass er dich fuer gar nichts bezahlen soll, wuerde mich> interessieren.
Das muss ich sogar garantieren, du Witzfigur.
mfg.
cybmorg schrieb:> Das ist eigentlich recht einfach, ich arbeite oft mit mehreren> Interruptebenen und dazu muss ich die manuelle Ueberlaufsteuerung> verwenden, um die Prioritaeten der Interruptebenen zu gewaehrleisten.
Wozu brauchst Du im AVR mehrere Interruptebenen? Ein Interrupt ist so
kurz wie möglich zu halten, und das heisst, wirklich wenige Takte.
Großartige Software-Division oder Speicher umkopieren oder PID-Regler
berechnen macht man einfach nicht im Interrupt.
Zum Beispiel Uart: Byte einlesen, in Ringpuffer schreiben, Ringbuffer
Pointer inc, Flag setzen, dass Daten vorhanden, raus. Braucht vielleicht
20 Takte. Die Auswertung, was dann mit den Daten passiert, machst Du im
Hauptprogramm.
> cybmorg schrieb:> Mehr als so ein blödes Gelaber fällt dir jetzt nicht ein?> Thomas Eckmann schrieb:> Das muss ich sogar garantieren, du Witzfigur.
Kleiner Kampf? Das ist ein Spiel mit kleinen ferngelenkten Modellpanzern
über's Internet. Ist umsonst. Ich wär' dabei...
Beitrag "Panzer über Internet fernsteuern für Jedermann"
@ Timm Thaler (timm-thaler)
>Wozu brauchst Du im AVR mehrere Interruptebenen?
Andere Controller haben die und können sie zweckdienlich nutzen. Der AVR
hat keine, man kann und muss damit leben.
> Ein Interrupt ist so>kurz wie möglich zu halten,
Ja.
> und das heisst, wirklich wenige Takte.
Nein. So kurz wie NÖTIG! Das kann je nach Anwendung auch mal ne
Millisekunde oder mehr sein. Manchmal auch nur 10us.
>Großartige Software-Division oder Speicher umkopieren oder PID-Regler>berechnen macht man einfach nicht im Interrupt.
Siehe oben.
>Zum Beispiel Uart: Byte einlesen, in Ringpuffer schreiben, Ringbuffer>Pointer inc, Flag setzen, dass Daten vorhanden, raus. Braucht vielleicht>20 Takte.
In Hardcore Assembler bestenfalls, in C geht unter 50 Takten kaum was.
Aber selbst damit lässt sich ganz gut leben.
Aber solange der OP nicht mal mit seinen realen Aufgaben und
Anforderungen rausrückt, ist das alles sinnlos. Fakt ist, der AVR ist
schon ein fixes Kerlchen, der auch ohne Interruptlevel verdammt viel
verdammt schnell machen kann. Ohne Interrupts zu verschlucken.
Falk Brunner schrieb:> Das kann je nach Anwendung auch mal ne> Millisekunde oder mehr sein.
Ich hab ja schon viel mit AVRs verbrochen, für das ich mich heute
schäme. Aber Interrupts, die ne Millisekunde, also um die 10.000 Takte
dauern, sind mir noch nicht untergekommen. Nicht dass ich nicht glaube,
dass es sowas gibt, aber ich kann mir nich vorstellen, wo man sowas
braucht.
Hast Du ein paar Beispiele? Das interessiert mich ernsthaft, man lernt
ja nie aus.
Falk Brunner schrieb:> In Hardcore Assembler bestenfalls, in C geht unter 50 Takten kaum was.
Wenn ich C programmieren wöllte, nähme ich nen PC. ;-) Im AVR wird
natürlich ASM programmiert.
Artur schrieb:>> cybmorg schrieb:>> Mehr als so ein blödes Gelaber fällt dir jetzt nicht ein?>>> Thomas Eckmann schrieb:>> Das muss ich sogar garantieren, du Witzfigur.
Das ist jetzt aber eine falsche Quellenangabe. Beide Zitate sind von
Thomas. Zur Vollständigkeit fehlt aber noch:
Thomas Eckmann schrieb:> Man kann aber auch vernünftig programmieren lernen und sich diesen Mist> komplett ersparen.
cybmorg hat hier einen interessanten Beitrag geleistet, der für
bestimmte Situationen für mich sicherlich hilfreich sein wird. Thanks
for that!
Ob diese Lösung für den OP geeignet ist sei dahingestellt. Bei
entsprechendem Vorwissen kann der OP das sicher auch selbst entscheiden.
Auf Risiken, zum Beispiel die Möglichkeit von Starvation, die nötige
Synchronisation des Zugriffs auf gemeinsame Resourcen auch in der ISR,
könnte man hinweisen.
Ich sehe aber keinen triftigen Grund angesichts eines fachlichen
Beitrags hier persönlich beleidigend zu werden.
LG, Sebastian
An alle ein herzliches Dankeschön!
Hallo Falk, ich möchte das Programm zumindest vorerst nicht an die
Öffentlichkeit geben, entschuldige bitte. Es läuft ja auch schon recht
stabil, lediglich vereinzelt gibt es Abstürze, die vielleicht ein
Interruptüberlauf sein könnten, oder was ganz anderes. Heute habe ich
wieder einen Bug gefunden, ein vergessenes Atomic. Wenns richtig gut
läuft wars das schon.
Besonderen Dank an cybmorg, für die unkonventionelle Idee dem AVR
Fähigkeiten abzutrotzen, die eigentlich nicht vorgesehen sind. Sowas
finde ich großartig. Meine Fragen sind beantwortet. Vielen Dank für eure
Hilfsbereitschaft! Ich werde mich revanchieren. Lasst euch nicht
abhalten weiterzudiskutieren.
Schönen Gruß
Artur
@ Timm Thaler (timm-thaler)
>Hast Du ein paar Beispiele? Das interessiert mich ernsthaft, man lernt>ja nie aus.
Ich hab hier eine Steuerung in einem kommerziellen Gerät, dort läuft ein
kooperatives Multitasking. Ein Timer mit 10ms gibt den Grundtakt vor. In
diesem Timer steckt die wesentliche Verarbeitung, d.h. Datenerfassung
über einen externen ADC, PI-Regler, Überwachung der Parameter, Daten für
den Netzwerktransport vorbereiten, wobei hier nochmal ein Teiler in
Software drinsteckt, d.h. nicht alle Funktionen laufen mit 10ms
Periodendauer, die meisten deutlich langsamer! Dieser Timerdurchlauf
dauert je nach Konstellation bis zu 4ms. Was bei 10ms Periodendauer kein
Problem ist.
Man muss aber auch sagen, dass dieser Controller kein ganz normales C
nutzt, es ist ein etwas eigenes Framework, wo es nur ereignisgesteuerte
Funktionen gibt und eben diese Timer. Eine main-Funktion gibt es nicht!
>Wenn ich C programmieren wöllte, nähme ich nen PC. ;-) Im AVR wird>natürlich ASM programmiert.
Jaja, als Hobby ganz nett, im produktiven Einsatz aber meist nicht
sinnvoll. Bestenfalls die ISR könnte man als reinen Assembler machen,
wenn es denn WIRKLICH nötig ist. Ist es aber gar nicht so oft wie man
denkt.
Falk Brunner schrieb:> kooperatives Multitasking. Ein Timer mit 10ms gibt den Grundtakt vor. In> diesem Timer steckt die wesentliche Verarbeitung, d.h. Datenerfassung> über einen externen ADC, PI-Regler, Überwachung der Parameter, Daten für> den Netzwerktransport vorbereiten...
Also nichts, was man mit einem Timer auf 10ms mit 15 Takten, einer
Mainloop im Timertakt mit zeitgesteuerten Calls der einzelnen
Subroutinen und ein bißchen Buffer für die Netzwerkdaten auch machen
könnte.
> Jaja, als Hobby ganz nett, im produktiven Einsatz aber meist nicht> sinnvoll.
Dieses Hobby bringt mir in einem aktuellen Projekt mit 15 AVRs für
verschiedenste Steueraufgaben etwa 20kEur. Ich weiss, Peanuts, aber so
ein Hobby würde sich mancher wünschen, denke ich.
Eine jitterfreie Software-PWM für 8 Kanäle in C? Bis da die Daten aus
dem SRAM geladen sind, ist meine PWM-Routine mit direktem
Registerzugriff schon durch.
@ Timm Thaler (timm-thaler)
>Also nichts, was man mit einem Timer auf 10ms mit 15 Takten, einer>Mainloop im Timertakt mit zeitgesteuerten Calls der einzelnen>Subroutinen und ein bißchen Buffer für die Netzwerkdaten auch machen>könnte.
Du bist ein Pfennigfuchser, ähhh Taktzähler. ;-)
>> Jaja, als Hobby ganz nett, im produktiven Einsatz aber meist nicht>> sinnvoll.>Dieses Hobby bringt mir in einem aktuellen Projekt mit 15 AVRs für>verschiedenste Steueraufgaben etwa 20kEur.
In C wäre das wahrscheinlich ebenso, ggf. sogar einfacher machbar. Aber
ich will niemanden bekehren. Die ewige Diskussion hatten wir schon zur
Genüge.
>Ich weiss, Peanuts, aber so>ein Hobby würde sich mancher wünschen, denke ich.
20kEur Umsatz oder Gewinn?
>Eine jitterfreie Software-PWM für 8 Kanäle in C? Bis da die Daten aus>dem SRAM geladen sind, ist meine PWM-Routine mit direktem>Registerzugriff schon durch.
Jaja, alles ganz nett und ne sportliche Herausforderung, aber Profis
nehmen einfach einen passenden PWM-IC, von dem es heute mehr als genug
gibt und fertig. Professionelle Industrielösungen reizen Teilkomponenten
selten aus, dafür setzen sie auf bestehende, getestete Komponenten. Ist
In Summe deutlich effektiver. Und wie gesagt, es gibt schon noche in
paar kleine Nischen für ASM. Und dass man auch in C eine recht gute
Soft-PWM hinkriegt, ist nichts neues. (Jaja, es gibt geringen Jitter
und man braucht mehr Takte als in ASM, spielt aber in Summe keine
Rolle).
Falk Brunner schrieb:> Professionelle Industrielösungen reizen Teilkomponenten> selten aus, dafür setzen sie auf bestehende, getestete Komponenten.
Ja, diese Industrielösungen kenne ich auch: Schaltkreisgräber mit völlig
überdimensionierten µC, weil da wahrscheinlich Java programmiert wird.
Die Peripherie mit irgendwelchen Spezial-IC gemacht, die es in 5 Jahren
nicht mehr gibt.
Falk Brunner schrieb:> aber Profis> nehmen einfach einen passenden PWM-IC
Ein PWM-IC, der 8 PWM jeweils um 1/8 Periode versetzt ausgibt, um nicht
alle Verbraucher gleichzeitig einzuschalten? Wäre mir neu...