Moduly a knižnice #
Časti kódu a moduly môžeme v MicroPython-e používať nasledujúcimi spôsobmi
priamo ako kód v ineratktívnom móde alebo nahratý priamo do prostredia v zdrojovom kóde
pridaný ako knižnica v skompilovanom kóde Pythonu ako bytecode do firmware pre cielovú platformu
vytvorený ako knižnica v programovacom jazyku C a skompilovaný ako modul pri generovaní firmware
Modul v MicroPython#
Je uložený v priamo v pamäti MCU (flash) v prostredí MicroPython-u, t.j. zaberá najviac miesta v pamäti.
# Kniznica pre LM92
def read_LM92_TR(ic, addr):
raw = ic.readfrom_mem(addr, 0, 2) # nacitanie 2 byte z registra 0
data = (raw[0] << 8) + raw[1] # konverzia 16 bit format
td = data >> 3 # 2'compl b15-b3 temperature
TEMP = (-(td & 0x1000) | (td & 0xFFF))* 0.0625
L = data & 0x01 # T_LOW -> H, TEMP < 10 deg
H = (data & 0x02) >> 1 # T_HIGH -> H TEMP > 64 deg
C = (data & 0x04) >> 2 # T_CRIT -> H TEMP > 80 deg
return TEMP, C, H, L
a jeho použitie v interaktívnom móde z konzoly terminálu
from machine import I2C
i2c = I2C(1,freq=400000) # I2C - port 1
print(read_LM92_TR(i2c, 75))
Nahratie súboru z prostredia terminálu #
V picocom termináli pre skopírovanie programu do prostredia môžeme použiť skratky CTRL+E a CTRL+D.
Nahratie súboru online #
Interný filesystém je dostupný aj mimo prostredia MicroPython-u, pomocou utility ./tools/pyboard.py (adresár v distribúcii z github-u) je možné do neho ukladať, mazať súbory a vyvárať adresárovú štruktúru.
usage: pyboard.py [-h] [--device DEVICE] [-b BAUDRATE] [-u USER] [-p PASSWORD]
[-c COMMAND] [-w WAIT] [--follow] [-f]
[files [files ...]]
Doplňujúce argumenty pre -f (–filesystem)
ls
ls ./adresar
cp ./file ./
rm ./file
rmdir addr
mkdir addr
cat ./subor vypis suboru na terminal resp
cat./subor > lokalny.txt
Príklad
python pyboard.py -f ls
python pyboard.py -f cp ./test.py :
Ak sa prepíšeme resp. upravíme súbor main.py v koreňovom adresári tak aby obsahoval vykonateľný kód, tento sa po resete automaticky spustí. Spustenie nahratého kódu je jedmoducho možé aj priamo
python pyboard.py test.py
Modul skompilovaný do bytecode #
Aby nebolo potrebné po resete mikrokontroléra opakovane nehrávať časti odladeného kódu do prostredia MicroPython-u, tento umožňuje pridanie nového kódu (frozen module) ako knižnice, ktorá sa stane súčasťou firmware. Celý postup je veľmi jednoduchý a spočíva v uložení súboru s kódom knižnice v Pythone do adresáru vytvoreného adresáru .ports/stm32/modules a následnom skompilovaní firmware a jeho nahratí do mikrokontroléra. Knižnica je dostupná pomocou štandardneho príkazu import.
micropython
|
+--ports
| |
| +--stm32
... | |
... +--my_modules <--- vytvoreny adresar
| |
| +--manifest.py <--- popis konfiguracie modulu
| |
| +--test <--- adresar s modulom
| | |
... ... +-- demo.py <--- kod naseho modulu
Modul môže pozostávať z jedného alebo viacerých súborov, pred kompiláciou potrebujeme vytvortiť súbor manifest.py do ktorého konfiguráciu modulu. Dokumentácia k formátu manifest súboru je dostupná online - link.
Pre našu konfiguráciu bude mať súbor manifest.py tvar
package("test")
Firmware skompilujeme štandardným postupom, len musíme naviac zadefinovať premennú FROZEN_MANIFEST Prekročenie rozsahu pamäte Flash má za následok chybu kompilácie.
adresar ./ports/stm32/, kompilacia pre Nucleo32 STM32L432KC
make BOARD=NUCLEO_L432KC clean
make BOARD=NUCLEO_L432KC FROZEN_MANIFEST=./my_modules/manifest.py
Po kompilácii a nahratí firmware do MCU je modul dostupný cez import test.demo. Kontrolu modulu prevedieme pomocou príkazu dir()
>>> import test.demo as dt
>>> dir(dt)
['__class__', '__name__', '__dict__', '__file__', 'machine', 'read_LM92_TR']
>>>
Pri mikrokontroléroch s väčšou FLASH pamäťou je možné jej voľnú časť využiť ako pamäťové médium mapované ako file systém. Knižnica os poskytuje základné funkcie pre vytváranie adresárov a manipuláciu so súbormi.
>>> import os
>>> help(os)
object <module 'uos'> is of type module
__name__ -- uos
uname -- <function>
chdir -- <function>
getcwd -- <function>
ilistdir -- <function>
listdir -- <function>
mkdir -- <function>
...
mount -- <function>
umount -- <function>
Modul implementovaný v C #
Pri vývoji neštandardných periférií nemusia štandardné drivery, ktoré sú súčasťou MicroPython-u, vyhovovať a môže vzniknúť požiadavka na nízkoúrovňovú obsluhu periférie. Podobne ako pri štandardnom Pythone, je možné aj MocroPython rozširovať o natívne moduly napísané v C/C++ a ktoré môžu využívať aj systémové knižnice pre obsluhu periférií mikrokontroléra. Pre vytvorenie modulu musíme rovnako ako v štandardnom Pythone vytvoriť rozhranie medzi natívnym modulom a jeho reprezentáciou v Pythone.
Pretože rozhranie k natívnym modulom je v značnej miere štandardizované, pre štandardný Python existujú generátory kódu, napr. SWIG, ktoré vygenerujú potrebné rozhranie na základe zdrojového kódu modulu. Pri MicroPythone sa používa opačný postup, môžeme použiť generátor rozhrania ustubby, experimentálne implementácia sú napr. v link, ktorý vytvorí stub pozostávajúci z makier v C na základe deklarácie funkcie v Pythone.
Rozhranie modulu #
Vytvorenie rozhrania modulu je možné pomocou online generátora zadaním mena funkcie, argumentov a návratovej hodnoty.
Alternatívnym postupom je vygenerovanie rozhrania pomocou generátora ustubby priamo z deklarácie funkcie v Pythone pomocou generátora. Inštalácia ustubby je možná priamo z repozitárov
pip install ustubby
Vytvoríme jednoduchý modul pre ST32L476, ktorý pozostáva z funkcie, ktorá prepína LED stanovený počet krát a s nastaviteľnou dĺžkou intervalu.
Deklarácia funkcií v Pythone pre vygenerovanie rozhrania má tvar:
# Subor blink.py
def blink(n: int, delay: int) -> None:
"""Blikanie LED
:param n: pocet bliknuti
:param b: delay
:return: None
"""
Generovanie skeletonu #
Na základe tejto deklarácie vygenerujeme pomocou ustubby, do ktorého doplníme implementáciu príslušnej funkcie. Pre vygenerovanie môžeme použiť postup uvedený v návode ku generátoru alebo môžeme použiť nasledujúci jednoduchý skript.
# Subor gen_stub.py
# skript pre generovanie stubb pre moduly mikropythonu podla
# https://github.com/pazzarpj/micropython-ustubby
import ustubby
import sys
if len(sys.argv) < 1:
print("Pouzitie: python gen_stub.py input.py > output.c")
exit()
md = sys.argv[1].split(".")[0]
stub = __import__(md)
s = ustubby.stub_module(stub)
print(s)
Implementácia modulu #
Implementáciu vlastného kodu je možné vytvoriť pomocou HAL alebo LL, príklad časti kódu s implementáciou využívajúcou low-level knižnice STM32 je nižšie
#include "py/runtime.h"
#include <stdlib.h>
#include "stm32l4xx.h"
#include "stm32l4xx_ll_cortex.h"
#include "stm32l4xx_ll_gpio.h"
#include "stm32l4xx_ll_system.h"
#include "stm32l4xx_ll_utils.h"
static mp_obj_t blink(mp_obj_t n_obj, mp_obj_t delay_obj) {
int n = mp_obj_get_int(n_obj);
int delay = mp_obj_get_int(delay_obj);
int i = 0;
for(i=0; i<n; i++){
LL_mDelay(delay);
LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
}
return mp_const_none;
}
// Vytvorenie Python referencie na funkciu
// blink_obj - meno referencie
// blink - meno funkcie - z definicie
static MP_DEFINE_CONST_FUN_OBJ_2(blink_obj, blink);
//======================================================================
// tabulka mapovania modulu
// MP_ROM_QSTR(MP_QSTR_demo) - meno modulu (adresaru s implementaciou modulu)
// MP_ROM_PTR(&blink_obj) - referencia na funkciu modulu
static const mp_rom_map_elem_t blink_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_demo) },
{ MP_ROM_QSTR(MP_QSTR_blink), MP_ROM_PTR(&blink_obj) },
};
// referncia na tabulku
// blink_module_globals_table - zaradenie tabulky do slovnika modulov
static MP_DEFINE_CONST_DICT(blink_module_globals, blink_module_globals_table);
// definovanie objektu modulu
const mp_obj_module_t blink_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&blink_module_globals,
};
// registracia modulu
MP_REGISTER_MODULE(MP_QSTR_demo, blink_cmodule);
Štruktúra adresárov má potom tvar
my_project/
|
+-- modules/ <-- adresar modulov
| +--demo/
| +--blink.c <-- vygenerovany a doplneny zdrojovy kod
| +--micropython.mk <-- konfiguracia modulu
|
+-- micropython/ <-- originalny MicroPython
+--ports/ <-- porty pre platformy
... +--stm32/ <-- adresar pre kompilaciu firmware
...
Kompilácia s použitím HAL knižníc nevyžaduje žiadne úpravy, pri kompilácii implementácie modulov s LL knižnicami musíme upraviť ./stm32/Makefile
doplniť inicializáciu príznaku USE_FULL_LL_DRIVER pre sprístupnenie LL knižníc
doplniť kompiláciu LL knižníc
V sekcii CFLAGS doplniť (riadok 117)
CFLAGS = $(INC) -Wall ...
...
CFLAGS += -DUSE_FULL_LL_DRIVER <- doplneny flag
V sekcii HAL_SRC doplniť (riadok 326)
HAL_SRC = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
hal.c \
...
hal_uart.c \
ll_gpio.c \ <- doplnene LL drivery bez prefixu
...
)
Pre kompiláciu modulu ešte musíme v adresári modulu vytvoriť súbor micropython.mk, v ktorom je definovaná štruktúra modulu, ktorý môže pozostávať aj z viacerých súborov.
# Subor micropython.mk
BLINK_MOD_DIR := $(USERMOD_DIR)
# Add all C files to SRC_USERMOD.
SRC_USERMOD += $(BLINK_MOD_DIR)/blink.c
Spustenie kompilácie je potom rovnaké ak v predchádzajúcom prípade, v adresari ./ports/stm32/ spustíme kompiláciu firmware
make BOARD=NUCLEO_L432KC USER_C_MODULES=../../../modules
ktorý štandardným postupom zapíšeme do pamäte mikrokontroléra. Použitie modulu v MikroPythone je rovnaké ako akejkoľvek inej knižnice
>>> import demo
>>> demo.blink(10, 100)