工程源码

通过网盘分享的文件:fr30xxc_sdk__202411(1).zip

链接: https://pan.baidu.com/s/1XyNkwqjrxEVSexzCbyYooQ?pwd=tmri 提取码: tmri

--来自百度网盘超级会员v3的分享

前言

前面我们分享了micropython的移植,至此还只有一些内置的模块,我们现在开始就来移植平台相关的模块,先以最简单IO驱动LED为例。

以下是前文一些补充

修改输出不对齐问题

213119ritopib0is77vg76

遇到\n输出为\r\n

这样原来只有\n换行的地方,可以回车到行首再换行就会对齐了。

uint32_t uart_send(uint8_t* buffer, uint32_t len)

{

    g_data_transmit_flag = false;

    for(uint32_t i=0;i<len;i++)

    {

                        if(buffer=='\n'){

                          putchar('\r');

                        }

                        putchar(buffer);

    }

    return len;

}

大数据支持

mpconfigport.h中配置

#define MICROPY_LONGINT_IMPL              MICROPY_LONGINT_IMPL_MPZ

原来1<<32不支持

213119t4dpkxkhs634ehss

现在1<<32可以正常输出,甚至1<<160都可以

213119r6yyxbbxpe3c6st1

支持复数

mpconfigport.h中配置

#define MICROPY_PY_BUILTINS_COMPLEX       (1)

213120ql09acye8a9u4ccc

查看math支持的运算

import math

math. 按tab按键

213120us2i0ysmo522h8hs

配置

#define MICROPY_PY_MATH                   (1)

#define MICROPY_PY_CMATH                  (1)

#define MICROPY_PY_BUILTINS_FLOAT         (1)

#define MICROPY_FLOAT_IMPL                (MICROPY_FLOAT_IMPL_DOUBLE)

genhdr\moduledefs.h中可以看到注册了math模块。

#define MICROPY_REGISTERED_MODULES \

    MODULE_DEF_BUILTINS \

    MODULE_DEF_CMATH \

    MODULE_DEF_GC \

    MODULE_DEF_MATH \

    MODULE_DEF_MICROPYTHON \

    MODULE_DEF_SYS \

MODULE_DEF___MAIN__ \

extern const struct _mp_obj_module_t mp_module_math;

#undef MODULE_DEF_MATH

#define MODULE_DEF_MATH { MP_ROM_QSTR(MP_QSTR_math), MP_ROM_PTR(&mp_module_math) },

mp_module_math在

py\modmath.c中实现

关键词hash值计算

前文我们看到需要genhdr下自动生成的头文件,之前是通过从其他已经构建的地方复制过来的。其中genhdr/qstrdefs.generated.h定义了关键词对应的hash值,通过hash值来快速索引关键词,这个文件是通过python脚本生成的,对于支持的构建环境是自动调用脚本生成。而我们移植到MDK目前还没去添加对应的脚本(MDK也是可以配置执行脚本的,后面可以再完善),我们这一小节就来介绍下在新增关键词后如何手动更新该文件。

参考docs\develop\qstr.rst

从支持的构建环境的构建过程可以看到它是通过脚本命令生成的,参考

ports\windows\msvc\genhdr.targets可以看到其具体生成过程

其中如下位置指定文件qstrdefscollected.h

    <QstrDefsCollected>$(DestDir)qstrdefscollected.h</QstrDefsCollected>

该文件由以下命令产生

    <Exec Command="$(PyPython) $(PySrcDir)makeqstrdefs.py split qstr $(DestDir)qstr.i.last $(DestDir)qstr _"/>

    <Exec Command="$(PyPython) $(PySrcDir)makeqstrdefs.py cat qstr _ $(DestDir)qstr $(QstrDefsCollected)"/>

对应

python makeqstrdefs.py split qstr genhdr/qstr.i.last genhdr/qstr _

makeqstrdefs.py使用格式如下usage: makeqstrdefs.py command mode input_filename output_dir output_file

即将genhdr/qstr.i.last文件生成到qstr下,使用split命令qstr模式。

qstr.i.last先使用基础版本,最后再手动添加新内容。

python makeqstrdefs.py cat qstr _ genhdr/qstr genhdr/qstrdefscollected.h

    <Exec Command="$(PyClTool) /nologo /I@(PyIncDirs, ' /I') /D@(PreProcDefs, ' /D') /E $(PyQstrDefs) $(QstrDefs) > $(DestDir)qstrdefs.preprocessed.h"/>

    <!--Because makemanifest.py relies on this file to have all Q() and QCFG() entries.-->

    <Exec Command="type $(QstrDefsCollected) >> $(DestDir)qstrdefs.preprocessed.h"/>

    <Exec Command="$(PyPython) $(PySrcDir)makeqstrdata.py $(DestDir)qstrdefs.preprocessed.h > $(TmpFile)"/>

对应

type genhdr/qstrdefscollected.h >> genhdr/qstrdefs.preprocessed.h

python makeqstrdata.py genhdr/qstrdefs.preprocessed.h > genhdr/qstrdefs.generated.h

前面原始输入文件是genhdr\qstr.i.last该文件由编译器产生,格式类似于

(# n "file")  GCC产生的

(#line n "file") MSVC产生的

213120gelvlecflcv9hh5q

那么如何产生这个文件呢,qstr.i.last由编译器的预处理器产生,

对if等条件编译删除,宏展开,添加行信息

需要添加-DNO_QSTR编译选项

py\mkrules.mk中qstr.i.last由

如下命令生成

$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(QSTR_GLOBAL_REQUIREMENTS)

    $(ECHO) "GEN $@"

    $(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py pp $(CPP) output $(HEADER_BUILD)/qstr.i.last cflags $(QSTR_GEN_CFLAGS) cxxflags $(QSTR_GEN_CXXFLAGS) sources $^ dependencies $(QSTR_GLOBAL_DEPENDENCIES) changed_sources $?

我们无需从头开始,只需要修改原来的

genhdr\qstrdefs.preprocessed.h添加

新的字符串

213121kd22h8va8tbm5h2v

213121zxx7tgebexyxqqxx

然后执行 python makeqstrdata.py genhdr/qstrdefs.preprocessed.h > genhdr/qstrdefs.generated.h生成即可。

213121bk462z84i6civbxp

整个过程如下,我们手动修改qstrdefs.preprocessed.h执行最后一步生成genhdr/qstrdefs.generated.h

213121bjjqz1v36kiqkpzn

三.添加LED模块

我们参考参考已有的示例去做,参考

ports\stm32\modpyb.c

ports\stm32\led.h

ports\stm32\led.c

Io控制驱动

这一部分和具体的硬件平台相关,我们这里由两个LED

213121lu9zhvvu3uydk7vk

先实现LED控制IO的初始化

app_micropython.c中

#include "fr30xx.h"

#include "FreeRTOS.h"

#include "task.h"

#include "app_micropython.h"

TaskHandle_t micropython_task_handle;

extern int py_main(int argc, char **argv);

static void micropython_task(void *arg);

static void led_init(void)

{

        GPIO_InitTypeDef gpio_config;

        __SYSTEM_GPIOD_CLK_ENABLE();

  gpio_config.Pin = GPIO_PIN_14 | GPIO_PIN_15;

  gpio_config.Mode = GPIO_MODE_OUTPUT_PP;

  gpio_config.Pull = GPIO_PULLUP;

  gpio_config.Alternate = GPIO_FUNCTION_0;

  gpio_init(GPIOD, &gpio_config);

}

void app_micropython_init(void)

{

    xTaskCreate(micropython_task, "micropython", 2048*2, NULL, 3, µpython_task_handle);

}

static void micropython_task(void *arg)

{

         led_init();

         py_main(0,0);

}


然后实现LED的控制接口

py_port\mphalport.c中

#include "py/runtime.h"

#include "py/mphal.h"

#include "mphalport.h"

#include "fr30xx.h"

void mp_hal_pin_low(mp_uint_t id)

{

        if(id==1)

  {

                gpio_write_pin(GPIOD,GPIO_PIN_14,GPIO_PIN_CLEAR);

        }

        else if(id == 2)

  {

                gpio_write_pin(GPIOD,GPIO_PIN_15,GPIO_PIN_CLEAR);

        }

        else

  {


        }

}

void mp_hal_pin_high(mp_uint_t id)

{

        if(id==1)

  {

                gpio_write_pin(GPIOD,GPIO_PIN_14,GPIO_PIN_SET);

        }

        else if(id == 2)

  {

                gpio_write_pin(GPIOD,GPIO_PIN_15,GPIO_PIN_SET);

        }

        else

  {


        }

}

void mp_hal_pin_toogle(mp_uint_t id)

{

        if(id==1)

  {

                if(gpio_read_pin(GPIOD,GPIO_PIN_14))

    {

                   gpio_write_pin(GPIOD,GPIO_PIN_14,GPIO_PIN_SET);

                }

                else

    {

                   gpio_write_pin(GPIOD,GPIO_PIN_14,GPIO_PIN_CLEAR);

                }

        }

        else if(id == 2)

  {

                if(gpio_read_pin(GPIOD,GPIO_PIN_15))

    {

                   gpio_write_pin(GPIOD,GPIO_PIN_14,GPIO_PIN_SET);

                }

                else

    {

                   gpio_write_pin(GPIOD,GPIO_PIN_15,GPIO_PIN_CLEAR);

                }

        }

        else

  {


        }

}

py_port\mphalport.h中

#ifndef MICROPY_MPHALPORT_H

#define MICROPY_MPHALPORT_H

static inline mp_uint_t mp_hal_ticks_ms(void) {

    return 0;

}

static inline void mp_hal_set_interrupt_char(char c) {

}

void mp_hal_pin_low(mp_uint_t id);

void mp_hal_pin_high(mp_uint_t id);

void mp_hal_pin_toogle(mp_uint_t id);

#endif

Led实例

构建实例

static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on);

static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off);

static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle);

static const mp_rom_map_elem_t led_locals_dict_table[] = {

    { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&led_obj_on_obj) },

    { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&led_obj_off_obj) },

    { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&led_obj_toggle_obj) },

};

static MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table);

MP_DEFINE_CONST_OBJ_TYPE(

    pyb_led_type,

    MP_QSTR_LED,

    MP_TYPE_FLAG_NONE,

    make_new, led_obj_make_new,

    print, led_obj_print,

    locals_dict, &led_locals_dict

);

led.c中

#include <stdio.h>

#include "py/runtime.h"

#include "py/mphal.h"

#include "led.h"

/// \moduleref pyb

/// \class LED - LED object

///

/// The LED object controls an individual LED (Light Emitting Diode).

// the default is that LEDs are not inverted, and pin driven high turns them on

#ifndef MICROPY_HW_LED_INVERTED

#define MICROPY_HW_LED_INVERTED (0)

#endif

typedef struct _pyb_led_obj_t {

    mp_obj_base_t base;

    mp_uint_t led_id;

} pyb_led_obj_t;

static const pyb_led_obj_t pyb_led_obj[] = {

    {{&pyb_led_type}, 1},

    {{&pyb_led_type}, 2},

    {{&pyb_led_type}, 3},

    {{&pyb_led_type}, 4},

};

#define NUM_LEDS MP_ARRAY_SIZE(pyb_led_obj)

void led_init(void) {

    /* Turn off LEDs and initialize */

    for (int led = 0; led < NUM_LEDS; led++) {

    }

}

void led_state(pyb_led_t led, int state) {

    if (led < 1 || led > NUM_LEDS) {

        return;

    }

                mp_uint_t led_id = pyb_led_obj[led].led_id-1;

    if (state == 0) {

        // turn LED off

        mp_hal_pin_low(led_id);

    } else {

        // turn LED on

        mp_hal_pin_high(led_id);

    }

}

void led_toggle(pyb_led_t led) {

    if (led < 1 || led > NUM_LEDS) {

        return;

    }

                mp_uint_t led_id = pyb_led_obj[led].led_id-1;

    // toggle the output data register to toggle the LED state

    mp_hal_pin_toogle(led_id);

}

void led_set_intensity(pyb_led_t led, mp_int_t intensity) {

    // intensity not supported for this LED; just turn it on/off

    led_state(led, intensity > 0);

}

void led_debug(int n, int delay) {

    led_state(1, n & 1);

    led_state(2, n & 2);

    led_state(3, n & 4);

    led_state(4, n & 8);

    //mp_hal_delay_ms(delay);

}

/******************************************************************************/

/* MicroPython bindings                                                       */

void led_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {

    pyb_led_obj_t *self = MP_OBJ_TO_PTR(self_in);

    mp_printf(print, "LED(%u)", self->led_id);

}

/// \classmethod \constructor(id)

/// Create an LED object associated with the given LED:

///

///   - `id` is the LED number, 1-4.

static mp_obj_t led_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {

    // check arguments

    mp_arg_check_num(n_args, n_kw, 1, 1, false);

    // get led number

    mp_int_t led_id = mp_obj_get_int(args[0]);

    // check led number

    if (!(1 <= led_id && led_id <= NUM_LEDS)) {

        mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("LED(%d) doesn't exist"), led_id);

    }

    // return static led object

    return MP_OBJ_FROM_PTR(&pyb_led_obj[led_id - 1]);

}

/// \method on()

/// Turn the LED on.

mp_obj_t led_obj_on(mp_obj_t self_in) {

    pyb_led_obj_t *self = MP_OBJ_TO_PTR(self_in);

    led_state(self->led_id, 1);

    return mp_const_none;

}

/// \method off()

/// Turn the LED off.

mp_obj_t led_obj_off(mp_obj_t self_in) {

    pyb_led_obj_t *self = MP_OBJ_TO_PTR(self_in);

    led_state(self->led_id, 0);

    return mp_const_none;

}

/// \method toggle()

/// Toggle the LED between on and off.

mp_obj_t led_obj_toggle(mp_obj_t self_in) {

    pyb_led_obj_t *self = MP_OBJ_TO_PTR(self_in);

    led_toggle(self->led_id);

    return mp_const_none;

}

static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on);

static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off);

static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle);

static const mp_rom_map_elem_t led_locals_dict_table[] = {

    { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&led_obj_on_obj) },

    { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&led_obj_off_obj) },

    { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&led_obj_toggle_obj) },

};

static MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table);

MP_DEFINE_CONST_OBJ_TYPE(

    pyb_led_type,

    MP_QSTR_LED,

    MP_TYPE_FLAG_NONE,

    make_new, led_obj_make_new,

    print, led_obj_print,

    locals_dict, &led_locals_dict

    );

Led.h中

#ifndef MICROPY_INCLUDED_XX_LED_H

#define MICROPY_INCLUDED_XX_LED_H

typedef enum {

    PYB_LED_RED = 1,

    PYB_LED_GREEN = 2,

    PYB_LED_YELLOW = 3,

    PYB_LED_BLUE = 4,

} pyb_led_t;

void led_init(void);

void led_state(pyb_led_t led, int state);

void led_toggle(pyb_led_t led);

void led_debug(int value, int delay);

extern const mp_obj_type_t pyb_led_type;

#endif

注册pyb模块,绑定LED实例

py_port\modpyb.c中,绑定led实例pyb_led_type到pyb模块

#include <stdint.h>

#include <stdio.h>

#include "py/runtime.h"

#include "py/mphal.h"

#include "shared/runtime/pyexec.h"

#include "led.h"

//#include "portmodules.h"

//#include "modmachine.h"

//#include "extmod/modmachine.h"

//#include "extmod/modnetwork.h"

//#include "extmod/vfs.h"

//#include "extmod/modtime.h"

MP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c

// Provide a no-op version of pyb.country for backwards compatibility on

// boards that don't support networking.

static mp_obj_t pyb_country(size_t n_args, const mp_obj_t *args) {

    (void)n_args;

    (void)args;

    return mp_const_none;

}

static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_network_country_obj, 0, 1, pyb_country);

static const mp_rom_map_elem_t pyb_module_globals_table[] = {

    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyb) },

    { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) },

};

static MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table);

const mp_obj_module_t pyb_module = {

    .base = { &mp_type_module },

    .globals = (mp_obj_dict_t *)&pyb_module_globals,

};

MP_REGISTER_MODULE(MP_QSTR_pyb, pyb_module);

py\genhdr\moduledefs.h中注册pyb模块

extern const struct _mp_obj_module_t pyb_module;

#undef PYB_BUILTIN_MODULE_CONSTANTS

#define PYB_BUILTIN_MODULE_CONSTANTS \

    { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) },

#define MICROPY_REGISTERED_MODULES \

    MODULE_DEF_BUILTINS \

    MODULE_DEF_CMATH \

    MODULE_DEF_GC \

    MODULE_DEF_MATH \

    MODULE_DEF_MICROPYTHON \

    MODULE_DEF_SYS \

    MODULE_DEF___MAIN__ \

                PYB_BUILTIN_MODULE_CONSTANTS

// MICROPY_REGISTERED_MODULES

四.测试

见视频

https://mp.weixin.qq.com/s/JdFb3x7KOag114Fb72URGA?token=1312261758&lang=zh_CN

import pyb

led1 = pyb.LED(1)

led2 = pyb.LED(2)

led1.on()

led2.on()

led1.off()

led2.off()

led1.toggle()

led2.toggle()

总结

可以看到micropython新增模块支持比较简单,只需要按照模板注册模块,绑定对应的驱动即可。后续就可以不断添加新的模块支持使更具备实用性。