Prenošenje MicroPythona¶
Projekt MicroPython sadrži nekoliko portova za različite obitelji mikrokontrolera i arhitekture. Repozitorij projekta ima direktorij ports koji sadrži poddirektorij za svaki podržani port.
Port će tipično sadržavati definicije za više „ploča”, od kojih je svaka određeni komad sklopovlja na kojem taj port može raditi, npr. razvojni komplet ili uređaj.
Minimalni port dostupan je kao pojednostavljena referentna implementacija MicroPython porta. Može raditi i na host sustavu i na STM32F4xx MCU-u.
Općenito, pokretanje porta zahtijeva:
Postavljanje lanca alata (konfiguriranje Makefilea itd.).
Implementaciju konfiguracije pokretanja i inicijalizacije CPU-a.
Inicijalizaciju osnovnih upravljačkih programa potrebnih za razvoj i otklanjanje pogrešaka (npr. GPIO, UART).
Izvođenje konfiguracija specifičnih za ploču.
Implementaciju modula specifičnih za port.
Minimalni MicroPython ugrađeni program¶
Najbolji način za početak prenošenja MicroPythona na novu ploču jest integriranjem minimalnog MicroPython interpretera. Za ovaj vodič stvorite poddirektorij za novi port u direktoriju ports:
$ cd ports
$ mkdir example_port
Osnovni MicroPython ugrađeni program implementiran je u glavnoj datoteci porta, npr. main.c:
#include "py/builtin.h"
#include "py/compile.h"
#include "py/gc.h"
#include "py/mperrno.h"
#include "shared/runtime/gchelper.h"
#include "shared/runtime/pyexec.h"
// Allocate memory for the MicroPython GC heap.
static char heap[4096];
int main(int argc, char **argv) {
// Initialise the MicroPython runtime.
mp_cstack_init_with_sp_here(2048);
gc_init(heap, heap + sizeof(heap));
mp_init();
// Start a normal REPL; will exit when ctrl-D is entered on a blank line.
pyexec_friendly_repl();
// Deinitialise the runtime.
gc_sweep_all();
mp_deinit();
return 0;
}
// Handle uncaught exceptions (should never be reached in a correct C implementation).
void nlr_jump_fail(void *val) {
for (;;) {
}
}
// Do a garbage collection cycle.
void gc_collect(void) {
gc_collect_start();
gc_helper_collect_regs_and_stack();
gc_collect_end();
}
// There is no filesystem so stat'ing returns nothing.
mp_import_stat_t mp_import_stat(const char *path) {
return MP_IMPORT_STAT_NO_EXIST;
}
// There is no filesystem so opening a file raises an exception.
mp_lexer_t *mp_lexer_new_from_file(qstr filename) {
mp_raise_OSError(MP_ENOENT);
}
U ovom trenutku također nam je potreban Makefile za port:
# Include the core environment definitions; this will set $(TOP).
include ../../py/mkenv.mk
# Include py core make definitions.
include $(TOP)/py/py.mk
include $(TOP)/extmod/extmod.mk
# Set CFLAGS and libraries.
CFLAGS += -I. -I$(BUILD) -I$(TOP)
LIBS += -lm
# Define the required source files.
SRC_C = \
main.c \
mphalport.c \
shared/readline/readline.c \
shared/runtime/gchelper_generic.c \
shared/runtime/pyexec.c \
shared/runtime/stdout_helpers.c \
# Define source files containing qstrs.
SRC_QSTR += shared/readline/readline.c shared/runtime/pyexec.c
# Define the required object files.
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
# Define the top-level target, the main firmware.
all: $(BUILD)/firmware.elf
# Define how to build the firmware.
$(BUILD)/firmware.elf: $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
$(Q)$(SIZE) $@
# Include remaining core make rules.
include $(TOP)/py/mkrules.mk
Ne zaboravite koristiti ispravne tabulatore za uvlačenje Makefilea.
MicroPython konfiguracije¶
Nakon integriranja minimalnog koda iznad, sljedeći korak je stvaranje MicroPython konfiguracijskih datoteka za port. Konfiguracije u vrijeme kompilacije navedene su u mpconfigport.h, a dodatne funkcije apstrakcije sklopovlja, poput vođenja vremena, u mphalport.h.
Sljedeće je primjer datoteke mpconfigport.h:
#include <stdint.h>
// Python internal features.
#define MICROPY_ENABLE_GC (1)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
// Fine control over Python builtins, classes, modules, etc.
#define MICROPY_PY_ASYNC_AWAIT (0)
#define MICROPY_PY_BUILTINS_SET (0)
#define MICROPY_PY_ATTRTUPLE (0)
#define MICROPY_PY_COLLECTIONS (0)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_IO (0)
#define MICROPY_PY_STRUCT (0)
// Type definitions for the specific machine.
typedef long mp_off_t;
// We need to provide a declaration/definition of alloca().
#include <alloca.h>
// Define the port's name and hardware.
#define MICROPY_HW_BOARD_NAME "example-board"
#define MICROPY_HW_MCU_NAME "unknown-cpu"
#define MP_STATE_PORT MP_STATE_VM
Ova konfiguracijska datoteka sadrži konfiguracije specifične za stroj, uključujući aspekte poput toga trebaju li se omogućiti različite MicroPython značajke, npr. #define MICROPY_ENABLE_GC (1). Postavljanje toga na (0) onemogućuje značajku.
Ostale konfiguracije uključuju definicije tipova, korijenske pokazivače, naziv ploče, naziv mikrokontrolera itd.
Slično, minimalni primjer datoteke mphalport.h izgleda ovako:
static inline void mp_hal_set_interrupt_char(char c) {}
Podrška za standardni ulaz/izlaz¶
MicroPython zahtijeva barem način za ispis znakova, a da bi imao REPL zahtijeva i način za unos znakova. Funkcije za to mogu se implementirati u datoteci mphalport.c, na primjer:
#include <unistd.h>
#include "py/mpconfig.h"
// Receive single character, blocking until one is available.
int mp_hal_stdin_rx_chr(void) {
unsigned char c = 0;
int r = read(STDIN_FILENO, &c, 1);
(void)r;
return c;
}
// Send the string of given length.
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
int r = write(STDOUT_FILENO, str, len);
(void)r;
}
Te ulazne i izlazne funkcije moraju se izmijeniti ovisno o specifičnom API-ju ploče. Ovaj primjer koristi standardni ulazno/izlazni tok.
Izgradnja i pokretanje¶
U ovoj fazi direktorij novog porta trebao bi sadržavati:
ports/example_port/
├── main.c
├── Makefile
├── mpconfigport.h
├── mphalport.c
└── mphalport.h
Port se sada može izgraditi pokretanjem make (ili na drugi način, ovisno o vašem sustavu).
Ako koristite zadane postavke kompilatora u gore navedenom Makefileu, tada će se time stvoriti izvršna datoteka pod nazivom build/firmware.elf koja se može izravno izvršiti. Da biste dobili funkcionalni REPL, možda ćete prvo morati konfigurirati terminal u sirovi (raw) način rada:
$ stty raw opost -echo
$ ./build/firmware.elf
To bi vam trebalo dati MicroPython REPL. Zatim možete pokretati naredbe poput:
MicroPython v1.26.0-preview on 2025-08-01; minimal with unknown-cpu
>>> def sum(n, m):
... return n + m
...
>>> 3, 4, sum(3, 4)
(3, 4, 7)
>>>
Koristite Ctrl-D za izlaz, a zatim pokrenite reset za resetiranje terminala.
Dodavanje modula u port¶
Da biste dodali prilagođeni modul poput myport, prvo dodajte definiciju modula u datoteku modmyport.c:
#include "py/runtime.h"
static mp_obj_t myport_info(void) {
mp_printf(&mp_plat_print, "info about my port\n");
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_0(myport_info_obj, myport_info);
static const mp_rom_map_elem_t myport_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_myport) },
{ MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&myport_info_obj) },
};
static MP_DEFINE_CONST_DICT(myport_module_globals, myport_module_globals_table);
const mp_obj_module_t myport_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&myport_module_globals,
};
MP_REGISTER_MODULE(MP_QSTR_myport, myport_module);
Također ćete morati urediti Makefile kako biste dodali modmyport.c na popis SRC_C, te novi redak koji dodaje istu datoteku u SRC_QSTR (kako bi se qstrovi tražili u toj novoj datoteci), ovako:
SRC_C = \
main.c \
modmyport.c \
mphalport.c \
...
SRC_QSTR += modmyport.c
Ako je sve prošlo ispravno, nakon ponovne izgradnje trebali biste moći uvesti novi modul:
>>> import myport
>>> myport.info()
info about my port
>>>