Gibt es irgendeine Möglichkeit WinAVR dazu zu bringen die ganzen pushs in der Interruptroutine etwas zu optimieren ? In der Routine werden 4 Register benötigt, aber alle 15 auf den Stack geschoben. Das sind immerhin 44 CPU Takte, die sinnlos verschwendet werden, fast genausoviel wie der Code in der Interruptroutine benötigt.
Du rufst warscheinlich im Interrupt eine Unterfunktion auf, die erst nach dem Interrupt oder in einem anderen Objekt definiert wird. Dann weiß der Compiler ja nicht, daß nur 4 Register verwendet werden. Abgesehen davon kostet ein Funktionsaufruf selber ja schon 7 Zyklen. Peter
Stimmt, daran lags. Allerdings ist das ganze immer noch ziemlich mies. Der Compiler sichert z.B. das zero und temp reg obwohl diese nicht benötigt werden, und einige weitere Register könnte man auch sparen. Ich will aber nicht weiter meckern, immerhin ist WinAVR kostenlos (im Gegensatz zum M16C Compiler NC30, der in der Vollversion immerhin ca. 3k kostet.
Bei CodeVisionAVR mit #pragma savereg- kann man selber entscheiden welche von den Register zu reten sind. Naturlich am Ende nicht vergessen #pragma savereg+ /* Turn registers saving off */ #pragma savereg- /* interrupt handler */ interrupt [1] void my_irq(void) { /* now save only the registers that are affected by the routines in the interrupt handler, for example R30, R31 and SREG */ #asm push r30 push r31 in r30,SREG push r30 #endasm /* place the C code here */ /* now restore SREG, R31 and R30 */ #asm pop r30 out SREG,r30 pop r31 pop r30 #endasm
Beim AVR-GCC geht das mit: void signame (void) _attribute_ ((naked)); siehe signal.h Aber wirklich nur, wenn es garnicht anders geht !!! Man muß dann nach jeder Änderung des Quelltextes oder der Compilereinstellungen überprüfen, ob man auch wirklich alle benutzten Register manuell gesichert hat ! Nochn Tip für die ganz eiligen: Der AVR-GCC benutzt fast nie R2..R11, d.h. die kann man dann in dem schnellen Interrupt nehmen, das spart richtig: movw r3:r2, r17:16 ... mache was mit r17, r16 movw r17:r16, r3:r2 sind nur 2 Zyklen gegenüber 8 Zyklen bei PUSH/POP Aber dann auch im gesamten Listing prüfen ob R2..R11 nicht doch irgendwo anders auftauchen ! Peter
> Aber dann auch im gesamten Listing prüfen ob R2..R11 nicht doch > irgendwo anders auftauchen ! Besser wäre es, stattdessen dafür eine festzugewiesene Registervariable zu deklarieren (... asm("r2");). Dann kann man sich u. U. auch gleich das Inline-Asm-Gewurschtel sparen und die Zuweisung selbst auch noch in C machen. Aber auch hier: alle Module müssen mit dieser Deklaration übersetzt worden sein. Besonders für die Bibliothek ist das natürlich normalerweise nicht der Fall, ich habe keine Ahnung, ob wirklich keine der Bibliotheksfunktionen je eins dieser Register benutzt oder (in einer anderen Compilerversion) mal benutzen könnte.
"Besser wäre es, stattdessen dafür eine festzugewiesene Registervariable zu deklarieren" Nützt bloß nichts. Der Compiler gibt keinerlei Fehlermeldung aus, wenn er auch das Register benutzen will. Um das Überprüfen des Listings nach jedem Compile kommt man also nicht drumrum. Daß R2..R11 in der Regel oft unangetastet bleiben, ist noch lange keine Garantie dafür. Peter
> Der Compiler gibt keinerlei Fehlermeldung aus, wenn er auch das > Register benutzen will. Das wäre allerdings einen GCC-Bugreport wert.
@Jörg Wunsch, ich habs nochmal getestet: Warnungen erhalte ich bei R18..R31. Keine Warnungen erhalte ich bei R0..R17. Frei sind aber nur R2..R11. Deklariert habe ich sie im h-File, z.B.: register unsigned char PCMValB1 asm("r11"); Peter
> Keine Warnungen erhalte ich bei R0..R17. > Frei sind aber nur R2..R11. Eigentlich sollten R2...R17 frei sein. Dass er R0 und R1 nicht warnt, ist ganz sicher ein Bug, aber einer spezifisch für den AVR-Port des GCC (der für R0 und R1 Sonderbedeutungen zugewiesen hat). Für R2...R17 würde ich erwarten, dass bereits der generische Code von GCC diese Register einfach nicht anderweitig benutzt. Wie gesagt, das kann nur funktionieren, sofern in der jeweiligen compilation unit (also das aktuelle C-File plus alle Includes) die entsprechende ... asm("rXX")-Deklaration auch wirksam war. Im fertigen Binary sollte man dabei insbesondere natürlich drauf gucken, dass nichts aus der avr-libc (die ja ohne derartige Deklarationen compiliert worden ist) eventuell das entsprechende Register benutzt (oder man arbeitet gleich mit einer privaten Kopie der avr-libc, die ebenfalls die entsprechende Deklaration benutzt). Wenn du das mit einem kurzen Beispiel nachweisen kannst, dass der GCC innerhalb eines Quellfiles trotz ... asm("r2")-Deklaration trotzdem noch R2 in seinem eigenen Code benutzt, dann halte ich das für einen berichtenswerten Bug (zumal sehr wahrscheinlich einen nicht-AVR-spezifischen).
@Jörg, daran lags. Ich Depp hatte natürlich nur dort included, wo ich sie benutzte. Man muß sie in alle C-Files includieren und dann versucht der Compiler ohne sie auszukommen bzw. wird wohl auch eine Warnung erzeugen, wenn ihm das nicht gelingt. Der Bug betrifft also doch nur R0 und R1. Schön ist auch, daß ich nun R16 und R17 benutzen kann, das macht meine nackten Interrupts nochmal nen Zacken schneller. Allerdings liefert mir der neue WINAVR nun eine Warnung: I2C.C:49: warning: `i2c_interrupt' appears to be a misspelled signal handler Der Grund ist, daß ein I2C-Interrupt ja langsam ist, aber sich nicht selber löscht. D.h. ich brauche einen nackten Interrupt, der nur den I2C disabled und dann erst den eigentlichen Handler aufruft. Damit nun dieser Handler aber auch alle seine Register selber sichert, muß er als signal deklariert sein, ist aber keinem Interruptvektor zugeordnet: void i2c_interrupt ( void ) _attribute_ ((signal)); void i2c_interrupt ( void ) { ... } Aber irgendwas paßt dem WINAVR daran nicht und er macht besagte Warnung. Sollte ich ihn vielleicht doch einem unbenutzten Interrupt zuordnen, z.B. dem SPM_READY ? Peter
Gut, dass das erstmal grundlegend funktioniert. Für R0/R1 kannste ja ruhig mal einen Bugreport öffnen. Die Warnung ist die ,,Notbremse'', falls sich jemand mit den SIG_*- Namen verschreibt. Das ist früher sehr häufig passiert (und führt dann zu einem spontanen Neustart ab Adresse 0), und irgendwann fiel dann Ted Roth ein genialer Trick ein, wie man den GCC selbst für bestimmte Dinge eigene Warnungen erstellen lassen kann. Das einfachste ist natürlich, du lebst mit der Warnung (du weißt ja, warum sie kommt und dass sie bei dir harmlos ist). Ansonsten bliebe noch die ,,Eigenerfindung'' eines ,,Interruptvektors''. Meiner Meinung nach werden die __attribute__((signal))-Routinen darauf überprüft, ob sie mit _vector anfangen und auf einer Zahl enden. Mit __vector_999 oder so solltest du auf der sicheren Seite sein.
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.