AVR-Interrupts im Mikrosekundenbereich

Hallo,

ich habe hier einen Atmega 8, mit dem ich alle 4 Mikrosekunden per Interrupt eine Ausgangsleitung auf L oder H schalten will. Viel mehr ist dazwischen nicht zu tun, ich wollte zunächst testen ob ich das dann noch in die Zeit dazwischen bekomme.

Mit 14, 7xx Mhz Takt ist das von der Geschwindigkeit her scheinbar auch kein Problem, jedoch bemerke ich gerade, dass sich auch schon bei sehr kurzen Codestücken in der Interruptroutine die Zeit zwischen zwei Aufrufen mit der Länge dieses Codes ändert.

Der verwendete Timer (mit Timer 0 und 1 getestet) wird jeweils am Beginn der Interruptroutine gleich wieder mit dem Ursprungswert geladen, so dass der nächste Interrupt ja IMHO immer wieder nach dieser Zeit ausgelöst werden müsste, unabhängig davon wieviel Befehle dann noch folgen (solange es nicht insgesamt zu viel Code ist). Testweise habe ich deshalb die Zeit für die Interrupts auch schon mal verdoppelt, der Effekt war aber genau so vorhanden.

Im Moment scheint es so, als ob der Timer erst nach dem verlassen der Interruptroutine wieder weiterläuft. Ich war davon ausgegangen, dass er das sofort nach dem neu laden tut. Übersehe ich da was?

Bisher hatte ich immer nur mit Interrupts im Millisekundenbereich zu tun, so dass mir das vielleicht nicht auffiel.

Hier die Interruptroutine (mit ICCAVR erstellt, der erzeugte Assemblercode sieht auch unverdächtig kurz und kompakt aus)

#pragma interrupt_handler timer1_ovf_isr:9 void timer1_ovf_isr(void) { //TIMER1 has overflowed TCNT1H = 0xFF; //reload counter high value TCNT1L = 0xC6; //reload counter low value

Setlow; //kurzen Puls an Ausgang, der mit Oszi sichtbar gemacht wird Sethigh;// dahinter sind zwei kurze Makros, die ein Bit setzen und löschen

//counter++; // jeder weitere Befehl hier verlängert die Zeit zwischen den Interrupts??

}

Danke für eure Tips

Lutz

--
Mit unseren Sensoren ist der Administrator informiert, bevor es Probleme im 
Serverraum gibt: preiswerte Monitoring Hard- und Software-kostenloses Plugin 
auch für Nagios - Nachricht per e-mail,SMS und SNMP: http://www.messpc.de
Neu: Ethernetbox jetzt auch im 19 Zoll Gehäuse mit 12 Ports für Sensoren
Reply to
Lutz Schulze
Loading thread data ...

Lutz Schulze schrieb: ,> //counter++;

Der Interrupt wird ja auch erst nach dem Verlassen dieser Routine wieder akzeptiert.

Es ist natürlich völliger Schwachsinn, alle 4 usec einen Code auszuführen, der incl. allem Overhead >4usec benötigt.

Auch wenn Du die Interrupts direkt am Anfang wieder freigibst, wird erforderliche Rechenzeit "verbraten". Vielleicht hast Du ja auch noch andere Aufgaben zu erledigen, ausser ein Rechtecksignal zu erzeugen? Dann wird's knapp.

Viel Erfolg.

Gruss Udo

Reply to
Udo Piechottka

Ich kenne den AVR zwar nicht, aber beim HCS08 und dem ICC08 C Compiler ist es z.B. so, daß in der Interruptroutine normalerweise keine weiteren Interrupts aufgerufen werden können. Wenn also deine Routine zu lange braucht, dann wird die Interruptanforderung zwischengespeichert und erst bei Verlassen der Interruptroutine der Interrupt sofort neu ausgelöst, wenn die Zeit, die die Interruptroutine braucht, länger als die Timer-Zeit ist, was das beobachtete Verhalten erklären könnte. Im Zweifelsfalls das Assembler-Listing anschauen und die Anzahl benötigter Takte abschätzen (Interrupt Latenzzeit nicht vergessen).

Den Timer jedesmal neu zu laden ist übrigens keine gute Idee, da es Ungenauigkeiten mit reinbringen kann, denn die Interrupt Latenzzeit kann immer ein paar Takte schwanken, je nachdem, was zuletzt ausgeführt wurde bei Verlassen des Interrupts oder falls noch ein Programm ohne Interrupt parallel läuft. So ist es zumindest bei den meisten CPUs, kann aber sein, daß es beim AVR nicht so ist.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

Am Sun, 06 Jan 2008 21:25:02 +0100 schrieb Udo Piechottka:

Klar, der Timer dafür kann ja aber derweil schon wieder laufen um dann wieder pünktlich den nächsten Interrupt anzustossen.

Meinst du, er braucht dafür länger als die 4 Mikrosekunden? Die Vermutung hatte ich auch, allerdings scheint dem nicht so zu sein.

Der AVR macht in der Zeit 56 Takte, im Datenblatt ist von 4 Takten die Rede, nach denen er über den Vektor zur Interruptroutine springt. Der erzeugte Assemblercode für die Routine ist sehr kurz (mit reti 12 Befehle).

Aber auch wenn ich den Interrupt auf 18 Mikrosekunden verlängere, macht der Befehl mit dem Counter konstant ca. eine Mikrosekunde aus (zum Test eine inkrementierung einer long-Variable, deshalb etwas rechenaufwendig).

Passiert da noch etwas, was ich übersah?

Da ist nicht viel zu machen ausser ein paar Bytes seriell auf die Leitung zu schieben. Ich bin optimistisch, dass das da reinpasst. Alles weitere kann dann in den Pausen zwischen den Bytefolgen passieren.

Lutz

--
Mit unseren Sensoren ist der Administrator informiert, bevor es Probleme im 
Serverraum gibt: preiswerte Monitoring Hard- und Software-kostenloses Plugin 
auch für Nagios - Nachricht per e-mail,SMS und SNMP: http://www.messpc.de
Neu: Ethernetbox jetzt auch im 19 Zoll Gehäuse mit 12 Ports für Sensoren
Reply to
Lutz Schulze

Am Sun, 6 Jan 2008 21:32:21 +0100 schrieb Frank Buss:

Das ist einleuchtend, soll so auch nicht passieren. Aber der Timer für das auslösen des nächsten Interrupts sollte doch schon wieder seine Arbeit aufnehmen?

Wenn ich mich da nicht vertan habe sollte das hinkommen (siehe Antwort an Udo).

Das scheint dort das übliche Verfahren zu sein, da die Initialisierungsstände für die Timer sonst nirgends gespeichert werden.

Lutz

--
Mit unseren Sensoren ist der Administrator informiert, bevor es Probleme im 
Serverraum gibt: preiswerte Monitoring Hard- und Software-kostenloses Plugin 
auch für Nagios - Nachricht per e-mail,SMS und SNMP: http://www.messpc.de
Neu: Ethernetbox jetzt auch im 19 Zoll Gehäuse mit 12 Ports für Sensoren
Reply to
Lutz Schulze

Er hat doch einen PWM-Ausgang, oder? Der wäre doch viel geeigneter.

- Udo

Reply to
Udo Piechottka

Am Sun, 06 Jan 2008 22:25:37 +0100 schrieb Udo Piechottka:

Nein, es geht am Ende nicht um ein Rechtecksignal, das ist jetzt nur zum testen des Timings für die Ausgabe.

Später sollen die 8 Bits eines Byte + Start- und Stopbit seriell über einen Pin ausgegeben werden (den UART des Atmega brauche ich anderweitig).

Da ich mir zwischen den einzelnen Bytes Zeit lassen kann könnte ich die Ausgabe einzelner Bits des jeweiligen Bytes aber auch fortlaufend ohne Interrupts machen, mit wäre es allerdings eleganter und vom exakten Timing her einfacher (dachte ich zumindest bisher;-)

Lutz

--
Mit unseren Sensoren ist der Administrator informiert, bevor es Probleme im 
Serverraum gibt: preiswerte Monitoring Hard- und Software-kostenloses Plugin 
auch für Nagios - Nachricht per e-mail,SMS und SNMP: http://www.messpc.de
Neu: Ethernetbox jetzt auch im 19 Zoll Gehäuse mit 12 Ports für Sensoren
Reply to
Lutz Schulze

Keine Ahnung, müsste im Datenblatt stehen, aber würde ich auch mal vermuten. Setze die Zeit doch mal auf ein paar hundert Mikrosekunden und messe dann mit dem Scope nach, ob sich noch was ändert. Kannst dann jeweils halbieren, bis sich die gemessene Frequenz nicht mehr ändert, dann hast du den Zeitbedarf der Interruptroutine plus Overhead. Bei 7 MHz Takt hättest du ja bei Interuppts alle 4 Mikrosekunden nur 28 Takte pro Interrupt. Bei einigen CPUs braucht auch ein Opcocde-Zyklus 2 Takte, sodaß du nur 14 Opcode-Zyklen Zeit hättest. Je nachdem, wieviel dann ein Befehl braucht, wird es dann knapp.

Das wäre aber schon ziemlich merkwürdig. Ich habe mir von dem Atmega 8 mal das Datenblatt angesehen:

formatting link

Auf Seite 88 steht dort, daß man die Register so programmieren kann, daß die automatisch bei Erreichen eines bestimmten Wertes zurückgesetzt werden. Alles andere wäre auch nicht sinnvoll, da zu ungenau, weil es Befehle gibt, die länger als ein Taktzyklus dauern und somit die Neuprogrammierung des Timers nicht exakt wäre.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

Das braucht man doch nicht testen, das kann man ausrechnen. (Zumindest den worst case)

Das kann eigentlich nicht sein. Eine Routine zum Togglen eines Portbits in einem Timerinterrupt sieht ungefähr so aus:

Takte push R16 1 push R17 1 in R16,SREG 1 push R16 1 ldi R17,1Interruptroutine gleich wieder mit dem Ursprungswert geladen

??? Wozu willst du "von Hand" den Zähler neu laden? Das können die Timer doch selber auch viel besser. Dafür gibt's den CTC-Mode.

Nein, garantiert nicht. Der läuft ständig, auch während du in der ISR steckst. Allerdings können natürlich Interrupts "verloren gehen", wenn du zu lange in der Interruptroutine steckst.

Wenn du an die Limits gehen willst, helfen nur zwei Sachen: Assembler lernen und Hardware-Referenz lesen! Nur über die Reihenfolge, in der man sich das antun sollte, kann man vielleicht streiten...

Reply to
Heiko Nocon

ich glaub, du solltest die kapitel zu den timern im datasheet nochmal lesen. für so einen zweck (interrupts in regelmäßigen abständen) würd ich einen der "clear timer on compare match"-modi verwenden, wo du den TOP-wert des timers nach OCR1A oder ICR1 schreibst, der timer von 0 raufzählt und bei erreichen von TOP einen interrupt generiert und automatisch bei 0 wieder anfängt. schon hast du interrupts in genau festgelegten abständen...

HTH,

cm.

--
** christian mock in vienna, austria -- http://www.tahina.priv.at/
Vielleicht ist es aber auch nur einfach Zeit, dem Wolfi wieder den
root-Account wegzunehmen. Er ist noch zu klein dafuer.
 Ferdinand Goldmann in at.gesellschaft.politik
Reply to
christian mock

Moin!

[Timer jedesmal in Software neu starten]

Und das ist die Umschreibung für "völlig unsinnig", wenn man einfach nur mit festem Takt einen Interrupt auslösen will.

Genau. Und ab S.98 gibts nochmal ne Auflistung der Modi.

WGM4 oder WGM12 = CTC = Clear Timer on Compare.

Der Timer läuft dann immer von Null bis OCR1A (WGM4) oder ICR1 (WGM12) und startet wieder bei Null. Um durch n zu teilen, muss das Register also auf n-1 gesetzt werden. Da hier wahlweise der Output Compare oder der Input Capture missbraucht wird, kann man sich anhand des Modus (WGM) aussuchen, worauf man eher verzichten kann. Interrupt ist entsprechend OC oder IC.

Gruß, Michael.

Reply to
Michael Eggert

"Lutz Schulze" schrieb [Timerproblem]

Für Timer gibt es genau zwei Möglichkeiten:

a) Der Interrupt des Timers wird einfach nicht akzeptiert während der Code bearbeitet wird und der Timer läuft einfach durch... (kann man übrigens einstellen. Tip: IQs können Prioritäten haben Tip2: Jeder IQ hat eine höhere Prio als der Haupttask)

b) Es existiert auf der CPU ode rMicrocontroller eine Warteschlange für Interrupts und der Interrupt wird ausgeführt sobald dein Code zu Ende ist. (Ist beim Mega 8 aber IMHO nicht der Fall)

Reply to
Markus Gronotte

Am Mon, 7 Jan 2008 00:54:31 +0000 (UTC) schrieb christian mock:

Wird gemacht. Ich hatte mich bisher auf das verlassen, was der Application Builder des Compilers vorschlug. Ein Fehler.

Das wird funktionieren.

Lutz

--
Mit unseren Sensoren ist der Administrator informiert, bevor es Probleme im 
Serverraum gibt: preiswerte Monitoring Hard- und Software-kostenloses Plugin 
auch für Nagios - Nachricht per e-mail,SMS und SNMP: http://www.messpc.de
Neu: Ethernetbox jetzt auch im 19 Zoll Gehäuse mit 12 Ports für Sensoren
Reply to
Lutz Schulze

Ist definitiv einfacher. Es kommt nur drauf an, wieviel Zeit zwischen den Bytes vergehen darf, und ob der Rest deines Programms die ca. 40us, die der Prozessor zum senden braucht unterbrochen werden darf.

Angenommen, du musst alle 100us ein Byte senden, dann setze den Timer auf 100us und sende bei jedem INT ein ganzen Byte. Dir bleiben dann noch ca. 50% der Rechenleistung und das ganze wird vom Timining her unkritisch.

Die Bitlänge stellt man dann einfach über NOPs ein.

Gruß

Stefan

Reply to
Stefan Brröring

Wenn du den prescaler auf /8 eingestellt hast passt das. Es darf aber kein anderer interrupt laufen und auch cli ist tabu. Du hast pro 4 us 69 takte zur Verfügung. Hast du geschaut ob zusätzliche POP und PUSH befehle eingebaut werden sobald die Interruptroutine komplexer wird?

--
MFG Gernot
Reply to
Gernot Fink

Am Mon, 07 Jan 2008 07:52:31 +0100 schrieb Stefan Brröring:

Ja, das ist problemlos. Dass zwischen zwei Bytes eine Pause bis maximal 1 Sekunde sein kann sah ich bei nochmaligem genauen Blick in das Protokoll. Vorher war ich von strafferem Timing ausgegangen, deshalb der Ansatz über den Interrupt.

Ansonsten muss der Prozessor nur gelegentlich mal ein paar Zeichen vom UART entgegennehmen und verarbeiten, das ist aber nicht weiter zeitkritisch.

Yepp, das habe ich heute morgen zwischen sechs und sieben schon (erst einmal grob) so umgesetzt ;-)

Bin gerade beim Feinabgleich ...

Danke an alle für die Tips.

Lutz

--
Mit unseren Sensoren ist der Administrator informiert, bevor es Probleme im 
Serverraum gibt: preiswerte Monitoring Hard- und Software-kostenloses Plugin 
auch für Nagios - Nachricht per e-mail,SMS und SNMP: http://www.messpc.de
Neu: Ethernetbox jetzt auch im 19 Zoll Gehäuse mit 12 Ports für Sensoren
Reply to
Lutz Schulze

Schau Dir mal bitte den erzeugten Assembler an, bzw. poste ihn hier. Moderne C-Compiler sortieren die Reihenfolge von Instruktionen gerne mal um. Solange am Ende die gleichen Werte herauskommen und die zeitliche Abfolge egal ist, ist das kein Problem, wenn's aber darum geht Zeitverhalten zu definieren ist das =C3=A4tzend...

#pragma interrupt_handler ...? Das ist nicht der AVR-GCC, oder? Denn in dem verwendet man das Makro "ISR(...)" um einen Interrupt-Handler zu definieren.

Wolfgang Draxinger

--=20 E-Mail address works, Jabber: snipped-for-privacy@jabber.org, ICQ: 134682867

Reply to
Wolfgang Draxinger

Am Mon, 07 Jan 2008 09:08:53 +0100 schrieb Wolfgang Draxinger:

Es lag an zusätzlichen Registern, die vor dem neu laden des Zählers noch gerettet wurden, wenn die zusätzliche Anweisungen dazu kam. Habe das im Moment nicht weiter verfolgt, da mir der andere Ansatz (ein Interrupt pro Byte) besser gefällt.

ICCAVR

Habe mich mit dem mal den AVRs genähert, so oft brauche ich das nicht um mich wieder in was neues einzuarbeiten.

Lutz

--
Mit unseren Sensoren ist der Administrator informiert, bevor es Probleme im 
Serverraum gibt: preiswerte Monitoring Hard- und Software-kostenloses Plugin 
auch für Nagios - Nachricht per e-mail,SMS und SNMP: http://www.messpc.de
Neu: Ethernetbox jetzt auch im 19 Zoll Gehäuse mit 12 Ports für Sensoren
Reply to
Lutz Schulze

Das stimmt so nicht, einige dieser Befehle brauchen 2 Takte:

Takte push R16 2 push R17 2 in R16,SREG 1 push R16 2 ldi R17,1 Vektortabelle, 4 Takte für die konstante Interrupt-Latenz und bis zu 4

Das waeren dann 32 Takte. Aber wenn man es staendig aufruft, dann sollte man es vielleicht eher so implementieren:

Takte sbic PORTx, Pxn 1 bzw. 2 rjmp clear 2 sbi PORTx, Pxn 2 reti 4 clear: cbi PORTx, Pxn 2 reti 4 -------- 8 bzw. 9

Geht schneller und braucht keinen Stack.

Micha

Reply to
Michael Baeuerle

Lutz Schulze schrieb:

In den Assemblercode hätte ich als erstes reingeschaut, zumindest bevor ich die Instruktionen taktweise zusammenrechne. Hast Du die C-Zeile selber in Assembler codiert und dann ausgezählt?

Udo

Reply to
Udo Piechottka

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.