Hallo,
ich arbeite unter Linux und habe ein Problem mit dem kompilieren von
Assembler mit dem avr-gcc.
Habe den Code bei einem Kollegen unter Windows im AVR Studio simuliert
und auf den Controller programmiert. Damit hat es ohne Probleme
funktioniert. Ausgenommen natürlich das ändern von hi8 (RAMEND) auf
high(RAMEND) und das gleiche für low.
Am Board liegt es nicht, dies habe ich bereits ausgiebig getestet,
vieleicht findet jemand von euch einen Fehler.
Für mich sieht es so aus als würde einfach der Interrupt nicht ausgelöst
werden.
Nach dem Start leuchtet die Led korrekterweise an Pin A0.
Danke im Vorraus
Jasmin
Folgender Code:
1
.NOLIST
2
.INCLUDE "m16def.inc"
3
.LIST
4
5
.org 0x000
6
rjmp main ; Reset Handler
7
.org INT0addr
8
rjmp int0_handler ; IRQ0 Handler
9
10
11
12
main: ; hier beginnt das Hauptprogramm
13
14
ldi r16, lo8(RAMEND)
15
out SPL, r16
16
ldi r16, hi8(RAMEND)
17
out SPH, r16
18
19
ldi r16, (0<<DDD2) ;INT0(PORT D2) muss als input konfiguriert werden)
20
out DDRD, r16
21
22
ldi r16, (1<<PD2) ;Pullup
23
out PORTD, r16
24
25
ldi r16,(1<<PA0)+(1<<PA1)+(1<<PA2); Ausgänge
26
out DDRA, r16
27
28
ldi r16, (1<<ISC00)+(0<<ISC01) ;0b00000001 ; INT0 konfigurieren - Jede änderung löst einen interrupt aus
@Jasmin T.
>ich arbeite unter Linux und habe ein Problem mit dem kompilieren von>Assembler mit dem avr-gcc.
Ähhh, der AVR-gcc ist ein C-Compiler. Der "frisst" deinen Source Code
der unten dranhängt nicht. Das ist reiner Assembler. AVR-Studio (auf
Windows) ist die allgemeine Oberfläche, welche sowohl Assembler als auch
C Projekte verwalten kann.
MfG
Falk
gcc bedeutet GNU Compiler Collection. Also nicht unbedingt nur c.
Wenn ich den Code unter Windows im AVRStudio kompiliere, funktioniert
das Programm, aber ich muss es unter Linux übersetzen können und da
macht die Interruptroutine eben Probleme (Ohne Interrupts läufts auch
dort!) und ich weis nicht wieso.
@Jasmin T.
>gcc bedeutet GNU Compiler Collection. Also nicht unbedingt nur c.
Ach so, wieder was gelernt.
>macht die Interruptroutine eben Probleme (Ohne Interrupts läufts auch>dort!) und ich weis nicht wieso.
Gibt es eine Fehlermeldung? Vielleicht ein Fehler in den Include Files?
MFG
Falk
Nein gibt es keine, dann wüsst ich ja wo suchen, das Programm
kompiliert, wird korrekt übertragen und dann leuchtet das erste Led wies
soll. Der Interrupt der zwar aktiviert ist wird allerdings nie
aufgerufen.
Wie hast du denn den Assembler und Linker aufgerufen?
Wenn du dafür den GCC als Frontend nimmst, dann baut der den
normalen startup-Code ein, der auch die Interruptvektoren definiert.
Dann hälst du dich besser an das Protokoll, wie es z. B. in
http://www.nongnu.org/avr-libc/user-manual/group__asmdemo.html
demonstriert wird.
irgendeine deiner Aussagen stimmt nicht
AVR Studio benutzt einen eigenen Assembler "AVR-Assembler" , der hat
einen anderen Syntax als der Assembler des gcc "gas"
wenn du in AVRStudio assemblierst hast du nicht den gas benutzt.
Bei assembler spricht man nicht von compilieren sondern assemblieren.
>ldi r16,(1<<PA0)+(1<<PA1)+(1<<PA2);
gewöhn dir sowas erst gar nicht an, das sind logische verknüpfungen
nicht arithmetische Ausdrücke
deine LED ist doch in r17, wenn du die nicht setzt ist sie undefiniert
für den Anfang oder steht irgendwo das die Register am Anfang 0 sind?
Nehmen wir mal 0 an. Was passiert wenn du 0 shiftest? Meiner Meinung
nach bleibt es 0.
>irgendeine deiner Aussagen stimmt nicht>AVR Studio benutzt einen eigenen Assembler "AVR-Assembler" , der hat>einen anderen Syntax als der Assembler des gcc "gas">wenn du in AVRStudio assemblierst hast du nicht den gas benutzt.>Bei assembler spricht man nicht von compilieren sondern assemblieren.
Deswegen sag ich ja im 1. Post dass der Syntax etwas anders ist, es ist
mir schon bewusst.
Hab mir überlegt vieleicht behandelt der Gnu-asm das SEI anders als der
AvrStudio-asm.
>gewöhn dir sowas erst gar nicht an, das sind logische verknüpfungen>nicht arithmetische Ausdrücke
Wie soll ich es dann machen? Etwa ldi r16,0b00000111
Ändert allerdings auch nix daran, dass es nicht geht g>deine LED ist doch in r17, wenn du die nicht setzt ist sie undefiniert>für den Anfang oder steht irgendwo das die Register am Anfang 0 sind?>Nehmen wir mal 0 an. Was passiert wenn du 0 shiftest? Meiner Meinung>nach bleibt es 0.
Naja r17 wird doch bei loadfirst initialisiert mit 0x01.
r16 benutz ich zum Initialisieren der einzelnen Ein/Ausgaberegister.
>Naja r17 wird doch bei loadfirst initialisiert mit 0x01.>r16 benutz ich zum Initialisieren der einzelnen Ein/Ausgaberegister.
einen rcall mit reti beenden?
Bleibt da nicht das Flagregister auf dem Stack, so daß du mit der Zeit
einen Stacküberlauf produzierts?
Aber dazu scheint es ja bis jetzt nicht zu kommen
entweder hältst du dich an Jörgs Vorschlag oder du rufst avr-as direkt
auf.
Hallo,
beim AVR ist der Unterschied zwischen RET und RETI nur der, daß RETI die
Interrupts wieder freigibt, die der Ausruf der ISR gesperrt hat.
Es hat hier also keine Nebenwirkungen, man sollte es sich aber garnicht
erst angewöhnen. RCALL -> RET, ISR -> RETI.
Zu
>ldi r16,(1<<PA0)+(1<<PA1)+(1<<PA2)
Der Präprozessor macht eine Addition, das gent nur gut, solange die
Werte nur Bitwerte sind und solange nicht das gleiche Bit betroffen ist.
Mal es Dir auf Papier unter der Annahme, daß die Werte nicht Portbits
sind, sondern andere Vereinbarungen:
.equ X1 = 1
.equ Y1 = 2
.equ Z1 = 1
>ldi r16,(1<<X1)+(1<<Y1)+(1<<Z1)
Ich habe das früher auch meist so gemacht, stört in 99% der Fälle auch
nicht, den Fehler beim letzten Prozent sucht man dafür dann eine
Woche...
>ldi r16,(1<<PA0)|(1<<PA1)|(1<<PA2)
Der Präprozessor macht eine OR-Verknüpfung
>ldi r16,(1<<X1)|(1<<Y1)|(1<<Z1)
Schau Dir den Unterschied beim Ergebnis an. ;)
Gruß aus Berlin
Michael
@ Wolfram
>einen rcall mit reti beenden?
Nee, es ist ein branch (brge). Ist aber dennoch schlechter
Programmierstil, die zwei Zeilen sollte man lieber in die
Interruptroutine integrierern und dann am Ende nur ein RETI haben.
>Ich habe das früher auch meist so gemacht, stört in 99% der Fälle auch>nicht, den Fehler beim letzten Prozent sucht man dafür dann eine>Woche...>>ldi r16,(1<<X1)|(1<<Y1)|(1<<Z1)>Schau Dir den Unterschied beim Ergebnis an. ;)
Böse Falle! ;-)
MfG
Falk
Jasmin T. wrote:
> Ich habe den Assembler folgendermaßen aufgerufen:>> avr-gcc -x assembler -mmcu=ATmega16 -o demo.aout demo.s
Aha, also über den Compilertreiber. Damit linkst du implizit den
C-Startup-Code mit, da der Compiler nach dem Assemblieren den
Linker aufruft. Dieser Code wiederum beinhaltet die Vektoren.
Bitte sieh dir das genannte Demo an sowie die Doku überhaupt, die
enthält auch noch ein reines Assemblerbeispiel. Prinzipiell denke
ich, dass du bei der Variante mit dem Compiler bleiben solltest,
aber dann musst du dich an die Konventionen für Interruptvektornamen
etc. halten.
Außerdem nimmt man in diesem Kontext normalerweise nicht
1
.INCLUDE "m16def.inc"
sondern wie in C-Programmen üblich
1
#include <avr/io.h>
zusammen mit der entsprechenden -mmcu= Option des Compilers. Dazu
benennst du bitte die Datei nicht mehr foo.s sondern foo.S (und
gibst sie auch mit dem großen S so auf der Kommandozeile des
Compilers an), damit sie durch den Präprozessor geschickt wird.
Das mit dem -x assembler entweder ganz weglassen (das merkt der
Compiler anhand des Suffixes), oder du musst dir das passende
aus dem Manual raussuchen (-x assembler-with-cpp oder so ähnlich --
ich benutze immer die impliziten Regeln an Hand der Suffixe, ich
kann's dir nicht genau sagen).
Der Billischassembler von Atmel ist wirklich nur 'ne Einsteigerversion
ohne jeglichen Komfort, entsprechend auch ohne Linker. Daher muss
man dort alles (auch die Vektoren) in einer Datei drin haben.
@Jasmin T.
>Hab mir überlegt vieleicht behandelt der Gnu-asm das SEI anders als der>AvrStudio-asm.
Das wäre äusserst komisch. Aber bei Linus ist ja alles möglich.
duckundwech>Wie soll ich es dann machen? Etwa ldi r16,0b00000111>Ändert allerdings auch nix daran, dass es nicht geht *g*
Nein. Du sollst anstatt
ldi r16,(1<<PA0)+(1<<PA1)+(1<<PA2) ; Addition
besser schreiben
ldi r16,(1<<PA0)|(1<<PA1)|(1<<PA2) ; ODER Verknüpfung
>>deine LED ist doch in r17, wenn du die nicht setzt ist sie undefiniert>>für den Anfang oder steht irgendwo das die Register am Anfang 0 sind?>>Nehmen wir mal 0 an. Was passiert wenn du 0 shiftest? Meiner Meinung>>nach bleibt es 0.>Naja r17 wird doch bei loadfirst initialisiert mit 0x01.>r16 benutz ich
FALSCH!
Wenn r17 beim Start zufällig Null ist, wird load first nie angesprungen.
Assembler != C !
In C sind alle Variablen initialisiert, und sei es implizit mit 0.
IN Assembler musst du das von Hand machen. Und gerade die Register und
die Variablen im SRAM haben nach dem Reset UNDEFINIERTE Werte! Das kann
böse ins Auge gehen. Nichtinitialisierte Variablen sind ein immer wieder
gern gesehener Fehler, Das Debugging kann ewig dauern (weil der Fehler
ggf. nur äusserst sporadisch auftritt).
MfG
Falk
Falk wrote:
>>Hab mir überlegt vieleicht behandelt der Gnu-asm das SEI anders als>>der AvrStudio-asm.> Das wäre äusserst komisch. Aber bei Linus ist ja alles möglich.
Was hat der GNU-Assembler (noch dazu für das AVR-Target) mit Linus zu
tun? Außer dass er diesen Assembler natürlich nutzt, aber dann hat er
genauso viel mit Falk zu tun...
> Nein. Du sollst anstatt> ldi r16,(1<<PA0)+(1<<PA1)+(1<<PA2) ; Addition> besser schreiben> ldi r16,(1<<PA0)|(1<<PA1)|(1<<PA2) ; ODER Verknüpfung
Wobei der Konflikt nur auftreten kann, wenn jemand aus Versehen
ldi r16, (1 << PA0) | (1 << PA0);
schreibt, weil er sich beim zweiten Bit verschrieben hat, und dann
hat derjenige so oder so ein Problem. Du bläst das hier gerade unnütz
auf (m. E.). Solange es ausschließlich verschiedene Bits sind, isses
wurscht.
@Falk:
so dachte ich das am Anfang auch aber er macht
sei ; Interrupts allgemein aktivieren
rcall loadfirst <<<<<<
loop: rjmp loop ; eine leere Endlosschleife
im Hauptprogramm
was ich dann ziemlich autsch finde ist der Abschluß des rcall mit iret
Ok, das geht. Das Flags register wird tatsächlich nicht gesichert. Aber
sowas zu machen wenn man noch 15,8 KB im FLASH frei hat,
also ich würde es nicht machen.
@Jörg Wunsch
>> Das wäre äusserst komisch. Aber bei Linus ist ja alles möglich.>Was hat der GNU-Assembler (noch dazu für das AVR-Target) mit Linus zu>tun?
Tippfehler, sollte auf X enden. ;-)
>Wobei der Konflikt nur auftreten kann, wenn jemand aus Versehen>ldi r16, (1 << PA0) | (1 << PA0);>schreibt, weil er sich beim zweiten Bit verschrieben hat, und *dann*>hat derjenige so oder so ein Problem.
Ja, aber du weisst ja wie das ist mit den Pferden vor der Apotheke . . .
;-)
@Wolfram
>so dachte ich das am Anfang auch aber er macht> sei ; Interrupts allgemein aktivieren> rcall loadfirst <<<<<<>loop: rjmp loop ; eine leere Endlosschleife>im Hauptprogramm
Ohh, jetzt seh ichs auch.
>was ich dann ziemlich autsch finde ist der Abschluß des rcall mit iret
Eben.
MfG
Falk
@Wolfram
>so dachte ich das am Anfang auch aber er macht
Ich glaube der ER ist eine SIE, wenn man im Internet den Nicknames
trauen darf;-).
Oder meinst du DEN AVR? ;-)
MfG
Falk
@ Jörg Wunsch
>> Tippfehler, sollte auf X enden. ;-)>Selbst dann sehe ich noch keinen Bezug. Oder sind die GNU Binutils>mittlerweile von Linux aufgekauft worden?
ES WAR EIN GAG!!!!
Linux und Linus und GCC sind ganz toll!
;-)
MfG
Falk
Danke an Jörg Wunsch der hat mich auf die richtige Spur gebracht, da es
sich bei meiner
1
m16def.inc
um eine modifizierte Version mit Wordadressen handelt muss ich nur alle
Adressen * 2 rechnen und schon funktioniert das Zeug.
1
.org INT0addr*2
2
rjmp int0_handler ; IRQ0 Handler
Aber danke an alle, die mir auch was zum Thema schönen Code beigebracht
haben. Ich geh jetzt mal jemanden lünchen.
@Wolfram
Ich verzeih dir nochmals, wegen des Namens. :P