hallo! Ich habe eine Frage zu relativen Sprüngen: im define steht ein rjmp +4, d.h. er soll dem ProgramCounter 4 byte vom Aktuellen Platz weitersetzen: #define PA5_TOG _asm__ __volatile_ ( "sbis 0x1B, 5 \n\t" \ "sbi 0x1B, 5 \n\t" \ "rjmp +4 \n\t" \ "cbi 0x1B, 5 \n\t" \ ) wenn ich aber folgenden Code schreibe: int main(void) { PA5_TOG; PA5_TOG; PA5_TOG; :::::::::::: kommt folgendes heraus: int main(void) { b2: cf ef ldi r28, 0xFF ; 255 b4: d4 e0 ldi r29, 0x04 ; 4 b6: de bf out 0x3e, r29 ; 62 b8: cd bf out 0x3d, r28 ; 61 PA5_TOG; ba: dd 9b sbis 0x1b, 5 ; 27 bc: dd 9a sbi 0x1b, 5 ; 27 be: fb cf rjmp .-10 ; 0xb6 c0: dd 98 cbi 0x1b, 5 ; 27 PA5_TOG; c2: dd 9b sbis 0x1b, 5 ; 27 c4: dd 9a sbi 0x1b, 5 ; 27 c6: f7 cf rjmp .-18 ; 0xb6 c8: dd 98 cbi 0x1b, 5 ; 27 PA5_TOG; ca: dd 9b sbis 0x1b, 5 ; 27 cc: dd 9a sbi 0x1b, 5 ; 27 ce: f3 cf rjmp .-26 ; 0xb6 d0: dd 98 cbi 0x1b, 5 ; 27 das heisst der rjump landet stets 4 plätze Relativ zur Main-Routine. er soll aber 4 plätze relativ zum PC springen. Wie muss ich das formulieren? Gruß Martin
Hi ich frage mich erstens warum Inline-ASM für sowas wie ein Pin-Toggle anwenden? Der GCC macht aus PORTA^=1<<5; 254: 8b b3 in r24, 0x1b ; 27 256: 90 e2 ldi r25, 0x20 ; 32 258: 89 27 eor r24, r25 25a: 8b bb out 0x1b, r24 ; 27 was mindestens genauso schnell ist wie deine Lösung. BTW: Bei deinem Ansatz wird cbi 0x1B, 5 nie ausgeführt (sagt mir zumindest meine Interpretation von sbis :) Matthias
Der Assemblercode in meinem Beispiel ist falsch, das hast Du völlig richtig erkannt - das mache ich auch noch besser. Aber: der Code ist nicht interruptfest, d.h. es kann zu konflikten in einer ISR kommen. mit meinem Assemblercode werden nämlich nichtunterbrechbare bitoperationen ausgeführt - die sind bei meuiner anwendung vonnöten Meine Frage zielt vielmehr auf Sprungmarken in Makros - Thema verfehlt - trotzdem danke für die antwort Gruß Martin
Hi wieso ist dein Code interruptfest? Kommt nach dem sbis ein INT kannst du auch nicht mehr zu 100% sagen wie der Zustand des Ports ist. Du solltest also entweder: Während des toggelns die INT's ausschalten oder besser den Port nur im INT bzw. nur in main() ändern. Matthias
RJMP +4 ist falsch geschrieben. RJMP .+4, aber ich würde an Deiner Stelle besser einen lokalen label benutzen. Das sind die, die nur aus Ziffern bestehen und deren Referenz ein `f' oder `b' angehängt bekommt. Ist in der avr-libc Doku ein bißchen mit beschrieben. Ansonsten stimme ich natürlich Matthias zu. Wenn Du Assembler willst, dann nimm ihn, ansonsten kannste das alles (einschließlich Interruptfestigkeit) auch alles ordentlich in C schreiben. Kann ja sein, daß der Compiler manchmal einen Takt mehr braucht als Dein handgefeilter Assembler, dafür kann man aber auch in 3 Jahren noch auf den ersten Blick sagen, was es tut.
@Matthias: Du kannst natürlich niemals erwarten, dass eine Haupt- und eine Int-Routine an dem Gleichen Port-Pin herumschalten und das dann keine Konflikte gibt! Das geht weder mit Assembler noch mit C noch überhaupt. meine Assmblerroutine soll ja nur verhindern, dass sich die Port-Bits eines Port-Bytes GEGENSEITIG stören Gruß Martin @Joerg: ( by the way: RJMP .+4 ist das was ich eigentlich wissen wollte! Der punkt wars, damit läufts so wie ich es brauche, der sorgt wohl für einen Sprung RELATIV ZUM AKTUELLEN PC) sicher ist die C-Formulierung in 3 Jahren noch lesbar und die asseblerlösung nicht. Aber ich brauche halt eine interuptfeste Lösung, die sowohl in einem Haupt-als auch in einer interuptroutine an dem ports herumschaltet. die C-Variante PORTA^=1<<5; 254: 8b b3 in r24, 0x1b ; 27 256: 90 e2 ldi r25, 0x20 ; 32 258: 89 27 eor r24, r25 25a: 8b bb out 0x1b, r24 ; 27 ist halt nicht interuptfest. Die Assemblervariante (nach Fehlerkorrektur): sbis 0x18,3 rjmp PORT_H PORT_L: cbi 0x18,3 rjmp PORT_END PORT_H: sbi 0x18,3 PORT_END: verträgt sicher einen interrupt, der an den anderen Port-Bits herumfummelt. Wie würdest Du das in C formulieren? - Ich habe lange probiert, so was in C zu schreiben, aber es gab immer den Fall, dass entweder etwas wegoptimiert wurde oder die interuptfestigkeit nicht gegeben war. Gruß Martin
> verträgt sicher einen interrupt, der an den anderen Port-Bits > herumfummelt. Das kann man zwar nicht allgemein als ,interruptfest' ansehen, aber wenn Du diesen Fall wirklich brauchst: #define TOGGLE do {\ if (PORTB & _BV(3)) \ PORTB &= ~_BV(3); \ else \ PORTB |= _BV(3); \ } while (0) Dieser Makro compiliert bei mir exakt zu Deinem Assemblercode: sbis 56-0x20,3 rjmp .L3 cbi 56-0x20,3 rjmp .L2 .L3: sbi 56-0x20,3 .L2: Das hier würde ich als generell interruptfest bezeichnen: #define TOGGLE do {\ unsigned char sreg = SREG; \ cli(); \ PORTB ^= _BV(3); \ SREG = sreg; \ } while (0)
vieln Dank, ich werde wahrscheinlich letzteres verwenden, das sollte wohl alles abdecken Deine erste Variante (ohne d-while(0) hatte ich zeitweilig auch, aber die hatte halt Aussetzer. warum auch immer, während die Assemblervariante letztlich lief. Nur die Versteht ja kein Mensch.... Allerdings wird die variante 1 bei mir wie folgt kopmiliert, was aber wohl aufs gleiche herausläuft, solange der Prozessor weit genug springen kann: #define TOGGLE do {\ if (PORTB & _BV(3)) \ PORTB &= ~_BV(3); \ else \ PORTB |= _BV(3); \ } while (0) TOGGLE; b2: c3 9b sbis 0x18, 3 ; 24 b4: 47 c0 rjmp .+142 ; 0x144 b6: c3 98 cbi 0x18, 3 ; 24 TOGGLE; b8: c3 9b sbis 0x18, 3 ; 24 ba: 42 c0 rjmp .+132 ; 0x140 bc: c3 98 cbi 0x18, 3 ; 24 ::::::::::::::::::::::::: 140: c3 9a sbi 0x18, 3 ; 24 142: bd cf rjmp .-134 ; 0xbe 144: c3 9a sbi 0x18, 3 ; 24 146: b8 cf rjmp .-144 ; 0xb8 Gruß Martin
> Allerdings wird die variante 1 bei mir wie folgt kopmiliert, Hmm, ekliges Disassemblerlisting, warum nimmst Du nicht den Assembler-Output des Compilers? ;-) Sieht nach Optimierung größer als 1 oder s aus. > ... was aber wohl aufs gleiche herausläuft, solange der Prozessor > weit genug springen kann Diese Einschätzung würde ich dem Compiler zutrauen. ;-)
ja wie sieht es denn bei dir aus, du wolltest sicher ne datei anhängen???? wo/wie finde ich denn das assembleroutput des compilers ?? ich trau dem compiler mittlerweile auch - wenn er auc für meinen Geschmack zuviel optimiert!
Hi du kannst dir den ASM-Output anschauen indem du dem Compiler -S übergibst. Dann wird der Vorgang allerdings abgebrochen und du erhälst kein .o das du dann dem Linker übergeben kannst. Ich erzeuge mir deshalb aus der .elf-Datei das ASM-Listing per avr-objdump.exe -t -h -S $(BIN).elf >$(BIN).lst Matthias
Das mit der objdump anweisung kannte ich schon, nicht aber den Tip mit dem Compiler - das probier ich gleich aus vielen Dank
Mit dem Disassemblieren bekommst Du insbesondere nicht mehr die originalen Kommentare des Compilers zu sehen. Tip: bei Benutzung von -S den Compiler besser ohne -g aufrufen, die Debug-Pseudoanweisungen verwirren nur unnütz. Das aktuelle WinAVR-Makefile-Template kann sowas schon automatisch (bis auf das Weglassen des -g): für eine C-Datei foo.c kann man mit »make foo.s« verlangen, daß die zugehörige Assemblerdatei erstellt wird. Auf Dateisystemen, die nicht zwischen Groß- und Kleinschreibung unterscheiden, sollte man dann aber besser keine Quelldate mit dem Namen foo.S haben... ;-)
Hmmm ich habe folgenden Compileraufruf gemacht: avr-gcc -S -Wall -O2 -mmcu=atmega162 -c main.c und es kommt tatsächlich ein Listing main.s heraus. Leider ist die Zuordnung C-Quelltest -> Assembler nicht zu erkennen. Hab ich da wohl noch ne Option vergessen? Bei der Variante, die Matthias vorschlägt, ist das dagegen schön zu sehen: avr-objdump.exe -t -h -S $(BIN).elf >$(BIN).lst Gruß Martin
> Leider ist die Zuordnung C-Quelltest -> Assembler nicht zu > erkennen. Hab ich da wohl noch ne Option vergessen? Nein, dafür gibt es keine Compileroption. Allerdings kann man sich da ganz gut reinlesen. Mit bißchen Übung versteht man durchaus, welche Assemblerteile zu welchen C-Statements gehören. > Bei der Variante, die Matthias vorschlägt, ist das dagegen schön zu > sehen: Das wird dort nachträglich über die Debug-Statements hergestellt. Die müssen übrigens nicht immer richtig sein, optimierter Code ist oft nicht mehr so eindeutig zuordenbar. Das Problem hat man natürlich beim Debuggen selbst ebenfalls. Du kannst natürlich beim Compileraufruf auch ein -g mit reinnehmen, dann hast Du alle Debug-Statements wieder drin, damit auch die Zeilennummern. Ich find's aber unübersichtlicher, als gleich den reinen Assembler zu lesen.
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.