Hallo Leute,
ich habe heute (mehr oder weniger) erfolgreich meinen AVR Dragon unter
Linux in Betrieb genommen, und weil das nicht ganz einfach ist wollte
ich meine Erfahrung hier mit euch teilen.
Hintergrund: Ich verwende seit einigen Jahren den USBasp Programmer mit
avrdude um meine Programme zu flashen. Bauen tue ich das mit einfachen
Makefiles. Kompilieren und flashen geht dann einfach mit "make" bzw.
"make upload". Das geht auch aus Vim, KDevelop, oder <any other IDE>.
Das einzige was mir immer gefehlt hat war eine vernünftige
Debug-Möglichkeit mit USBasp. Darum habe ich mir jetzt den AVR-Dragon
zugelegt.
Siehe http://www.atmel.com/tools/avrdragon.aspx
Im wesentlichen ist das ein ICE mit JTAG Unterstützung, aber viel
wichtiger für mich ist, dass er DebugWire unterstützt. Ich verwende
nämlich hauptsächlich kleine ATMEGA8/168/328 o.ä. Diese unterstützen
kein JTAG, aber dafür DebugWire. Bis auf den Atmega8, der kann nicht mal
DebugWire. Siehe https://www.mikrocontroller.net/articles/DebugWIRE
Jetzt aber zur Verwendung:
Ich erkläre jetzt nicht wie man avr-gcc/gdb usw installiert, das setzte
ich mal voraus (oder siehe hier: https://gergap.wordpress.com/tag/avr/)
Man muss die folgenden Tools installiert haben:
* avr toolchain: avr-gcc, avr-gdb, avrdude, GNU make
* avarice (gdbserver der mit dem Dragon kommuniziert)
* (optional) GDB Debugger Frontend wie cgdb, kdevelop, etc.
Eines der größten Probleme ist die Verkabelung. Der AVR-Dragon bietet
hier sehr viele Möglichkeiten, die aber nicht besonders gut dokumentiert
sind. Man findet alles, aber muss entsprechend suchen.
Die beste Übersicht, neben der offiziellen Doku ist diese Seite:
http://www.trimension.de/wiki/AVR-Dragon
Der Dragon bietet die Möglichkeit einen Test-Sockel aufzulöten. Dies
bietet die Möglichkeit einfach die µC auf den Sockel zu stecken, zu
flashen und zu debuggen. Das Debuggen macht ohne Peripherie natürlich
nur beschränkt Sinn.
Leider muss man sich um die Verdrahtung selber kümmern. Wer keinen Bock
darauf hat mit Jump-Wires rum zu frickeln bastelt sich am besten eine
Adapter-Platine, welche man auf die Stiftleisten aufstecken kann und so
die Verdrahtung vornimmt. So kann man durch Wechsel der Adapter den
Dragon umkonfigurieren.
In-System-Programing (ISP): Die meiner Meinung nach sinnvollsten
Methode.
Der Dragon bietet dazu schon einen 6-poligen ISP Pfostenstecker.
Stolperfalle 1: der ISP kann die Platine mit dem µC nicht mit Spannung
versorgen (das ist bei echter HW oft auch nicht gewünscht). Aber für das
Steckbrett wäre das hilfreich. Hierfür gibt es auf dem Dragon einen
zweiten 6 poligen Stecker mit VCC und GND. Man kann so das Board mit
einer separaten Verkabelung mit Strom versorgen. Ich habe mir allerdings
einfach mittels LM7805 eine Spgsversorgung auf das Steckbrett gebaut.
Über den ISP bekommt der Dragon das Spannungs-Niveau und passt sich
entsprechend an (Pegelwandler).
Problem 2) da ich auf dem Steckbrett meinen Adapter 10-poligen
ISP-Stecker verwende, der zu meinem USBasp passt, habe ich mir ein
ISP-Adapter-Kabel bestellt, welches von 6-polig auf 10-polig geht.
Leider hat das nicht geklappt. Nachdem ich schon Angst hatte durch das
rum probieren den Dragon geschrottet zu haben, habe ich doch mal das
Kabel durchgemessen. Wie sich raus gestellt hat ist das totaler
Nonesense.
Jetzt habe ich zum Testen eine recht wilde Vedrahtung mit 6 poligen
Kabel und Schaltdrähten vorgenommen. Und siehe da es funktioniert, wenn
auch nicht zuverlässig.
Merke: Nächstes mal das Kabel selber machen!
avrdude: Das gute alte Tool zum Flashen wollte ich jetzt auch mit dem
Dragon testen, bevor ich DebugWire aktiviere.
Im Prinzip bekommt man so ein Verbindung zu einem Atmega168:
1 | avrdude -v -v -p atmega168 -c dragon_isp -P usb
|
Da durch die wilde Verkabelung das etwas wackelig ging, habe ich die
Geschwindigkeit (Bitclock) gedrosselt von 1 µs (default) auf 10µs. Damit
klappt es bei mir wunderbar.
1 | avrdude -v -v -p atmega168 -c dragon_isp -P usb -B 10
|
So bekommt man beispielweise ein Programm auf den Chip:
1 | avrdude -v -v -p atmega168 -c dragon_isp -P usb -B 10 -e -U flash:w:tempctrl.hex:i
|
Will man DebugWire aktivieren muss man DWEN fuse aktivieren. Die Seite
http://www.engbedded.com/fusecalc/ sei für Fuse Einstellungen jedem ans
Herz gelegt, und das Datenblatt natürlich ;-)
Achtung: Ist DebugWire aktiv, funktioniert die Reset-Leitung nicht mehr,
da diese für DebugWire verwendet wird. Normaler ISP-Betrieb wie mit
USBasp geht dann nicht mehr. Über ein spezielles DebugWire Kommando kann
der ISP Mode temporär wieder aktiviert werden (bis zum nächsten Reset).
Um das dauerhaft wiederherzustellen muss DWEN wieder deaktiviert werden.
Zum Glück kann das alles avrdude, also keine Angst.
Ich habe mir hierfür folgende zwei Scripte angelegt:
Das ist natürlich nur ein Beispiel und muss an eigene Bedürfnisse
angepasst werden.
enable_debugwire:
1 | #!/bin/sh
|
2 | avrdude -v -v -p atmega168 -c dragon_isp -P usb -B 10 -U hfuse:w:0x9f:m
|
disable_debugwire:
1 | #!/bin/sh
|
2 | avrdude -v -v -p atmega168 -c dragon_isp -P usb -B 10 -U hfuse:w:0xdf:m
|
Debuggen: Jetzt gehts endlich los.
Nachdem man DWEN aktiviert hat, kann man avarice starten.
Den Prozesser sollte man zuvor allerdings erst mal resetten.
Hier nochmal der Überblick über die Funktionsweise:
1 | µC <--debugWire--> Dragon <--USB--> avarice <--TCP socket--> avr-gdb --- gdb-frontend (optional)
|
avarice starten:
1 | $> avarice -g -w :4242
|
2 | AVaRICE version 2.13, Apr 12 2015 13:50:38
|
3 |
|
4 | JTAG config starting.
|
5 | Found a device: AVRDRAGON
|
6 | Serial number: 00:a2:00:06:24:72
|
7 | Reported debugWire device ID: 0x9406
|
8 | Configured for device ID: 0x9406 atmega168
|
9 | JTAG config complete.
|
10 | Preparing the target device for On Chip Debugging.
|
11 | Waiting for connection on port 4242.
|
12 | Connection opened by host 127.0.0.1, port 46828.
|
Erklärung der Optionen:
-g : Dragon verwenden
-w : DebugWire verwenden
:4242 : die fehlende IP (localhost) getrennt vom Port 4242, welcher vom
avarice GDB-Server verwendet wird. Hier wartet avarice auf eingehende
Verbindungen vom GDB.
jetzt kann man sich schon mit dem GDB verbinden:
1 | $> avr-gdb tempctrl.elf
|
2 | target remote :4242
|
3 | break main
|
4 | c
|
Jetzt sollte man Anfang seines Programmes stehen.
Erklärung:
target remote :4242: Stellt die Verbindung zum avarice her
break main: setzt einen breackpoint in der Funktion main()
c: kurz für continue. Lässt den ICE los laufen bis er auf einen
Breakpoint läuft.
Was man noch wissen sollte. DebugWire unterstützt keine HW-Breakpoints.
D.h. beim Setzen eines Breakpoints wird eine Break-Anweisung im Code
eingefügt, d.h. das Flash wird modifiziert. Das kann die Lebensdauer des
Flashes negative beinträchtigen.
Das Steppen mit 'step' und 'next' geht sehr zäh. Im Endeffekt wird für
jeden Schritt ein impliziter Breakpoint gesetzt und wieder entfernt.
Sinnvoller ist es auf dem kleinen µC selber Breakpoints zu setzen und
mit 'continue' dort hinzulaufen.
Watchpoints werden von der HW ebenfalls nicht unterstützt.
Das inspizieren von Variablen und Registern mit 'print', 'display' und
'info' geht einwandfrei.
CGDB-Frontend: Mein liebstes Frontend für solche Low-Level Dinge.
Es zeigt den Quellcode, breakpoints und Ausführungsposition schön an.
Man bedient es einfach mit normalen GDB Kommandos, d.h. geht der GDB
geht auch CGDB. Keine von GUIs verursachten Probleme.
Man legt sich hierzu eine kleine Hilfsdatei an um sich Tipp-Arbeit zu
sparen:
1 | # load symbols from ELF file (needed for DDD)
|
2 | file tempctrl.elf
|
3 | # connect to GDB server
|
4 | target remote localhost:4242
|
5 | # run to main (optional)
|
6 | break main
|
7 | c
|
Dann startet man CGDB folgendermaßen:
1 | cgdb -d /usr/bin/avr-gdb tempctrl.elf -x gdb.conf
|
DDD: Leider klappt es damit nicht. Sobald ich mich damit verbinde crasht
avarice. Irgendwas macht DDD, was avarice nicht gefällt.
Im Prinzip ginge es aber so:
1 | ddd --debugger "avr-gdb -x gdb.conf"
|
KDevelop: Funktioniert auch. Hier muss man halt in der GUI rum klickern
um alles einzustellen. Es lässt sich im Debug Lauchner unter Debugger in
der Sektion "Remote Debugging" auch das gdb.conf Script wiederverwenden.
Die Textbox heißt "Run gdb Script:"
Was gibt es noch zu beachten?
1.) Natürlich sollte man mit "-O0 -g" bauen. Die Optimierung erzeugt
schwer nachvollziehbaren Code. Man sollte höchstens O1 verwenden. -g
erzeugt die Debug Info.
2.) Der Debugger will das ELF file mit der Debug Info. Mit dem HEX file,
welches man zum Flashen verwendet kann der Debugger nix anfangen.
Ich hoffe ich konnte mit dem Beitrag jemanden helfen.
PS: Was mich noch interessieren würde: Mit AVR Studio unter Windows und
AVR Dragon. Geht dort das Steppen auf einem m168 besser, oder genauso
zäh? Das Modifizieren des Flash dauert seine Zeit, deswegen würde mich
das wundern. Bei mir dauert ein Step so etwa 2-3 Sekunden.