[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
posted @ 2022-04-04 18:59  邪恶法师  阅读(363)  评论(0编辑  收藏  举报