Für die ASM Programmierung kann man an Stelle von AVRStudio auch den Assembler von GCC (AS) benutzen. Dieser läuft z.B. auch unter Linux. Anders als der Atmel Assembler, der direkt ein .hex oder .bin File erzeugt, wird beim GNU Assembler wie beim C-Compiler erst ein Objektfile erzeugt und dann der Linker aufgerufen, um das .hex-file zu erzeugen. Ein Grund den GNU Assembler zu nutzen ist es, wenn man C und ASM Code mischen will, der ASM-Teil aber zu lang ist, um dafür Inline-Assembler zu nutzen.
Die Syntax unterscheidet sich etwas vom Atmel Assembler, vor allem bei den Direktiven.
Eigentlich ist es ein normales GCC-Project, nur dass kein C-Programm da ist. Daher muss die Definition von der "main"-Funktion, die ja obligat ist, im Assembler erfolgen.
#include <avr/io.h> ; das definiert die SFRS usw., je nach Controllertyp .text ; was nun folgt, gehört in den FLASH-Speicher .global main ; main ist auch in anderen Modulen bekannt main: ; zu 'main' wird nach Reset hingesprungen ;.... eigene befehle Hauptschleife: ; ein Sprunglabel ;.... eigene befehle rjmp Hauptschleife ; immer wiederholen
Und das wars auch schon.
Es bietet sich an, GCC aufzurufen und ihn die Arbeit an Assembler und Linker delegieren zu lassen. Standard Datei-Erweiterung dazu ist *.S
:
avr-gcc -o beispiel.elf -mmcu=atmega8 beispiel.S
Falls die Plattform Ärger mit Groß/Kleinschreibung macht wie Windows, dann geht auch
avr-gcc -x assembler-with-cpp -o beispiel.elf -mmcu=atmega8 beispiel.ss
GCC legt die Vektortabelle selbständig an und nimmt die richtigen Einträge vor. Dies gilt auch für den RESET-Vektor. Bevor zu main
gesprungen wird, wird noch eine kleine Initialisierung gemacht: Stackpointer setzen und Y-Reg darauf initialisieren, um es als Framepointer nutzen zu können.
Falls man eine IRQ bedienen möchte, schreibt man
.text .global SIG_OVERFLOW0 ; alternativ: __vector_9 schreiben, wenn 9 die IRQ-Nummer ist ; SIG_XXX ist ein #define aus avr/ioxxxx.h ; das durch #include <avr/io.h> mitincludet wird SIG_OVERFLOW0: ; dito ; ISR-Code reti
Dadurch wird an der richtigen Stelle der Vektortabelle ein Eintrag veranlasst.
Ein Disassemble des Maschinencodes sieht dann so aus (Vectab gekürzt):
Disassembly of section .text: 00000000 <__vectors>: 0: 12 c0 rjmp .+36 ; 0x26 2: 18 c0 rjmp .+48 ; 0x34 4: 17 c0 rjmp .+46 ; 0x34 ... 12: 11 c0 rjmp .+34 ; 0x36 ... 00000026 <__ctors_end>: 26: 11 24 eor r1, r1 28: 1f be out 0x3f, r1 ; 63 2a: cf e5 ldi r28, 0x5F ; 95 2c: d4 e0 ldi r29, 0x04 ; 4 2e: de bf out 0x3e, r29 ; 62 30: cd bf out 0x3d, r28 ; 61 32: 02 c0 rjmp .+4 ; 0x38 00000034 <__bad_interrupt>: 34: e5 cf rjmp .-54 ; 0x0 00000036 <__vector_9>: 36: 18 95 reti 00000038 <main>: 38: ff cf rjmp .-2 ; 0x38