1. decembra, 2017

MicroPython za razvoj realno-časovnih aplikacij

Revija logo digikey 300x150 - MicroPython za razvoj realno-časovnih aplikacijDigi-Key Electronics
Avtor: Rich Miron

Realno-časovni ugnezdeni sistemi postajajo vse bolj kompleksni. To zahteva poglobljeno razumevanje tako zapletenih 32-bitnih mikrokontrolerjev kot tudi tipal, algoritmov, spletnih protokolov in širokega nabora različnih aplikacij za končnega uporabnika. Z vedno več funkcijami in krajšimi razvojnimi cikli morajo razvijalci najti načine za pohitritev razvoja kot tudi za prenos kode na nove izdelke. Tako se pojavi potreba po ugnezdeni in prilagodljivi razvojni platformi.

258 31 01 300x56 - MicroPython za razvoj realno-časovnih aplikacij

Slika 1: primer strukture imenikov, ki prikazujejo razpoložljive platforme, ki trenutno podpirajo MicroPython. Mednje spadajo ARM, CC3200, esp8266, Microchip PIC in STM32. (Vir slike: Beningo Embedded Group)

Na voljo je več platform za posamezne mikrokontrolerje, ki omogočajo pohitritev razvojnega postopka, vendar je težava v tem, da razvijalce vežejo na enega ponudnika mikrokontrolerjev. Prenašanje programske opreme z ene platforme na drugo je lahko časovno potratno in drago.

Edinstvena in inovativna rešitev, ki je vedno bolj sprejeta in pridobiva vedno več zagona, je povezovanje nizkonivojske strojne opreme mikrokontrolerja z visokonivojskim programskim jezikom, kot je Python. Ena izmed teh rešitev je MicroPython. MicroPython se izvaja na več različnih mikrokontrolerjih in je odprtokoden, tako da ga razvijalci lahko uporabljajo in prilagajajo glede na svoje potrebe.

Spletno mesto MicroPython.org ga opisuje kot vitko in učinkovito implementacijo programskega jezika Python 3, ki vključuje majhen del Pythonove standardne knjižnice, ki je optimizirana za izvajanje na mikrokontrolerjih in v omejenih okoljih. MicroPython se je začel kot projekt na Kickstarterju, ki je bil uspešno financiran in je pridobil veliko občinstvo, danes pa se uspešno uporablja v projektih v različnih panogah, na primer v industrijskih in vesoljskih sistemih.

Izbira pravega mikrokontrolerja

MicroPython se izvaja na več različnih mikrokontrolerjih, pri čemer ni večjih omejitev za prenos kode v MicroPythonu na druge mikrokontrolerje, če imajo slednji dovolj delovnega pomnilnika, Flash pomnilnika in procesorske moči za izvajanje tolmača. Kljub temu obstaja nekaj ključnih zahtev za mikrokontroler, ki bo izvajal kodo v MicroPythonu, na katere mora biti razvijalec pozoren:

  • najmanj 256 kB Flash pomnilnika,
  • najmanj 16 kB delovnega pomnilnika,
  • najmanj 80-MHz takt procesorja.

To so splošna priporočila in razvijalci jih lahko upoštevajo v različni meri glede na potrebe svoje aplikacije in čas, ki so ga pripravljeni porabiti za prilagajanje jedra MicroPythona. MicroPython lahko na primer prilagodijo, da porabi veliko manj kot 256 kB Flash pomnilnika. Ta priporočila razvijalcem zagotavljajo najboljšo izkušnjo in omogočajo nadaljnji razvoj njihovih aplikacij.

Ta programski jezik že podpira več različnih serij mikrokontrolerjev, ki jih lahko uporabite kot odlično odskočno desko za prenos kode na novo platformo ali za izbiro mikrokontrolerja, ki je že podprt. Glavni imenik MicroPython z izvorno kodo je prikazan na sliki 1. V imeniku je prikazanih več različnih podprtih mikrokontrolerskih naprav, na primer:

  • mikrokontrolerji na osnovi procesorjev ARM®.
  • CC3200 podjetja Texas Instruments.
  • ESP8266 podjetja Adafruit.
  • 16-bitni PIC mikrokontrolerji podjetja Microchip Technology.
  • STM32 podjetja STMicrolectronics.

Vsaka mapa, navedena v korenskem imeniku, je visokonivojska mapa, ki vsebuje splošne gonilnike in podporne datoteke za določeno serijo čipov. V vsaki mapi se lahko nahaja več različnih podprtih razvojnih plošč ali procesorjev. Mapa stmhal na primer vsebuje podporne datoteke za razvojni plošči STM32F429 Discovery Board in STM32 IoT Discovery Node (STM32L) podjetja STMicroelectronics, poleg teh pa še za številne druge, na primer STM32F405 pyboard podjetja Adafruit Industries. Mapa ESP8266 vsebuje podporne datoteke za plošči Huzzah break-out board za ESP8266 in Feather Huzzah Stack Board podjetja Adafruit.

Razvojne plošče, ki lahko izvajajo MicroPython, niso drage, zato je priporočeno, da razvijalec kupi več različnih plošč, da preveri, koliko pomnilnika, shrambe in procesorske moči potrebuje za svojo aplikacijo. Razvijalec lahko na primer začne uporabljati ploščo STM32F405 pyboard in se nato odloči, da želi za lažji nadaljnji razvoj in nadgradnjo končni izdelek prenesti na ploščo STM32F429. Plošča STM32F429 ima 2 MB Flash pomnilnika, 256 KB delovnega pomnilnika in poseben delovni pomnilnik brez čakalnih stanj, imenovan CCM.

Kode aplikacije v MicroPythonu, ki jo razvijalec napiše, ni treba shraniti v notranji Flash pomnilnik mikrokontrolerja. Jedro MicroPythona mora biti v mikrokontrolerju, vendar je koda aplikacije lahko v zunanjem mediju za shranjevanje, na primer kartici microSD Panasonic 8 GB. Shranjevanje kode aplikacije na zunanji napravi omogoča uporabo mikrokontrolerja z manj pomnilnika, kar lahko zmanjša stroške celotnega sistema.

Začnite z delom z MicroPythonom

258 31 02 300x65 - MicroPython za razvoj realno-časovnih aplikacij

Slika 2: kloniranje repozitorija MicroPython v lokalni datotečni sistem, kjer lahko razvijalec nato namesti jedro MicroPython za svojo ploščo ali ga prilagodi za potrebe svoje aplikacije. (Vir slike: Beningo Embedded Group)

MicroPython je predhodno nameščen na plošči Adafruit STM32F405 pyboard. Za druge razvojne komplete ali strojno opremo po meri bo razvijalec moral prenesti izvorno kodo MicroPython, jo namestiti za ciljno ploščo in nato programsko opremo prenesti v mikrokontroler. Pridobivanje dostopa do izvorne kode MicroPython je preprosto, saj je na voljo v storitvi GitHub. Za nastavitev orodij in konfiguracijo okolja za namestitev jedra MicroPython mora razvijalec upoštevati zaporedje več korakov. V tem primeru bomo namestili jedro MicroPython za ploščo STM32F429 Discovery. Najprej mora razvijalec ustvariti virtualni stroj, ki izvaja operacijski sistem Linux, ali uporabiti domorodno namestitev sistema Linux. Ko je sistem Linux na voljo prek terminala, mora razvijalec namestiti orodja prevajalnika ARM z naslednjim ukazom:

sudo apt-get install gcc-arm-none-eabi

Če je sistem Linux na novo nameščen, sistem za nadzor različic git morda ni nameščen. Sistem git lahko namestite prek terminala z naslednjim ukazom:

sudo apt-get install git

Ko je sistem git nameščen, lahko izvorno kodo MicroPythona prenesete iz repozitorija sistema z naslednjim ukazom:

git clone https://github.com/micropython/
micropython.git

Postopek se bo morda izvajal nekaj minut, vendar bi razvijalec moral videti prikazano zaporedje izvajanja (slika 2).

Ko je izvorna koda MicroPython klonirana v lokalni datotečni sistem, se mora razvijalec pomakniti v imenik, ki vsebuje izvorno kodo, in v terminal vnesti ukaz »cd stmhal«. Imenik stmhal vsebuje datoteko makefile za MicroPython za mikrokontrolerje STM32. Vsebuje tudi mapo »boards«, ki si jo razvijalec lahko ogleda in prikazuje vse trenutno podprte plošče STM32. Prek terminala lahko razvijalec nato namesti MicroPython za katerokoli ploščo, ki se nahaja v mapi »boards«. Razvijalec lahko na primer namesti MicroPython za ploščo STM32F4 Discovery z naslednjim ukazom:

make BOARD=STM32F4DISC

MicroPython se bo nameščal nekaj minut. Med nameščanjem mora razvijalec namestiti orodje za posodobitev strojno-programske opreme naprave (DFU), ki se uporablja za nalaganje MicroPythona prek USB-ja v mikrokontroler. Orodje je treba namestiti samo enkrat, in sicer prek terminala z ukazom:

sudo apt-get install dfu-util

Ko je jedro MicroPython nameščeno in je orodje dfu-util nameščeno, lahko razvijalec naloži MicroPython v mikrokontroler. Razvijalec mora najprej preklopiti mikrokontroler v način nalagalnika zagona DFU. To lahko izvede tako, da zagonske nožice nastavi tako, da se ob ponastavitvi naloži notranji nalagalnik zagona namesto kode iz Flash pomnilnika.
Ko je mikrokontroler v načinu nalagalnika zagona in povezan z gostiteljskim računalnikom prek USB-ja, lahko razvijalec uporabi orodje dfu-util za prenos MicroPythona z vnosom naslednjega ukaza:

dfu-util -a 0 -d 0483:df11 -D build-
STM32F4DISC/firmware.dfu

Orodje dfu-util bo uporabilo datoteko dfu, ki se ustvari pri prevajalskem postopku. Postopek bo trajal nekaj minut, ker se mikrokontroler popolnoma izbriše in znova programira. Postopek bo podoben postopku, ki je prikazan na sliki 3. Ko orodje dokonča postopek, je treba zagonske mostičke prilagoditi tako, da se programska oprema naloži iz notranjega Flash pomnilnika, nato pa se mikrokontroler lahko znova zažene. MicroPython se sedaj izvaja v mikrokontrolerju.

Povezovanje tipal in povezanih naprav

Največja prednost uporabe visokonivojskega programskega jezika, kot je MicroPython, pri razvoju realno-časovne vgrajene programske opreme je, da je programska oprema neodvisna od strojne opreme. To pomeni, da lahko razvijalec razvije skripto v MicroPythonu, ki se bo izvajala na plošči pyboard, in z malo ali nič spremembami tudi na plošči ESP8266 ali STM32F4 Discovery board. Oglejmo si primer osnovne skripte v MicroPythonu, ki povezuje barometer in tipalo temperature Bosch Sensortec BMP280 z vodilom I2C ter prenaša podatke prek zaporedne povezave Bluetooth z modulom Bluetooth RN-42 podjetja Microchip Technology.

258 31 03 300x225 - MicroPython za razvoj realno-časovnih aplikacij

Slika 3: MicroPython se nalaga v mikrokontroler z orodjem dfu-util. (Vir slike: Beningo Embedded Group)

BMP280 je barometer in tipalo temperature, skladen z vodilom I2C s privzetim podrejenim naslovom l2C 119 v decimalnem zapisu. Napravo najlažje povežete s ploščo pyboard prek plošče Gravity board podjetja DFRobot, ki zagotavlja robusten priključek za preprosto dostop do vodila I2C in napajanje naprave. Za povezavo plošče Gravity board lahko razvijalec izbere vodilo I2C1 ali I2C2. Ko sta plošči povezani, je pisanje skripte v MicroPythonu preprosto.

Razvijalec najprej uvozi razred I2C iz knjižnice pyb. Knjižnica pyb omogoča dostop do perifernih funkcij mikrokontrolerja, kot so SPI, I2C in UART. Pred uporabo perifernih naprav mora razvijalec ustvariti instanco razreda peripheral, da ustvari objekt, s katerim bo lahko nadziral periferno napravo. Ko je instanca razreda peripheral ustvarjena, lahko razvijalec izvede druge inicializacije, na primer preveri, ali so naprave prisotne, preden program vstopi v glavno zanko aplikacije. Koda glavne aplikacije bo nato vsako sekundo zajela odčitke tipala. Vzorec kode 1 prikazuje primer implementacije, glej vzorec kode 1.

Zajemanje podatkov tipala, ki se jih nato ne uporabi, ni zelo uporaben prikaz uporabnosti MicroPythona za razvojno ekipo. Številne razvojne ekipe se soočajo s tehničnimi izzivi pri povezovanju tipal z internetom ali lokalnim središčem tipal prek Bluetootha. Bluetooth lahko projektu preprosto dodate z uporabo modula RN-42. Modul RN-42 lahko nastavite tako, da mikrokontroler preprosto pošilja podatke na UART, ki naj bi se poslali prek Bluetootha, modul RN-42 pa upravlja s celotnim skladom Bluetooth Napaka: vira sklicevanja ni mogoče najti(slika 4).

Ko je plošča Bluetooth povezana, lahko razvijalec ustvari skripto, ki podatke, zajete s tipalom, pošlje prek Bluetootha mobilni napravi, ki nato podatke shrani ali jih posreduje v oblak za nadaljnjo analizo. Prikazan je primer skripte (vzorec kode 2). V tem primeru je enota UART1 konfigurirana z naslednjimi nastavitvami: hitrost prenosa 115.200 b/s, 8-bitni prenos, brez paritete, en bit za zaustavitev, glej vzorec kode 2.
Poleg tega, da lahko kodo aplikacije v Pythonu preprosto prenesete v platforme z drugo strojno opremo, aplikacija tudi uporablja skupne knjižnice in funkcije, ki so že bile implementirane, kar pomaga razvijalcem, da pohitrijo razvoj. Zgornjo aplikacijo je mogoče ustvariti v uri ali manj v primerjavi s tednom ali več, kolikor bi lahko porabil razvijalec, če bi razvoj začel na najnižjih nivojih programske opreme.

Nasveti in triki za razvoj realno-časovne programske opreme

Razvoj uignezdenih aplikacij z MicroPythonom je preprost, vendar je zagotavljanje delovanja sistema v realnem času težje, kot bi si mislili. Čeprav MicroPython nudi ogromne prednosti pri poenostavljanju in ponovni uporabi kode, je zagotavljanje predvidljivega in doslednega ritma delovanja sistema velik izziv za razvijalca, ki ni seznanjen z nekaj zanimivimi dejstvi in knjižnicami.

MicroPython vključuje čistilca pomnilnika, ki se izvaja v ozadju ter upravlja s kopico in drugimi pomnilniškimi viri. Čistilec pomnilnika je nedeterminističen, tako da lahko razvijalci, ki pričakujejo deterministično vedenje, zaidejo v težave, če se čistilec pomnilnika začne izvajati v delu kode, ki je občutljiv na čas. Obstaja več priporočil, ki jih morajo razvijalci upoštevati, da se izognejo težavam.

Razvijalci lahko uvozijo knjižnico za sproščanje pomnilnika, gc, in uporabijo metode enable in disable za omogočanje ali onemogočanje čistilca pomnilnika. Razvijalec lahko onemogoči čistilec pomnilnika pred kritičnim delom in ga nato znova omogoči (vzorec kode 3).

import gc
gc.disable()
#My time critical code
gc.enable()

Vzorec kode 3: onemogočanje čistilca pomnilnika v MicroPythonu pred časovno občutljivim delom kode. (Vir kode: Beningo Embedded Group)

258 31 04 300x132 - MicroPython za razvoj realno-časovnih aplikacij

Slika 4: povezovanje plošče pyboard, ki izvaja kodo v MicroPythonu, z modulom Bluetooth RN-42 prek enote UART. (Vir slike: Beningo Embedded Group)

Razvijalec lahko tudi ročno upravlja postopek sproščanja pomnilnika. Ko razvijalec ustvarja in uničuje objekte, dodeljuje pomnilnik v kopico. Čistilec pomnilnika se zažene in sprosti neuporabljen prostor. Ker se čistilec pomnilnika zaganja v nerednih intervalih, lahko razvijalci uporabljajo metodo collect, da v enakomernih razmikih zaženejo čistilec pomnilnika in zagotovijo, da se kopica ne prenapolni z neuporabnimi strukturami. Na ta način se lahko čas izvajanja čistilca pomnilnika zmanjša z 10 milisekund na manj kot milisekundo na zagon. Ročno klicanje čistilca pomnilnika omogoča tudi, da ima aplikacija nadzor nad nedeterminističnim časovnim izvajanjem kode. To razvijalcem omogoča, da določijo, kdaj zagnati čistilec pomnilnika in zagotoviti, da aplikacija deluje v realnem času.

Obstaja še več dobrih praks, ki jih lahko upoštevajo razvijalci, ki želijo pisati kodo, ki se izvaja v realnem času. Mednje sodijo:

  • uporaba predhodno dodeljenih medpomnilnikov za komunikacijske kanale,
  • uporaba metode readinto pri uporabi komunikacijskih perifernih naprav,
  • neobičajno dokumentiranje kode v Pythonu z oznako ###,
  • zmanjšanje števila ustvarjenih in uničenih objektov med izvajanjem,
  • spremljanje časa izvajanja aplikacije.

Razvijalci, ki se želijo bolje seznaniti z »najboljšimi praksami«, si lahko tukaj ogledajo dokumentacijo o optimizaciji v MicroPythonu.

Zaključek

MicroPython je zanimiva platforma za razvijalce, ki želijo implementirati realno-časovne vgrajene aplikacije, ki so neodvisne od strojne opreme mikrokontrolerja. Razvijalci lahko pišejo visokonivojske skripte v Pythonu z uporabo standardnih knjižnic, vključenih v MicroPythonu, in jih izvajajo na podprtih mikrokontrolerjih. To razvijalcem omogoča številne prednosti, med drugim:

  • boljše možnosti za ponovno uporabo aplikacije,
  • hitrejšo izdajo aplikacije na trg,
  • ločevanje aplikacije od strojne opreme.

MicroPython ni popoln za vsak namen, vendar se je do zdaj uspešno uporabljal za razvoj industrijskih in vesoljskih sistemov ter za hiter razvoj prototipov in dokazovanje uspešnosti zamisli.

www.digikey.com
vzorec kode 1 
from pyb import I2C

GlobalTemp = 0.0
GlobalBarometer = 0.0

# Initialize and Instantiate I2C peripheral 2
I2C2 = I2C(2,I2C.MASTER, baudrate=100000)

while True:
SensorSample()
pyb.delay(1000)

def SensorSample():
#Read the Temperature Data
TempSample = I2C2.readfrom_mem(119, 0xFA,3)

#Read the Pressure Data
PressureSample = I2C2.readfrom_mem(119, 0xF7,3)

Vzorec kode 1: skripta v MicroPythonu, ki inicializira periferno napravo I2C in komunicira s ploščo DFRobot podjetja Gravity board za pridobivanje podatkov o temperaturi in tlaku tipala. (Vir kode: Beningo Embedded Group)

vzorec kode 2 
from pyb import uart
from pyb import I2C

GlobalTemp = 0.0
GlobalBarometer = 0.0

# Initialize and Instantiate I2C peripheral 2
I2C2 = I2C(2,I2C.MASTER, baudrate=100000)

# Configure Uart1 for communication
Uart1 = pyb.UART(1,115200)
Uart1.init(115200, bits=8, parity=None, stop=1)

while True:
SampleSensor()
pyb.delay(1000)

def SensorSample():
#Read the Temperature Data
TempSample = I2C2.readfrom_mem(119, 0xFA,3)

#Read the Pressure Data
PressureSample = I2C2.readfrom_mem(119, 0xF7,3)

#Convert Sample data to string
data = “#,temperature=”str(TempSample)+”,pressure”+str(PressureSample)+”,#,\n\r”

#Write the data to Bluetooth
Uart1.write(data)

Vzorec kode 2: primer skripte v MicroPythonu, ki inicializira enoto UART1 in komunicira z zunanjo napravo. (Vir kode: Beningo Embedded Group)

Tags: