移植 MicroPython

Posted 温人之周.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了移植 MicroPython相关的知识,希望对你有一定的参考价值。

  MicroPython项目支持多个不同的MCU或平台,他们在 MicroPython的port 目录里面。当我们的项目能够在port 目录里面找到支持的单片机时,我们可以直接应用port 目录里面的工程,但是当port 目录里面没有支持我们的单片机时,就需要我们自己移植MicroPython到相应的的单片机上。
  通常来说,向单片机移植MicroPython时需要的工作有:
  1、设置工具链(配置 Makefile 等)
  2、初始化CPU和编写bootloader
  3、初始化一切开发和调试所需的基本驱动程序(例如 GPIO、UART)。
  4、编写特定的配置
  5、实现单片机的modules。
  下面以一个最小的MicroPython 固件为演示案例:
  在port 目录下创建一个example_port文件夹,该文件夹就是放置工程文件的地方。该文件夹最少要包含5个文件,分别为main.c、 Makefile、mpconfigport.h、 mphalport.c、 mphalport.h。结构如下:

ports/example_port/
├── main.c
├── Makefile
├── mpconfigport.h
├── mphalport.c
└── mphalport.h

  其中main.c文件是工程的主文件,Makefile是编译文件,mpconfigport.h文件的作用是MicroPython 配置文件,mphalport.c是单片机特有的一些其他配置,mphalport.c文件的作用是实现标准输入/输出。

一、各文件代码内容

1.1、main.c文件

#include "py/compile.h"
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/stackctrl.h"
#include "lib/utils/gchelper.h"
#include "lib/utils/pyexec.h"

// Allocate memory for the MicroPython GC heap.
static char heap[4096];

int main(int argc, char **argv) 
    // Initialise the MicroPython runtime.
    mp_stack_ctrl_init();
    gc_init(heap, heap + sizeof(heap));
    mp_init();
    mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
    mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);

    // 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(const char *filename) 
    mp_raise_OSError(MP_ENOENT);

1.2、Makefile文件

# Include the core environment definitions; this will set $(TOP).
include ../../py/mkenv.mk

# Include py core make definitions.
include $(TOP)/py/py.mk

# Set CFLAGS and libraries.
CFLAGS = -I. -I$(BUILD) -I$(TOP)
LIBS = -lm

# Define the required source files.
SRC_C = \\
    main.c \\
    mphalport.c \\
    lib/mp-readline/readline.c \\
    lib/utils/gchelper_generic.c \\
    lib/utils/pyexec.c \\
    lib/utils/stdout_helpers.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

1.3、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 intptr_t mp_int_t; // must be pointer size
typedef uintptr_t mp_uint_t; // must be pointer size
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

#define MICROPY_PORT_ROOT_POINTERS \\
    const char *readline_hist[8];

1.4、mphalport.h文件

static inline void mp_hal_set_interrupt_char(char c) 

1.5、mphalport.c文件

#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;

二、添加module

  要添加一个自定义module名字为myport,首先在文件夹中添加module定义的文件名字为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, 1);

  编写完modmyport.c文件后,还需要再次编辑 Makefile ,作用是添加modmyport.c到SRC_C列表中。如下所示:

SRC_C = \\
    main.c \\
    modmyport.c \\
    mphalport.c \\
    ...

SRC_QSTR += modport.c

以上是关于移植 MicroPython的主要内容,如果未能解决你的问题,请参考以下文章

i.MX RT1021核心板的Micropython移植的相关文档

移植 MicroPython

[长文干货]MicroPython移植到野火STM32F429开发板

调试来自于逐飞的MM32F3277移植有MicroPython开发板

MindMotion MM32 单片机上的MicroPython移植-PWM

MM32F3277 MicroPython移植过程中对应的接口文件