Python a AVR

Nedávno jsem narazil na projekt Python-on-a-chip, který vytváří interpret Pythonu pro mikrokontroléry. Jelikož je Python můj oblíbený jazyk, nemohl jsem si tuhle hračku nevyzkoušet.

Testoval jsem na MCU ATMega1284P, která je dostatečně velká (128kB flash a 16kB SRAM), aby se do ní vlezl interpret Pythonu i vlastní skript.

Python-on-a-chip (zkráceně p14p) lze provozovat na mikrokontrolérech PIC, AVR i dalších. Já se budu soustředit na AVR, konkrétně na ATMega1284P. Lze ale použít libovolná Mega, která má alespoň 55kB flash paměti a 5kB RAM (ideálně alespoň 8kB). Těmto požadavkům odpovídá i ATMega2560, která je na desce Arduino Mega, takže pokud máte tuhle verzi Arduina, můžete ji bez problému použít.

Celý postup je malinko komplikovanější, především proto, že kód pro AVR obsahuje chyby, které budeme muset opravit. Také budeme k překladu potřebovat virtualenv s Pythonem2.6 (kompilujeme interpret Pythonu pro mikrokontroléry a k tomu je potřeba mít nainstalovaný Python). K celému postupu doporučuji mít Unixový OS. Jdeme na to…

Zdrojové kódy a virtualenv

Nejdříve si stáhneme zdrojové kódy z Mercurial repozitáře:

$ hg clone https://code.google.com/p/python-on-a-chip/

P14p implementuje některá klíčová slova a instrukce Pythonu 2.6 a k překladu zdrojových kódu je tedy potřeba mít nainstalovaný Python 2.6. Většina Linuxových distribucí i Mac OS používá defaultně Python2.7. Použijeme proto nástroj virtualenv, kterým vytvoříme virtuální pracovní prostředí. Pokud nemáte virtualenv, nainstalujte si jej příkazem easy_install virtualenv nebo pip install virtualenv.

$ cd python-on-a-chip
$ virtualenv -p /usr/bin/python2.6 pyenv

Tímto jsme v adresáři se zdrojovými kódy vytvořili adresář s názvem pyenv. Ten obsahuje naše virtuální prostředí Pythonu2.6. Teď ho jenom aktivujeme.

$ source ./pyenv/bin/activate
(pyenv)$

Pokud je vše v pořádku, měl by se před promptem objevit název virtuálního prostředí. Teď můžeme zkompilovat p14p pro desktop a spustit jeho jednořádkový interpret.

 
(pyenv)$ make ipm
imp> 1 + 1
2
ipm> s = "Hello p14p World!"
ipm> print s
Hello p14p World!
ipm> len(s)
17
ipm>

Interpret opustíme pomocí Ctrl+D.

Kompilace p14p pro AVR

Teď přijde samotná kompilace pro AVR. To bude mnohem obtížnější. Ve složce src/platform/ naleznete podporované platformy. Kromě několika ARM architektur a PIC zde najdete i arduino mega a avr. Nás bude zajímat platforma avr.

Tato platforma v současné době podporuje pouze mikrokontroléry ATMega103 a ATMega128. Já mám k dispozici ATMega1284P a proto jsem musel přepsat soubor plat.c tak, aby fungoval i na mém MCU. Pro zjednodušení jsem vytvořil patch, který přidá podporu pro ATMega1284P. Stáhněte si jej, aplikujte a přeložte p14p pro AVR ATMega1284P::

(pyenv)$ patch -p0 -i p14p-avr_plat_c.txt
patching file src/platform/avr/Makefile
patching file src/platform/avr/pmfeatures.py
patching file src/platform/avr/plat.c
(pyenv)$ make PLATFORM=avr

Pravděpodobně skončí překlad chybou error: __builtin_avr_delay_cycles expects an integer constant. Problém je ve volání funkcí _delay_ms() z knihovny avr/delay.h, které jako parametr očekávají konstantu. Řešení, které mám sice není příliš košér, ale je funční :) Zde je patch pro tuto chybu, stačí jej aplikovat:

(pyenv)$ patch -p0 -i p14p-delay_err.txt
patching file src/lib/avr.py
(pyenv)$ make clean
(pyenv)$ make PLATFORM=avr

Spuštění Pythonu na MCU

Pokud proběhl překlad úspěšně, v adresáři src/platform/avr je soubor main.hex. Ten nahrajeme do našeho mikrokontoléru ATMega1284P. K programování používám Arduino Uno jako ISP programátor, ale lze použít libovolný AVR programátor.

(pyenv)$ cd src/platform/avr
(pyenv)$ avrdude -p m1284p -c avrisp -b 19200 -P /dev/tty.usbmodem411 \
> -U flash:w:main.hex \
> -U hfuse:w:0xD9:m \
> -U lfuse:w:0xFF:m \
> -U efuse:w:0xFD:m

A to je vše. Fuses jsou nastaveny pro 16MHz externí krystal. Samotné pogramování chvilinku trvá, ale po jeho skončení by se měl spustit Python interpret a začít zpracovávat skript main.py (v adresáři src/platform/avr/). Ten je již přímo zakompilován v paměti, takže pokud jej budete chtít upravit, budete muset editovat main.py, znovu vše zkompilovat a naprogramovat do MCU.

Současný skript vypadá nějak takto:

print "Hello world."

import avr

print "Counting from 0 to 249 on portA's pins"

avr.ddrA(0xFF)
i = 0
while i < 250:
    avr.portA(i)
    avr.delay(250)
    i += 1
print "Done."

Pokud na piny portu A připojíte LED, objeví se na nich postupně 0 až 250. Zároveň se na rozhraní UART0 (baud rychlost 19200) posílá stdout stream (a také čte stdin).

P14p má i jednořádkový interpret, který běží na MCU a komunikuje na rozhraní UART0. Upravte soubor main.py následovně:

import ipm
ipm.ipm()

Znovu zkompilujte celý projekt a nahrajte do MCU. Po připojení nějakého UART převodníku k PC byste měli na sériové lince (baud rychlost 19200) komunikovat s jednořádkovým interpretem a manuálně spouštět skripty:

ipm> import avr
ipm> avr.ddrA(0xFF)
ipm> avr.portA(0xFF)

Mně se bohužel tento interpret nepodařilo zprovoznit. Z nějakého důvodu, pokud importuji ipm nastane chyba import error a celý skript skončí. (Zmiňoval jsem se, že p14p nemá výjimky a tudíž jakákoliv chyba končící výjimkou ukončí celý skript? Stejně tak nefungují kláčová slova try a except). Pokud by se někomu podařilo přijít na příčinu, rád se podívám na řešení.

Závěr

Python-on-a-chip je hezká hračka, zabaví na jedno odpoledně, ale na nějaké seriózní programování to asi nebude. Jazyk je dost omezený (viz absence výjimek) a také neobsahuje téměř žádné knihovny (což je logické), takže vše si musíte napsat sami.

I tak, nedávno se mi dostal do ruky ARM STM32F4, který je založen na jádře Cortex4. P14p podporuje STM32, takže se budu dál hrát :)