Hallo,
ich habe mir eine kleine Demo mit der avr-libc zusammengebastelt und es
funktioniert auch ganz gut, solange ich keine Variablen definiere und
darauf zugreife.
Das Problem liegt vermutlich an meinem selbstgestrickten Makefile und
eben wenig Kenntnis was die avr-libc (und auch Assembler) betrifft.
Man findet bei denen auf der Seite zwar eine Menge Erklärungen und das
Ganze gefällt mir auch sehr gut. Aber leider gibt es keine lauffähige
Assembler-Demo, die auch ein Makefile beinhaltet.
Das Assembler Beispiel, welches vorgestellt wird besteht nur aus einer
Quelldatei. Ausserdem wird dabei auch auf die Definition von Variablen
verzichtet.
Da ich mich hier erst einarbeite, würde ich mich sehr freuen, wenn mir
jemand eine kleine Demo zur Verfügung stellt (Zugriff auf Variablen,
inclusive Makefile).
Vielen Dank schonmal, Gruß Peter
Peter schrieb:> Wenn ich> rcall data_init>> in main einfüge, dann geht die Led nicht mehr an / der Controller stürzt> ab.>> Bitte einmal drüberschauen, Gruß Peter
Du hast Stack Pointer nicht auf einen bestimmten Wert gesetzt, rufst
aber eine Routine mit rcall auf:
Vielen Dank für Eure Hilfe! Genau das wars.
Ich komme halt von der C-Schiene und da ist man darauf eingestellt
einfach alles in Funktionen zu verlegen.
Bei Assembler kann man das auch machen, aber natürlich erst nach der
Initialisierung das Stacks.
Danke und Gruß Peter
Prinzipiell könntest du auch den init-Code der avr-libc verwenden, indem
du __init anspringst anstatt main. Dadurch würde stach_init und
ram_init entfallen. Der Start-Code der avr-libc springt am Ende nach
main, so dass du nix weiter tunb musst.
Falls du Funktionen der avr-libc verwenden willst brauchst du die
Bibliotheken, die in deinem Link-Aufruf nicht enthalten sind. Am
einfachsten bekommst du den Bibliothekssupport, indem avr-gcc als
Linker-Treiber verwendet wird anstatt avr-ld händisch zu verwenden.
Das wird dann auch gegen die libgcc linken, die auch Teile des
Startup-Codes anthält, nämlich Init von .data und .bss. avr-gcc linkt
aber nur gegen die benötigten Funktionen, wenn sie tatsächlich gebraucht
werden, d.h. avr-gcc gibt ein ".global __do_copy_data" aus falls etwas
in .data ist und __do_clear_bss falls etwas in .bss oder COMMON ist.
Der Startup-Code der avr-libc bringt auch eine Vektortabelle, die dann
nicht mehr händisch und Device-abhängig geschrieben werden muss.
Johann L. schrieb:> Prinzipiell könntest du auch den init-Code der avr-libc verwenden, indem> du __init anspringst anstatt main. Dadurch würde stach_init und> ram_init entfallen. Der Start-Code der avr-libc springt am Ende nach> main, so dass du nix weiter tunb musst.
Das würde ich ja auch gerne. Aber für reinen Assembler findet man auf
der libc-Seite nur Code-Snippets und kein Demo-Projekt mit Makefile und
Quellcode.
Wie meinst Du das mit __init? Wenn ich das statt main an Adresse 0
schreibe, dann bekomme ich eine 'undefined reference'. Was muss ich
einbinden und wie?
Johann L. schrieb:> Falls du Funktionen der avr-libc verwenden willst brauchst du die> Bibliotheken, die in deinem Link-Aufruf nicht enthalten sind. Am> einfachsten bekommst du den Bibliothekssupport, indem avr-gcc als> Linker-Treiber verwendet wird anstatt avr-ld händisch zu verwenden.
Wie mach ich das am einfachsten?
Johann L. schrieb:> Der Startup-Code der avr-libc bringt auch eine Vektortabelle, die dann> nicht mehr händisch und Device-abhängig geschrieben werden muss.
Finde ich ganz klasse. Aber wie binde ich das alles zusammen?
Kannst Du mir nicht ein einfaches Projekt mit Makefile hochladen?
Das wäre eine tolle Hilfe.
Gruß Peter
Die .file, .size und .type Direktiven sind hilfreich beim Debuggen oder
mit avr-nm, avr-size etc. aber wirklich notwendig sind sie nicht. Die
.global Direktiven werden nur gebraucht, wenn die Applikation in mehrere
Module aufgespalten werden soll und aus anderen Modulen auf die
Variablen zugegriffen wird.
Der Code kann also vereinfacht werden zu:
1
.text
2
.global main
3
main:
4
loop:
5
rjmp loop
6
7
.data
8
9
y: .word 1
10
11
.section .bss
12
13
x: .zero 2
14
15
.global __do_copy_data ;; weil .data nicht leer ist
16
.global __do_clear_bss ;; weil .bss nicht leer ist
Die Datei kann als main.S oder main.sx benannt werden und mit
1
$ avr-gcc main.S -save-temps -c
übersetzt werden zu main.o. Das save-temps bewirkt, dass die
Zwischendatei main.s behalten wird. Das ist das, was nach Auflösung der
C-Makros und C-Includes von main.S übrig bleibt.
Falls ISRs erstellt werden sollen, dann z.B. so:
1
#include <avr/io.h>
2
3
.text
4
5
.global INT0_vect
6
INT0_vect:
7
reti
8
9
.global __vector_default
10
__vector_default:
11
panic:
12
wdr
13
rjmp panic
Der Startup-Code der avr-libc ist so geschrieben, dass INT0_vect
automatisch in die Vektortabelle eingetragen wird, händisch muss da nix
mehr gemacht werden.
An einigen Stellen werden ein paar Bytes verschwendet, z.B. wird main
per [r]call aufgerufen und danach gemäß C-Standard exit etc. Falls das
wirklich stören sollte kann man das auch umgehen, aber für ein einfaches
Einsteige-Beispiel ist das i.d.R. nicht der Fall.
Peter schrieb:> Johann L. schrieb:>> Prinzipiell könntest du auch den init-Code der avr-libc verwenden, indem>> du __init anspringst anstatt main. Dadurch würde stach_init und>> ram_init entfallen. Der Start-Code der avr-libc springt am Ende nach>> main, so dass du nix weiter tunb musst.>> Das würde ich ja auch gerne. Aber für reinen Assembler findet man auf> der libc-Seite nur Code-Snippets und kein Demo-Projekt mit Makefile und> Quellcode.>> Wie meinst Du das mit __init? Wenn ich das statt main an Adresse 0> schreibe, dann bekomme ich eine 'undefined reference'. Was muss ich> einbinden und wie?
Mein Fehler. Es genügt eine .global main zu schreiben. Der Rest
erledigt die avr-libc und der Startup-Code.
> Johann L. schrieb:>> Falls du Funktionen der avr-libc verwenden willst brauchst du die>> Bibliotheken, die in deinem Link-Aufruf nicht enthalten sind. Am>> einfachsten bekommst du den Bibliothekssupport, indem avr-gcc als>> Linker-Treiber verwendet wird anstatt avr-ld händisch zu verwenden.>> Wie mach ich das am einfachsten?
Im Makefile LD zu avr-gcc setzen anstatt zu avr-ld. Wichtig ist dabei,
dass auch beim Linken -mmcu= mitgegeben wird.
> Johann L. schrieb:>> Der Startup-Code der avr-libc bringt auch eine Vektortabelle, die dann>> nicht mehr händisch und Device-abhängig geschrieben werden muss.>> Finde ich ganz klasse. Aber wie binde ich das alles zusammen?
avr-gcc anstatt avr-ld.
> Kannst Du mir nicht ein einfaches Projekt mit Makefile hochladen?
Ich hab weder Projekte nocht entsprechende Makefiles, ich kann dir aber
sagen wie's geht.
Über o-Files zu gehen ist bei kleinen Projekten nicht wirklich
notwendig, man kann auch den ganzer Rumms mit einem einzigen Aufruf
übersetzen, also z.B.
avr-gcc ruft denn den richtigen "Compiler" für jedes Modul auf (as für
main.S, cc1 + as für cdatei.c, etc) und gibt die ganzen o-Dateien dann
an collect2 und ld zum Linken.
Natürlich geht auch, zuerst o-Dateien per -c zu erhalten und die dann in
einem Linkschritt mit den Bibliotheken zusammenzubacken so wie es in
deinem Makefile gemacht wird.
Aber ich hab bis heute noch kein Projekt gesehen, wo es hilfreich oder
gar notwendig war, ld händisch aufzurufen.
Hallo Johann L.,
das Beispiel und die Erklärungen von Dir sind genau was ich gesucht
habe. Vielen Dank dafür.
Ich habe jetzt beide Teile (ISR und main) zusammengefasst und es
funktioniert hervorragend. Auch das Initialisieren der Variablen klappt
nun.
Dazu kann man dann das Makefile der C-Demo verwenden.
Sehr Klasse. Ich bin wirklich froh, dass ich das jetzt mal habe und mir
keine Gedanken mehr machen muss, ob denn der Linker auch wirklich alles
an den richtigen Platz schreibt.
Eine Frage habe ich noch:
Ich habe ein paar Subroutinen in eine 'misc.S' ausgelagert, welche ich
dann am Ende der main.S einfach per
1
#include "misc.S"
einbinde.
Wenn ich das so mache, dann muss ich auch im Makefile nichts weiter für
die 'misc.S' hinzufügen.
Ist das ein gängiges Vorgehen (Stichwort: verschiedene Module)? Oder
kann man das geschickter lösen?
MFG Peter
Peter schrieb:> Ich habe ein paar Subroutinen in eine 'misc.S' ausgelagert,> welche ich dann am Ende der main.S einfach per>
1
#include "misc.S"
> einbinde.>> Wenn ich das so mache, dann muss ich auch im Makefile nichts weiter für> die 'misc.S' hinzufügen.
Aber nur, weil dein Makefile all von clean abhängig macht, d.h. bei
jedem Build werden alle generierten Dateien gelöscht anstatt nur
diejenigen Dateien neu zu erzeugen, die wirklich erzeugt werden müssen.
Zum Beispiel hängt die main.o jetzt nicht mehr nur von main.S ab,
sondern auch von misc.S.
> Ist das ein gängiges Vorgehen (Stichwort: verschiedene Module)?
Nein.
Wenn es wirklich nur ein Modul ist, dann braucht es nicht includet zu
werden und es genügt, dagegen zu linken. Wie bereits oben erklärt
müssen die Symbole, die außerhalb des definierenden Moduls verwendet
werden, per .global oder .globl global gemacht werden.