Hallo zusammen!
Ich möchte die Zustände zweier Ports (Port B, Port C) mit einer Frequenz
von 200 kHz einlesen. Dazu verwende ich den Timer1 mit entsprechender
Vorladung im CTC-Modus: Vergleichswert 80, Prescaler 1, f=16MHz.
Laut Simulator benötigt die ISR 31 Takte von der 1. zur letzten
Code-Zeile, also knapp 2us. Setzen ich einen Breakpoint auf die 1.
Codezeile und messe die Zeit zwischen 2 Aufrufen der ISR, komme aich auf
6,69 us -> ca. 150 kHz. Woher kommen die zusätzlichen 4us? Hat das was
mit dem Stack zutun? Was kann ich tun um die Zeit zu reduzieren?
Gruß
probiere mal am Anfang und Ende von deinem Code ein Bit zu toggeln und
mit Oszi die Zeit zu messen, ohne Hardwarebreakpoints, damit kannst du
dein Ergebnis mal verifizieren :) Womöglich braucht dein Debugging ein
paar Zyklen, wobei du natürlich gar nicht angegeben hast welchen
Mikrocontroller du überhaupt verwendest
lg
Der µC braucht eine gewisse Anzahl an Takte bis er die ISR ausführt (bis
zu 50). Beschleunigen kann man das leider nicht wirklich. Aber evtl.
heit dein µC ja DMA, dann geht das ganze Hardwareseitig
Gerd schrieb:> Woher kommen die zusätzlichen 4us?
Das wird an deinem Programm und der Art liegen, wie dein Prozessor die
ISR abarbeitet. Guck im Simulator einfach im Single Step nach, was
zwischen den Breakpoints passiert. Dann siehst du vielleich eher, wo dir
die Zeit verloren geht. Vermutlich macht der Prozessor alles richtig und
du hast einen Fehler in deiner Rechnung ;-)
Thomas schrieb:> welchen> Mikrocontroller du überhaupt verwendest
Atmega8535
Matthias Sch. schrieb:> Bitte schreibe doch wenigstens, welche Programmiersprache du benutzt.
C - noch...
Max Mustermann schrieb:> Aber wozu überhaupt Interups?> Was soll der MC noch in der Loop erledigen?
20 Werte pro Port mit einer (einstellbaren) Frequenz von bis zu 200 kHz
einlesen. Da die Frequenz einstellbar ist, verwende ich den Timer. Bis
100 kHz geht es auch.
M.O. schrieb:> Das wird an deinem Programm und der Art liegen, wie dein Prozessor die> ISR abarbeitet. Guck im Simulator einfach im Single Step nach, was> zwischen den Breakpoints passiert. Dann siehst du vielleich eher, wo dir> die Zeit verloren geht. Vermutlich macht der Prozessor alles richtig und> du hast einen Fehler in deiner Rechnung ;-)
Die Ausführung der ISR dauert 31 Takte. Das Problem ist die Zeit
zwischen 2 Aufrufen der ISR, die bei 105 Takten liegt. Mir ist unklar
was in den 68 Takten nach Ende der ISR und aufruf der nächsten ISR
passiert.
> Die Ausführung der ISR dauert 31 Takte. Das Problem ist die Zeit> zwischen 2 Aufrufen der ISR, die bei 105 Takten liegt. Mir ist unklar> was in den 68 Takten nach Ende der ISR und aufruf der nächsten ISR> passiert.
Vermutlich wird jeweils ein Interrupt vom Controller verpasst.
Ansonsten: Beitrag "Re: Port mit 200 kHz einlesen"
Gerd schrieb:> Mir ist unklar was in den 68 Takten nach Ende der ISR und aufruf der> nächsten ISR passiert.
Da pusht und popt der µC Registerinhalte und rennt im Hauptprogramm rum,
falls nicht noch andere Interrupts anstehen.
Gerd schrieb:> Mir ist unklar> was in den 68 Takten nach Ende der ISR und aufruf der nächsten ISR> passiert.
Der MC tut dass was jeder Prozessor bei einem Interupt tut!
Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem
Stack. Erhöht den Stackpointer. Setzt den Programmpointer auf den Anfang
der ISR. Arbeitet die ISR ab. Holt Alle Register incl Stackpointer und
Programmpointer wieder vom Stack. Und versucht mit dem Hauptprogramm
weiterzumachen.
Wenn nämlich in der Zwischenzeit ein neuer Interupt aufgetreten ist geht
das gleich wieder los mit Register sichern......
Max Mustermann schrieb:> Der MC tut dass was jeder Prozessor bei einem Interupt tut!> Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem> Stack. Erhöht den Stackpointer. Setzt den Programmpointer auf den Anfang> der ISR. Arbeitet die ISR ab. Holt Alle Register incl Stackpointer und> Programmpointer wieder vom Stack. Und versucht mit dem Hauptprogramm> weiterzumachen.> Wenn nämlich in der Zwischenzeit ein neuer Interupt aufgetreten ist geht> das gleich wieder los mit Register sichern......
Ja, dass wird mein Problem sein... Es gibt wohl keine Möglichkeit der uC
daran zu hindern? ;-)
Mir bleibt dann für die besagte Frequenz wohl keine andere Möglichkeit,
als das ohne Timer zu realisieren, oder? Also sozusagen im
Hauptprogramm. Die erfoderliche Abtastzeit erreiche ich dann durch
einsetzen von NOPs. Bessere Idee?
Gerd schrieb:> Max Mustermann schrieb:>> Der MC tut dass was jeder Prozessor bei einem Interupt tut!>> Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem>> Stack. Erhöht den Stackpointer. Setzt den Programmpointer auf den Anfang>> der ISR. Arbeitet die ISR ab. Holt Alle Register incl Stackpointer und>> Programmpointer wieder vom Stack. Und versucht mit dem Hauptprogramm>> weiterzumachen.>> Wenn nämlich in der Zwischenzeit ein neuer Interupt aufgetreten ist geht>> das gleich wieder los mit Register sichern......>> Ja, dass wird mein Problem sein... Es gibt wohl keine Möglichkeit der uC> daran zu hindern? ;-)
Das könnt' schon gerade noch gehen, denn der beschrieben Ablauf ist
bestenfalls als ganz grobe Umschreibung ok, in Beziehung auf 8Bit AVRs
in mehrfacher Hinsicht falsch.
Der ATM8535 schiebt im Interruptfall nur den ProgrammCounter auf den
Stack, sonst macht er nichts, er sichert keine Register, er schiebt
keinen Stackpointer auf den Stack.
C sichert die verwendeten Register selektiv, je nachdem wie gut die ISR
geschrieben ist, müssen mehr oder weniger Register gesichert werden.
Das ist entscheidend, denn ein Paar Takte gehen noch für den Ein- und
Rücksprung in die ISR weg (min. 7 Takte) und dann bleiben bei 31 Takten
in der ISR für das Sichern und Wiederherstellen 42 Takte, also 21 beim
Aufruf der ISR, 21 beim Ende. Das ist kanpp, aber nicht unmöglich.
Du wurdest bereits aufgefordert den Code zu zeigen, nur daran kann man
sehen, ob das klappen kann. Scheinbar verstehst Du das nicht so recht.
Max Mustermann schrieb:> Der MC tut dass was jeder Prozessor bei einem Interupt tut!> Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem> Stack.
Das höre ich zum ersten Mal. Lediglich das Sichern von Statusregister
und Programmpointer wird man dem µC nicht verwehren können. Alles andere
ist Sache der Software. Und wenn man genau weiss, welche Register in der
ISR verändert werden, reicht es auch nur genau diese beim Einsprung in
die ISR zu sichern.
Max Mustermann schrieb:> Der MC tut dass was jeder Prozessor bei einem Interupt tut!
Das tut nicht der Prozessor, ein AVR sichert lediglich die
Rücksprungadresse auf dem Stack von alleine. Alles andere macht die
Kompilerumgebung. Bei avrgcc besteht aber die Möglichkeit, ISR von
jeglichem Gedöns zu befreien, wenn du selber weisst, was du tust.
1
ISR(ADC_vector,ISR_NAKED){}
schafft z.B. eine leere ISR, bei dem die automatische Sicherung von
Registern wegfällt.
Siehe die Doku zur avrlib.
Matthias Sch. schrieb:> ein AVR sichert lediglich die Rücksprungadresse auf dem Stack von alleine.
Das Statusregister wird er sich schon noch zusätzlich sichern müssen.
Sonst geht das schief. Die Rücksprungadresse alleine reicht nur bei
einer Subroutine.
Die Aufgabe schreit förmlich nach einem MCU mit DMA. Die gibt's doch
schon billig, sogar bei den AVRs. Da hast du dann sogar noch genug
CPU-Zeit übrig um was anderes nebenbei zu machen.
Max Mustermann schrieb:> Der MC tut dass was jeder Prozessor bei einem Interupt tut!
Das muß schon deshalb grandioser Schwachsinn sein, weil das jeder µC
anders macht. Da wir inzwischen vom OP wissen, daß es sich um einen
Atmega8535 handelt...
> Er sichert ALLE Register incl Stackpointer und Programmpointer auf dem> Stack.
...ist zumindest das definitiv Schwachsinn. Ein Atmega sichert genau
eine Sache von sich aus auf dem Stack, nämlich die Rücksprungadresse.
Dazu braucht er zwischen 4 (Normalfall) und theoretisch maximal 6
Takten. Letzteres erfordert aber schon einen Mega, dessen Stack in
externem RAM liegt. Der 8535 hat keinen externen RAM, das wäre aber z.B.
beim Mega8515 oder Mega128 immerhin möglich.
Also definitiv vier Takte konstante Interruptlatenz. Dazu noch mal vier
Takte für reti. Zusammen also genau acht Takte unvermeidlichem
Interupt-Overhead der Hardware. Nicht mehr und nicht weniger.
Alles, was darüber hinausgeht, ist mehr oder weniger vermeidbar. Wenn
man in der einzig wahren Sprache für kleine µC programmiert, der
einzigen, die die volle Kontrolle über alle Aspekte der Hardware
garantiert. Und die heißt numal einfach nicht C, das ist schon alles,
was dazu zu sagen ist. Und irgendwie wohl auch oft genug gesagt wurde...
M.O. schrieb:> Das Statusregister wird er sich schon noch zusätzlich sichern müssen.> Sonst geht das schief. Die Rücksprungadresse alleine reicht nur bei> einer Subroutine.
Nö, der Prozessor selbst sichert nur die Rücksprungadresse. Das SREG
muss dann nicht gesichert werden, wenn man in der ISR ausschließlich
Opcodes verwendet, die das Statusregister nicht beeinflussen.
Was nützt es, Portpins in der Geschwindigkeit abzufragen,
wenn bei den Standard-µCs nur für einige 1000 Messwerte
Speicherplatz vorhanden ist. Also für einige 100-stel bis
10-tel Sekunden.
Kann man mit nem µC machen, wenn man genau weiß, dass nach einer
Auslösebedingung, nur so wenig "Aufnahmezeit" nötig ist.
Aber, ob da so viel vorher überlegt wurde...
c-hater schrieb:> Also definitiv vier Takte konstante Interruptlatenz. Dazu noch mal vier> Takte für reti. Zusammen also genau acht Takte unvermeidlichem> Interupt-Overhead der Hardware. Nicht mehr und nicht weniger.
Nein. Beim Auftreten eines Interrupts muß zunächst mal der aktuell
abgearbeitete Befehl zuende gebracht werden, also im Falle z.B. eines
RET bis zu 4 (oder 5 je nach Prozessor-Typ) zusätzliche Takte. Wenn das
abgeschlossen ist, wird erstmal in die Interrupt-Vektor-Tabelle
gesprungen, was die von dir erwähnten 4 Takte benötigt. Da findet sich
dann in der Regel ein RJMP, der nochmal 2 Takte braucht. Das heißt, daß
es bis zu 10 Takte dauern kann, bevor überhaupt an den Anfang der ISR
gesprungen wird. Der Rücksprung braucht dann zusätzlich die erwähnten 4
Takte. Eine komplett leere ISR braucht also schon mal bis zu 14 Takte
(mal angenommen, daß kein Sleep-Modus benutzt wird, denn sonst
verlängert sich das nochmal deutlich).
Dann kommt die Register-Sicherung. Selbst minimale Vertreter dieser Art
sichern normalerweise erstmal ein Register auf dem Stack, um dann über
dieses das SREG ebenfalls auf dem Stack zu sichern. 2 * PUSH und ein IN,
macht 5 Takte, am Ende das umgekehrte, nochmal 5 Takte. So sind wir dann
schon bei 24 Takten und können dann auch schon anfangen, der ISR ihren
eigentlichen Inhalt zu geben.
Hi
>Das heißt, daß>es bis zu 10 Takte dauern kann, bevor überhaupt an den Anfang der ISR>gesprungen wird.
Wenn du schon so genau sein willst, sind es maximal 9 Takte (10 bei
22Bit-PC), da ein Befehl schon in Bearbeitung sein muss um noch
abgearbeitet zu werden.
MfG Spess
Rolf Magnus schrieb:> So sind wir dann> schon bei 24 Takten und können dann auch schon anfangen, der ISR ihren> eigentlichen Inhalt zu geben.
Tja, und woher kam jetzt nochmal das Gerücht her, dass die ARMs
besonders lange Interrupt-Latenz haben? Ein Cortex-M3 sichert den
gesamten Kontext in 12 Zyklen!
Rolf Magnus schrieb:> c-hater schrieb:>> Also definitiv vier Takte konstante Interruptlatenz. Dazu noch mal vier>> Takte für reti. Zusammen also genau acht Takte unvermeidlichem>> Interupt-Overhead der Hardware. Nicht mehr und nicht weniger.>> Nein. Beim Auftreten eines Interrupts muß zunächst mal der aktuell> abgearbeitete Befehl zuende gebracht werden
Das ist die variable Interruptlatenz, nicht die konstante. Und diese
variable Interuplatenz ist zwar sicher oft sehr störend bezüglich der
Reaktionszeit für die Bearbeitung eines Interrupts (denn sie kann
sogar noch sehr viel länger sein als nur die Beendigung der aktuellen
Instruktion, z.B. durch konkurrierende Interrupts oder CLI/SEI-Blöcke in
main), aber sie ist kein Interrupt-Overhead im engeren Sinne, denn genau
die Takte, die die ISR dadurch später zur Auführung kommt, kommt ja der
unterbrochene Code derweil auch noch weiter in seiner Arbeit. Die
Rechenzeit ist also im Unterschied zur konstanten Latenz nicht verloren,
die variable Latenz verringert also im Gegensatz zur konstanten nicht
den Durchsatz des Gesamtsystems.
> Wenn das> abgeschlossen ist, wird erstmal in die Interrupt-Vektor-Tabelle> gesprungen, was die von dir erwähnten 4 Takte benötigt. Da findet sich> dann in der Regel ein RJMP
Und genau das ist schon der erste Punkt, der in Asm nicht mehr zwingend
ist. Wenn ich eine im Bezug auf den Durchsatz extrem zeitkritische ISR
habe, kann ich die notfalls auch direkt in den Vektorbereich legen.
Schlimmstenfalls muß ich dann irgendwas anderes ohne Interrupt lösen,
weil der zugehörige Vektor nicht mehr verfügbar ist.
> Eine komplett leere ISR braucht also schon mal bis zu 14 Takte
Das ist eindeutig falsch.
> Dann kommt die Register-Sicherung. Selbst minimale Vertreter dieser Art> sichern normalerweise erstmal ein Register auf dem Stack, um dann über> dieses das SREG ebenfalls auf dem Stack zu sichern
Auch wieder eine Sache, die in Assembler oft nicht nötig ist, denn es
gibt erstens viele Instruktionen, die die Flags überhaupt nicht
anfassen, dementsprechend gibt es dann auch keinen Grund, ebendiese zu
retten, wenn man eine ISR nur mit solchen Instruktionen gebacken bekommt
und zweitens kann ich in Assembler bei hinreichender Wichtigkeit der
ISRs für den Durchsatz des Systems einfach ein Register systemweit für
den Zweck reservieren, als Scratchregister zum Sichern der Flags in ISRs
zu dienen. Wenn alle ISRs so kurz sind, daß ich sie vollständig exklusiv
laufen lassen kann, brauchen dann nichtmal mehr die Flags vom
Scratchregister auf den Stack, sondern sie bleiben einfach nur dort und
werden auch von dort wiederhergestellt. Zweimal push gespart, zweimal
pop gespart, total 8 Takte pro Interrupt. Wenn dabei nur ein einzelner
Interrupt mit 400kHz ausgelöst wird und das System mit 20 MHz läuft,
spare ich allein durch diese kinderleichten Manipulationen 3,2MTakte/s.
Was nichts anderes bedeutet, das ich bezüglich des Durchsatzes mit
diesem Ansatz Sachen realisieren kann, für die du sonst mindestens
23,2MHz Systemtakt benötigen würdest. So einfach ist das...
Bezüglich der Reaktionszeiten ist das sogar oft noch extremer, denn hier
wirkt sich jeder im exklusiven Teil einer ISR unnütz vertrödelte Takt
auf die variable Latenz aller anderen ISRs gleichermaßen schädlich
aus. Hier kann bei entsprechender Aufgabenstellung schon ein einziger
gesparter Takt in irgendeiner ISR über geht oder geht nicht für das
Gesamtsystem entscheiden.