mikrocontroller.net

Forum: Compiler & IDEs avr-gcc + Assembler Problem


Autor: Jasmin T. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
.NOLIST
.INCLUDE "m16def.inc"
.LIST
 
.org 0x000
         rjmp main            ; Reset Handler
.org INT0addr
         rjmp int0_handler    ; IRQ0 Handler

 
 
main:                         ; hier beginnt das Hauptprogramm
 
         ldi r16, lo8(RAMEND)
         out SPL, r16
         ldi r16, hi8(RAMEND)
         out SPH, r16

         ldi r16, (0<<DDD2) ;INT0(PORT D2) muss als input konfiguriert werden)
         out DDRD, r16 
     
     ldi r16, (1<<PD2) ;Pullup
         out PORTD, r16 
 
         ldi r16,(1<<PA0)+(1<<PA1)+(1<<PA2); Ausgänge
         out DDRA, r16

         ldi r16, (1<<ISC00)+(0<<ISC01) ;0b00000001  ; INT0 konfigurieren - Jede änderung löst einen interrupt aus
         out MCUCR, r16
 
         ldi r16, (1<<INT0) ; INT0 aktivieren
         out GICR, r16

         sei       ; Interrupts allgemein aktivieren 
    rcall loadfirst

loop:    rjmp loop             ; eine leere Endlosschleife
 
int0_handler:
        
    lsl r17    ; left shift
   cpi r17,0x8  ;wenn > led 3
   brge loadfirst  ;Springe zurück
   out PORTA, r17

reti
 

 
loadfirst:    
  
         ldi r17,(1<<PA0);0x01  ; este Lampe brennt
         out PORTA, r17         ; erleuchte dich
reti


Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Jasmin T. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Jasmin T. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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__...

demonstriert wird.

Autor: Jasmin T. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe den Assembler folgendermaßen aufgerufen:

avr-gcc -x assembler -mmcu=ATmega16 -o demo.aout demo.s
avr-objcopy -O ihex demo.aout demo.ihex

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Jasmin T. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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.

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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.

Autor: Michael U. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
.INCLUDE "m16def.inc"

sondern wie in C-Programmen üblich
#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.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Tippfehler, sollte auf X enden. ;-)

Selbst dann sehe ich noch keinen Bezug.  Oder sind die GNU Binutils
mittlerweile von Linux aufgekauft worden?

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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


Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Oder meinst du DEN AVR?
NATÜRLICH!!!  ;-)

(Sorry Jasmin T., ich sollte wohl öfters auf den Nickname schauen,
sonst ist 8-) nötig.)

Autor: Jasmin T. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die vielen Tipps, leider brachte mich bisher keiner auf das 
Problem bezogen weiter.

Autor: Jasmin T. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke an Jörg Wunsch der hat mich auf die richtige Spur gebracht, da es 
sich bei meiner
m16def.inc
 um eine modifizierte Version mit Wordadressen handelt muss ich nur alle 
Adressen * 2 rechnen und schon funktioniert das Zeug.
.org INT0addr*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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.