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
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
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
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.
OVF0addr ist zwar in m8def.inc aber nicht in avr/io.h definiert. org nicht verwenden ist unsinn.
> ....... // 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 ;-)
@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!
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
Versuch mal das vor #include <avr/io.h> #define _ASSEMBLER_ 1 #define __SFR_OFFSET 0 #include <avr/io.h>
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
@Stefan: Jep, das hilft, aber warum? @holger: kann da keinen Unterschied bemerken, was soll das bewirken? so, nun bleibt dieses Problem hier über:
1 | 17 .org 0x0000 |
2 | 18 rjmp main // Reset Handler |
3 | 19 .org 0x007 |
4 | 20 rjmp timer0_overflow // Timer Overflow Handler |
führt zu: ../test.S:18: Error: odd address operand: 9
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.
Aike Terjung wrote: > so, nun bleibt dieses Problem hier über: > >
1 | 17 .org 0x0000 |
2 | > 18 rjmp main // Reset Handler |
3 | > 19 .org 0x007 |
4 | > 20 rjmp timer0_overflow // Timer Overflow Handler |
5 | > |
> > führt zu: > > ../test.S:18: Error: odd address operand: 9 Vermutlich arbeitet der gcc-as mit Byte-Adressen.
Versuchs mal mit .org 0x00E rjmp timer0_overflow // Timer Overflow Handler Vieleicht zählt der ja nicht wortweise.
> ../test.S:18: Error: odd address operand: 9
sagte ja schon das 0x07 sicher nicht stimmen kann, weil 0x07 nicht even
ist.
Cheers
Ritchie
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
1 | #include <avr/io.h> /* das gibt den Controllertyp an */ |
2 | |
3 | #define temp r16 |
4 | |
5 | #define PWMCount r17 |
6 | |
7 | #define ocr_1 r18 // Helligkeitswert Led1: 0 .. 127 |
8 | #define ocr_2 r19 // Helligkeitswert Led2: 0 .. 127 |
9 | #define ocr_3 r20 // Helligkeitswert Led3: 0 .. 127 |
10 | #define ocr_4 r21 // Helligkeitswert Led4: 0 .. 127 |
11 | #define ocr_5 r22 // Helligkeitswert Led5: 0 .. 127 |
12 | #define ocr_6 r23 // Helligkeitswert Led6: 0 .. 127 |
13 | |
14 | .org 0x12 |
15 | rjmp timer0_overflow // Timer Overflow Handler |
16 | |
17 | .global main |
18 | main: |
19 | ldi temp, lo8(RAMEND) |
20 | out _SFR_IO_ADDR(SPL), temp |
21 | ldi temp, hi8(RAMEND) |
22 | out _SFR_IO_ADDR(SPH), temp |
23 | |
24 | ldi temp, 0xFF // Port B auf Ausgang |
25 | out DDRB, temp |
26 | |
27 | ldi ocr_1, 0 |
28 | ldi ocr_2, 1 |
29 | ldi ocr_3, 10 |
30 | ldi ocr_4, 20 |
31 | ldi ocr_5, 80 |
32 | ldi ocr_6, 127 |
33 | |
34 | ldi temp, 0b00000001 // CS00 setzen: Teiler 1 |
35 | out _SFR_IO_ADDR(TCCR0), temp |
36 | |
37 | ldi temp, 0b00000001 // TOIE0: Interrupt bei Timer Overflow |
38 | out _SFR_IO_ADDR(TIMSK), temp |
39 | |
40 | sei |
41 | |
42 | loop: rjmp loop |
43 | |
44 | timer0_overflow: // Timer 0 Overflow Handler |
45 | inc PWMCount // den PWM Zähler von 0 bis |
46 | cpi PWMCount, 128 // 127 zählen lassen |
47 | brne WorkPWM |
48 | clr PWMCount |
49 | |
50 | WorkPWM: |
51 | ldi temp, 0b11000000 // 0 .. Led an, 1 .. Led aus |
52 | |
53 | cp PWMCount, ocr_1 // Ist der Grenzwert für Led 1 erreicht |
54 | brlt OneOn |
55 | ori temp, 0x01 |
56 | |
57 | OneOn: cp PWMCount, ocr_2 // Ist der Grenzwert für Led 2 erreicht |
58 | brlt TwoOn |
59 | ori temp, 0x02 |
60 | |
61 | TwoOn: cp PWMCount, ocr_3 // Ist der Grenzwert für Led 3 erreicht |
62 | brlt ThreeOn |
63 | ori temp, 0x04 |
64 | |
65 | ThreeOn:cp PWMCount, ocr_4 // Ist der Grenzwert für Led 4 erreicht |
66 | brlt FourOn |
67 | ori temp, 0x08 |
68 | |
69 | FourOn: cp PWMCount, ocr_5 // Ist der Grenzwert für Led 5 erreicht |
70 | brlt FiveOn |
71 | ori temp, 0x10 |
72 | |
73 | FiveOn: cp PWMCount, ocr_6 // Ist der Grenzwert für Led 6 erreicht |
74 | brlt SetBits |
75 | ori temp, 0x20 |
76 | |
77 | SetBits: // Die neue Bitbelegung am Port ausgeben |
78 | out PORTB, temp |
79 | |
80 | reti |
> 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!
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.