mikrocontroller.net

Forum: Compiler & IDEs Atmel ASM portieren


Autor: Aike T. (biertrinker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich versuche momentan ein bischen Asembler zu lernen. Da ich einen Mac
habe und sonst auch mit Eclipse AVR Programme scheibe würde ich dafür
gerne den gcc-as nehmen.
Bei den ersten kleinen Testprogrammen hat das noch ganz gut funktionert.
Jetzt versuche ich das Software-PWM Beispiel hier für den GNU-Assembler
umzubauen, aber leider finde ich nur wenig Dokumentation dazu.
Daher habe ich 1. die Frage ob jemand eine Seite kennt die sich mit dem
GNU-Assember beschäftigt und 2. ob mir jemand mal dabei helfen kann das
Programm umzuarbeiten.

Original:

.include "m8def.inc"

.def temp  = r16

.def PWMCount = r17

.def ocr_1 = r18                      ; Helligkeitswert Led1: 0 .. 127
.def ocr_2 = r19                      ; Helligkeitswert Led2: 0 .. 127
.def ocr_3 = r20                      ; Helligkeitswert Led3: 0 .. 127
.def ocr_4 = r21                      ; Helligkeitswert Led4: 0 .. 127
.def ocr_5 = r22                      ; Helligkeitswert Led5: 0 .. 127
.def ocr_6 = r23                      ; Helligkeitswert Led6: 0 .. 127

.org 0x0000
        rjmp    main                  ; Reset Handler
.org OVF0addr
        rjmp    timer0_overflow       ; Timer Overflow Handler

main:
        ldi     temp, LOW(RAMEND)     ; Stackpointer initialisieren
        out     SPL, temp
        ldi     temp, HIGH(RAMEND)
        out     SPH, temp

        ldi     temp, 0xFF            ; Port B auf Ausgang
        out     DDRB, temp

        ldi     ocr_1, 0
        ldi     ocr_2, 1
        ldi     ocr_3, 10
        ldi     ocr_4, 20
        ldi     ocr_5, 80
        ldi     ocr_6, 127

        ldi     temp, 0b00000001      ; CS00 setzen: Teiler 1
        out     TCCR0, temp

        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer
Overflow
        out     TIMSK, temp

        sei

loop:   rjmp    loop

timer0_overflow:                      ; Timer 0 Overflow Handler
        inc     PWMCount              ; den PWM Zähler von 0 bis
        cpi     PWMCount, 128         ; 127 zählen lassen
        brne    WorkPWM
        clr     PWMCount

WorkPWM:
        ldi     temp, 0b11000000      ; 0 .. Led an, 1 .. Led aus

        cp      PWMCount, ocr_1       ; Ist der Grenzwert für Led 1
erreicht
        brlt    OneOn
        ori     temp, $01

OneOn:  cp      PWMCount, ocr_2       ; Ist der Grenzwert für Led 2
erreicht
        brlt    TwoOn
        ori     temp, $02

TwoOn:  cp      PWMCount, ocr_3       ; Ist der Grenzwert für Led 3
erreicht
        brlt    ThreeOn
        ori     temp, $04

ThreeOn:cp      PWMCount, ocr_4       ; Ist der Grenzwert für Led 4
erreicht
        brlt    FourOn
        ori     temp, $08

FourOn: cp      PWMCount, ocr_5       ; Ist der Grenzwert für Led 5
erreicht
        brlt    FiveOn
        ori     temp, $10

FiveOn: cp      PWMCount, ocr_6       ; Ist der Grenzwert für Led 6
erreicht
        brlt    SetBits
        ori     temp, $20

SetBits:                              ; Die neue Bitbelegung am Port
ausgeben
        out     PORTB, temp

        reti

Was ich bisher draus gemacht habe:
#include <avr/io.h>                /* das gibt den Controllertyp an */

#define temp r16

#define PWMCount r17

#define ocr_1 r18                      // Helligkeitswert Led1: 0 .. 127
#define ocr_2 r19                      // Helligkeitswert Led2: 0 .. 127
#define ocr_3 r20                      // Helligkeitswert Led3: 0 .. 127
#define ocr_4 r21                      // Helligkeitswert Led4: 0 .. 127
#define ocr_5 r22                      // Helligkeitswert Led5: 0 .. 127
#define ocr_6 r23                      // Helligkeitswert Led6: 0 .. 127

.org 0x0000
        rjmp    main                  // Reset Handler
.org OVF0addr
        rjmp    timer0_overflow       // Timer Overflow Handler

main:
        ldi     temp, LOW(RAMEND)     // Stackpointer initialisieren
        out     SPL, temp
        ldi     temp, HIGH(RAMEND)
        out     SPH, temp

        ldi     temp, 0xFF            // Port B auf Ausgang
        out     DDRB, temp

        ldi     ocr_1, 0
        ldi     ocr_2, 1
        ldi     ocr_3, 10
        ldi     ocr_4, 20
        ldi     ocr_5, 80
        ldi     ocr_6, 127

        ldi     temp, 0b00000001      // CS00 setzen: Teiler 1
        out     TCCR0, temp

        ldi     temp, 0b00000001      // TOIE0: Interrupt bei Timer
Overflow
        out     TIMSK, temp

        sei

loop:   rjmp    loop

timer0_overflow:                      // Timer 0 Overflow Handler
        inc     PWMCount              // den PWM Zähler von 0 bis
        cpi     PWMCount, 128         // 127 zählen lassen
        brne    WorkPWM
        clr     PWMCount

WorkPWM:
        ldi     temp, 0b11000000      // 0 .. Led an, 1 .. Led aus

        cp      PWMCount, ocr_1       // Ist der Grenzwert für Led 1
erreicht
        brlt    OneOn
        ori     temp, $01

OneOn:  cp      PWMCount, ocr_2       // Ist der Grenzwert für Led 2
erreicht
        brlt    TwoOn
        ori     temp, $02

TwoOn:  cp      PWMCount, ocr_3       // Ist der Grenzwert für Led 3
erreicht
        brlt    ThreeOn
        ori     temp, $04

ThreeOn:cp      PWMCount, ocr_4       // Ist der Grenzwert für Led 4
erreicht
        brlt    FourOn
        ori     temp, $08

FourOn: cp      PWMCount, ocr_5       // Ist der Grenzwert für Led 5
erreicht
        brlt    FiveOn
        ori     temp, $10

FiveOn: cp      PWMCount, ocr_6       // Ist der Grenzwert für Led 6
erreicht
        brlt    SetBits
        ori     temp, $20

SetBits:                              // Die neue Bitbelegung am Port
ausgeben
        out     PORTB, temp

        reti


kann mir da jemand helfen?

viele Grüße

Aike

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau Dir erstmal Dein Posting selber an und dann überlege, wie jemand 
da helfen können soll.

Niemand kann in Deinen Kopf sehen, also mußt Du schon sagen, wo Dich der 
Schuh drückt.

Niemand kann diesen Code so assemblieren, also Forenregel 5 beachten.


Der Assembler wird bestimmt eine Fehlermeldung ausgegeben haben, es ist 
unklug diese geheim zu halten oder im Wortlaut zu verändern.
Insbesondere die Zeilennummer in der Fehlermeldung sollte man mal näher 
untersuchen.


Peter

Autor: Aike T. (biertrinker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun ja, ich dache das es vielleicht in diesem Fall für einen etwas 
erfahreneren assembler Progrogrammierer ein leichtes ist die nötigen 
Änderungen zu erkennen.

Dann will ich die Probleme mal genauer aufdröseln.

Also, ich bekomme hier eine Warnung:

.org OVF0addr
        rjmp    timer0_overflow       ; Timer Overflow Handler

Warning: symbol "OVF0addr" undefined; zero assumed

warum ist OVR0addr nicht bekannt? Ok, sollte man wohl durch 0x07 
ersetzen können. Schön ist anders. Ausserdem habe ich irgendwo gelesen, 
das man .org nicht verwenden soll. Allerding ist mir an dieser Stelle 
nicht klar, wie ich Sprünge auf die Interupt-Handler anders da hin 
bekommen soll.

also weiter:

        ldi     temp, LOW(RAMEND)     // Stackpointer initialisieren
        out     SPL, temp
        ldi     temp, HIGH(RAMEND)
        out     SPH, temp

und die Fehlermeldungen:

../test.S:20: Error: garbage at end of line
../test.S:21: Error: number must be less than 64
../test.S:22: Error: garbage at end of line
../test.S:23: Error: number must be less than 64

ja, und dann noch die hier:

../test.S:57: Error: junk at end of line, first unrecognized character 
is `0'
../test.S:61: Error: junk at end of line, first unrecognized character 
is `0'
../test.S:65: Error: junk at end of line, first unrecognized character 
is `0'
../test.S:69: Error: junk at end of line, first unrecognized character 
is `0'
../test.S:73: Error: junk at end of line, first unrecognized character 
is `1'
../test.S:77: Error: junk at end of line, first unrecognized character 
is `2'

das sind jeweils die Zeilen mit dem $01 ...

viele Grüße

Aike

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Statt $01 nimm mal 0x01

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
holger wrote:
> Statt $01 nimm mal 0x01
...Und statt LOW lo8 (und statt HIGH hi8), wenn ich mich recht 
entsinne...

(Alle Angaben ohne Gewähr)

Und dann schau in die Headerdatei vom ATMega8, wie da die Vektoradressen 
angegeben sind.

Es gibt hier im Forum übrigens auch für AVR-Assembler eine 
Formatierungsfunktion. Damit sieht der Code gleich viel besser und 
übersichtlicher aus.

Autor: Skua C:\> (skua)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OVF0addr ist zwar in m8def.inc aber nicht in avr/io.h definiert.

org nicht verwenden ist unsinn.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>      .......                // Stackpointer initialisieren
Das ist kein Assembler-Kommentar, sondern eben Garbage.
Kommentare im Assembler beginnen mit ';'
So etwa:
        .......                ; Stackpointer initialisieren

Ja, man sieht es genau: ein C-Programmierer  ;-)

Autor: Aike T. (biertrinker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Lothar
  Ja, das stimmt, ist ein C-Kommentar. Das ist aber nicht der Fehler, 
der wird vom Preprozessor vor dem Assemblerlauf entfernt.

@allen anderen
  Ich setze gerade noch eure Tipps um!

Autor: Aike T. (biertrinker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ein Problem bleibt über:

       ldi     temp, lo8(RAMEND)
        out     SPL, temp
        ldi     temp, hi8(RAMEND)
        out     SPH, temp

führt zu:

../test.S:21: Error: number must be less than 64
../test.S:23: Error: number must be less than 64

was will der denn da?

viele Grüße

Aike

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuch mal das vor #include <avr/io.h>

#define _ASSEMBLER_ 1
#define __SFR_OFFSET 0

#include <avr/io.h>

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aike Terjung wrote:
> So, ein Problem bleibt über:
>
>        ldi     temp, lo8(RAMEND)
>         out     SPL, temp
>         ldi     temp, hi8(RAMEND)
>         out     SPH, temp
>
> führt zu:
>
> ../test.S:21: Error: number must be less than 64
> ../test.S:23: Error: number must be less than 64
>
> was will der denn da?

out SPL, temp
->
out _SFR_IO_ADDR(SPL), temp

SPH entsprechend

Autor: Aike T. (biertrinker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan: Jep, das hilft, aber warum?

@holger: kann da keinen Unterschied bemerken, was soll das bewirken?

so, nun bleibt dieses Problem hier über:
17 .org 0x0000
18        rjmp    main                  // Reset Handler
19 .org 0x007
20         rjmp    timer0_overflow       // Timer Overflow Handler

führt zu:

../test.S:18: Error: odd address operand: 9

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aike Terjung wrote:
> @Stefan: Jep, das hilft, aber warum?

Weil jedes IO-Register über 2 Adressen angesprochen werden kann, der 
IO-Adresse und der Memory-Mapped-Adresse. Die Register-Definitionen in 
den IO-Headern sind die Memory-Mapped-Adressen, weil das einfacher für C 
ist. Der Asm-Befehl out erwartet aber die IO-Adresse.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aike Terjung wrote:

> so, nun bleibt dieses Problem hier über:
>
>
17 .org 0x0000
> 18        rjmp    main                  // Reset Handler
> 19 .org 0x007
> 20         rjmp    timer0_overflow       // Timer Overflow Handler
> 
>
> führt zu:
>
> ../test.S:18: Error: odd address operand: 9

Vermutlich arbeitet der gcc-as mit Byte-Adressen.

Autor: Skua C:\> (skua)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuchs mal mit

.org 0x00E
       rjmp    timer0_overflow       // Timer Overflow Handler

Vieleicht zählt der ja nicht wortweise.

Autor: Kernighan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ../test.S:18: Error: odd address operand: 9

sagte ja schon das 0x07 sicher nicht stimmen kann, weil 0x07 nicht even 
ist.

Cheers
Ritchie

Autor: Aike T. (biertrinker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, ich habe noch etwas weiter geforscht und gesucht. 1. Fehler ist 
wohl das die Adresse nicht 0x07 sondern 0x09 ist. Ganz so durchblicke 
ich das mit den Byte und Wort Adressen zwar noch nicht, aber für denn 
gcc müsste es dann ja 0x09*2 sein, also 0x12.
Damit assembliert das Programm schon mal durch, aber an den Ports 
passiert nix weiter.
Ich habe es inzwischen auch geschaft mittels Wine AVR Studio auf dem Mac 
zum laufen zu bringen. Jetzt kann ich damit zumindest den Simulator 
nutzen.
Vielleicht finde ich ja noch was dazu raus.

Ich pack trotzdem nochmal den Code dazu, vielleicht habe ich ja einfach 
noch einen Fehler den jemand entdecken kann.

vielen Dank

Aike
#include <avr/io.h>                /* das gibt den Controllertyp an */

#define temp r16

#define PWMCount r17

#define ocr_1 r18                      // Helligkeitswert Led1: 0 .. 127
#define ocr_2 r19                      // Helligkeitswert Led2: 0 .. 127
#define ocr_3 r20                      // Helligkeitswert Led3: 0 .. 127
#define ocr_4 r21                      // Helligkeitswert Led4: 0 .. 127
#define ocr_5 r22                      // Helligkeitswert Led5: 0 .. 127
#define ocr_6 r23                      // Helligkeitswert Led6: 0 .. 127

.org 0x12
        rjmp    timer0_overflow       // Timer Overflow Handler

.global main
main:
        ldi     temp, lo8(RAMEND) 
        out     _SFR_IO_ADDR(SPL), temp
        ldi     temp, hi8(RAMEND)
        out     _SFR_IO_ADDR(SPH), temp

        ldi     temp, 0xFF            // Port B auf Ausgang
        out     DDRB, temp

        ldi     ocr_1, 0
        ldi     ocr_2, 1
        ldi     ocr_3, 10
        ldi     ocr_4, 20
        ldi     ocr_5, 80
        ldi     ocr_6, 127

        ldi     temp, 0b00000001      // CS00 setzen: Teiler 1
        out     _SFR_IO_ADDR(TCCR0), temp

        ldi     temp, 0b00000001      // TOIE0: Interrupt bei Timer Overflow
        out     _SFR_IO_ADDR(TIMSK), temp

        sei

loop:   rjmp    loop

timer0_overflow:                      // Timer 0 Overflow Handler
        inc     PWMCount              // den PWM Zähler von 0 bis
        cpi     PWMCount, 128         // 127 zählen lassen
        brne    WorkPWM
        clr     PWMCount

WorkPWM:
        ldi     temp, 0b11000000      // 0 .. Led an, 1 .. Led aus

        cp      PWMCount, ocr_1       // Ist der Grenzwert für Led 1 erreicht
        brlt    OneOn
        ori     temp, 0x01

OneOn:  cp      PWMCount, ocr_2       // Ist der Grenzwert für Led 2 erreicht
        brlt    TwoOn
        ori     temp, 0x02

TwoOn:  cp      PWMCount, ocr_3       // Ist der Grenzwert für Led 3 erreicht
        brlt    ThreeOn
        ori     temp, 0x04

ThreeOn:cp      PWMCount, ocr_4       // Ist der Grenzwert für Led 4 erreicht
        brlt    FourOn
        ori     temp, 0x08

FourOn: cp      PWMCount, ocr_5       // Ist der Grenzwert für Led 5 erreicht
        brlt    FiveOn
        ori     temp, 0x10

FiveOn: cp      PWMCount, ocr_6       // Ist der Grenzwert für Led 6 erreicht
        brlt    SetBits
        ori     temp, 0x20

SetBits:                              // Die neue Bitbelegung am Port ausgeben
        out     PORTB, temp

        reti

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> out     DDRB, temp
> out     PORTB, temp

Wie gesagt, out benötigt die IO-Adresse.

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

Bewertung
0 lesenswert
nicht lesenswert

Autor: skua (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein

.org 0
       rjmp main

könnte helfen.

Autor: Aike T. (biertrinker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wie gesagt, out benötigt die IO-Adresse.

Ja, das stimmt, so weit hatte ich das gestern noch nicht durchdrungen, 
das hätte mir auffallen sollen.

Jörg Wunsch wrote:
> Siehe auch Beitrag "Re: avr-tutorial timer, interruptvektor ist nicht definiert"

der Beitrag hilft wirklich weiter. Jetzt habe ich glaube ich deutlich 
besser verstanden, wie das alles zusammen hängt.

Interessant ja vor allem auch für das Zusammenspiel zwischen C und ASM 
bestandteilen eines gemischten Programms.

viele Dank!

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.