Hallo,
ich habe mir mittels objdump den ASM-Code für eine Interruptroutine angeschaut:
ISR (TIMER0_COMPA_vect){
ca0: 1f 92 push r1 //Wieso?
ca2: 0f 92 push r0
ca4: 0f b6 in r0, 0x3f ; 63
ca6: 0f 92 push r0 //Warum?
ca8: 11 24 eor r1, r1 //Weshalb der Blödsinn?
caa: 2f 93 push r18
cac: 8f 93 push r24
cae: 9f 93 push r25
byte p=PWM+=PWMAdd;
cb0: 90 91 00 01 lds r25, 0x0100 ; 0x800100 <__data_start>
cb4: 9f 5b subi r25, 0xBF ; 191
cb6: 90 93 00 01 sts 0x0100, r25 ; 0x800100 <__data_start>
byte a=PORTB&0x0F;
cba: 85 b1 in r24, 0x05 ; 5
cbc: 8f 70 andi r24, 0x0F ; 15
if(MotorOn){
cbe: 20 91 05 01 lds r18, 0x0105 ; 0x800105 <MotorOn>
cc2: 22 23 and r18, r18
cc4: a1 f0 breq .+40 ; 0xcee <__vector_21+0x4e>
if(p>PWMSoll1) a|=0x10;
cc6: 20 91 04 01 lds r18, 0x0104 ; 0x800104 <PWMSoll1>
cca: 29 17 cp r18, r25
ccc: 08 f4 brcc .+2 ; 0xcd0 <__vector_21+0x30>
cce: 80 61 ori r24, 0x10 ; 16
if(p>PWMSoll2) a|=0x20;
cd0: 20 91 03 01 lds r18, 0x0103 ; 0x800103 <PWMSoll2>
cd4: 29 17 cp r18, r25
cd6: 08 f4 brcc .+2 ; 0xcda <__vector_21+0x3a>
cd8: 80 62 ori r24, 0x20 ; 32
if(p>PWMSoll3) a|=0x40;
cda: 20 91 02 01 lds r18, 0x0102 ; 0x800102 <PWMSoll3>
cde: 29 17 cp r18, r25
ce0: 08 f4 brcc .+2 ; 0xce4 <__vector_21+0x44>
ce2: 80 64 ori r24, 0x40 ; 64
if(p>PWMSoll4) a|=0x80;
ce4: 20 91 01 01 lds r18, 0x0101 ; 0x800101 <PWMSoll4>
ce8: 29 17 cp r18, r25
cea: 08 f4 brcc .+2 ; 0xcee <__vector_21+0x4e>
cec: 80 68 ori r24, 0x80 ; 128
}
PORTB=a;
cee: 85 b9 out 0x05, r24 ; 5
}
cf0: 9f 91 pop r25
cf2: 8f 91 pop r24
cf4: 2f 91 pop r18
cf6: 0f 90 pop r0 //Weg damit
cf8: 0f be out 0x3f, r0 ; 63
cfa: 0f 90 pop r0
cfc: 1f 90 pop r1 //Und auch das, warum denn nur?
cfe: 18 95 reti
Der erzeugte Code für die Routine ist wirklich gut, besser kann man das glaube ich nicht selber machen.
Nur stören mich einige, meiner Meinung nach, unnütze pushs und pops für die Register r0 und r1.
Über r0 wird das SREG gesichert, muss sein. Aber da r0 im eigentlichen Programm nicht verwendet wird könnte man r0 doch nur 1 mal pushen und poppen. Und vorallem r1. Wird nicht verwendet aber einfach mal pushen und mit eor r1,r1 löschen. Was soll das?
Kann man in der Arduino-IDE diese bescheuerte “Vorlage” verändern oder das ganze ASM einfach rauskopieren, anpassen und in C++ einfügen mit einer Option das der Compiler da nix mehr hinzufügen soll?
MfG
Andi
EDIT: Ach ja, wieso wird denn überhaupt r0 und r1 hergenommen? Man kann doch sowieso nur mit den Registern r16 bis r31 Imediate-Befehle wie ori oder addi machen. Irgendwie scheint mir die Arduino-IDE nicht wirklich gut für die AVRs angepasst zu sein.
Soweit ich weiss ist im C-Kontext das Register 1 als 0 vorausgesetzt.
Das gilt aber nicht auf Assembler Ebene, da könnte sinnvoller Inhalt im Register sein.
Da ein Interrupt jederzeit (also auf Assembler Ebene) auftreten kann, ist es nötig auch R1 zu retten,
da aber wiederum C das Register als 0 erwartet, wird das durch den "Blödsinn" sichergestellt.
Aber in diesem Fall wird r1 ja nicht ein mal verwendet aber trotzdem gepusht und auf 0 gesetzt was ich als Unfug empfinde. Kostet mit dem pop nur Rechenzeit von 5 Takte.
Kann man da nix ändern?
MfG
Andi
Typischer Fall von ‘Optimieren’ an der völlig falschen Stelle, meiner Ansicht nach.
3/4 Zyklen pro Interrupt, würde mich nicht jucken.
Du glaubst der Interrupt Entry Kode sei ohne Sinn und Verstand geschrieben worden?
Ich tu das nicht.
Keine Ahnung wo man das ändern könnte, es mag tief im Kode-Generator verborgen sein,
ich kenne den Quelltext des gcc nicht.
Schreib deine Interruptroutinen in Assembler und benutze die Interrupt Definition, die keinen Entry/Exit Kode erzeugt.
Wenn du die Frage stellen musst, solltest du es nicht tun.
Denn dann hast du die Dokumentation noch nicht gelesen (und Google oder andere nicht gefragt).

http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__interrupts.html
Gesagt und gemacht:
ISR (TIMER0_COMPA_vect, ISR_NAKED){
asm("push r24 \n in r24,0x3F \n push r24 \n push r25 \n push r18");
ca0: 8f 93 push r24
ca2: 8f b7 in r24, 0x3f ; 63
ca4: 8f 93 push r24
ca6: 9f 93 push r25
ca8: 2f 93 push r18
byte p=PWM+=PWMAdd;
caa: 90 91 00 01 lds r25, 0x0100 ; 0x800100 <__data_start>
cae: 9f 5b subi r25, 0xBF ; 191
cb0: 90 93 00 01 sts 0x0100, r25 ; 0x800100 <__data_start>
byte a=PORTB&0x0F;
cb4: 85 b1 in r24, 0x05 ; 5
cb6: 8f 70 andi r24, 0x0F ; 15
if(p>PWMSoll1) a|=0x10;
cb8: 20 91 04 01 lds r18, 0x0104 ; 0x800104 <PWMSoll1>
cbc: 29 17 cp r18, r25
cbe: 08 f4 brcc .+2 ; 0xcc2 <__vector_21+0x22>
cc0: 80 61 ori r24, 0x10 ; 16
if(p>PWMSoll2) a|=0x20;
cc2: 20 91 03 01 lds r18, 0x0103 ; 0x800103 <PWMSoll2>
cc6: 29 17 cp r18, r25
cc8: 08 f4 brcc .+2 ; 0xccc <__vector_21+0x2c>
cca: 80 62 ori r24, 0x20 ; 32
if(p>PWMSoll3) a|=0x40;
ccc: 20 91 02 01 lds r18, 0x0102 ; 0x800102 <PWMSoll3>
cd0: 29 17 cp r18, r25
cd2: 08 f4 brcc .+2 ; 0xcd6 <__vector_21+0x36>
cd4: 80 64 ori r24, 0x40 ; 64
if(p>PWMSoll4) a|=0x80;
cd6: 20 91 01 01 lds r18, 0x0101 ; 0x800101 <PWMSoll4>
cda: 29 17 cp r18, r25
cdc: 08 f4 brcc .+2 ; 0xce0 <__vector_21+0x40>
cde: 80 68 ori r24, 0x80 ; 128
PORTB=a;
ce0: 85 b9 out 0x05, r24 ; 5
asm("pop r18 \n pop r25 \n pop r24 \n out 0x3F,r24 \n pop r24");
ce2: 2f 91 pop r18
ce4: 9f 91 pop r25
ce6: 8f 91 pop r24
ce8: 8f bf out 0x3f, r24 ; 63
cea: 8f 91 pop r24
reti();
cec: 18 95 reti
Das sieht ja schon mal viel besser aus.
Ich habe mit AVR-ASM schon vor 15 Jahren programmiert. Nach dieser 15-jährigen Pause habe ich mit C++ (Arduino) dieses Jahr erst begonnen. ASM ist kein Problem für mich aber diese hundert tausende C-Optionen kommen halt erst mit der Zeit rein.
Vielen Dank für deine Hilfe.
MfG
Andi
Gerne.
Lies mal die ganze Referenz, zumindestens diagonal.
Praktisch braucht man an der Stelle nur in Ausnahmefällen optimieren,
insofern ist so etwas eher akademisch (oder direkt projektbezogen).
Whandall:
insofern ist so etwas eher akademisch (oder direkt projektbezogen).
Na ja, da der AVR noch die Länge von einem Mehrkanal PPM-Signal per Pin-Change-IRQ mithilfe von Timer1 messen soll sollte diese Routine so kurz wie möglich sein.
Bin selber gespannt was daraus wird.
MfG
Andi