Sicherheitskritisch

Tech project blog of Bastian Raschke

TinyUSBBoard - eine coole Arduino-kompatible Alternative für 4 Euro

Written by Bastian Raschke.
Published 2014-11-24 in the category Arduino.

Durch meine letzten Projekte wurde ich zunehmens motiviert, mich mehr mit Hardware zu beschäftigen. Durch einen angeschafften Arduino Leonardo und dessen verlockende Features (z.B. Emulierung von Tastatur und Maus) bin ich in die Welt der Atmel-Mikrocontroller vorgestoßen. Nach einigen, wenig aufregenden Arduino-Evergreen-Beispielen wollte ich etwas mehr hinbekommen, als z.B. eine LED durch einen Taster blinken zu lassen. Und schlussendlich bin ich bei komplett anderer Hardware gelandet.

Doch zurück zu meinen Anfängen mit Arduino: Ich merkte bei der Implementierung meiner ersten Bibliotheken recht schnell, dass meine C-Kenntnisse schon ein paar Semester zurückliegen und dank fehlender Praxis recht eingerostet sind. Weiterhin habe ich sofort Kontakt mit den frustrierenden Arduino-Wehwehchen gemacht á la Arduino-IDE Serialmonitor funktioniert nicht und wirft stattdessen wirre Java-Exceptions, oder ich schreibe meine Bibliothek und die Arduino-IDE kennt diese bis zum Verzweifeln nicht, bis ich merke, dass ein Neustart erforderlich ist. Dann gab es Probleme mit einem veralteten avr-gcc (das in der Arduino-IDE Version 1.0.1 mitgeliefert wurde), sodass zahlreiche Fremd-Bibliotheken nicht funktionierten (u.a. Stichwort: -assembler-with-cpp-Flag ist nicht bekannt). Nach etlichen Stunden suchen, der Installation von Arduino-IDE 1.0.6 und einigen Wochen C aufarbeiten ging es vorwärts.

Nun ist Arduino eine schöne Sache, nur wenn man kleine sehr spezielle Projekte geplant hat (in meinem Fall USB-Interaktion), kommt man mit den Standardboards nicht sehr weit beim geplanten Produktiveinsatz - sie sind zu groß, zu teuer und überladen mit unnötigen Hardware-Features - ich suchte Alternativen.

Und bin nach einiger Suche beim TinyUSBBoard von Stephan Bärwolf gelandet, welcher ein komplett eigenes Arduino-kompatibles Board mit ATmega8A in USB-Stick-Bauform entworfen hat. Weiterhin hat er einen sehr optimierten Bootloader (USBaspLoader) geschrieben, welcher bestens mit dem Board zusammenarbeitet. Was mich an dem Projekt gereizt hat, war der Minimalismus, dass nur das verwendet wird, was unmittelbar nötig ist (von ein paar LEDs mal abgesehen). Der Bootloader ist recht schlank und komplett Open-Source, wodurch er vollständig nachvollzogen werden kann. Und das alles habe ich mir schon immer mal vorgestellt: Möglichst nah an der (sogar selbst gebauten) Hardware sein und diese nicht wie den normalen Rechner als gigantische magische Blackbox-Wundermaschine sehen zu müssen. Weiterhin werden Bausätze für die Durchsteckbauform (THT) und neuerdings moderne SMT-Bauform bei Ebay (Benutzer „matrixprog“) für sehr verlockende 4 Euro angeboten.

Da ich mir noch nicht sicher war, ob die Hardware meinem geplanten Anwendungszweck genügen wird (eine USB-Tastatur via Arduino emulieren), wendete ich mich an Stephan Bärwolf, welcher mir generell wirklich gedultig und kompetent bei meinen Fragen und Problemen weiterhalf. An dieser Stelle ein großes Lob! Ich erfuhr zu meiner Freude, dass das TinyUSBBoard meiner Anwendung genügt und bestellte mir gleich ein THT-Bausatz.

Löten der Platine

Nach anfänglichen Löt-Problemen mit der mitgelieferten Lochrasterplatine (diese ist recht preiswert und die Lötaugen lösen sich leicht ab), welche jedoch auch dadurch begründet sein dürften, dass das meine erste eigene Lochrasterplatinelötung war, ging es langsam aber gut voran.

Der folgende TinyUSBBoard-Schaltplan wird empfohlen:

TinyUSBBoard-Schaltplan Rev. 3
TinyUSBBoard-Schaltplan Rev. 3 (Quelle: http://matrixstorm.com/avr/tinyusbboard/)

Mein erstes fertiges Board seht ihr hier:

Erste eigene Version des TinyUSBBoard Rev. 3 - Vorderseite Erste eigene Version des TinyUSBBoard Rev. 3 - Rückseite

Erster Test und Inbetriebname

Der im Bausatz vorhandene ATmega8A ist bereits mit dem USBaspLoader-Bootloader und der Standard-Firmware bespielt worden, was den Funktionstest und die Inbetriebnahme massiv vereinfacht: Es wäre nämlich bei einem blanken Mikrocontroller recht umständlich, einen Bootloader und/oder Firmware ohne einen Bootloader aufzuspielen (Henne-Ei-Problem). Die Standardfirmware macht generell ein paar Selbsttests, in dem sie u.a. die angeschlossenen LEDs blinken lässt, woraus man schließen kann, dass man beim Zusammenbau keine groben Fehler gemacht hat.

Danach wollte ich natürlich meine eigenen Arduino-Sketche testen, was noch ein bisschen Vorarbeit kostet: Zunächst muss in dem Sketch-Verzeichnis des Benutzers (in dem auch der library-Ordner liegt), der Ordner hardware angelegt werden, falls dieser noch nicht vorhanden ist. In diesen Ordner wird der Ordner tinyUSBBoard entpackt, welcher in dem unten verlinkten targz-Archiv [1] enthalten ist. Nach einem Neustart des Arduino-IDE sollte unter der Auswahl: „Tools > Boards“ auch das „tinyUSBboard (USBaspLoader ATmega8 at 16MHz, Rev.3 and newer)“ vorhanden sein, welches ausgewählt wird.

Als ich nun das TinyUSBBoard mit gedrücktem PROG-Taster (Erklärung siehe unten) an meinen Rechner steckte und ich eine neue Firmware (einen Arduino-Sketch) hochladen wollte, erhielt ich folgende Fehlermeldungen:

avrdude: Warning: cannot query manufacturer for device: error sending control message: Operation not permitted
avrdude: error: could not find USB device "USBasp" with vid=0x16c0 pid=0x5dc

Dies lag daran, dass das Gerät beim Einstecken von Linux standardmäßig dem Benutzer „root“ zugeschrieben wird und normale Benutzer auf dieses nicht schreiben dürfen. Folgender Workaround schafft Abhilfe:

Zunächst wird die Gruppe „usbasp“ angelegt:

~# groupadd usbasp

Dann wird der Benutzer (hier „bastian“), der mit dem Board arbeiten möchte, in diese Gruppe eingetragen:

~# usermod -a -G usbasp bastian

Nun wird ein zusätzlicher udev-Skript /etc/udev/rules.d/41-usbasp.rules mit dem folgenden Inhalt erstellt:

## USBAsp AVR VUSB Device
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", MODE="0664", GROUP="usbasp"

Wichtig: Es ist zu beachten, dass mind. eine Leerzeile am Ende steht!

Nach einem Neustart des Rechners müsste nun alles funktionieren.

Workaround: Serielles Debugging

Wenn man mit Arduino debuggt, dann wird gerne z.B. die Methode Serial.println() genutzt, um etwas aus dem Programm zur Laufzeit auf der seriellen Schnittstelle auszugeben. Das TinyUSBBoard hat jedoch keine direkte, serielle Schnittstelle via USB - es wird sogar stolz gesagt, dass kein rachsüchtiger FTDI-Chip vorhanden ist ;-) . Ohne serielles Debugging macht sich das Entwicklen mit Arduino jedoch recht schwer.

Jedoch kann man die seriellen PINs des ATmega nutzen, um die serielle Kommunikation durch ein zusätzlichen USB-TTL-Konverter mit dem Rechner zu ermöglichen. Beide Geräte werden wie auf dem folgenden Bild verbunden (die grüne Leitung ist am TX-PIN des TinyUSBBoard und am RX-PIN des USB-TTL-Konverters, die schwarze Leitung ist Ground (GND) auf beiden Seiten:

TinyUSBBoard mit angeschlossenem USB-Konverter

Mein zweites Board

Da ich an den enormen Speicherplatz des Leonardo (satte 32 kB für Firmware) gewöhnt war und ich dank des Platzbedarfes meiner Projekte durch viele eingebundene Bibliotheken nicht einfach zurück auf 8 kB (was der ATmega8A hat) konnte, brauchte ich etwas größeres. Dabei sei der generelle Grundsatz jedoch nicht zu vergessen, besser die Effizienz der eigenen Programme zu steigern, statt einfach hardwaretechnisch aufzurüsten - ich rede mich aber in dieser Situation damit heraus, dass ich noch ein Einsteiger in dem Thema bin und die riesen Fremd-Bibliotheken schuld sind ;-)

Da es komfortabel vorkompilierte Firmware für das TinyUSBBoard mit einem Atmega328P gibt, und dieser eben die gewünschten 32 kB Speicherplatz bietet, liebäugelte ich also nach einem Board mit diesem Chip. Jedoch erfuhr ich, dass dieser kleine Chip eine kleine Zicke ist, der weder zuviel Hitze mag (Löten), noch Störeinflüsse bei der Stromversorgung. Also bestellte ich bei dem Elektronikhandel meiner Wahl neben den normalen Komponenten zusätzlich einen IC-Sockel und einen entstörenden Kondensator.

Zusammengefasst noch mal die komplette Teileliste für die THT-Bauweise für Rev. 3:

  • 1x USB-Einbaustecker (Serie A, gewinkelt)
  • 2x Zener-Diode (0,5W 3,6V)
  • 1x Metall-/Kohle-Widerstand (1,5 kOhm)
  • 2x Metall-/Kohle-Widerstand (68 Ohm)
  • 1x ATmega328P-PU (DIL-28)
  • 1x passender IC-Sockel (28-polig, flach)
  • 1x Standardquarz (16,0 MHz, HC49-Gehäuse, möglichst flach)
  • 2x Keramikkondensator (18 pF, Rastermaß 2,5mm)
  • 1x Vielschicht-Keramikkondensator (100 nF, Rastermaß 2,5mm)
  • 2x Kurzhubtaster (vertikale Montage)
  • 4x LED (rot, 3mm)
  • 1x LED (grün, 3mm)
  • 5x Metall-/Kohle-Widerstand für LEDs (1,0 kOhm)

Zusätzlich habe ich noch verwendet:

  • bleihaltiges Lötzinn inkl. Flussmittel (1,0mm Durchmesser)
  • Entlötlitze (1,5mm Durchmesser)
  • Silberdraht (0,6mm Durchmesser)

Folgend einige Bilder, die den Aufbau etwas dokumentieren.

Zuerst habe ich etwas rumprobiert, wie ich die Bauelemente am besten verteile:

Zweite Version des TinyUSBBoard - Leiterplatte

Dann habe ich mit einer kleinen Fräse Platz für die Halterung des USB-Steckers gefräst:

Platz für USB-Stecker wird gefräst

Und den USB-Stecker angelötet:

Angelöteter USB-Stecker auf Leiterplatte - Oberseite Angelöteter USB-Stecker auf Leiterplatte - Unterseite

Jetzt werden die ersten Komponenten mit etwas Klebestreifen fixiert, um das Board umdrehen zu können, ohne dass diese wieder herausfallen. Daraufhin werden sie angelötet:

Weitere Komponenten wurden mit Klebestreifen fixiert

Weitere Komponenten wurden angelötet

Quarz mit passenden Kondensatoren wurde angelötet

Nun wird der Silberdraht gebogen, um schlanke Grundleiterbahnen zu bilden (was hübscher aussieht und Lot spart). Weiterhin wird die PIN-Leiste in passende Stücke geteilt (am besten mit einem heißen Messer auf beiden Seiten vorsichtig anschneiden, bis die Leiste gut bricht, ansonsten resultieren unsaubere Kanten):

Gebogener Silberdraht

Konfektionierte Steckerleisten

Dann werden die Teile Stück-für-Stück weiter verbunden und angelötet:

Rückseite der Leiterplatte mit ungekürzten Beinen der Bauteile

Rückseite der Leiterplatte

Schließlich wird der Sockel eingelötet und es werden die LEDs und Taster an den Sockel angeschlossen:

Montierte LEDs und Taster auf Leiterplatte Montierter Sockel verbunden mit feinen Kabeln

Alles in allem sieht es recht schick aus, hat mich dank meines Perfektionismusses jedoch auch knapp 4 Nachmittage gekostet ;) Für die Zwischenverbindungen verwendeten Kabel sollte darauf geachtet werden, dass diese halbwegs temperaturresistent sind, da sonst die heißen Lötungen die Enden schneller ausfransend zerstören, als man den Lötkolben weg nehmen kann.

Kurzes Vorwort zu Firmware

Bevor wir uns an das Bespielen eines Chips mit Software also der Firmware beschäftigen, werde ich noch ein paar Dinge nennen, die unbedingt zu beachten sind, um den Chip nicht „zu verhunzen“.

Zunächst etwas zum Bootloader, denn hier sind einige wichtige Punkte zu beachten: Der Bootloader ist eine spezielle Firmware, die am Ende des Firmware-Speicherbereiches „sitzt“ und eine komfortable Möglichkeit bietet, „normale“ Firmware auf den Chip aufzuspielen. Nun muss der Bootloader jedoch z.B. genau wissen, wie groß der verfügbare Firmwarespeicherplatz des Chips ist, um diesen der „normalen“ Firmware bereitzustellen und sich nicht aus versehen selbst zu überschreiben. Und da es eben einige Atmel-Chips mit verschiedenen Größen und anderen Hardware-Features gibt, ist es sehr wichtig, dass die richtige Version des Bootloaders passend für den Chip gewählt wird! Die Version steht u.a. üblicherweise im Dateinamen der vorkompilierten Firmware-Datei.

Aber auch bei normaler Firmware kann es sein, dass es je nach Chip eine andere Version gibt. Dies ist dann ebenfalls meist im Dateinamen der Firmware-Datei zu erkennen. Also im Regelfall immer darauf achten!

Wichtiger Hinweis: Es ist ebenfalls generell sehr wichtig, das neben der korrekten Firmware-Version bei Avrdude (im Folgenden erklärt) auch der Schalter -p immer äquivalent gewählt wird! Dieser gibt den Namen bzw. die Kennung des Ziel-Chip an, mit dem Avrdude arbeiten soll.

Weiterhin sollte die Funktion des PROG-Tasters verstanden sein: Mit diesem ist es möglich, statt der normalen Firmware den Bootloader zu starten. Dieser sogenannte PROGMODE ist eigentlich immer nötig, wenn es um die Programmierung des Gerätes geht. Um den PROGMODE zu erreichen, wird der PROG-Taster gedrückt gehalten, während das Gerät eingesteckt wird. Wenn das Gerät bereits im Rechner steckt, wird der PROG-Taster gehalten, während der RESET-Taster kurz gedrückt wird. Nach rund einer Sekunde (dann sollte das Gerät sicher neugestartet sein), kann der PROG-Taster wieder losgelassen werden. Nach dem Programmieren kann der PROGMODE wieder verlassen werden, indem erneut der PROG- oder der RESET-Taster kurz gedrückt wird.

Kurzes Vorwort zu Avrdude

Unter anderem zum Bespielen von Firmware wird das Programm avrdude verwendet, was sich gut eignet, um alle gewünschten Operationen auf der Kommandozeile auszuführen.

Hinweis: Für alle Befehle muss sich das Gerät im PROGMODE befinden!

Um allgemeine Informationen über ein angeschlossenes Gerät auszugeben, ist folgender Pseudo-Befehl nötig:

~$ avrdude -c PROGRAMMER -p CHIPVERSION [eigentliche Befehle]

Bei dem TinyUSBBoard wird als sogenannter Programmer (das verwendete „Protokoll“ zur Übertragung) USBasp verwendet (Schalter -c). Beim Schalter -p ist der Name bzw. die Kennung des verwendeten Chips einzutragen, also beispielsweise „atmega8“ oder „atmega328p“.

Beispielsweise werden Informationen eines verbundenen ATmega8-Gerätes mit folgendem Befehl ausgegeben:

~$ avrdude -c usbasp -p atmega8 -n -v

Analog werden eigentlich alle Avrdude-Befehle begonnen.

Schritt 1 - Flashen des ATmega328P

Nun haben wir jedoch das oben bereits erwähnte Henne-Ei-Problem vorliegen:

Wir wollen die Firmware (bzw. hier die spezielle Bootloader-Firmware) auf den Chip bekommen - ohne einen vorhandenen Bootloader, der normalerweise die Daten vom Computer entgegennimmt und in den richtigen Bereich auf dem Chip ablegt. Da wir dies ungern manuell machen wollen, bietet Stephan Bärwolf glücklicherweise eine ganz komfortable Möglichkeit: Auf ein bereits funktionierendes TinyUSBBoard (im folgenden Vermittler-Board genannt) können wir eine Vermittler-Firmware hochladen, die als temporäre Zwischenstelle von unserem Rechner zu dem blanken Chip dient. Somit können wir über das Vermittler-Board den Zielchip programmieren und dieses „selbstständig“ machen! Folgendes werde ich nun Schritt für Schritt erklären:

Zunächst wird die erwähnte „USBasp Programmer“-Firmware heruntergeladen [2]. Hier ist die richtige Version für den jeweiligen Chip zu wählen, der auf dem Vermittler-Board verbaut ist - in meinem Fall habe ich ein bereits funktionierendes TinyUSBBoard mit einem ATmega8A - also wähle ich diese Version aus.

Dann wird das Vermittler-Board in den PROGMODE gebracht. Mit folgendem Befehl wird die „USBasp Programmer“-Firmware auf das Board aufgespielt:

~$ avrdude -c usbasp -p atmega8 -U flash:w:rev3_usbaspprogrammer.hex:i

(die Datei rev3_usbaspprogrammer.hex muss natürlich im aktuellen Verzeichnis liegen)

Nach dem Beenden des Vorgangs wird der PROGMODE verlassen, um die gerade aufgespielte Firmware zu starten. Als Indikator, dass diese läuft, leuchtet mindestens eine rote LED konstant. Nun wird das Board vom Rechner abgezogen und auf einem Steckbrett wie folgt mit dem blanken Chip verbunden:

TinyUSBBoard zum Flashen verbunden mit Atmel-IC auf Steckplatine - Übersicht TinyUSBBoard zum Flashen verbunden mit Atmel-IC auf Steckplatine - Detail Seite TinyUSBBoard

TinyUSBBoard zum Flashen verbunden mit Atmel-IC auf Steckplatine - Detail Seite Atmel-IC - Vorderseite TinyUSBBoard zum Flashen verbunden mit Atmel-IC auf Steckplatine - Detail Seite Atmel-IC - Rückseite

Wenn alle Verbindungen absolut korrekt sind (lieber einmal mehr überprüfen), dann kann das USB-Verlängerungskabel mit dem Rechner verbunden werden. Das Vermittler-Board wird nun wieder aktiv und wartet auf eingehende Befehle, welche auf den blanken Chip umgesetzt werden.

Nun wird die eigentliche Firmware-Version für den Ziel-Chip heruntergeladen - in meinem Fall die ATmega328P-Version [3]. Weiterhin wird über den Schalter -p auch der jeweilige Ziel-Chip gewählt. Mit folgendem Befehl wird die Firmware via dem Vermittler-Board auf den blanken ATmega328P gebracht. Um die Geschwindigkeit etwas zu erhöhen, wird der Takt der Verbindung mit den Schalter -B etwas hochgesetzt:

~$ avrdude -c usbasp -p atmega328p -U flash:w:rev3_default328p_ger_lfxf7_hfxd0_efx04_v0x97x1.hex:i -B 10

(die Firmware-Datei muss natürlich wieder im aktuellen Verzeichnis liegen)

Schritt 2 - Fusen des ATmega328P

Nun muss nach dem Aufspielen des Booloaders noch ein letzter Schritt gemacht werden: Der Chip muss noch - einfach gesprochen - für die Firmware hardwaretechnisch konfiguriert werden. Dies geschieht über sogenannte Fuses (engl. Sicherungen), welche „gesetzt“ werden können und dadurch den Chip konfigurieren. Die Möglichkeiten sind recht umfangreich und für jeden Chip unterschiedlich.

Die vielleicht bekannteste Einstellung, die per Fuse geregelt wird, ist die Taktquelle - also woher der Chip seinen Arbeitstakt beziehen soll. In den Chips ist bereits ein interner Taktgeber vorhanden, welcher standardmäßig genutzt wird und relativ niedrig taktet (meist 1 MHz). Auf dem TinyUSBBoard ist jedoch extra ein externer 16Mhz-Quarz verbaut, der den Takt steigern soll (das ist für USB-Kommunikation nötig). Aus diesem Grund muss auf diesen „umgeschaltet“ werden, damit nicht weiterhin der interne Taktgeber genutzt wird.

Und damit komm ich auch zu einer wichtigen Warnung: Mit Fuses spielt man nicht! Falsch gesetzt können starke Probleme auftreten, die die Benutzung des Chips stark einschränken oder unmöglich machen. Weiterhin wird für jede Version des Bootloaders eine andere Fuse-„Empfehlung“ gegeben, welche strikt einzuhalten ist.

Um wieder auf unser Beispiel zurückzukehren: Wenn der Chip durch falsches Setzten einer Fuse eine falsche Taktquelle nutzt und diese beispielsweise nicht vorhanden ist, kann der Chip nicht starten und man kann die Fuse dann logischerweise auch nicht mehr ändern. Diese Fehlkonfiguration ist mit etwas Aufwand behebbar, muss jedoch nicht aus Unachtsamkeit provoziert werden!

Das Fusing wird ebenso wie das Bootloader-Flashen noch über das Vermittler-Board vorgenommen. Der Ziel-Chip ATmega328P hat ganze drei Fuses (Low-, High- und die Extended-Fuse), mit denen man den Chip beeinflussen kann. Um den Vorgang für den ATmega328P nun durchzuführen, lautet der Befehl:

~$ avrdude -c usbasp -p atmega328p -U lfuse:w:0xf7:m -U hfuse:w:0xd0:m -U efuse:w:0x04:m

Nun wird das Vermittler-Board zunächst vom Rechner getrennt, woraufhin der ATmega328P vom Steckbrett entnommen werden kann: Aus dem blanken Rohling ist eine leistungstarke Plattform geworden.

Board fertigstellen

Da nun der ATmega328P fertig vorbereitet ist, kann er vorsichtig in den Sockel des Boards gesteckt werden:

Fertige zweite eigene Version des TinyUSBBoard Rev. 3

Nun ist das Board komplett fertig, und kann am Rechner zum ersten Test eingesteckt werden. Nun sollten wieder die Selbsttests begonnen werden, worauf wir uns kräftig auf die Schulter klopfen dürfen :-)

Ressourcen zum Herunterladen


Tags: Arduino, TinyUSBBoard, DIY

Proudly generated with Pelican - without PHP, Perl, MySQL & Co. Jump to top