Manch einer mag das jetzt zwar als unsinnig abtun, aber ich habe mir aus
gegebenem Anlass mal ein paar Gedanken zu einer schnellen aber kleinen
Interruptroutine gemacht.
Der ISR soll eigentlich nicht mehr machen als bei einem Interrupt einen
16bit Counter hochzählen. Ausgehend vom avr-gcc generierten Code hab ich
mich bisher bis zu dem Code vorgearbeitet:
1
volatileuint16_tCounter;
2
3
ISR(INT0_vect,ISR_NAKED){
4
asmvolatile(
5
"PUSH R16\n"
6
"IN R16, __SREG__\n"
7
"PUSH R16\n"
8
"LDS R16, Counter\n"
9
"SUBI R16, 0xFF\n"
10
"STS Counter, R16\n"
11
"BRCS 0f\n"
12
"LDS R16, Counter+\n"
13
"SUBI R16, 0xFF\n"
14
"STS Counter+1, R16\n"
15
"0:"
16
"POP R16\n"
17
"OUT __SREG__,R16\n"
18
"POP R16\n"
19
"RETI\n"
20
:
21
);
22
}
Der avr-gcc code brauch 37 Takte. Meiner normal 21, bei einem overflow
25 (wenn ich micht nicht verzählt habe). Ausserdem braucht er weniger
flash.
Hat da noch jemand Verbesserungsvorschläge? Das einzig bessere was mir
noch einfallen würde wäre den Counter direkt an zwei Register zu binden,
was ich aber eigentlich gerne vermeiden würde.
Nico
P.S. Ja ich weiss, das man nicht grundlos überoptimieren sollte, ist für
mich in erster Linie aber auch nur ein Gedankenspiel. Also bitte kein
sinnloses bashen oder trollen, danke.
Hallo,
die alles entscheidende Frage ist hier: wie oft wird dieser Interrupt
aufgerufen? Wie hoch ist also der Gewinn an freier CPU-Zeit real?
Ich habe ähnliche Versuche mal bei DCF77-Experimenten mit dem Schieben
eines uint64_t um 1 Bit gemacht.
Da wwaren es aber mehr als 600 Takte gegen ca. 20. Mehr aus Interesse an
dem Stück Inline-ASM allerdings. Ich denke, die GCC-Routine hätte es
genauso getan. ;-)
Gruß aus Berlin
Michael
Der große Irrtum ist, daß man denkt, es reicht nur den einen
Zählinterrupt zu optimieren.
Der AVR hat keine Interruptprioritäten. Daher ist der Worst-Case, daß
auch alle anderen Interrupts auftreten können. Wenn Du z.B. einen
UART-Interrupt hast, der viel machen muß, dann verzögert dieser Dein
Zählen.
Die maximale Zählfrequenz ergibt sich also nicht aus der Laufzeit des
Zählinterrupts, sondern aus der Summe der Ausführungszeiten aller
Interrupts. Und da können schnell mal >500 Zyklen zusammmen kommen.
Peter
Falls noch ein Timer frei sein sollte, so kann man externe Signale in 0
Takten zählen, indem man den Timer per extern taktet.
Leider muss man den Start/Stop aber per Software machen, AVR bietet
nicht die Möglichkeit den Start/Stop per I/O-Port zu triggern.
Johann
Nico schrieb:
> Manch einer mag das jetzt zwar als unsinnig abtun, aber ich habe mir aus> gegebenem Anlass mal ein paar Gedanken zu einer schnellen aber kleinen> Interruptroutine gemacht.>> Der avr-gcc code brauch 37 Takte. Meiner normal 21, bei einem overflow> 25 (wenn ich micht nicht verzählt habe). Ausserdem braucht er weniger> flash.
Interessant und durchaus nicht unsinnig wäre auch, das avr-gcc
beizubringen!
Damit die unnötigen Operationen im ISR-Prolog/-Epilog entfallen :-)
Johann
man kann doch mit dem GCC auch globale variablen an Register binden,
damit sollte sich das ganze noch wesentlich schneller machen, weil man
nicht erst R16,R17 Retten muss und auch noch die Zählvariable aus dem
Speicher lesen und Zurückschreiben.
@Peter Dannegger
> Der große Irrtum ist, daß man denkt, es reicht nur den einen> Zählinterrupt zu optimieren.
"Ja ich weiss, das man nicht grundlos überoptimieren sollte, ist für
mich in erster Linie aber auch nur ein Gedankenspiel. Also bitte kein
sinnloses bashen oder trollen, danke."
Es sind immer die gleichen, die rumklugscheissern muessen...
jo schrieb:
> "Ja ich weiss, das man nicht grundlos überoptimieren sollte
Nö.
Man sollt nur vorher überlegen, ob das, was man macht, überhaupt einen
Effekt hat.
Es ist mir doch vollkommen schnurz, ob Du trotz Deiner super-duper
Optimierung Counts verlierst. Solange ich Deine Geräte nicht kaufen muß
und mich damit rumärgern.
> Also bitte kein> sinnloses bashen oder trollen, danke."
Nichts zu danken, wer so bescheuert reagiert, ist selber der Troll.
Schreib nächstes mal besser gleich dazu: "Ich verbitte mir jeden
ernsthaften Kommentar".
> Es sind immer die gleichen, die rumklugscheissern muessen...
Bleib nur weiter bei Deinem beschränkten Horizont. Sofort rumzumotzen,
wenn einer auf Probleme hinweist, wird Dich weit bringen und zu einem
guten Programmierer machen.
Peter
Peter schrieb:
> man kann doch mit dem GCC auch globale variablen an Register binden,> damit sollte sich das ganze noch wesentlich schneller machen, weil man> nicht erst R16,R17 Retten muss und auch noch die Zählvariable aus dem> Speicher lesen und Zurückschreiben.
Da würde ich aber nicht R16/R17 verwenden; die sind viel zu "wertvoll".
Ausserdem verliert man u.U ABI-konformität und kann viele Funktionen aus
der avr-libc bzw. libgcc nicht mehr verwenden!
Bei dem Lösungsansatz würde die Wahl also zB auf R2/R3 fallen. SUBI ist
dort nicht mehr anwendbar, aber es gehen ja auch INC/BRNE-Sequenzen:
> Bleib nur weiter bei Deinem beschränkten Horizont.
Fragt sich, wer hier beschraenkt ist, wenn er nicht mal 2 Namen
ausseinander halten kann...
> Sofort rumzumotzen, wenn einer auf Probleme hinweist, wird Dich weit> bringen und zu einem guten Programmierer machen.
Deine Kollegen koennen einem nur Leid tun.
Johann L. schrieb:
> Bei dem Lösungsansatz würde die Wahl also zB auf R2/R3 fallen. SUBI ist> dort nicht mehr anwendbar, aber es gehen ja auch INC/BRNE-Sequenzen:
Nachtrag:
Allerdings muss dann jedes Objekt mit -ffixed-2 -ffixed-3 compiliert
werden (bzw. die entsprechende globale Register-Deklaration includet
werden) -- auch dann, wenn es den Zähler überhaupt nicht verwendet.
Johann
@Johann L.
ja mir ist klar das das keine schöne universelle Lösung ist. Aber wenn
es wirklich sehr schnell gehen muss ist es immerhin eine Alternative.
Da ich erst mit ASM angefangen habe und dann mal ein paar versuche mit
dem gcc gemacht habe ärgere ich mich auch immer über den grossen
Overhead den der Compiler erzeugt.
Dafür schreibt sich C wesentlich schneller als ASM.
@Peter Danneger
Erstmal, ich bin nicht Jo. Die Anmerkung im OP hatte ich nur aus
Erfahrungen hier im Forum dazugeschrieben.
Das mit den Interruptlatenzen ist natürlich beim AVR immer ein Problem,
aber wie gesagt, es geht nur um ein Gedankenspiel, wie man das ganze
möglichst kompatibel und schnell hinbekommen kann.
@Johann L.
Ich bin mir jetzt nicht ganz sicher ... aber ist SUBI R16,0xFF nicht als
opcode das selbe wie INC R16? Meine das mal gelesen zu haben, kann es
aber grad nicht nachschauen.
Nico
Peter schrieb:
> Da ich erst mit ASM angefangen habe und dann mal ein paar versuche mit> dem gcc gemacht habe ärgere ich mich auch immer über den grossen> Overhead den der Compiler erzeugt.
Dieser Overhead ist in über 98% aller Fälle irrelevant und hat lediglich
"psychologische" Auswirkungen :-)
Johann
@jo:
Man merkt, dass du wohl noch neu im Forum bist. Sonst würdest du Peter
Dannegger wohl kaum als Troll bezeichnen. Damit hast du dich selbst
disqualifiziert.