Nahrávání programu do ATTINY84 z mobilního telefonu

V tomto příspěvku se dozvíte, jak navrhnout jednoduché zařízení s mikrokontrolérem ATTINY84, které umožňuje bezdrátové nahrávání programu pomocí infračerveného přenosu z Android telefonu. Řešení je navrženo s důrazem na nízkou spotřebu energie, minimální počet součástek, nízkou cenu a využití vlastního IR bootloaderu, napsaného v assembleru. Popsána je rovněž Android aplikace, která promění mobilní telefon v přenosný bezdrátový programátor – ideální pro vývoj, výuku nebo vzdálenou aktualizaci firmwaru bez nutnosti kabelového připojení.

Ačkoli jsou dnes dostupné výkonné platformy jako ESP32 nebo Raspberry Pi Pico, jejich použití v bateriově napájených aplikacích je omezené - zejména kvůli vysoké spotřebě energie mimo režim spánku. Ačkoliv tyto platformy nabízí široké možnosti konektivity a vysoký výkon, v aplikacích, kde je klíčová dlouhá výdrž na jedno nabití, často neobstojí.

Z tohoto důvodu se často vracíme ke klasickým 8bitovým mikrokontrolérům, které vynikají nízkou spotřebou, jednoduchostí a spolehlivostí.

Zařízení, které v tomto článku popiseme, je vytvořeno s důrazem na minimální počet součástek, nízkou cenu a spotřebu. K jeho sestavení budeme potřebovat:

Zařízení bude schopné přijímat programový kód vysílaný z Android telefonu pomocí infračerveného modulu (tzv. IR Blaster). Vlastní nahrávání programu tedy bude probíhat bezdrátově.

Veškeré příklady, zdrojové kódy bootloaderu i Android aplikace jsou volně dostupné na GitHubu. Samotná aplikace je navíc zdarma a bez reklam ke stažení na Google Play.

IR bootloader pro AVR

Při práci s novějšími čipy, jako jsou ESP32 nebo Raspberry Pi Pico, mě vždy fascinovala možnost snadného bezdrátového programování - tzv. OTA (Over-The-Air) aktualizací. U starších čipů architektury AVR mi tato možnost vzdáleného programování vždy chyběla, a proto jsem začal přemýšlet, jak si podobnou funkcionalitu doplnit vlastními prostředky. Řešením se ukázalo být využití infračerveného přenosu, protože ten pro účely programování plně postačuje - přenos probíhá na krátkou vzdálenost a zároveň tak odpadá potřeba složitého šifrování přenášených dat.

Díky implementaci bootloaderu v assembleru je možné se dostat pohodlně pod 512 bajtů strojového kódu, což je u mikrokontrolérů řady ATTINY vítané.

Přenos dat je realizován běžně používaným modulovaným signálem na 38 kHz, jaký známe z klasických dálkových ovladačů. Na straně vysílače tedy postačí obyčejná IR LED, která se rozbliká (nebo zhasne) podle toho, zda posíláme bit 1 nebo 0. Na straně přijímače pak stačí připojit levný IR modul, který při detekci modulovaneho IR signálu stáhne výstupní pin k zemi, jinak jej ponechá v otevřeném stavu (vysoké impedanci).

Na první pohled se nabízí jednoduché řešení: posílat firmware jako UART výstup z vysílače a v případě bitu 1 aktivovat na pevně daný čas (cca 500 us) vysílání IR signálu (blikání). Tento přístup však rychle narazí na problém spolehlivosti přenosu, pokud posíláme delší sekvenci stejných bitů (např. dlouhou řadu nul), není snadné udržet v mikrokontroleru synchronizaci a příjemce tak může rychle ztratit přehled o přenášených datech programu.

Řešení je naštěstí jednoduché: každých několik bitů je jen potřeba doplnit kódovaním, které zajistí časté střídání nul a jedniček. Inspirací mi byla knihovna RadioHead, která mimo jiné implementuje robustní bezdrátové komunikační protokoly a právě takové kódování. Bohužel je ale napsána v C++ a po překladu se do malých AVR čipů s omezenou pamětí nevejde.

Rozhodl jsem se proto implementovat funkce této knihovny ručně v assembleru. Používá se kódování, kdy každé 4 bity (nibble) jsou převedeny na 6 bitů s vyšší mírou střídání. Výsledkem je tak mnohem vyšší spolehlivost přenosu, i za cenu mírného zvětšení přenášených dat.

Tabulka používaná v bootloaderu pro kódování čtveřic bitů vypadá následovně:

.byte 0x0d, 0x0e, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c

.byte 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x32, 0x34

Pomocí této tabulky se každé slovo (2 bajty - 16 bitů) původních dat zakóduje do 3 bajtů - 24 bitů, přičemž výsledný datový tok obsahuje dostatek změn mezi 0 a 1, aby jej přijímač dokázal spolehlivě zpracovat. Například 4 bitová hodnota 0000b se zakóduje jako 6 bitová 0x0d.

Struktura přenosového protokolu

Přenos firmwaru do mikrokontroléru s nahraným bootloaderem probíhá ve velmi jednoduché struktuře. Firmware je nejprve rozdělen na bloky o velikosti 64 bajtů (bez ohledu na velikost flash stránky v cílovém zařízení). Každý blok je potom odeslán ve formátu:

Synchronizační sekvence: 0xCC 0xCC 0xCC 0xCC 0xCC 0xCC 0xCC

Start symbol: znaky F a U

[Počet zbývajících paketů] [Adresa ve Flash] [64 bajtů dat]
[Kontrolní součet (CRC)]

Jakmile je odeslán startovací symbol, veškerá další komunikace je kódována výše popsaným způsobem, aby bylo zajištěno časté střídání bitů..

Bootloader sleduje posloupnost přenášených paketů a vyžaduje, aby se hodnota „počet zbývajících paketů“ s každým dalším blokem snižovala o 1. Zároveň každý paket obsahuje kontrolní součet (CRC), který ověřuje integritu dat. Pokud se v průběhu přenosu vyskytne chyba — například narušená posloupnost paketů nebo neplatný součet — je paměť mikrokontroléru (s výjimkou samotného bootloaderu) vymazána a proces začíná znovu.

V průběhu testování se přenos tímto protokolem ukázal jako velmi spolehlivý - chyby byly detekovány pouze v případech, kdy byly záměrně vyvolány, například zakrytím vysílací IR diody během přenosu.

Android telefon jako vysílač

Některé mobilní telefony se systémem Android jsou vybaveny infračerveným vysílačem, běžně označovaným jako „IR Blaster“. Přestože nejde o běžnou součást výbavy moderních zařízení, stále se na trhu objevují nové modely – včetně těch vyšší třídy – které tuto technologii podporují. Vytvořil jsem Android aplikaci, která využívá IR Blaster k přenosu dat do mikrokontroléru ATTINY, vybaveného výše popsaným bootloaderem.

Tuto aplikaci si můžete stáhnout zdarma z Google Play nebo z GITHubu včetně zdrojového kódu. Aplikace promění mobilní telefon se systémem Android v jednoduchý server běžící na lokální WiFi síti. Z vašeho počítače pak můžete do ATTINY odeslat přeložený program ve formátu Intel HEX takto:

  1. Otevřete aplikaci na telefonu – zobrazí se vám jeho IP adresa.
  2. Přeložený HEX soubor odešlete na zobrazenou IP adresu přes port 12345.
  3. Například pokud aplikace zobrazí IP adresu telefonu jako 10.0.2.15, můžete v Linuxu nahrání provést následujícím příkazem:

cat main.hex | ncat 10.0.2.15 12345

Tímto způsobem lze jednoduše a bez nutnosti kabelového připojení nahrávat programy do mikrokontroléru ATTINY přímo z mobilního telefonu. Aplikace si navíc pamatuje všechny nahrané programy, takže je lze později znovu odeslat už bez potřeby odeslání z PC.

Pokud navíc ve svém programu kdekoliv uvedete značku ve formátu

FW:[Nazev programu];[verze];[Autor]

například jako v ukázce níže, budou tyto údaje uloženy společně s kódem a zobrazeny v archivu aplikace.

C

Assembler

#include <avr/pgmspace.h>

const char metadata[] PROGMEM = "FW:Blikac;1.1;MH";

metadata:

   .asciz "FW:Blikac;1.1;MH"

Aktivace bootloaderu z programu

Bootloader je v mikrokontroléru nahrán od adresy 0x1D00, přičemž tato paměťová oblast je bootloaderem chráněna proti náhodnému přepsání. Na rozdíl od běžné praxe se ale bootloader neaktivuje automaticky po zapnutí nebo resetu mikrokontroléru. Jeho spuštění je nutné výslovně vyvolat z hlavního programu, což dává vývojáři větší kontrolu nad tím, kdy a za jakých podmínek k aktualizaci bootloaderu dojde. Aktivace tak může být například vázána na stisk určitého tlačítka, přijetí konkrétní zprávy přes IR přijímač nebo detekci aktivity na infračerveném pásmu. Tento přístup nejen zvyšuje bezpečnost, ale také eliminuje riziko nechtěné aktualizace během běžného provozu zařízení.

Vlastní aktivace bootloaderu je v praxi velmi snadná a může být provedena například přímo z C volaním jednoduché funkce:

inline void jmp_to_bootloader()

{

   __asm__ __volatile__(

       "ldi r30, 0x00\n\t"

       "ldi r31, 0x1D\n\t"

       "ijmp\n\t");

}

Jednou z nejjednodušších možností, jak v hlavním programu aktivovat bootloader, je čekat na aktivitu na IR vstupu a reagovat na ni přerušením. Typická implementace pak může vypadat například takto (na pinu PB2 je připojen IR přijímač):

ISR(PCINT1_vect) {

   static uint8_t limit = 0;

   if ((PINB & _BV(PB2)) == 0)

   {

       if (limit++ > 20) jmp_to_bootloader();

   }

}

Tento jednoduchý přístup slouží pouze jako ilustrativní ukázka, protože s sebou nese zásadní nevýhodu – bootloader může být omylem aktivován jakýmkoliv jiným IR signálem, například z běžného dálkového ovladače.

Pro reálné použití je vhodnější implementovat vlastní komunikační protokol, který umožní odeslat do zařízení specifický příkaz přes IR rozhraní. Tím lze zajistit bezpečnou a jednoznačnou aktivaci bootloaderu pouze při cíleném požadavku.

Popsaný bootloader a přenosový protokol může najít uplatnění nejen při vzdálené aktualizaci firmwaru v hůře přístupných instalacích, ale také přímo při vývoji – odpadá totiž riziko poškození počítače v důsledku chybného zapojení. Využití je možné i ve volnočasových kroužcích nebo ve výuce, kde umožňuje snadné a hromadné programování všech zařízení ve třídě.

Zdrojové kódy jsou k dispozici na GitHubu: https://github.com/mhalama/senzor

Odkaz na Android aplikaci v Google Play:

https://play.google.com/store/apps/details?id=cz.zorn.iruploader