Beim Digispark, ein kleiner ATtiny85 mit USB-Anschluss per V-USB, wird der Reset-Pin (B5) per Fuses als (fast) normaler IO-Pin programmiert. Das erweitert die verfügbaren IO-Pins von drei auf vier (zwei Pins sind für USB reserviert).
Das Abschalten der Reset-Funktion verhindert leider das weitere Programmieren mit einem normalen Programmer. Möglich ist immer noch die Programmierung per HV-Programmer. Der ist jedoch teuer und ggf. verträgt die umgebende Schaltung keine 12V.
Stattdessen enthält der Digispark einen Bootloader im oberen Bereich des Flash zum Hochladen neuer Programme. Der Bootloader wird, wenn nicht bereits geschehen, initial mit einem normalen Programmer aufgebracht. Dabei werden auch die Fuses gesetzt. Wer den Bootloader selbst aufbringt, kann selbst entscheiden, wie er mit dem Reset-Pin umgeht.
Das Hochladen per Bootloader geschieht mit dem Uploader-Programm Micronucleus, das mit dem Bootloader kommuniziert. Der Bootloader auf dem ATtiny etabliert dazu direkt nach Power-On ein USB-Device, bei dem sich der Uploader anmelden kann. Meldet sich innerhalb von einen Latenzzeit von 6 Sekunden (Standard-Einstellung) kein Uploader, startet der Bootloader das "normale" Programm.
Der Uploader (micronucleus.exe) seinerseits fordert den Anwender auf, innerhalb von 60 Sekunden einen Bootloader zur Verfügung zu stellen, also Power-On durchzuführen. D.h., er muss einen ATtiny mit Bootloader in einen USB-Slot einzustecken. Ein bereits angeschlossenes Gerät muss entfernt und wieder angesteckt werden.
Will man den Bootloader anpassen, geht das leider nicht so einfach. Der Bootloader müsste sich dabei selbst überschreiben. Das gäbe Kuddelmuddel und wird vom Bootloader bzw. Uploader mit einer entsprechenden Verweigerungsmeldung verhindert.
Der Trick: Man schreibt ein Programm, dass den neuen Bootloader-Code als Daten enthält und nach dem Start den vorhandenen Bootloader überschreibt. Dies gibt keinen Konflikt, weil ein normales Programm autark ist und keine Funktionalität des Bootloaders benutzt. Nach der Ausführung des Programms steht der neue Bootloader für weitere Uploads bereit.
Sowohl der Bootloader als auch der Code des Uploaders sind Open Source und stehen auf GitHub zur Verfügung.
Der Code auf der GitHub-Seite enthält im Ordner firmware auch ein Programm namens upgrade.c, mit dem man einen neuen Bootloader hochladen kann. Allerdings sind noch einige vorbereitende Schritte notwendig. Das folgende Beispiel zeigt dies Schritt für Schritt.
Für eine Anwendung ist die Latenzzeit des Bootloaders von 6 Sekunden zu lang. Sie soll auf 2 Sekunden reduziert werden.
Das Vorhaben umfasst die folgenden Schritte:
Schritt | Ergebnis |
---|---|
A. Download der Bootloader-Quelle | Der Code steht zur Anpassung zur lokal Verfügung. |
B. Anpassen der Quellen-Dateien | Der Code verfügt über die angepassten Funktionalitäten. |
C. Kompilieren des angepassten Bootloaders | Der neue Bootloader steht im HEX-Format zur Verfügung. |
D. Umwandeln der HEX-Datei in ein C-Array | C-Programmausschnitt mit Array-Deklaration des Bootloader-Maschinencodes. |
E. Upgrade-Programm mit C-Array erstellen und kompilieren | Upgrade-Programm zum Überschreiben des Bootloader |
F. Upgrade-Programm laden (und starten) | Digispark mit angepasstem Bootloader |
Die Punkte C. und D. fasst man am besten in einer kleinen Batch-Date (.bat oder .cmd) zusammen. Das lohnt sich auf jeden Fall, wenn man mehr als einen Versuch benötigt. Die Batch-Datei wird am Ende von Abschnitt D. beschrieben.
Am besten lädt man sich das gesamte Gibhub-Verzeichnis herunter (als ZIP-Datei und dann entpacken). Interessant ist eigentlich nur der Ordner firmware, der den Source-Code und die Make-File für den Bootloader enthält.
Hat man den Ordner herunter geladen, muss man die Quellen seinen eigenen spezifische Anforderungen anpassen. Die wesentliche Datei ist main.c, die den Bootloader-Code enthält. Hinzu kommen die prozessorspezifischen Konfigurationsdateien im Unterordner configuration.
Die gestellte Aufgabe erledigt man durch Anpassung der Datei ...\configuration\t85_default\bootloaderconfig.h. In dieser Datei gibt es den Eintrag:
// AUTO_EXIT_MS The bootloader will exit after this delay if no USB communication
// from the host tool was received.
und
#define AUTO_EXIT_MS 6000
In main.c findet man
// Try to execute program when bootloader times out
if (AUTO_EXIT_MS&&(idlePolls.w==(AUTO_EXIT_MS/5))) {
...
und den Hinweis
#if ((AUTO_EXIT_MS>0) && (AUTO_EXIT_MS<1000))
#error "Do not set AUTO_EXIT_MS to below 1s to allow Micronucleus to function properly"
#endif
Eine Änderung von #define AUTO_EXIT_MS auf 2000 sollte also das geforderte neue Verhalten erreichen.
Das Kompilieren erfolgt, wie vorgesehen, vorzugsweise mit Hilfe des Build-Management-Tool make, über die bereit gestellte make-Steuerdatei (Makefile) und AVR-GCC. make und viele weitere nützliche (Unix-) Tools kann man unxutils.sourceforge.net herunterladen. AVR-GCC findet man im Digistump-Umfeld im Verzeichnis C:\Users\<UserName>AppData\Local\arduino15\packages\digistump\tools\avr-gcc\<AVR-GCC-Version>\bin. <UserName> und <AVR-GCC-Version> werden wahrscheinlich variieren. Eine andere Quelle für AVR-GCC wäre das Arduino-Verzeichnis C:\Users\<UserName>\AppData\Local\arduino15\packages\arduino\tools\avr-gcc\...
Am besten schreibt man eine kleine Batch-Datei (makeboot.bat, s.u.), die passende Pfade setzt und die Kompilierung startet.
Nach erfolgreicher Durchführung hat man neben anderen Dateien, eine Datei mir dem Namen main.hex erzeugt, die den angepassten Bootloader enthält. Diese Datei kann man, wie oben bereits erwähnt, nicht direkt hochladen (Stichwort: Kuddelmuddel).
Das Upgrade-Programm benötigt eine Datei namens bootloader_data.c, dass den Inhalt der HEX-Datei, umgewandelt in ein C-Array enthält. Leider wird hier nicht angegeben, wie man zu dieser Datei kommt. Sucht man ein wenig, findet man bei jbowes/micronucleus-t85 von James Bowes das Ruby-Programm generate-data.rb, das diese Datei erstellt. Nun wollte ich mich nicht mit einer weiteren Programmiersprache (Ruby) auseinander setzen. Einfacher erschien es mir, ein eigenes kleines VB-Programm (Hex2CArray) zu schreiben, das diese Aufgabe erledigt. Die GitHub-Seite enthält ein Muster für Input und Output, so dass man die korrekte Funktion gut überprüfen kann.
Das Programm Hex2CArray (Implementierung s.u.) wandelt die
oben erzeugte HEX-Datei in eine C-Datei, die das Bootloader-Binary als Array enthält.
Verwendung: Hex2CArray InputFileName OutputFileName
Hex2CArray main.hex bootloader_data.c
liefert die Datei bootloader_data.c mit folgendem Aufbau:
// This file contains the bootloader data itself and the address to install the bootloader at
// Use Hex2CArray to generate these values from a hex file
// Generated from 'main.hex' at 15.04.2017 10:07:52
const uint16_t bootloader_data[] PROGMEM = {
0xC022, 0xC040, 0xC06C, 0xC03E, 0xC03D, 0xC03C, ...
... 0xFF5A, 0xBC17, 0x0640
};
uint16_t bootloader_address = 0x17C0;
Dass das Array als Word-Array (uint16_t [ ]) generiert wird und nicht, wie vielleicht erwartet, als Byte-Array (uint8_t [ ]), ist dem Upgrade-Programm geschuldet, das dieses Format verlangt. Hier wollte ich so wenig wie möglich ändern.
Am besten schreibt man eine kleine Batch-Datei (makeboot.bat), die passende Pfade setzt, die Kompilierung startet und das C-Array erstellt.
@echo off
set path=%path%;<Pfad make> !! ERSETZEN
set path=%path%;<Pfad avr-gcc> !! ERSETZEN
set path=%path%;<Pfad Hex2CArray> !! ERSETZEN
make clean
make CONFIG=t85_default !! ggf. anpassen
Hex2CArray main.hex bootloader_data.c
Das Batch-Programm startet man optimalerweise von der Eingabeanforderung (DOS-Box) aus, damit man das Ergebnis des Vorgangs sehen kann:
C>makeboot
Building Micronucleus configuration: t85_default
Size of sections:
text data bss dec hex filename
1596 0 44 1640 668 main.bin
Size of binary hexfile. Use the "data" size to calculate the bootloader address:
text data bss dec hex filename
0 1596 0 1596 63c main.hex
bootloader_data.c erfolgreich erstellt
C>
make clean
meldet ggf. beim ersten Aufruf einen Fehler, da die Dateien, die
gelöscht werden sollen, noch nicht existieren.
Als letztes benötigt man nun ein Programm, dass den neu erstellten Bootloader-Code als Daten enthält und nach dem Start den alten Bootloader überschreibt. Im Verzeichnis firmware ist ein Programm mit dem Namen upgrade.c enthalten, das ein beigesteuertes Bootloader-Binary an die passende Stelle in den Flash-Speicher schreibt. Dies ist ein normales C-Programm. Am einfachsten ist, man "übersetzt" dieses Programm in ein Arduino-Programm. Dann steht über die IDE sowohl ein konfigurierter Compiler als auch ein entsprechender Upload-Mechanismus zur Verfügung. Der Transfer ist recht einfach. Man benenne main() um in setup() und füge eine leere loop()-Funktion ein. Das vorher erstellte bootloader_data.c hinzufügen. Kompilieren, Uploaden, Fertig. Danach kann mit dem neuen Bootloader das eigentliche Programm geladen werden.
Im Download (Digi-BootloaderUpgrade) ist der der originale Code ein wenig angepasst. Zum einem wurden die wenigen Zeilen aus der ursprünglich benötigten Datei util.h in den Code eingefügt, so das diese nicht mehr benötigt wird. Zum anderen wurde die Methode beep() so angepasst, dass die interne LED des Digispark nach Ende des Programms blinkt.
Digi-BootloaderUpgrade VS/VM-Projekt, enthält Digi_BootloaderUpgrade.ino benötigt bootloader_data.c | |
Hex2CArray Binary, enthält Hex2CArray.exe |
Den Aufbau eine HEX-Datei findet man bei RN-Wissen. Von Interesse sind nur die Satztypen 00 (enthält die Daten) und 03 (enthält die Startadresse).
Das prüft zunächst, ob genau 2 Kommandozeilen-Argumente angegeben wurden und versucht die angegebenen Dateien zu öffnen. Als erstes wird dann der Kopf der Ausgabedatei geschrieben. Danach wird die HEX-Datei zeilenweise eingelesen und analysiert. Dadurch, dass das zu erzeugende C-Array aus Elementen vom Typ uint16_t besteht, muss eine gerade Anzahl an Bytes vorliegen. Ist dies beim letzten Datensatz nicht der Fall, weil der Code zu einer ungeraden Byte-Zahl führt, wird eine zusätzliches Null-Byte angefügt. Die eingelesenen Bytes werden als 16-Bit-Zahlen ausgegeben.
Sind sämtliche Datensätze bearbeitet, wird das Datei-Ende mit der Startadresse ausgegeben.
Die fehlerfreie Ausführung wird mit der Meldung "<Dateiname> erfolgreich erstellt" angezeigt und der Exit-Code ist 0. Ansonsten wird eine Fehlermeldung ausgegeben und der Exit-Code ist 1.
Hex2CArray VS-Projekt |