Digispark Bootloader

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.

Micronucleus

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.

Aufgabe

Für eine Anwendung ist die Latenzzeit des Bootloaders von 6 Sekunden zu lang. Sie soll auf 2 Sekunden reduziert werden.

Vorgehen

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.

A. Download der Quellen und der Make-File

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.

B. Anpassung des Programms

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.

C. Kompilieren des Bootloaders

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).

D. Umwandeln der HEX-Datei in ein C-Array

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.

Batch-Datei zur Kompilierung und Erstellung des C-Array

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.

E. Update-Programm erstellen

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.

Downloads

Download Digi-BootloaderUpgrade Digi-BootloaderUpgrade VS/VM-Projekt, enthält Digi_BootloaderUpgrade.ino benötigt bootloader_data.c
Download Hex2CArray Binary Hex2CArray Binary, enthält Hex2CArray.exe

Implementierung von Hex2CArray

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.

 

Download Hex2CArray Projekt Hex2CArray VS-Projekt