通过网盘分享的文件:fr30xxc_sdk__202411(1).zip
链接: https://pan.baidu.com/s/1XyNkwqjrxEVSexzCbyYooQ?pwd=tmri 提取码: tmri
--来自百度网盘超级会员v3的分享
前面我们分享了micropython的移植,至此还只有一些内置的模块,我们现在开始就来移植平台相关的模块,先以最简单IO驱动LED为例。
以下是前文一些补充
遇到\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[i]=='\n'){
putchar('\r');
}
putchar(buffer[i]);
}
return len;
}
mpconfigport.h中配置
#define MICROPY_LONGINT_IMPL MICROPY_LONGINT_IMPL_MPZ
原来1<<32不支持
现在1<<32可以正常输出,甚至1<<160都可以
mpconfigport.h中配置
#define MICROPY_PY_BUILTINS_COMPLEX (1)
import math
math.按tab按键
配置
#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中实现
前文我们看到需要genhdr下自动生成的头文件,之前是通过从其他已经构建的地方复制过来的。其中genhdr/qstrdefs.generated.h定义了关键词对应的hash值,通过hash值来快速索引关键词,这个文件是通过python脚本生成的,对于支持的构建环境是自动调用脚本生成。而我们移植到MDK目前还没去添加对应的脚本(MDK也是可以配置执行脚本的,后面可以再完善),我们这一小节就来介绍下在新增关键词后如何手动更新该文件。
参考docs\develop\qstr.rst
从支持的构建环境的构建过程可以看到它是通过脚本命令生成的,参考
ports\windows\msvc\genhdr.targets可以看到其具体生成过程
其中如下位置指定文件qstrdefscollected.h
<QstrDefsCollected>$(DestDir)qstrdefscollected.hQstrDefsCollected>
该文件由以下命令产生
<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.lastgenhdr/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"/>
<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产生的
那么如何产生这个文件呢,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添加
新的字符串
然后执行python makeqstrdata.py genhdr/qstrdefs.preprocessed.h > genhdr/qstrdefs.generated.h生成即可。
整个过程如下,我们手动修改qstrdefs.preprocessed.h执行最后一步生成genhdr/qstrdefs.generated.h
我们参考参考已有的示例去做,参考
ports\stm32\modpyb.c
ports\stm32\led.h
ports\stm32\led.c
这一部分和具体的硬件平台相关,我们这里由两个LED
先实现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/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
构建实例
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 "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
py_port\modpyb.c中,绑定led实例pyb_led_type到pyb模块
#include
#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;
#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新增模块支持比较简单,只需要按照模板注册模块,绑定对应的驱动即可。后续就可以不断添加新的模块支持使更具备实用性。