Firmware-Update gegen streikende Digispark-Clones

Die Nachbauten des winzigen Mikrocontroller-Boards Digispark sind billig zu haben und lassen sich mit der Arduino-IDE programmieren. Oft sind die ersten Erfahrungen damit jedoch enttäuschend – nichts scheint so richtig zu funktionieren. Eine Aktualisierung der Firmware kann Abhilfe schaffen, sowohl bei Digispark-Clones als auch bei anderen Boards, die auf den Micronucleus-Bootloader setzen. Ganz nebenbei kann man damit auch die 5-Sekunden-Pause nach dem Einschalten umgehen.

digispark_overview


Inhalt
Kleinkern – Wie funktioniert Micronucleus?
Problem Child – Wenn der Kleine nicht mitspielt. Symptome.
What are you? – Welche Micronucleus-Version hat er denn?
Der Trick mit dem Upgrade – Micronucleus-Upgrade mit Micronucleus.
The Lazy Way – Micronucleus-Upgrade von der Stange.
The High Road – Micronucleus mit eigenen Anpassungen selber bauen.


Der Digispark nahm 2012 als Überraschungserfolg bei Kickstarter seinen Anfang. Konzipiert wurde die briefmarkengroße Platine als Winzig-Alternative für den Arduino. Da er billiger und ziemlich dolle viel kleiner ist, bietet er sich für den festen Einbau in das jeweilige Projekt an.

Wie auch beim Arduino steht das Hardware-Design des Digispark unter freien Lizenzen (relativ restriktive Creative-Commons-Lizenzen). Wenig verwunderlich also, dass bald Nachbauten auftauchten und die Preise zum Bier holen in den Keller gingen. Dort sind sie heute noch.

Das Original kostet 8 US-Dollar, die Kopien weitaus weniger. Selbst wenn man den Import aus China scheut, sind die Platinchen für ca. zwei Euro zu haben. Bei Aliexpress pendeln die Preise irgendwo um einen Euro. Ein Digispark-Klon kostet somit weniger als die Summe seiner Einzelteile im örtlichen Elektronik-Markt.

digispark_size
Zwei Clones. Die berüchtigte Revision 3 wurde von Digistump nie produziert; zwar steht das Design unter einer freien Lizenz, der Name jedoch nicht.

Ein Nachteil dieser verteilten, anarchistischen Produktionsweise ist, dass es bei den Klonen keine Qualitätssicherung gibt. Was unter dem Namen Digispark oder als dazu kompatibel angeboten wird, variiert daher recht stark. Wenig falsch machen können die Hersteller bei der Hardware: der Schaltplan des Digispark ist ausgesprochen spartanisch. Doch damit aus dem Platinchen tatsächlich ein Digispark wird, bedarf es etwas mehr: nämlich Software. Der Microcontroller – ein ATtiny85 – benötigt einen speziellen Bootloader, der ihn USB-fähig macht und so das flashen von Programmen vom PC auf den Digispark ohne zusätzliche Hardware ermöglicht. Hier herrscht leider ein wenig Chaos und Versionswirrwarr. Es sollen auch Exemplare im Umlauf sein, bei denen der Bootloader einfach vergessen wurde.

Kleinkern

Der Bootloader trägt den Namen Micronucleus. Zu Micronucleus gehören zwei Hälften: erstens die Firmware, also der Bootloader, der auf den ATtiny geflasht wurde. Zweitens das Kommandozeilenprogramm, das auf dem PC läuft und mit seinem Gegenstück auf dem Controller per USB sprechen kann.

Der Bootloader belegt etwa 2 KiB des 8 KiB großen Speichers. Um die übrigen 6 KiB mit einem eigenen Programm zu beschreiben, klickt man in der (für den Digispark konfigurierten) Arduino-IDE auf „Upload“. Im Hintergrund wird der Sketch zu einer Binärdatei kompiliert und an das PC-seitige Micronucleus weitergereicht. Micronucleus wartet dann darauf, dass man den Digispark an den USB-Port stöpselt. Sobald man das getan hat meldet sich der Bootloader beim Kommandozeilenprogramm, nimmt den kompilierten Sektch entgegen und schreibt ihn in die freien 6 KiB. Per Default ist der Bootloader so konfiguriert, dass er etwa 5 Sekunden auf ein neues Programm wartet, bevor er in ein bereits geflashtes Programm springt. Das führt zu einer in manchen Projekten unpraktischen Zwangspause nach dem Einschalten. Zum Glück lässt sich das Verhalten ändern. Noch größeres Glück: Wie es geht, steht in diesem Blog!

Problem Child

Im Vergleich zum Arduino Uno sind Digispark-Klone ziemlich schlecht erzogen. Es braucht nicht selten pädagogische Tricks, um sie zum Mitmachen zu bewegen. Ob originale Digisparks sich besser betragen, habe ich bisher nicht getestet. Ich vermute aber, dass nein. Im Folgenden einige Dinge, die schief gehen können (ohne Anspruch auf Vollständigkeit):

Der Digispark wird gar nicht erkannt

Unter Linux zeigt lsusb eine Liste aller verbundenen USB-Geräte an. Wenn keines der Geräte der Digispark ist, dann fehlt möglichweise der Bootloader. In einem solchen Fall müsste man ihn per In-System-Programmer (ISP) flashen. Als ISP lässt sich z. B. ein Arduino Uno verwenden.

digi_lsusb
Erfolg: Hier wurde der Digispark vom Rechner erkannt

Oft kommt es auch vor, dass der Digispark nicht mit jedem Rechner gleich gerne zusammen spielt. Das kann mehrere Gründe haben. Wenn hardwareseitig alles okay ist (bitte keine vernudelten USB-Kabel benutzen), dann kann nur noch die Software schuld sein – also auf der einen Seite der PC, mit OS, Treibern, Arduino-IDE und Digispark-Erweiterungen, und auf der anderen Seite der Microcontroller mit seiner Firmware.

Falls alles richtig eingerichtet ist und dennoch nichts geht, lohnt es sich immer noch, einen anderen Rechner auszuprobieren. Das kann daran liegen, dass der ATtiny keine hardwareseitige USB-Unterstützung bietet. Der Micronucleus-Bootloader benutzt zwei Digitalpins als USB D+ und D-. Mir plausibel erscheinenden Gerüchten zufolge führt das relativ ungenaue Timing des internen Oszillators zu Abweichungen jenseits der erlaubten Toleranzen – manche Rechner kommen damit besser klar als andere. Es ist halt ein Hack – und die Digispark-Erfinder weisen ausdrücklich darauf hin.

Als System zum Programmieren benutze ich Ubuntu. Generell mögen die Digisparks mein 32-Bit-Netboook lieber als meinen 64-Bit-Desktop-Rechner.

Pin 5 geht nicht

Kein Bug, sondern ein Feature: der Pin PB5 des ATtiny85 ist sein Reset-Pin. Beim originalen Digispark wird der Reset-Pin per Fuse deaktiviert. Auf diese Weise lässt er sich (mit Einschränkungen) als digitaler IO benutzen. Der Nachteil dabei: man verliert die Möglichkeit, ihn per ISP zu programmieren. Ach ja: Reset geht dann natürlich auch nicht mehr. Das Zurücksetzen der Fuse ist möglich, erfordert aber High-Voltage-Programming. Sollte der Bootloader zu Schaden kommen – sei es durch äußere Einflüsse oder durch kreative Programmierung – so ist ISP die einzige Rettung.

Am Laptop geht’s am Desktop nicht

Nicht jede Version des Bootloaders verhält sich überall gleich. In meinem Fall verweigerte ein Digiklon mit der Firmware-Version 1.06 die Zusammenarbeit mit dem Desktop-Rechner (Ubuntu, 64 Bit). Mit dem alten Aldi-Netbook funktionierte dagegen alles (Ubuntu, 32 Bit). Es ergab sich folgendes Bild:

Klon Firmware Desktop PC
(64 Bit)
Netbook
(32 Bit)
Klon A 1.01(?) geht geht
Klon B 1.06 geht nicht geht trotz
Fehlermeldung

Was dabei klar wird: mit dem PC stimmt eigentlich alles. Der Fehler steckt wohl in der  Firmware-Version 1.06. Die Lösung ist ein Upgrade auf neuere Versionen von Micronucleus. Immerhin: an einem der Rechner lassen sich Programme auf den Digiklon flashen. Mittels eines Tricks kann auf diesem Weg auch der Bootloader aktualisiert werden.

Nach zwei Upgrades setzt sich die Tabelle so fort:

Klon Firmware Desktop PC
(64 Bit)
Netbook
(32 Bit)
Klon B 1.11 geht geht
Klon B 2.03 geht geht

What are you?

Um den streikenden Digiklon zur Mitarbeit zu bewegen, bedarf es also eines Upgrades auf neuere Versionen der Micronucleus-Firmware. Findet sich kein Rechner, mit dem der Klon zusammenspielt, so bleibt nur der Weg über ISP.

Zunächst ermitteln wir die Versionsnummer der installierten Firmware (auf dem Digispark). Dazu führen wir Micronucleus (auf dem PC) direkt aus und schauen uns den Output an. Unter Ubuntu findet man Micronucleus nach der korrekten Einrichtung der Arduino-IDE im Home-Ordner des jeweiligen Users an der folgenden Stelle:

.arduino15/packages/digistump/tools/micronucleus/2.0a4/

Der letzte Unterordner steht dabei für die verwendete Micronucleus-Version. Nun wechseln wir in diesen Ordner und löschen das User-Programm auf der Briefmarke mit:

./micronucleus --erase-only

Ohne sudo klappt das natürlich nur, wenn man gemäß der Anleitung aus dem Digispark-Wiki die entsprechenden udev-Regeln angelegt hat. Der Output sieht dann so aus:

micronucleus_version
Die Firmware-Version ist 1.6

Jetzt wissen wir, dass ein Upgrade möglich ist. Mit der Version 2 wurde Micronucleus komplett neu geschrieben. Daher findet man auf Github verschiedene Zweige:

In den Repos gibt es unter „releases“ einige Varianten der Firmware als fertig kompilierte Binärdateien. Für den Digispark zählen hier natürlich nur die für den ATtiny85.

So weit, so gut. Aber wie bekommt man jetzt die Firmware auf den Digispark?

Der Trick mit dem Upgrade

Eine der Entwicklerinnen (bekannt als Bluebie) hatte die fixe Idee, wie man Micronucleus dazu überreden kann, sich selbst zu aktualisieren. Benötigt wird der neue Bootloader. Dieser wird dann in ein User-Programm gesteckt, das von dem alten Bootloader auf dem ATtiny geflasht und gestartet wird. Einmal ausgeführt legt das Programm den alten Bootloader lahm und überschreibt ihn mit dem Neuen. Aus dem Readme:

Upgrade is a virus-like payload you can upload via micronucleus (or other bootloaders!) to install a new version of micronucleus on the target chip. The upgrade program works by compiling the binary contents of a bootloader hex file in to a progmem array, then running on the chip bricking the device so it doesn't enter any existing bootloader anymore but instead runs the upgrade program exclusively. Next it erases and rewrites the bootloader in place at the same address the hex file specifies (BOOTLOADER_ADDRESS in the case of micronucleus). Once the bootloader has been rewritten, upgrade rewrites it's own interrupt vector table to point every interrupt including reset straight at the newly uploaded bootloader's interrupt vector table at whichever address it was installed.

Klare Sache: Wenn Micronucleus schon ein Hack ist, dann hackt diese Upgrade-Methode den Hack. Wenn dabei etwas schief geht, geht danach nix mehr – jedenfalls nicht ohne In-System-Programmer. Doch der Versuch lohnt sich, vor allem wenn man gerade keinen Programmer zur Hand hat oder der dafür erforderliche Reset-Pin deaktiviert wurde.

Wir spielen zwei Varianten durch:

  1. The Lazy Way – Upgrade runterladen und flashen
  2. The High Road – Micronucleus nach eigenen Bedürfnissen kompilieren, ein Upgrade daraus bauen und flashen

Zwar ist die erste Variante recht komfortabel, doch gibt es nicht alle möglichen Micronucleus-Varianten fertig kompiliert zum herunterladen. Möchte man zum Beispiel die lästige 5-Sekunden-Pause loswerden, so führt aktuell kein Weg am selbst Kompilieren vorbei.

The Lazy Way

Das Github-Repo bietet derzeit zwei Firmware-Varianten für den ATtiny85 zum Download an. Unter „firmware/releases/“ finden wir

t85_aggressive.hex
und
t85_default.hex

Der Unterschied ist, dass die aggressive Variante weniger Speicher braucht und so etwas mehr Platz für User-Programme auf dem ATtiny übrig bleibt. Die Upgrade-Versionen liegen unter „upgrade/releases/“ mit den entsprechenden Namen

upgrade-t85_aggressive.hex
und
upgrade-t85_default.hex

Die letztere laden wir herunter (öffnen, rechte Maustaste auf „RAW“, Ziel speichern unter – es ist wichtig hier nix verkehrt zu machen und am Ende irgend ein HTML zu flashen, ichweißwovonichrede) und kopieren sie zum Beispiel in einen Ordner namens „upgrade“ im Home-Ordner. Falls zur Hand kann man nun ein Piezo-Element an Pin 0 und Pin 1 anschließen. Wenn das Upgrade erfolgreich verläuft, gibt es zur Belohnung ein kurzes Piepen. Wenn es nicht piept – MUHAHAHAHAA! KAPUTT!

Um das Upgrade auszuführen wechseln wir wieder in den Micronucleus-Ordner:

cd ~/.arduino15/packages/digistump/tools/micronucleus/2.0a4/

Dort weisen wir Micronucleus an, das Upgrade zu flashen und auszuführen:

./micronucleus --run ~/upgrade/upgrade-t85_default.hex

flash_upgrade
Micronucleus weiß nicht, dass es gerade huckepack einen neuen Bootloader geflasht hat

Nachdem der Piezo-Summer hoffentlich signalisiert, dass die neue Firmware auf dem Digispark ist, kann man das Ergebnis wie gehabt überprüfen:

micronucleus_new_version
Firmware jetzt auf Version 2.3 (i.e. 2.03)

Wie mensch sehen kann, ist nicht nur die Firmware aktualisiert. Ganz wie von selbst sind auch die vormaligen Fehlermeldungen („connection lost“) verschwunden.

Mit der aktualisierten Firmware kann man nun sein Glück an Rechnern versuchen, die zuvor jede Zusammenarbeit verweigert haben.

The High Road

Wie bereits angedeutet, ist Micronucleus nicht bloß irgendein Bootloader für den ATtiny85. Vielmehr ist es ein konfigurierbares Build-System, das verschiedene Bootloader für verschiedene ATtinies produziert. Die möglichen Variationen sind zahlreich. Die Entwickler*innen haben nur einige Wenige vorkompiliert zum Download bereit gestellt.

Beim selber bauen des Bootloaders können wir das Ergebnis wunschgemäß beeinflussen und einige Parameter ändern. Dafür sind allerdings noch ein paar Zutaten notwendig.

Zunächst sollte man das Repo klonen oder einfach als ZIP von Github herunterladen und in einen Ordner entpacken. Per Vorgabe heisst dieser Ordner micronucleus-master.

Die Installation der nötigen Tools (Compiler etc.) sollte mit

sudo apt install avr-libc make ruby

erledigt sein. Das Paket gcc-avr ist in den Abhängigkeiten enthalten. Wenn man die Firmware per ISP flashen möchte, kann man auf ruby verzichten.

Bevor es ans Bauen geht, passen wir die Konfiguration an. Im Unterschied zur Standard-Variante verändern wir den Auslöser für den Flash-Vorgang. An Stelle der 5-Sekunden-Pause konfigurieren wir Pin 0 als Jumper. Wird er mit Masse verbunden, wartet Micronucleus auf Input, bleibt er offen, läuft das User-Programm. Der Pin ist weiterhin für andere Späße zu haben – man darf halt nur nix dranbasteln, was ihn beim Einschalten gegen Masse zieht.

Wir legen uns einen neuen Unterordner an und kopieren die Default-Konfiguration als Ausgangspunkt zum Rumpfuschen:

cd ~/micronucleus-master/firmware/configuration/
mkdir t85_custom
cp t85_default/* t85_custom/

In unserem Ordner finden wir zwei Dateien, einmal das Makefile.inc und die bootloaderconfig.h. Dank ausführlicher Anmerkungen ist die Bootloaderconfig relativ selbsterklärend. Fun fact: auch die Dauer der Zwangspause wird hier festgelegt. Es sind in der Tat 6000 ungenau gemessene Millisekunden – das erklärt, wieso die 5 Sekunden so lange wirken! Uns interessiert der Abschnitt zu der „entry condition“. Mit einem Texteditor unserer Wahl (nicht emacs) ändern wir nun die Zeile (derzeit Zeile 110)

# define ENTRYMODE ENTRY_ALWAYS
zu
# define ENTRYMODE ENTRY_JUMPER

und speichern die Änderung. Da wir den Code geändert haben, ergibt sich nun auch wahrscheinlich eine andere Größe des Bootloaders. Das heißt, dass in der Folge die Grenze zwischen Bootloader und dem freien Platz für User-Programme neu berechnet werden muss. Wie man das ausrechnet, steht in obigem Makefile, direkt über der dafür zuständigen Variable namens BOOTLOADER_ADDRESS.

Wir wechseln wir in den Ordner „firmware“ und bauen probeweise unsere Konfiguration mit make CONFIG=t85_custom. Als Ergebnis erhalten wir eine Tabelle, die uns unter anderem die Größe des kompilierten Bootloaders mitteilt (mit dem freundlichen Hinweis, wozu das gut sein soll).

micronucleus_bootadress

Mit dem Wert von data können wir nun rechnen: Zuerst wird der Wert von der Speichergröße des ATtiny85 abgezogen.

  8 KiB = 1024 x 8 Byte = 8192 Byte
                        - 1630 Byte
                        = 6562 Byte

Der Speicher ist in Blöcken (memory pages) organisiert. Aus Sicht der Speicherverwaltung haben wir jetzt sehr wahrscheinlich eine unmögliche Addresse ausgerechnet – in etwa so etwas wie die Hausnummer 3,76. Um zu korrigieren teilen wir den Wert durch die Größe der Memory Pages  (64 Byte) und runden das Ergebnis ab.

  6562 / 64 = 102,53125 ≈ 102

Nun rechnen wir von dem begradigten Wert wieder zurück und erhalten so die Addresse für den Bootloader:

  102 x 64 = 6528

Selbstverständlich brauchen wir die Addresse in Hexadezimalschreibweise, also 1980. Wie der Zufall es will, ist das genau die gleiche Addresse wie bei der Default-Konfiguration. Hätten wir uns das Ganze also sparen können? – Nein! Denn je nachdem, was mensch in der Konfiguration ändert, können auch ganz andere Zahlen dabei heraus kommen. In dem Fall ist die Variable im Makefile entsprechend anzupassen. Danach wird der Bootloader neu kompiliert:

cd ~/micronucleus-master/firmware/
make clean
make CONFIG=t85_custom

An selber Stelle finden wir nun eine Binärdatei namens main.hex – das ist unser neuer Bootloader. Mit einem ISP könnte die main.hex direkt auf den ATtiny geschrieben werden. Da wir aber die Upgrade-Methode verfolgen, müssen wir daraus zuerst ein Upgrade erzeugen. Im Ordner „upgrade“ liegt das dafür notwendige Ruby-Script und ein dazugehöriges Makefile.

cd ~/micronucleus-master/upgrade/
ruby generate-data.rb ../firmware/main.hex
make clean
make

Beim ersten mal ist make clean natürlich verzichtbar. Als Ergebnis erhält man eine Datei namens upgrade.hex. Mit dieser verfährt man nun genau wie im Abschnitt „The Lazy Way“ beschrieben. Wenn man Spaß dran hat, kann man sie vorher noch deskriptiv umbenennen:

mv upgrade.hex upgrade-t85_entry-jumper.hex

Damit wird das Leben leichter, wenn mensch das Spiel nach ein paar Tagen wiederholt. Warum wir es wiederholen möchten, können wir jetzt noch nicht wissen. Aber wenn es so weit ist, ist eine Datei namens upgrade.hex in etwa so gut wie gar keine. Upgrade flashen:

cd ~/.arduino15/packages/digistump/tools/micronucleus/2.0a4/
./micronucleus --run ~/micronucleus-master/upgrade/upgrade-t85_entry-jumper.hex

Das Hochladen eines Sketches mit der Arduino-IDE funktioniert nun wie sonst auch, nur eben mit Jumper. Pin 0 und GND müssen vor dem Einstöpseln kurzgeschlossen werden. Wird der Digispark ohne Jumper mit Strom versorgt, startet das User-Programm sofort.

Sonst so

Möglich sind auch andere „entry condtitions“, z. B. kann der Reset-Pin als Trigger verwendet werden. Mit zahlreichen weiteren Optionen kann man andere Feinheiten festlegen, etwa den Takt von einem (genaueren) externen Oszillator vorgeben lassen. Sicher keine schlechte Idee, wenn das Ergebnis so etwas wie eine LED-Uhr mit WS2812 werden soll.

Vielen Leuten dürfte die Upgrade-Methode ein wenig umständlich vorkommen. Das liegt in erster Linie daran, dass die Upgrade-Methode ein wenig umständlich ist. Normale Leute bringen die Firmware mittels ISP und avrdude auf ihren ATtiny. Sinnvoll ist das Upgrade, wenn dieser Weg versperrt ist. Für den Einsteiger gilt: der Versuch kann ja nicht schaden.

Werbeanzeigen

3 Gedanken zu “Firmware-Update gegen streikende Digispark-Clones

  1. Hi,

    bei mir funktioniert das nicht mit der 2.xx Firmware. Da bringt er immer „Program file is 1786 bytes too big for the bootloader!“
    Habe dann von 1.06 auf 1.11 versucht und dass geht. Wenn ich dann auf 2.xx Versuche, kommt wieder obriger Fehler.

    Eine Idee, woran es liegen kann?

    Gruss

    Helge

    Liken

  2. Schwer zu sagen.

    Der Fehlermeldung nach würde ich vermuten, dass du vielleicht gar nicht die Firmware heruntergeladen hast, sondern die Github-Seite, die die Firmware als Hex-Datei anzeigt. Die ist dann nämlich zu groß. In dem Fall hilft einfach nochmal richtig herunterladen.

    Hab das ganze gerade noch mal mit der aktuellen Micronucleus-Version durchgespielt. Update von 1.11 auf 2.04/2.4 lief ohne Probleme – also mit Repo clonen und alles Selberbauen (Firmware und Commandline-Tool). In der Arduino-IDE hinkt das Tool leider noch mit der Version 2.03 hinterher und die verweigert dann die Zusammenarbeit mit einem neueren Bootloader.

    (Unter Ubuntu 19.04 musste ich dafür noch das Paket libusb-dev installieren.)

    Also mein Tipp: neuste Version clonen, make (commandline, firmware und upgrade), damit sollte es gehen.

    Liken

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google Foto

Du kommentierst mit Deinem Google-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s