Elektronik und Roboterbau
AVR, avr-gcc, CAN, CPLD, Elektronik, Mikrocontroller, MSP430, PIC, Roboter, Schaltungen, Sensoren, Software, Testboards
Tags: AVR,
Software,
CAN,
avr-gcc
Stand: 15. September 2008, 17:30
25 Kommentar(e)
Mit dem hier vorgestellten Bootloader lassen sich AVRs die an einem MCP2515 angeschlossen sind über den CAN Bus programmieren.
Im Roboterclub verbauen wir eine ganze Menge AVRs, teilweise auch in den Tiefen des Roboters versteckt, so dass man nur sehr schwer mit einem Programmierkabel dorthin kommt. Allerdings haben sie einen CAN Anschluss. Die Idee war also einen Bootloader zu haben mit dem wir auch diese AVRs einfach per CAN programmieren zu können ohne extra Kabel nach außen zu legen und ohne jedesmal den halben Roboter zu zerlegen.
Der Bootloader ist hauptsächlich in C geschrieben, es wurden allerdings schon Teile der Kommunikation mit dem MCP2515 nach Assembler übersetzt um etwas Platz zu sparen. Aktuell belegt die Software trotzdem knapp über 1200 Bytes und verbraucht daher 1024 Words im Bootloaderbereich. Allerdings sind mit entsprechender Optimierung vermutlich auch noch die 200 Bytes Einsparung möglich um den Bootloader unter 1024 Bytes zu bekommen, damit würde sich der Platzbedarf auf 512 Words halbieren.
Der AVR wartet nach einem Reset 500ms auf ein für ihn bestimmte CAN Nachricht (siehe Aufbau der Nachrichten). Falls keine empfangen wird, so wird ein Sprung auf Adresse Null ausgeführt und damit das normale Programm gestartet.
Aktuell werden ATMega8/88/168, ATMega16/32 und ATMega644 unterstützt, weitere AVRs können allerdings ohne große Änderungen eingebaut werden.
Zur Kommunikation auf dem CAN-Bus werden nur Nachrichten mit zwei verschiedenen 11-Bit Identifiern verwendet um so möglichst wenig mit anderen Protokollen die über CAN laufen in Konflikt zu kommen. Verwendet werden 0x7ff (PC zu AVR) und 0x7fe (AVR zu PC), diese beiden haben die geringste Priorität und stören so den Rest der Kommunikation auf dem Bus nicht bzw. nur wenig. Damit ist auch ein aufspielen neuer Software mitten im Normalen Betrieb möglich.
Jeder AVR bekommt eine eigene 8-Bit Nummer zugewiesen die in Netzwerk einmalig sein muss und über die er direkt angesprochen werden kann. Es können also zwei AVRs gleichzeitig im Bootloader Modus sein, es darf aber immer nur einer programmiert werden, da sie ansonsten eventuell gleichzeitig Nachrichten mit dem gleichen CAN-Identifier verschicken würden was zu Kollisionen auf dem Bus führen könnte.

Wie man erkennt sind die ersten vier Bytes jeder Nachricht mit Status-Informationen belegt und müssen in dieser Form immer mitgesendet werden.
Über das erste Byte (Board Identifier) erfolgt eine eindeutige Identifikation des angesprochenen bzw. sendenden AVRs im Netzwerk.

Das zweite Byte codiert das Kommando sowie den Typ der Nachricht:
| Wert | Typ |
|---|---|
| 00 | REQUEST |
| 01 | SUCCESSFULL_RESPONSE |
| 10 | ERROR_RESPONSE |
| 11 | WRONG_NUMBER_REPSONSE |
| Wert | Kommando |
|---|---|
| 1 | IDENTIFY |
| 2 | SET_ADDRESS |
| 3 | DATA |
| 4 | START_APP |
Die verschieden Kommandos werden in den nächsten Abschnitten genauer vorgestellt.
Mit dem dritten Byte folgt ein fortlaufender Nachrichtenzähler (Message Number). Dieser wird verwendet um verloren gegangene Nachrichten zu erkennen. Detektiert der AVR eine falsche Nachrichtennummer so sendet er auf jede Anfrage Antworten vom Typ WRONG_NUMBER_REPSONSE mit der erwarteten Nummer in diesem Feld. Das PC-Programm muss dann auf die fehlende Nachricht reagieren und den Zähler bei sich anpassen um die Kommunikation wieder aufzunehmen.
Auf den Wert des vierten Bytes (Data Counter) wird bei den DATA-Nachrichten genauer eingegangen, bei allen anderen Nachrichten sollte in diesem Feld eine 0x80 stehen (SoB-Bit gesetzt sein und alle anderen Bits auf Null).
Der PC schickt ein IDENTIFY.REQUEST Kommando ohne zusätzliche Datenbytes um den AVR zu identifizieren und um Werte wie den Bootloadertyp, die Flash-Seitengröße usw. abzufragen.
Der AVR antwortet dann mit folgenden Paket:

Bootloader Type gibt den Typ des Bootloaders an und sollte aktuell immer Null sein. Es ist geplant weitere Bootloader Typen hinzuzufügen, die auf kosten eines höheren Speicherbedarfs zum Beispiel auch das Eeprom lesen und schreiben können.
RWW Page Count gibt die Anzahl der beschreibbaren Flash-Seiten und damit die Größe des beschreibbaren Speichers an.
Im Pagesize Identifier ist dann noch die Größe der einzelnen Flash-Seiten kodiert:
| Wert | Seitengröße |
|---|---|
| 0 | 32 Byte |
| 1 | 64 Byte |
| 2 | 128 Byte |
| 3 | 256 Byte |
Nach der AVR geantwortet hat befindet er sich im Bootloader Modus und wartet auf weitere Befehle. Auch der 500ms Timer wird damit beendet, so dass jetzt nur noch mit einem START_APP-Kommando das normale Programm gestartet werden kann.
Als nächstes muss festgelegt werden wohin geschrieben werden soll, dazu gibt es das SET_ADDRESS Kommando:

Der Wert für Flash Page entspricht der Seite die beschrieben werden soll und Page Buffer Position gibt dabei die Position innerhalb dieser Seite an.
Über den Wert von Page Buffer Position kann nach einem Fehler wieder an einer definierten Position mit dem Füllen des Puffers angefangen werden.
Es gilt dabei:
Buffer Address = Page Buffer Position * 4
Dies ist so gewählt, da die Daten immer in vier Byte großen Paketen gesendet werden. Es macht also keinen Sinn an Position die nicht durch vier teilbar sind anfangen zu wollen.
Kommen wir nun zu den eigentlichen Nutzdaten die man in den Flash schreiben möchte. Ist die über die anderen Kommandos eine Kommunikation aufgebaut, so können über das DATA-Kommando die Daten verschickt werden.
Die DATA.REQUEST Nachrichten sind immer acht Byte lang, die hinteren vier Bytes sind dabei die Nutzdaten.

Da es recht lange Latenzzeiten im PC beim Warten auf Antwort und dem Losschicken der nächsten Nachricht gibt und diese die Programmierzeiten stark in die Länge zogen wurden Nachrichtenblöcke eingeführt.
Dafür wird das vierte Byte (Data Counter) des Status-Informations-Feld am Anfang der Nachrichten verwendet.
Ist das SoB-Bit (Start of Block) gesetzt wird ein neuer Nachrichtenblock gestartet. die unteren sieben Bit geben dann an wie viele Nachrichten noch folgenden. Es sind beliebige Blockgrößen möglich.
Um zum Beispiel einen Block der Größe 16 Nachrichten zu senden wird bei der Start-Nachricht das Byte auf den Wert 0x8F (0x80 => Flag für den Start des Blocks + 15 (0x0F) => 15 noch folgende Nachrichten) gesetzt.
Bei den nächsten Nachrichten wird dieser Wert ohne das gesetzte SoB-Bit dann herunter gezählt, also 0x0E, 0x0D usw. bis mit einem 0x00 der Nachrichtenblock endet. Der AVR sendet daraufhin eine DATA.SUCCESSFULL_RESPONSE Nachricht.
Diese enthält im Normalfall außer den Status-Informationen keine weiteren Bytes. Wird mit dem Ende eines Blocks auch gleichzeitig das Ende des Puffers erreicht, so wird der Puffer in die aktuell aktive Flash-Seite geschrieben und die nächste Seite auf aktiv gesetzt. Damit können ohne ein SET_ADDRESS Kommando direkt die nächsten Daten verschickt werden. Tritt dieser Fall ein, so wird eine spezielle DATA.SUCCESSFULL_RESPONSE Nachricht verschickt, diese enthält in zwei zusätzlichen Bytes die Flash-Seite die gerade beschrieben wurde.

Das PC Programm ist dafür zuständig, dass das Ende des Puffers immer mit dem Ende eines Blocks erreicht wird, genauso dafür das immer vollständige Flash-Seiten geschrieben werden. Füllt zum Beispiel ein Programm für den AVR die letzte Flash-Seite nur zur Hälfte, so muss diese um entsprechend viele 0xFFs ergänzt werden bis wieder eine vollständige Flash-Seite daraus geworden ist.
Über dieses Kommando wird der Bootloader-Vorgang beendet und das neu geschriebene Programm durch einen Sprung auf die Adresse Null gestartet.
Sämtliche Kommunikation läuft nach einem Anfrage/Antwort Prinzip ab. Der AVR sendet niemals von sich aus, sondern antwortet immer nur auf Anfragen des PC. Dabei wird mit Ausnahme von Nachrichtenblöcken jede Nachricht des PCs beantwortet.
Nachrichtenblöcke wurden eingeführt um die Kommunikation zu beschleunigen, da die Latenzzeiten auf PC Seite zu lang waren. Es wird dabei ein größerer Block von Nachrichten auf einmal losgeschickt und erst die letzte Nachricht vom AVR beantwortet. Auf den größeren AVRs werden Blöcke mit einer Länge von 64 Nachrichten verwendet. Damit passt genau eine Flash-Seite (256 Byte) in einen Nachrichtenblock.
Nachdem der PC über ein IDENTIFY Kommando die Daten des AVRs wie Flashblock Größe, Anzahl der beschreibbaren Flash-Seite usw. ausgelesen hat setzt er die zu bearbeitende Flash-Seite und die Adresse innerhalb dieser. Danach werden in Blöcken die Daten übertragen. Erreicht ein Block das Ende einer Flash-Seite so wird diese vom Puffer in den Flash geschrieben und auf die nächste umgeschaltet. Dies wird über eine spezielle DATA.SUCESSFULL_RESPONSE Nachricht angezeigt.
Sind alle Daten geschrieben kann das neu geschriebene Programm gestartet und damit die Kommunikation beendet werden.
Es wird keine zusätzliche Verifikation der Daten vorgenommen da der CAN Controller von sich aus schon jede Nachricht mit einer CRC Checksumme absichert. Wird also ein Paket empfangen, so kann mit sehr großer Sicherheit davon ausgegangen werden das es korrekt war.
Es müssen in der config.h noch einige defines an das eigene Projekt angepasst werden, zum Beispiel:
#define MCP2515_CS B,4
#define MCP2515_INT B,2
#define BOOT_LED B,0
//#define BOOT_LED_SET_OUTPUT
//#define BOOT_LED_ON
//#define BOOT_LED_OFF
//#define BOOT_LED_TOGGLE
//#define BOOT_INIT
Hängt die Bootloader LED nicht direkt an einem Port Pin kann man über die Makros BOOT_LED_… die Ausgabe anpassen (ich habe dies zum Beispiel genutzt um eine Duo-LED über zwei Port-Pins anzusteuern). Wird BOOT_LED überhaupt nicht definiert, so läuft der Bootloader ohne die LED-Statusanzeige. Es wird zwar eine Warnung erzeugt, das schränkt jedoch die Funktionalität nicht ein.
BOOT_INIT wird beim Starten des Bootloaders einmal aufgerufen, dort können eigene speziell für die Platine notwendige Initialisierungen untergebracht werden.
Als nächstes muss im Makefile der verwendete AVR, die Taktfrequenz sowie die Adresse des Bootloaders einstellt werden.
Danach kann der Bootloader gebaut werden:
$ make all
Die entstandene Datei bootloader.hex kann jetzt per ISP aufgespielt werden. Außerdem müssen die Fusebits für einen Bootloader-Bereich von 1024 Words eingestellt werden.
Für einen ATMega32 wäre das zum Beispiel:
hfuse 0xDA
lfuse 0x2F
Der PC Teil ist in Python geschrieben wird über die Kommandozeile gestartet. Eine entsprechende GUI fehlt noch, vielleicht hat ja jemand Lust daran weiterzumachen?
Bisher habe ich die Software nur unter Linux mit meinem CAN Debugger getestet. Das ganze sollte aber genauso unter Windows lauffähig sein. Allerdings muss das Script vermutlich an den verwendeten CAN Adapter angepasst werden wenn man einen anderen verwendet.
$ python bootloader_can.py -i BOARD_ID -p COM_PORT -f FILE.hex
BOARD_ID, COM_PORT und FILE müssen natürlich an das eigene Projekt angepasst werden. Der Wert von BOARD_ID muss dabei den bei erstellen des Bootloaders unter BOOTLOADER_BOARD_ID angegeben Wert entsprechen.
Mit CAN Bus von 125 Kbps und einem ATMega32 (Flash-Seitengröße 128 Byte) braucht man für 20 kByte ungefähr 14-15 Sekunden.
Für ein ATMega644 (Flash-Seitengröße 256 Byte) braucht man bei der gleichen Menge Daten ungefähr 10-12 Sekunden.
Je größer die Nachrichtenblöcke und je höher die CAN Bitrate um so schneller geht es.
Falls es noch Fragen zum Bootloader schickt mir am besten eine E-Mail oder schreibt einen Kommentar. Würde mich über Feedback freuen ;-)
Kommentare
# dude meinte am 28. September 2008, 19:45 dazu:
Danke danke danke, du hast die Lösung für all meine Probleme!
# Philipp Putzer meinte am 16. Dezember 2008, 11:10 dazu:
Respekt, nicht schlecht!
Eine Frage hätte ich noch. Wenn du ein Programm in irgendeinen AVR laden willst, wie kommunizierst du zwischen PC und CAN-BUS?
Danke und Gruß
Philipp
# Fabian Greif meinte am 16. Dezember 2008, 11:27 dazu:
Ich verwende dafür den CAN Debugger, andere Adapter habe ich bisher noch nicht getestet. Wenn mir aber jemand welche sponsert hole ich das gerne nach ;-)
Grüße Fabian
# Peppe meinte am 4. Februar 2009, 12:17 dazu:
Hallo Fabian,
Sehr genial Projekt, ich würde das gerne in meine Hausautomatisierung implementieren, es nervt doch gewaltig bei jeder änderung zu jedem Teilnehmer laufen zu müssen? Wie kann ich dein Pc-Tool unter Windows ans laufen bekommen? Meine Linux Kentnisse sind ein wenig eingerostet und ich habe momentan auch kein Rechner mit Linux am laufen?
Über eine Anwort würde ich mich riesig freuen!
Viele Grüße
Peppe
# Fabian Greif meinte am 5. Februar 2009, 18:47 dazu:
Hast du einfach mal ausprobiert es zu starten? Das sollte nämlich funktionieren (schon getestet) ;-)
(Installiertes Python natürlich vorausgesetzt).
Grüße
Fabian
# Guido meinte am 13. Februar 2009, 17:31 dazu:
Hi
Ich bekomm die Sache einfach nicht compiliert. Leider habe ich auch kaum Erfahrung damit. Mir fehlen dauern irgendwelche Files. Einige habe ich jetzt aus der avrlib genommen aber z.B can/mcp2515_defs.h find ich nicht kann mir jemand einen kompletten Ordner schicken in dem ich nur noch wie oben Beschrieben die Ports und die Tacktfrequenz ändern muss.
Wär klasse.
Guido.Stappert|at|gmx.de
# Fabian Greif meinte am 19. Februar 2009, 11:43 dazu:
Ich habe das Archiv mal überarbeitet, die fehlenden Dateien sollten jetzt enthalten sein.
Grüße Fabian
# Andreas meinte am 4. März 2009, 20:21 dazu:
Hi Fabian,
echt Klasse Bootloader! War schon dabei für meine Rolladensteuerung, die auch auf dem MCP2515 aufbaut, einen selber zu programmieren. Du hast mir damit einiges an Aufwand erspart. Danke!
Übrigens bei meiner WinAVR vom 21.12.2007 ist der Define für MCUSR beim ATmega8 nicht drin. Durch Ersetzen von MCUSR durch MCUCSR in get_mcusr klappte es aber auch.
Gruß Andreas
# Boris meinte am 4. Mai 2009, 11:52 dazu:
Wie komme ich denn vom “Normalbetrieb” in den Bootloader? Sendet das Skript eine Reset-Nachricht oder muss ich das manuell machen. Ansonsten super Sache und die Platinen v3 sind 1a.
Gruß, Boris
# Fabian Greif meinte am 4. Mai 2009, 20:46 dazu:
Ja, das müsstest du manuell machen bzw. in das Script einbauen. Je nach verwendetem Protokoll sieht diese ja anders aus.
Alternativ immer Bootloader starten und dann den Reset Taster drücken. Ist zwar nicht so super komfortabel, funktioniert aber auf jeden Fall.
Grüße Fabian
# Ronny M meinte am 22. August 2009, 20:01 dazu:
Hallo,
ich finde den Bootloader klasse. Ich habe die config.h und das make file an den ATmega8 8MHz angepasst. Die BOOTLOADER_BOARD_ID ist doch die eindeutige Nummer im Netzwerk, oder?
Wenn ich das Programm per ISP übertrage funktioniert das ganze. Wenn ich danach das Anwendungsprogramm per ISP aufspiele ist der Bootloader weg.
Zum Kompilieren verwende ich WinAVR und AVRDude zum programmieren mit den Einstellungen: avrdude -p atmega8 -P com2 -c avr911 -U flash:w:bootloader.hex
als Fusebits verwende ich: lfuse:0x2F hfuse:0xDA lock:0xFF
Was mache ich falsch?
Danke Ronny
# Fabian Greif meinte am 24. August 2009, 14:21 dazu:
Hallo Ronny,
Genau.
Natürlich, beim einem programmieren per ISP wird zuerst der gesamte Flash gelöscht und dann das Programm geschrieben. Das ist einfach Technologie-bedingt und lässt sich leider nicht ändern.
Nachdem du den Bootloader aufgespielt hast solltest du also auch den Bootloader verwenden um dein eigentliches Programm hochzuladen. Sobald du zwischendurch wieder ISP verwendest musst du ihn halt vor der nächsten Verwendung wiederherstellen (auch per ISP).
Grüße Fabian
# Ronny M meinte am 1. September 2009, 18:12 dazu:
Hallo Fabian,
danke hilft mir weiter. Da der µC sich danach sowieso im Bootloader befindet ist das ja kein Problem mehr.
liebe Grüße Ronny
# Frank meinte am 3. September 2009, 17:04 dazu:
Hallo,
hat schon jemand eine Windows GUI für den Bootloader? Sonst Super Sache! Danke dafür!
Frank
# Frank meinte am 6. September 2009, 13:36 dazu:
Hallo,
ich versuche gerade das Python Tool unter der Windows CMD zum laufen zu bringen. Python31 habe installiert. Was muss ich jetzt machen damit es läuft? Von Python habe ich nicht wirklich die Ahnung.
Noch ne Frage: Ich habe mir mit einen Atmega32 , selbts ein Can Rs232 Interface gebaut. Was muss ich dann als Board ID angeben?
Wäre schön wenn mir da jemand helfen könnte!
Gruss Frank
# Fabian Greif meinte am 6. September 2009, 15:41 dazu:
Einfach das Script ausführen. Im Prinzip also das oben angegebene Kommando eintippen (siehe “Benutzen der Software”).
Ich weiß allerdings gerade nicht auswendig ob das Script mit Python 3.1 funktioniert, habe es bisher nur mit den Versionen bis 2.6 getestet.
Die mit der du den AVR-Teil des Bootloader übersetzt hast. Das verwendete CAN Interface ist davon vollkommen unabhängig.
Grüße Fabian
# Frank meinte am 11. September 2009, 08:58 dazu:
Hallo nochmal, ich habe jetzt das Python Programm zum laufen gebracht. Der Atmega8 ist auch soweit vorbereitet. Nun habe ich das Problem das das Python Prog nicht auf meine Com zugreifen kann. Ich habe mein Interface an der rs232 Com 1 hängen. Ist im Programm eine USB Schnittstelle implementiert? Wenn ja, wie kann ich das ändern? Danke und Gruss Frank
# Frank meinte am 9. Oktober 2009, 19:58 dazu:
Hallo, das Debugger Interface von Dir läuft jetzt hervoragend! Danke noch mal! Der Bootloader läuft jetzt auch. Nur bricht er manchmal mittendrin ab. No Respone! Bei mir auf dem Can ist eigentlich recht viel los. Kann man da irgendwie die Timeout Zeit hochsetzen? Oder das er es öfter probiert? Danke und Gruss Frank
# Fabian Greif meinte am 13. Oktober 2009, 11:45 dazu:
Das ist leider ein bekanntes Problem. Es fehlt noch ein bisschen Logik im Programm es sich besser von Fehlern “erholt”. Leider fehlt mir im Moment so ein bisschen die Zeit dazu mich darum zu kümmern.
Grüße Fabian
# Martin meinte am 10. November 2009, 15:01 dazu:
Hallo Fabian, kannst du mir sagen, wie ich dein Python Programm zum uplout nutzen muss, irgendwie bekomm ich da nix zum laufen.
Kann man den Bootloader auch für einen AT90can nutzen?
danke dir
# Fabian Greif meinte am 10. November 2009, 15:29 dazu:
Wie hast du es denn probiert? Und was für Fehlermeldungen hast du bekommen?
Nein, bisher nicht. Es müsste noch der C Teil angepasst werden.
Grüße Fabian
# Martin S. meinte am 2. Februar 2010, 19:52 dazu:
Hi Fabian, ich würde Unterstützung anbieten für die Anpassung des C Teils für einen AT90CAN
# Tobias meinte am 16. April 2010, 20:21 dazu:
Hi Fabian, Eine Frage was bedeutet es wenn bei dem bootloader_can.py “connecting” steht? So wie ich das in dem Python Script sehe wohl dass der can-debugger auf Nachricht von dem angeschlossenen µC wartet. Ich habe nämlich vom Martin die Dateien für den AT90CAN128 bekommen und bin am austesten. Doch ich komme nicht weiter als bis zu dieser Meldung.
# Markus meinte am 18. Mai 2010, 11:48 dazu:
Was hängt denn konkret? Will auch den Bootloader verwenden, leicht modifiziert, um beim Kunden mittels eines AT90USB1287 an dem ein MCP2515 hängt per USB Stick die CAN Nodes upzudaten.
Gehen Messages verloren? Ich dachte das kann bei CAN nicht passieren?
Kannst Du das evtl. mal näher erläutern, dann schau ich mal ob ich was machen kann.
Markus
# Adrian meinte am 11. Juni 2010, 22:46 dazu:
Windows-Anwender brauchen außer python noch http://sourceforge.net/projects/pywin32/
Deine Meinung: