[openmv]添加用户micropython底层硬件接口
添加python的C接口
参考地址
在src/micropython/examples/usercmodule/cexample
中有添加示例,但是在src/omv中也是可以添加自己的module,这里的omv表示openmv缩写。
根据在src/omv/modules
下的micropython.mk
凡是只要在src/omv/modules的*.c
文件都会被编译成模块。那么接下来添加自己的模块:
在改文件夹创建px.c
// 包含python得API
#include "py/runtime.h"
// 这个函数会被python调用作为cexample.add_ints(a, b).
STATIC mp_obj_t px_sub_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
// 提取出ints数据重python micropython 输入 对象.
int a = mp_obj_get_int(a_obj);
int b = mp_obj_get_int(b_obj);
// 计算加法并且传给MicroPython 对象
return mp_obj_new_int(a - b);
}
// 定义一个python参考到上面的函数
STATIC MP_DEFINE_CONST_FUN_OBJ_2(px_sub_ints_obj, px_sub_ints);
// 定义所有的模块属性
// 表条目是属性名称
// 和 MicroPython 对象引用的键/值对。
// 所有的定义和字符串通过编译器被写成MP_QSTR_xxx和被优化成字宽长度的整数
STATIC const mp_rom_map_elem_t px_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_px) },
{ MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&px_sub_ints_obj) },
};
STATIC MP_DEFINE_CONST_DICT(px_module_globals, px_module_globals_table);
// 定义模块对象
const mp_obj_module_t px_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&px_module_globals,
};
// 注册模块使其可在python中使用。
// 注:在第三个参数中的"1"表示的是这个模块会常开
// 这个"1"也可以使用预编译的宏定义比如:MODULE_CEXAMPLE_ENABLED来替代,它能够变得有条件的使用改模块
MP_REGISTER_MODULE(MP_QSTR_px, px_cmodule, 1);
这样一个python的模块接口节完成了。执行make -j$(nproc) TARGET=OPENMV4 -C src
编译一遍,没有问题,且生成了px.o文件。使用方法如下:
import px #根据MP_REGISTER_MODULE(MP_QSTR_px, px_cmodule, 1);中MP_QSTR_px中"MP_QSTR_"后面
print(px.sub_ints(1, 3))#根据STATIC MP_DEFINE_CONST_FUN_OBJ_2(px_sub_ints_obj, px_sub_ints);中px_sub_ints中除掉module名剩余的函数名。
那么如何为STM32或者其他芯片添加一个调用底层硬件的接口?在src/omv/modules/micropython.mk
中有如下:SRC_USERMOD += $(wildcard $(OMV_PORT_MOD_DIR)/*.c)
而OMV_PORT_MOD_DIR
为:OMV_PORT_MOD_DIR := $(OMV_MOD_DIR)/../ports/$(PORT)/modules
也就是说在src/omv/ports/stm32/modules
中也是被编译器搜索module的目录。(这里ports表示一类板子的意思,且ports目录下stm32仅仅是作为示例)。根据原有的代码,这里我给出自己的一些示例代码如下led模块与digital_iput模块。编写流程可参考:https://www.jianshu.com/p/1b2915bb570d
函数声明宏源代码(如MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN
)可在src/micropython/py/obj.h
中看到。其意义和用法如下(从源码src/micropython/py/obj.h
函数fun_builtin_1_call
可以推断):
宏名 | 意义 | 用法 |
---|---|---|
MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) | 声明一个函数不带参数的 | obj_name=对象名。 func_name=函数名。 |
MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) | 声明一个函数带1个参数的 | obj_name=对象名。 func_name=函数名。 |
MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) | 声明一个函数带2个参数的 | obj_name=对象名。 func_name=函数名。 |
MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) | 声明一个函数带3个参数的 | obj_name=对象名。 func_name=函数名。 |
MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) | 声明一个函数带变参且无关键字,参数个数下限可设置,上限为无限制(实际上是0xffff) | obj_name=对象名。 n_args_min=参数最少个数 func_name=函数名。 |
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) | 声明一个函数带变参且无关键字,参数个数下限可设置,上限也可设置 | obj_name=对象名。 n_args_min=参数最少个数 n_args_max=参数最大个数 func_name=函数名。 |
MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) | 声明一个函数带变参带关键字,参数个数下限可设置,上限为无限制(实际上是0xffff) | obj_name=对象名。 n_args_min=参数最少个数 func_name=函数名。 |
这里带关键字还没了解清楚。
而MP_DEFINE_CONST_DICT这个的表,例如:
static const mp_rom_map_elem_t globals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_led) },//类名
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_INT(is_en) },//成员数据
{ MP_ROM_QSTR(MP_QSTR_setup), MP_ROM_PTR(&py_led_setup_obj) },//成员函数
{ MP_ROM_QSTR(MP_QSTR_en), MP_ROM_PTR(&py_led_en_obj) }
};
//MP_ROM_QSTR向python中声明一个成员。函数用MP_ROM_PTR,数据用MP_ROM_INT或其他。
使用真机验证
无板子。
其他
整个工程的main
用我比较熟悉的STM32:
位置应该在:src\omv\ports\stm32\main.c
示例代码
请放在
openmv\src\omv\ports\stm32\modules
下。
LED.C
/*
* This file is part of the OpenMV project.
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* Buzzer Python module.
*/
#include "py/obj.h"
#include "omv_boardconfig.h"
#include STM32_HAL_H
static GPIO_TypeDef *led_port = 0;
static int led_pin = 0;
static int led_act_low = 0;
static int is_en = 0;
typedef struct gpio_map{
char gpio_name;
GPIO_TypeDef *port;
}gpio_map;
static gpio_map GPIO_MAPs[6] = {
{'A', GPIOA},
{'B', GPIOB},
{'C', GPIOC},
{'D', GPIOD},
{'E', GPIOE},
{'H', GPIOH},
};
static int led_setup( char gpio_port, int gpio_pin, int arctive_low)
{
if( gpio_port != 'H')
{
led_port = GPIO_MAPs[5].port;
}
else if( gpio_port <= 'E' && gpio_port >= 'A')
{
led_port = GPIO_MAPs[(gpio_port-'A')].port;
}
else
return -1;
led_pin = gpio_pin;
led_act_low = arctive_low;
is_en = 0;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pull = led_act_low?GPIO_PULLUP:GPIO_PULLDOWN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = led_pin;
HAL_GPIO_Init(led_port, &GPIO_InitStructure);
return 1;
}
STATIC mp_obj_t py_led_setup(mp_obj_t gpio_port, mp_obj_t gpio_pin, mp_obj_t arctive_low)
{
const char *port = mp_obj_str_get_str( gpio_port);
int32_t pin = mp_obj_get_int( gpio_pin);
int32_t act_low = mp_obj_get_int( arctive_low);
int res = led_setup( port[0], pin, act_low);
return mp_obj_new_int( res);
}
//声明成员函数,这里是需要不同的参数那么只能使用变参,且有3个参数需要设置。
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_led_setup_obj, py_led_setup);
STATIC mp_obj_t py_led_en(mp_obj_t en_obj)
{
if( led_port)
return mp_obj_new_bool(0);
int32_t en = mp_obj_get_int( en_obj);
is_en = en;
en = led_act_low?!en:en;
HAL_GPIO_WritePin( led_port, (unsigned short)led_pin, en);
return mp_obj_new_bool(1);
}
//声明成员函数,且有1个参数需要设置。
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_led_en_obj, py_led_en);
STATIC mp_obj_t py_led_status()
{
return mp_obj_new_bool(is_en);
}
//声明成员函数,且有1个参数需要设置。
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_led_status_obj, py_led_status);
static const mp_rom_map_elem_t globals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_led) },
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&py_led_status_obj) },
{ MP_ROM_QSTR(MP_QSTR_setup), MP_ROM_PTR(&py_led_setup_obj) },
{ MP_ROM_QSTR(MP_QSTR_en), MP_ROM_PTR(&py_led_en_obj) }
};
//MP_ROM_QSTR向python中声明一个成员。函数用MP_ROM_PTR,数据用MP_ROM_INT或其他。
STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table);
const mp_obj_module_t led_module = {
.base = { &mp_type_module },
.globals = (mp_obj_t) &globals_dict,
};
MP_REGISTER_MODULE(MP_QSTR_led, led_module, MICROPY_PY_LED);
digital_iput.C
未实现C