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
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.