Digispark i micronucleus: crash

W pewnym momencie jeden z moich Digispark’ów przestał odpowiadać. Nie – nie tak jak jak zwykle, kiedy trzeba go było wkładać do portu USB kilka razy. Całkiem. udevadm monitor milczał jak zaklęty, nie wykrywał włożenia ani wyciągnięcia urządzenia USB.

Co gorsza: Digispark zaczął się zachowywać tak jakby… zniknął mu bootloader. Zwyczajowe 5 sekund zwłoki przy starcie, skurczyło się do góra 1/2 sekundy…


Bootloader

Bootloader to niewielki programik znajdujący się w pamięci flash czipu (czyli tej, w której zapisuje się programy). Jego zadaniem jest między innymi sprawdzenie, czy przypadkiem „ktoś” (np. Arduino IDE) nie chce załadować nowego programu użytkownika. Jeżeli tak – bootloader odbiera nowy program i zapisuje go w odpowiednim miejscu w pamięci. Jeżeli nie – bootloader kontynuuje start urządzenia ładując program wcześniej zapisany w pamięci czipu.

Digispark używa bootloadera micronucleus.

Micronucleus na Digisparku, po włączeniu zasilania, czeka 5 sekund zanim uruchomi załadowany do flasha program użytkownika. Podczas tych 5 sekund zwłoki oczekuje na instrukcje co do załadowania nowego programu.

Kłopoty

Mojego Digisparka nie udało się już przeprogramować – system go po prostu nie widział. Pod linuksem możecie użyć polecenia:

$ udevadm monitor

Narzędzie raportuje każde włożenie i usunięcie urządzenia USB.  U mnie włożenie (usunięcie) Digisparka z portu USB nie powodowało żadnych zdarzeń.

Kolejną oznaką kłopotów było to, że mój program  uruchamiał się dosłownie po pół-sekundzie. Nie było standardowego 5s oczekiwania. Tak jakby bootloader… zniknął?

Zawsze staram się dodać jakąś oznakę, że mój program wystartował – migam diodą trzy razy (pin P1) albo dodaję jednoznaczne logi na serialu w funkcji setup(). W ten sposób wiem, że program prawidłowo się zainicjował. Co więcej – wiem, kiedy czip się „spontanicznie” zrestartował!

Wbrew pozorom, np. dla Arduino, bootloader znika (ulega uszkodzeniu lub nadpisaniu) stosunkowo rzadko… Dla Arduino IDE, żeby wypalić bootloader,  trzeba użyć programatora ISP (podłączanego do osobnego złącza na płytce Arduino). Najczęstszą przyczyną braku komunikacji z kontrolerem są inne problemy na hoście (jednostce, do której kontroler jest podłączony). Może to być np. nieodpowiedni sterownik czy (jeszcze częściej) zły port wybrany w Arduino IDE.

Tutaj jednak objawy wydawały się jednoznacznie wskazywać na problemy z bootloaderem. Mój program generował sygnał PWM na pinie P1. Efektem ubocznym tego było zapalanie LED podłączonej do tego pinu. W ten sposób dokładnie wiedziałem, kiedy mój program startuje – a startował dużo za wcześnie.

Wymiana bootloadera…

…na oryginalnym Digispark jest znacznie utrudniona. Ciekawy tekst na ten temat: Beginners Guide to Extended Programming Attinys with Digispark. Stwierdza wprost:

The digispark cannot be programmed via ISP (at least not without prior modification)

Problemem jest pin resetu czipa – wyprowadzony na P5. W oryginalnym Digisparku  (jak wyczytałem, bo oryginalnego nie posiadam:)) wyłączono możliwość zewnętrznego resetu czipu. W ten sposób udało się uzyskać dodatkowy pin do innych zastosowań. Przy okazji – uniemożliwiono też programowanie przez ISP (np.  wymianę bootloadera).

Jak to zrobiono? Poprzez zmianę ustawienia tzw. high fuse, a konkretnie  zaprogramowanie jego bitu RSTDISBL (7). Bit ten wyłącza reset na PB5 (podłączonym do wyprowadzenia P5 Digispark). W ten sposób sprowadzając go do stanu niskiego nie zrestartujemy kontrolera – co jest konieczne przy programowaniu przez ISP.

Na oryginalnych Digisparkach można zresetować to ustawienie za pomocą HVSP – High Voltage Serial Programming. Wymaga to impulsu 12v i trochę innego sposobu programowania kontrolera.

Nie porzucajcie nadziei!

Postanowiłem jednak spróbować. Budowanie HVSP mi się nie uśmiechało, ale najpierw postanowiłem sprawdzić, czy da się odczytać fusy. W tym celu użyłem programatora usbasp2:

IMG_20150127_210950Programatory tego typu podłączamy do portu USB komputera.

Dla linux będziecie musieli uzupełnić reguły w /etc/udev/rules.d. Stwórzcie tam plik np. 47-usbasp.rules:

Teraz wystarczy odświeżyć reguły (z poziomu roota, po „su”):

 

Z drugiej strony, programowany układ podłączamy do gniazda IDC6. Jak to zrobić dla Digispark’a? Ano według tego schematu:

digi_isp_1Na programatorze ustawiłem zasilanie 5V (żółta zworka).

Na linuxie musicie dodać kilka narzędzi:

Teraz wystarczyło użyć avrdude:

$ sudo avrdude -c usbasp -v -p t85
avrdude: Version 6.0.1, compiled on Oct 21 2013 at 15:55:32
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
Copyright (c) 2007-2009 Joerg Wunsch
System wide configuration file is "/etc/avrdude.conf"
User configuration file is "/home/arek/.avrduderc"
User configuration file does not exist or is not a regular file, skipping
Using Port : usb
Using Programmer : usbasp
AVR Part : ATtiny85
...
Programmer Type : usbasp
Description : USBasp, http://www.fischl.de/usbasp/
avrdude: auto set sck period (because given equals null)
avrdude: AVR device initialized and ready to accept instructions
Reading
...
avrdude: Device signature = 0x1e930b
avrdude: safemode: lfuse reads as F1
avrdude: safemode: hfuse reads as DF
avrdude: safemode: efuse reads as FE
...
avrdude done. Thank you.

Super! Programator skomunikował się z czipem! Sygnatura czipu AVR się zgadza. Sprawdziłem jeszcze wysoki-fuse (hfuse). Programator odczytał go jako 0xDF. Użyjecie kalkulatora fusów., żeby zdekodować tą wartość na ustawienia poszczególnych bitów.  W rezultacie, wartość ta oznacza, że zewnętrzny reset jest włączony!

Digispark podłączony do programatora USBASP2
Digispark podłączony do programatora USBASP2

Nowy bootloader

Teraz pobrałem nowy bootloader:
$ git clone https://github.com/micronucleus/micronucleus.git
...
$ cd ./micronucleus/firmware

Upewnijcie się, że Makefile jest ustawiony na AtTiny85:
$ nano Makefile

Początek pliku powinien wyglądać jak:

# Name: Makefile
# Project: Micronucleus
# Author: Jenna Fox; portions by Christian Starkjohann, Louis Beaudoin
# Creation Date: 2007-12-10
# Tabsize: 4
# Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
# License: GNU GPL v2 (see License.txt)
CONFIG ?= t85_default
#CONFIG ?= t85_aggressive
#CONFIG ?= t841_default
#CONFIG ?= t167_default

Widć stąd, że make jest ustawiony na AtTiny85 (CONFIG ?= t85 default). Wyjdźcie z pliku, i skompilujcie:
$ make

W ten sposób powinniście uzyskać plik binarny  main.hex, który zawiera bootloader. Pozostaje go przenieść na Digisparka. Wpiszcie:

$ sudo make flash
avrdude -c USBasp -p attiny85 -U flash:w:main.hex:i -B 20
avrdude: set SCK frequency to 32000 Hz
avrdude: AVR device initialized and ready to accept instructions
Reading
avrdude: Device signature = 0x1e930b
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: set SCK frequency to 32000 Hz
avrdude: reading input file "main.hex"
avrdude: writing flash (8120 bytes):
Writing ...
avrdude: 8120 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex contains 8120 bytes
avrdude: reading on-chip flash data:
Reading ...
avrdude: verifying ...
avrdude: 8120 bytes of flash verified
avrdude: safemode: Fuses OK (H:FE, E:DF, L:F1)
avrdude done. Thank you.

Voila! Teraz już nie powinniście mieć problemów z wgraniem nowego kodu na Digisparka. Ja nie miałem.

Problemy

Może się zdarzyć, że po przeflashowaniu Digisparka, przy próbie programowania w Arduino IDE pojawi się komunikat:

Problem polega na tym, że ściągnęliście z git-a najnowszą wersję bootloadera, która może nie być zgodna z bibliotekami Arduino IDE.

W związku z tym (opisane: tutaj):

W ten sposób „podmienicie” micronucleus’a w narzędziach arduino.

Podsumowanie

Oczywiście miałem trochę szczęścia. Mój Digispark to klon, w którym producent postanowił nie blokować zewnętrznego resetu. Z tego co czytałem, w oryginalnym produkcie funkcja ta została zablokowana w fabryce (przez wypalenie odpowiednich fusów). Zresztą zrobiono to celowo. Dzięki temu, pin P5 (podłączony do PB5) może być wykorzystywany jako port ogólnego przeznaczenia. W moim klonie – zbytnie obniżenie na nim napięcia spowoduje zresetowanie czipu. Już się o tym przekonałem – w ramach doświadczeń z przetwornikiem analog/cyfra. Ale o tym będzie już w kolejnym poście.

Źródła

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *