Einrichten der AVR-C-Programmierung unter Ubuntu

Dieter Holzhäuser
http://www.system-maker.de
E-Mail: [email protected]
30.05.2011
Überarbeitung 27.02.2013
Überarbeitung 10.03.2013
Einrichten der AVR-C-Programmierung unter
Ubuntu-Linux 12.04
Ein Erfahrungsbericht
Vorbemerkung
Der Auslöser für die vorliegende Überarbeitung war ein Problem bei den fertigen deb-Paketen, die
ich bisher für die Installation von avr-gcc und avrdude benutzt habe. Bei Atmel habe ich einen um
Längen besseren Ersatz gefunden, und zwar eine Toolchain mit hervorragender Dokumentation,
die sich durch einfaches Entpacken installieren lies. Das Paket avrdude wird unabhängig davon
aus dem Ubuntu Software-Center installiert.
Ich werde zukünftig Programme nur noch mit Code::Blocks entwickeln. Daher ist der Editor gedit
als Mini-Entwicklungsumgebung in diesem Artikel kein Thema mehr.
Es gibt also Gründe genug für eine Überarbeitung.
Worum es geht
Ich schreibe C-Programme, und zwar hauptsächlich für den Mikrocontroller ATmega32 aus der
AVR-Familie von Atmel. Die ganze Entwicklung findet auf dem PC statt. Weil der C-Code in den
Maschinencode des Mikrocontrollers übersetzt („cross“-compiliert) wird, muss das Programm in
den Speicher des Mikrocontrollers übertragen werden, denn nur dort kann es laufen. Zwecks
Übertragung sind PC und Mikrocontroller durch einen Programmieradapter verbunden.
Ich verwende den AVR ISP mk II von Atmel (siehe Bild oben), der bei Reichelt ( www.reichelt.de )
für etwa 40 € zu haben ist. Er ist an eine USB-Schnittstelle des PC und an das SPI (Serial
Interface) des Mikrocontrollers angeschlossen.
1
Man sollte den Betrag investieren und sich nicht mit Bastellösungen herumschlagen, die meistens
für die parallele oder serielle Schnittstelle gemacht sind. Solche Schnittstellen hat ein moderner
PC ohnehin nicht mehr.
Der Artikel handelt von meinen Erfahrungen bei der Einrichtung der integrierten
Entwicklungsumgebung (IDE) Code::Blocks für die Entwicklung von C-Programmen und die
Programmierung von AVR-Mikrocontrollern. Unter Letzterem ist das Schreiben von
Maschinencode in den Flash-Speicher des Mikrocontrollers zu verstehen.
Benötigte Programme
Im Mittelpunkt stehen der C Cross Compiler avr-gcc mit seinen Bibliotheken und der Programmer
avrdude.
avr-gcc liefert als Endprodukt eine Datei *.hex, während avrdude mit dieser Datei den
Mikrocontroller programmiert.
Es ist allerdings nicht einfach, den avr-gcc und auch avrdude so aufzurufen, dass die Programme
genau das tun, was sie sollen. Das liegt an den unglaublich vielen Aufrufoptionen, was eine
Eigenart aller Compiler ist, nicht nur von avr-gcc. Es würde viel zu viel Arbeit machen, diese
Parameter immer richtig im Terminal einzugeben. Deshalb bringt Linux das Programm make mit,
das komplizierte Aufrufe erledigt, indem es die Datei makefile auswertet, die der Anwender nach
bestimmten Regeln zu schreiben hat. Damit muss man sich aber nicht abgeben, wenn man
Code::Blocks eingerichtet hat.
Code::Blocks ist eine Cross-Compile-Plattform, die mit einer Reihe von Cross-Compilern
zusammenarbeiten kann. Der avr-gcc ist einer davon. Auch Tools können generiert werden.
Installation und Konfiguration der Programme
avr-gcc
Es handelt sich nicht um ein Programm, sondern um mehrere und eine ganze Reihe von Dateien.
Alles zusammen wird auch als Toolchain bezeichnet. Es gibt viele Möglichkeiten die AVRToolchain zu installieren. Manche Pakete installieren den Compiler und den Programmer avrdude
in einem Vorgang. Keine der Möglichkeiten, die ich probiert habe, war völlig problemlos, bis auf
die Toolchain, die Atmel zum Download anbietet, und zwar unter
http://www.atmel.com/tools/ATMELAVRTOOLCHAINFORLINUX.aspx
Weil der ATmega32 ein 8-Bit Mikrocontroller ist, habe ich Atmel AVR 8-bit Toolchain 3.4.1 - Linux
32-bit heruntergeladen. Das geht aber nicht ohne Registrierung. Man gibt Name und E-MailAdresse an und erhält eine E-Mail mit dem eigentlichen Link für den Download.
Die Installationsanleitung (pdf) kann man sich ohne Registrierung ansehen.
Was dann folgt, kann man kaum Installation nennen. Die heruntergeladene Datei wird in das
gewählte Installationsverzeichnis verschoben (bei mir /usr/local/bin ) und dort entpackt. Das war's
schon fast. Die ganze Toolchain befindet sich nun im Verzeichnis avr8-gnu-toolchain-3.4.1.798linux.any.x86 Weil mir der Name zu lang war, habe das Verzeichnis in avrtoolchain umbenannt.
Die Orte von avr-gcc, von der Dokumentation und von den Header-Dateien, die beim
Programmieren ggf. zu includieren sind, sollte man kennen:
In /usr/local/bin/avrtoolchain/bin befindet sich avr-gcc Man muss den Pfad nicht zum Suchpfad
in der Umgebungsvariablen PATH machen, wie es die Installationsanleitung fordert, wenn man
ihn in Code::Blocks setzt (s.u.)
In /usr/local/bin/avrtoolchain/avr/include und in drei Verzeichnissen darunter stehen die HeaderDateien, die in Programmen relativ zu diesem Pfad eingebunden werden, z.B. #include <stdio.h>
oder #include <avr/pgmspace.h> .
2
Die Dokumentation ist in /usr/local/bin/avrtoolchain/doc/avr-libc/avr-libc-user-manual/index.html
zu finden. Eine pdf-Datei des Manuals gibt es auch. Die Doku dürfte keine Wünsche offen lassen.
avrdude
Den Programmer avrdude gibt es als Paket im Ubuntu Software-Center. Die Installation ist ohne
Besonderheiten. Aufgerufen wird das Programm mit /usr/bin/avrdude und einer ganzen Reihe von
Optionen. Die vollständige Zusammenstellung ist im Manual enthalten, das mit man avrdude im
Terminal erscheint.
Die Aufrufe von avrdude, die ich brauche, habe ich in Code::Blocks als Tool konfiguriert (siehe
Code::Blocks Tools).
Eine ziemlich unangenehme Besonderheit hat avrdude aber doch. Nur root kann die USBSchnittstelle öffnen. Es kostet einigen Aufwand, unter dieser Restriktion mit dem Programmer zu
arbeiten, denn die ganze Programmentwicklung als root zu machen kommt nicht in frage. Erst
vor kurzem habe ich herausgefunden, wie das zu ändern ist.
Der Editor gedit wird aufgerufen mit :
gksudo gedit /etc/udev/rules.d/80­usbprog.rules In die Datei 80-usbprog.rules wird der folgende Text geschrieben, und zwar in einer Zeile:
ATTR{idVendor}==“03eb“, ATTR{idProduct}==“2104“, GROUP=“plugdev“, MODE=“0660“
# AVRISP mkII Dieser Text ist im wesentlichen eine Regel, die angibt, welche Gruppe von Usern mit dem
AVRISP mkII arbeiten kann, wenn er in eine USB-Schnittstelle eingesteckt wird. Ob der jeweilige
User Mitglied der Gruppe plugdev ist, lässt sich mit groups <username> überprüfen. Damit die
Regel wirksam wird, muss udev mit sudo /etc/init.d/udev restart neu gestartet werden. Zur
Sicherheit sollte man danach den USB-Stecker ziehen und wieder einstecken.
Hat man einen anderen Programmer als den AVRISP mkII, kann man mit lsusb dessen
Identcodes feststellen, aber auch die aller anderen eingesteckten USB-Geräte.
Wahrscheinlich wegen einer Software-Aktualisierung nach der beschriebenen Änderung konnte
bei mir plötzlich wieder nur root mit avrdude arbeiten. Nur eine ganz radikale Lösung hat
geholfen: Ich habe meine Festplatte in zwei Partionen aufgeteilt und ein zweites Ubuntu-Linux
(12.04 LTS) installiert. Dort habe ich dann avr-gcc, avrdude und Code::Blocks so eingerichtet,
wie es hier beschrieben ist. Dennoch, für den Fall, dass das Problem wieder auftreten sollte, habe
ich mir eine Lösung überlegt (siehe: Code::Blocks Tools / Das root / non-root Problem).
Weil eine Distributionsaktualisierung bei mir noch nie völlig problemlos war, werde ich in Zukunft
nur noch LTS (Long Time Support)-Updates machen, und zwar als Neuinstallation in eigener
Partition. Nach und nach werde ich dann mit meinen Daten dahin „umziehen“, wodurch die alte
Partition für die nächste Installation zur Verfügung steht.
Code::Blocks IDE
Das Paket dieser integrierten Entwicklungsumgebung ist im Ubuntu-Software-Center zu finden.
Nach dem ersten Start muss man sich um die Settings kümmern.
Unter Settings/Compiler and debugger/Selected compiler erscheint der GNU CC Compiler als
voreingestellt. Das ist der Compiler für C-Programme, den jedes Linux mitbringt. Die von diesem
Compiler übersetzten Programme laufen auf dem PC.
Durch einen Klick auf das Feld rechts erscheint die Auswahlliste der anderen Compiler, mit denen
Code::Blocks arbeiten kann, und da ist dann auch der GNU AVR CC Compiler dabei. Den habe
ich ausgewählt und zum default Compiler erklärt. Installiert ist er bereits. Die Registerkarten im
Fenster beziehen sich auf den jeweils ausgewählten Compiler.
3
Compiler settings
Hier wird der verwendete Mikrocontroller markiert.
Linker settings
Damit die Funktionen printf() und scanf() aus der Standardbibliothek stdio.h float-Typen aus- bzw.
eingeben können, müssen bei den Linker settings (am besten per copy and paste) die folgenden
Options eingetragen werden :
­Wl,­u,vfprintf ­lprintf_flt ­Wl,­u,vfscanf ­lscanf_flt ­lm Man verwendet die Options nur, wenn man sie unbedingt braucht, denn ihr Ressourcenverbrauch
ist hoch. Um die Options unwirksam zu machen, kenne ich bisher nur die Methode, sie aus dem
Fenster zu entfernen.
Search directories
Hier wird der Suchpfad zu avr-gcc eingetragen, wodurch es überflüssig wird, ihn in die PATHUmgebungsvariable aufzunehmen.
4
Toolchain executables
An dieser Stelle ist das Installationsverzeichnis des Compilers einzutragen, wobei vorausgesetzt
wird, dass sich die auszuführenden Programme in dessen Unterverzeichnis bin befinden, was bei
der AVR-Toolchain der Fall ist.
Code::Blocks Tools
Die Tools, die ich konfiguriert habe, sind ausschließlich Aufrufe von /usr/bin/avrdude . Die
notwendigen Parameter sind bei den folgenden Beschreibungen der Tools zu finden.
avrdude verlangt bei seinen Parametern die Seriennummer des Programmieradapters, die nach
usb: steht und jeweils anzupassen ist. Das gilt zumindest dann, wenn der Adapter AVR ISP mkII
verwendet wird.
Außer pg und writefuseshex verwendet jeder Aufruf die Datei temp. Bei den Aufrufen read..... wird
sie überschrieben, wenn sie im aktuellen Verzeichnis existiert, andernfalls wird sie angelegt. Der
Zusatz :i bedeutet Hex-Format.
pg
(program)
­p atmega32 ­P usb:0200040133 ­c avrisp2 ­U flash:w:${TARGET_OUTPUT_FILE}.hex
Dieses Tool wird am häufigsten verwendet. Es schreibt den Maschinencode des Programms, der
nach einer erfolgreichen Compilierung in der Datei bin/Release/<project name>.elf.hex enthalten
ist, in den Flash-Speicher des Mikrocontrollers. Da der Name der Hex-Datei von Projekt zu
Projekt wechselt, ist ein Makro verwendet worden, der auch für den Pfad steht.
5
Die folgenden Tools werden im gleichen Fenster editiert. Makros kommen nicht vor.
readflash
­p atmega32 ­P usb:0200040133 ­c avrisp2 ­U flash:r:temp:i
Der Flash-Speicher des Mikrocontrollers wird in die Datei temp ausgelesen.
writeflash
­p atmega32 ­P usb:0200040133 ­c avrisp2 ­U flash:w:temp:i
Dieses Tool macht das gleiche wie pg. Nur ist die Datei, die verwendet wird, wiederum temp.
Dadurch wird es zum Gegenstück von readflash. Das heißt, die mit readflash ausgelesenen
Daten können mit writeflash zurück geschrieben werden. Das braucht man zum Beispiel, um
Kopien von Mikrocontrollern herzustellen, ohne auf den Quelltext zurückzugreifen.
readeeprom
­p atmega32 ­P usb:0200040133 ­c avrisp2 ­U eeprom:r:temp:i
Wirkt wie readflash, nur dass der EEPROM-Speicher gelesen wird.
writeeeprom
­p atmega32 ­P usb:0200040133 ­c avrisp2 ­U eeprom:w:temp:i
Das Tool schreibt die mit readflash gelesenen Daten zurück. Auch dieser Vorgang gehört zum
Herstellen von Kopien.
6
readhfuse und readlfuse
­p atmega32 ­P usb:0200040133 ­c avrisp2 ­U hfuse:r:temp:b
­p atmega32 ­P usb:0200040133 ­c avrisp2 ­U lfuse:r:temp:b
Diese beiden Tools lesen das High-Fuse-Byte bzw. das Low-Fuse-Byte des Mikrocontrollers
ATmega32 jeweils in die Datei temp. Die Fuse-Bytes enthalten die Fuse-Bits, die für
grundlegende Funktionen stehen.
High-Fuse-Byte ATmega32
Hex
OCDEN
JTAGEN
CKOPT
EESAVE BOOTSZ1 BOOTSZ0 BOOTRST
fabrikneu
0x99 1
0
0
1
1
0
0
1
Praxis
0xC1 1
1
0
0
0
0
0
1
BODEN
SU1
SUT0
CKSEL3
CKSEL2
CKSEL1
CKSEL0
Low-Fuse-Byte ATmega32
Hex
BODLEVEL
fabrikneu
0xE1 1
1
1
0
0
0
0
1
Praxis
0xFF 1
1
1
1
1
1
1
1
Ganz wichtig: Eine Null bedeutet, dass die mit dem Bit verbundene Funktion (siehe Datenblatt),
aktiviert ist. Das Bit wird auch als programmiert bezeichnet. Die Eins bedeutet: Funktion ist
deaktiviert. Das ist entgegen der Gewohnheit und hat wohl damit zu tun, dass Bits im gelöschten
Flash-Speicher im Zustand 1 sind.
Die Datei temp enthält beispielsweise nach dem Aufruf von readhfuse beim fabrikneuen
ATmega32 die folgenden Zeichen, die denen in der vorstehenden Tabelle entsprechen:
0b10011001
Der Zusatz :b bedeutet Binär-Format, was für Kontrollzwecke am zweckmäßigsten ist. Dennoch
ist die Kopie eines MC erst dann vollständig, wenn auch die Fuse-Bytes kopiert wurden.
writefuseshex
­p atmega32 ­P usb:0200040133 ­c avrisp2 ­u ­U hfuse:w:0xC1:m ­U lfuse:w:0xFF:m
Der Aufruf schreibt die Fuse-Bytes, diesmal allerdings nicht aus einer Datei. Die Hex-Bytes sind
Parameter, hier C1 und FF. Diese beiden Werte habe ich bisher immer verwendet (siehe auch die
Zeile Praxis in der obigen Tabelle).
Im High-Byte deaktiviere ich das JTAG-Interface und schütze den EEPROM gegen Löschen. Im
Low-Byte stelle ich die Taktquelle ein, die bei mir ein externer 16 MHz-Quarz ist.
Fehler sollte man keine machen, insbesondere muss man die eingestellte Taktquelle auch
verwenden, sonst läuft nichts, auch nicht das Lesen und Schreiben der Fuse-Bytes. Dumm, wenn
man nicht mehr weiß, welche Taktquelle im Fuse-Byte eingetragen ist. Ich kann mir vorstellen,
dass mit Ausprobieren aller Taktquellen, die in frage kommen könnten, das Problem zu lösen ist.
Dieses Tool irrtümlich anzuklicken, wäre also fatal. Weil das sehr leicht passieren kann, habe ich
einen Fehler in den Aufruf eingebaut ( /usr/bin/avrdu ), der zuerst korrigiert werden muss. Dieser
Ersatz für eine Bestätigungsabfrage stört nicht weiter, da das Tool sehr selten gebraucht wird.
7
Das root / non-root-Problem
Sollte der Fall eintreten, dass plötzlich nur noch root mit avrdude arbeiten kann (siehe avrdude
oben), sind die Tools nicht mehr brauchbar. Mit der folgenden Notlösung kann die Arbeit jedoch
fortgesetzt werden:
Terminal öffnen und mit sudo -s -h root werden. Dann wird der Aufruf /usr/bin/avrdude in die
Kommandozeile geschrieben. Die Parameter des jeweils auszuführenden Tools überträgt man am
besten mit copy and paste. Beim Tool pg ist der Makro durch den Pfad/Namen der Hex-Datei zu
ersetzen, z.B. bin/Release/demo.elf.hex
Das Terminal bleibt geöffnet. Mit der Auf- und Ab-Taste kann man durch die zurückliegenden
Aufrufe scrollen, auch wenn der Rechner zwischenzeitlich ausgeschaltet wurde. Wiederholte
Aufrufe müssen also nur gesucht und nicht von Hand eingegeben werden.
Arbeiten mit Code::Blocks
Man eröffnet ein neues Projekt, indem man ein Muster dafür auswählt, z.B. das AVR Projekt. Der
Projektname, der vergeben werden muss, wird für die Projektdatei *.cbp , aber auch für das
Projektverzeichnis verwendet, das gleichzeitig Arbeitsverzeichnis ist. Es enthält nach der
Projekterzeugung ein leeres Hauptprogramm main.c
Eigene Quellcode-Dateien werden in das Arbeitsverzeichnis kopiert oder im Editor geöffnet und
mit save as dorthin gespeichert.
Unter Project / Add Files werden Quellcode- und Header-Dateien explizit dem Projekt zugefügt.
Dann kann der jedem Programmierer bekannte Arbeitszyklus beginnen.
Sehr vorteilhaft finde ich in Code::Blocks die Suchfunktion über mehrere Dateien hinweg und die
Möglichkeit, sich Deklarationen und Implementationen anzeigen zu lassen und dorthin zu
wechseln. Nur die Shortcuts, die ich gerne den Tools zuordnen würde, vermisse ich.
8