Das STK200 ist eine Experimentierplatine, auf der sich neben Stecksockeln für alle Ports auch eine LED- und eine Taster-Reihe befinden. Die Platine lässt sich die Platine über das mitgelieferte Kabel einfach an den Parallelport anschließen, um ihn mit der mitgelieferten Software zu programmieren - natürlich handelt es sich nur um Software für Windows. Aber es ist durchaus möglich, das STK200 auch unter Linux einzusetzen, und Programme für die AT90Sxxxx-Controller zu entwickeln.
Die elementarsten Software-Komponenten eines Entwicklungssystems sind ein Assembler, ein STK200-kompatibler ISP-Programmierer, und vielleicht noch ein C-Compiler. Die Installation dieser - kostenlosen - Linuxsoftware wird im Folgenden beschrieben.
[user@totekuh]:downloads/> wget http://www.blabla.com/ava-0.3b-0815.src.tar.gz [user@totekuh]:downloads/> tar xzvf ava-0.3b-0815.src.tar.gz [user@totekuh]:downloads/> cd ava-0.3b-0815 [user@totekuh]:ava-0.3b-0815/>Im neuen Verzeichnis ./ava-0.3b findet sich eine Datei INSTALL, in die man auf jeden Fall einen Blick werfen sollte. Danach wechseln wir ins src-Verzeichnis, um im Makefile Anpassungen bei den Zielverzeichnissen für die Installation vorzunehmen. Wichtig sind dabei diese Einträge:
# Directory Setup AVA_BIN = /usr/local/bin AVA_LIB = /usr/local/lib/uTools/avaMan beachte, dass AVA_BIN nur ganz unten im Makefile Verwendung findet in der Zeile:
cp ava $(AVA_BIN)Gibt man bei AVA_BIN ein nicht existierendes Verzeichnis an, so wird ava auf den Namen des (nicht existierenden) Verzeichnisses kopiert - unter Umständen kann also ava mit dem Namen eines Verzeichnisses enden. Man kann nun entweder selbst sicherstellen, dass alle Zielverzeichnisse existieren, oder man passt das Makefile entsprechend an:
# Directory Setup AVA_DIR = /home/hansolo/bin/avr_asm AVA_BIN = $(AVA_DIR)/ava AVA_LIB = $(AVA_DIR)/libAchtung, vor den Einträgen MUSS ein Tabulator stehen! Das gilt auch für den install-Block, bei dem wir die oberste makedir-Zeile hinzufügen:
install: mkdir -p $(AVA_DIR) mkdir -p $(AVA_LIB) rm -r $(AVA_LIB) cp -r ../avalib $(AVA_LIB) cp ava $(AVA_BIN)Nun können wir das Programm kompilieren und installieren:
[user@totekuh]:src/> make [user@totekuh]:src/> make install (ggf. als root)Um das Programm bequem aufrufen zu können, sollten wir einen Link in einem Verzeichnis des PATH anlegen, der auf das Binary ava zeigt, oder den PATH anpassen. Wie man der ava-Dokumentation entnehmen kann, muss ava zweimal aufgerufen werden, um ein Assembler-Programm in eine HEX-Datei für den ISP-Prommer umzuwandeln. Dazu kommen noch ein paar lästige Parameter - ein hübsches Perl-Script, siehe Listing 1, nimmt uns die lästige Tipparbeit ab:
Listing 1: Perlscript für den Assembleraufruf |
#!/usr/bin/perl -w # Dieses Script startet den ava-Assembler:# Aufruf: avrassembler source.s $ava = "/usr/local/bin/avr_asm/ava"; if ($#ARGV != 0) { print "\nUsage: avrassembler source.s\n"; print "\nHilfe zu ava: $ava -h\n\n"; exit 1; } $basename = substr($ARGV[0],0,rindex($ARGV[0],".")); $asmopts = "--intel -favr_noendianbug"; $linkopts = "$asmopts --multiple-output-files"; print "Assembliere...\n"; system("$ava $asmopts $basename.s"); print "Linke...\n"; system("$ava $linkopts $basename.o -o $basename.hex"); |
Wer mag, kann auch die Programm-Dokumentation von ava installieren (siehe INSTALL-Datei). Sie liegt als TeX- und Postscriptdatei vor. Die Ansicht der ersteren setzt ein installiertes TeX-System voraus, die der zweiten Datei einen guten PS-Viewer. Ich habe bei mir die Datei ava.ps mit latex2html nach html konvertiert, da der Text im WebBrowser wesentlich besser zu lesen ist. Wer sich dafür interessiert, kann es sich die HTML-Doku bei [3] downloaden.
Listing 2: Testprogramm |
; Testprogramm: "Hübsch blinkende LEDs" ;* Ziel MCU : AT90S8515 #arch AT90S8515 #include "avr.inc" ; Sprungtabelle mit RESET-Vektor: rjmp RESET ;Reset Handle reti reti reti ;***** Code RESET: ldi R16,low(RAMEND) ; STACK-PTR einstellen: out SPL,R16 ldi R16,high(RAMEND) out SPH, R16 ldi r16, $ff ; PortB -> Ausgang out DDRB, r16 ldi r20, $00 ; Startwert f. Zaehler forever: ; ============================= ; Warteschleifen-Generator ; 1999994 Zyklen: ; ----------------------------- ; Warte 1999980 Zyklen: ldi r17, $29 WGLOOP1: ldi r18, $47 WGLOOP2: ldi r19, $E4 WGLOOP3: dec r19 brne WGLOOP3 dec r18 brne WGLOOP2 dec r17 brne WGLOOP1 ; ----------------------------- ; Warte 12 Zyklen: ldi r17, $4 WGLOOP6: dec r17 brne WGLOOP6 ; ----------------------------- ; Warte 2 Zyklen: nop nop ; ============================= ; Ausgabe des Wertes r20 auf Port B (invertiert, 0 = LED AN): mov r18, r20 ; 1 Takt, Zaehlerstand holen: com r18 ; 1 Takt, Zaehlerstand invertieren: out PORTB, r18 ; 1 Takt, r18 -> PORT B (LEDs): inc r20 ; 1 Takt, Zaehlerstand erhoehen: rjmp forever ; 2 Takte |
Mit den Zeilen
#arch AT90S8515 #include "avr.inc"wird dem ava-Assembler mitgeteilt, für welchen Chip der Code erzeugt werden soll. Es empfiehlt sich, einen Blick in das lib-Verzeichnis von ava zu werfen - dort finden sich avr.inc und alle chipspezifischen Includes.
Das Initialisieren des STACKS hätten wir uns u.U. sparen können, ist aber notwendig, sobald wir es mit Sprüngen in Unterprogramme zu tun bekommen.
Der Code ab der Marke forever: wird in endloser Wiederholung ausgeführt. Die Warteschleife habe ich mir mit einem selbstgeschriebenen Perl-Script erzeugt, dass der geneigte Leser unter der Url [2] findet. Natürlich kann jeder auch selbst versuchen, passende Werte für die Schleifeniteration zu finden. Viel Spaß dabei! ;-). Die Warteschleife ist ingesamt 1'999'994 Taktzyklen lang, zusammen mit den 6 Taktzyklen der Befehle zum Ausgeben des Zählerstandes ergibt sich für die forever-Schleife eine Taktlänge von 2'000'000 Taktzyklen - bei 4MHz leuchtet also die rechteste LED pro Sekunde einmal auf und erlischt wieder.
Die Übersetzung des Programms erfolgt entweder von Hand durch Aufruf von ava mit allen notwendigen Optionen:
ava --intel -favr_noendianbug counter.s ava --intel -favr_noendianbug --multiple-output-file counter.o -o counter.hexoder einfacher mit dem Perl-Script aus Listing 1:
avrassembler counter.sWenn alles fehlerfrei lief, finden wir nun im aktuellen Verzeichnis eine Datei counter.hex - das ist die hex-Datei, die wir in den AT90S8515 programmieren werden, sobald die ISP-Software installiert ist.
[user@totekuh]:downloads/> tar xzvf uisp-0.2b-1026.src.tar.gz [user@totekuh]:downloads/> cd uisp-0.2b [user@totekuh]:uisp-0.2b/> less INSTALL [user@totekuh]:uisp-0.2b/> cd src [user@totekuh]:src/>Laut INSTALL-Datei reicht ein einfacher Aufruf von make und make install, um uisp zu compilieren. Zumindest auf meinem Suse6.3-System war es damit nicht getan. Es kommt eine Fehlermeldung mit "LP_PSTROBE". Auf meinem System rührt der Fehler daher, dass die includierte Headerdatei sys/lp.h zwar eine Definition von LP_PSTROBE enthält - allerdings in einem Block, der der Kernelcompilierung vorbehalten ist. Meine Problemlösung besteht darin, die Datei /usr/include/linux/lp.h lokal ins uisp-Sourcedirectory zu kopieren (mein-lp.h), und die Zeile
#ifdef __KERNEL__sowie ganz unten die Zeile:
#endifzu löschen. Diese veränderte Includedatei mein_lp.h includiere ich dann in DAPA.C anstelle der sys/lp.h:
#include <linux/lp.h>Durch:
#include "mein_lp.h"Nun sollte die Compilierung fehlerfrei klappen:
[user@totekuh]:src/> make [user@totekuh]:src/> su Passwort: ********* [user@totekuh]:src/> make install ; exitDamit wird uisp im Verzeichnis /usr/local/bin installiert. Soll in ein anderes Zielverzeichnis installiert werden, so muss man halt des Makefile entsprechend anpassen.
Der ISP-Programmierer uisp bietet nur vier interessante Optionen: erase, verify, program und segment. Mehr Funktionen bieten die avr1-Tools, deren Installation im folgenden Kapitel behandelt werden:
[user@totekuh]:downloads/> tar xzvf avr1-0.50.tar.gz [user@totekuh]:downloads/> tar xzvf stk200-1.tar.gz
[user@totekuh]:downloads/> cp stk200/libstk200.* avr1-0.50/ [user@totekuh]:downloads/> cd avr1-0.50 [user@totekuh]:avr1-0.50/> cp libstk200.c libavr1.c [user@totekuh]:avr1-0.50/> makeNach erfolgreicher Compilierung finden sich im Unterverzeichnis ./bin/ die fertigen Programme. Am besten kopiert man sie als root in das Verzeichnis /usr/local/bin. Das README von avr1 gibt leider nicht viele Informationen über die Funktion der Programme her, allerdings folgt die Namensgebung einem klaren Schema:
avrlock | Lockbits setzen usw. |
avreep | EEPROM programmieren |
avreer | EEPROM lesen (read) |
avrerase | Flash löschen |
avrid | Controller-ID auslesen |
avrprg | Flash programmieren |
avrrd | Flash auslesen |
Auf einem Heimrechner, auf man man eigentlich nur selbst arbeitet, ist das Setzen des SUID-Flags der einfachste Weg. Dazu stellt man sicher, dass das entsrechende Programm dem user root und der gruppe root gehört, für alle User ausführbar ist, und setzt dann das s-Flag. Wie gesagt, auf einem Multiusersystem ist das keine gute Lösung, da dann JEDER Benutzer - absichtlich oder versehentlich - die Programmierprogramme starten kann.
Setzen des SUID-Flags (Programm wird mit der userid des Besitzers (root) ausgeführt):
su - Passwort: ******** chown root:root /usr/local/bin/avrprg chmod a+rx /usr/local/bin/avrprg chmod u+s /usr/local/bin/avrprg exit
Damit ist die Installation der ISP-Software abgeschlossen. Testen können wir die Funktion am einfachsten mit dem Programm avrid, das die ID des Controllers ausliest. Dazu starten wir avrid mit root-Rechten, bei eingeschaltetem betriebsbereitem STK200. Die Ausgabe auf dem Bildschirm sollte sinnvoll aussehen :-). Sollte das nicht klappen, müssen wir uns auf den Weg der Fehlersuche begeben: Falls eine Meldung zum Thema "IOPERM" kommt, dann haben wir versucht, den Parallelport ohne root-Recht zu benutzen. Überprüfen Sie auch, ob das STK200 wirklich an ist, und der Stecker wirklich im Parallelport steckt. Verwenden Sie Port 2 statt 1, so müssen Sie in mein_lp.h die Portadresse anpassen und die Programme neu compilieren.
Als nächstes werden wir unseren Zähler aus dem Kapitel über den Assembler in den Controller programmieren, allergings nicht ohne vorher das Programm, dass sich bereits im Controller befindet, auszulesen und zu sichern. Das ist dann gleichzeitig noch ein Funktionstest, bei dem das aktuelle Programm im Controller nicht zerstört werden kann. Mit dem folgenden Kommando lesen wir das Programm aus dem FLASH-Speicher des Controllers im STK200 aus:
avrrdbzw.:
[user@totekuh]:.../> avrrd >sicherheitskopie.lstSollte auch hier kein Fehler aufgetreten sein, können wir guten Mutes unseren assemblierten Zähler in den Controller uploaden:
[user@totekuh]:.../> avrprg -f counter.hex.flash
Nach einem erfolgreichem Upload wird übrigends automatisch ein Controller-RESET durchgeführt, und unser Programm startet mit lustigem Geblinke.
Das Einarbeiten der jeweiligen Patches ist eine simple Sache, die so funktioniert:
[user@totekuh]:.../> tar xIvf binutils-2.9.5.0.13.tar.bz2 [user@totekuh]:.../> cd binutils-2.9.5.0.13 [user@totekuh]:binutils-2.9.5.0.13/> gzip -dc ../binutils-2.9.5.0.13-avr-patch-1.1.gz | patch -p1Das "-dc" bedeutet "auspacken nach STDOUT", die Ausgabe wird direkt zu "patch -p1" gepipet. Man sollte darauf achten, wirklich "patch" und nicht "path" einzutippen - zumindest bei mir verschwindet das "c" immer auf geheimnisvolle Weise... ;-)
Die weiteren Installationsschritte für die binutils sind:
[user@totekuh]:binutils-.../> configure --target=avr [user@totekuh]:binutils-.../> make [user@totekuh]:binutils-.../> make install (als root)Zu den avr-binutils zählen diverse Programme wie avr-as (Assembler), avr-ld (Linker), und weiter. Diese werden vom Compiler, den wir gleich bauen, aufgerufen, um den AVR-Binärcode zu erzeugen. Den Compiler entpacken, patchen und compilieren wir (fast) äquivalent zu den binutils:
[user@totekuh]:.../> tar xzvf gcc-core-2.95.2.tar.gz [user@totekuh]:.../> cd gcc-core-2.95.2 [user@totekuh]:gcc-2.95.2> gzip -dc ../gcc-core-2.95.2-avr-patch-1.1.gz | patch -p1 [user@totekuh]:gcc-2.95.2> configure --target=avr [user@totekuh]:gcc-2.95.2> make [user@totekuh]:gcc-2.95.2> make install (als root)Die Compilierung der 41MB kann je nach Computersystem etwas Zeit in Anspruch nehmen. Wenn, wie zu erwarten ist, die Compilierung fehlerfrei verlaufen ist, steht ab sofort der C-Compiler avr-gcc zur Verfügung.
Bevor wir ein erstes C-Programm compilieren, sollten wir noch die aktuelle avr-libc installieren - das geht schnell und unkompliziert:
[user@totekuh]:.../> tar xzvf avr-libc-20000201.tar.gz [user@totekuh]:.../> cd avr-libc-20000201 [user@totekuh]:avr-libc-.../> cd src [user@totekuh]:src/> make [user@totekuh]:src/> make install (als root)
Listing 3: Simples Makefile |
.c.o: avr-gcc -mmcu=at90s8515 -O -c $< ispload: test2.rom uisp -dstk200 --erase --upload --verify if=test2.rom test2.rom: test2.out avr-objcopy -O srec test2.out test2.rom test2.out: test2.o avr-gcc test2.c -o test2.out |
Mit dem Makefile aus Listing 3 können wir recht einfach eine Datei test2.c compilieren. Um Makefiles für andere Sourcefiles zu erstellen, passen wir Listing 3 entweder an, oder wir schreiben uns z.B. mit Perl einen Makefile-Generator, wobei wir uns an Listing 1 orientieren können. Als Tip mag der Hinweis genügen, dass ein "\t" in der print-Anweisung einem Tabulatorzeichen entspricht. Aber vielleicht ist es auch einfacher, ein kleines Bash oder Perlscript zu schreiben, dass alle notwenigen Kommandos in der richtigen Reihenfolge startet, wenn man ihm den Namen des Quelltextes übergibt.
Als erstes Testprogramm für avr-gcc reicht jedes einfache C-Programm (test1.c), wie z.B. das aus Listing 4:
Listing 3: Simples Makefile |
main() { int i; for (i = 0; i <= 100; i++) { /* Zaehlt von 1..100 */ ; } } |
Da es kaum Sinn macht, dieses Programm in den Controller zu schreiben, reicht vorerst ein
avr-gcc test1.c -o test1.outum zu sehen, ob der Compiler läuft. Wenn alles geklappt hat, sollte jetzt eine neue Datei test1.out existieren - sie enthält ein statisch gelinktes AVR-Binary. Mit dem binutil avr-objdump kann man den Inhalt disassemblieren:
[user@totekuh]:.../> avr-objdump -d test1.outDie Ausgabe auf dem Bildschirm bestärkt mich persönlich in der Meinung, dass man so einen überschaubaren Controller doch besser in Assembler programmiert... ;-)
Bleibt dann nur noch zu hoffen, dass es nicht zu lange dauert, bis es einen AVR-Perlcompiler gibt... ;-)
Autorinfo: | Der Autor studiert Technische DV an der Uni Siegen. Aktuelles Lieblingsprojekt: Sein Abalone-Server (Perl,PHP3,JavaScript). |