在mm32f3270为micropython创建Pin模块(2)

Introduction
上文书说,已经搭建了一个基本的能够在REPL中引用到的Pin模块。为了规避Hardfault的问题,暂时屏蔽了history的功能。勉强已经可以用起来了。

本文将要打通python对底层硬件的操作,进一步完成Pin模块。

本文可能会涉及到引脚表的设计问题

make_new()
 

static inline void mp_arg_check_num (
	size_t n_args,     /* 位置参数的总数量 */
	size_t n_kw,       /* 关键字参数的数量 */
	size_t n_args_min, /* 位置参数最少数量 */
	size_t n_args_max, /* 位置参数最大数量 */
	bool   takes_kw )  /* 是否包含关键字参数 */
{
    mp_arg_check_num_sig(n_args, n_kw, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, takes_kw));
}

感觉在machine_pin_obj_make_new()里检查这个参数清单没啥功能性作用。如果参数无效,则直接报错?

后来在试用程序的过程发现挺有用的,当用户输入参数不正确时,会提示错误类型。

接下来用第一个make_new()的第一个传参找引脚。这个args[0]是个什么鬼?当传入pin_find时,是当它为一个对象的,可能是一个预先初始化好的引脚对象,也可能是一个数字
 

const machine_pin_obj_t *pin = pin_find(args[0]);

在machine_pin.c中实现pin_func()函数如下:

/* 格式化pin对象,传入参数无论是已经初始化好的pin对象,还是一个表示pin清单中的索引编号,通过本函数都返回一个期望的pin对象。 */
const machine_pin_obj_t *pin_find(mp_obj_t user_obj)
{
    //const machine_pin_obj_t *pin_obj;

    /* 如果传入参数本身就是一个Pin的实例,则直接送出这个pin。 */
    if ( mp_obj_is_type(user_obj, &machine_pin_type) )
    {
        return user_obj;
    }

    /* 如果传入参数是一个代表Pin清单的索引,则通过索引在Pin清单中找到这个pin,然后送出这个pin。 */
    if ( mp_obj_is_small_int(user_obj) )
    {
        uint8_t pin_idx = MP_OBJ_SMALL_INT_VALUE(user_obj);
        if ( pin_idx < machine_pin_board_pins_num)
        {
            return machine_pin_board_pins[pin_idx];
        }
    }

    /* 如果传入参数是一个字符串,则通过这个字符串在Pin清单中匹配引脚名字,然后送出找到的pin */
    const machine_pin_obj_t *named_pin_obj = pin_find_by_name(&machine_pin_board_pins_locals_dict, user_obj);
    if ( named_pin_obj )
    {
        return named_pin_obj;       
    }

    mp_raise_ValueError(MP_ERROR_TEXT("Pin doesn't exist"));
}

/* 通过字符串在引脚清单中匹配引脚 */
const machine_pin_obj_t *pin_find_by_name(const mp_obj_dict_t *name_dict, mp_obj_t name)
{
    mp_map_t *name_map = mp_obj_dict_get_map((mp_obj_t)name_dict);
    mp_map_elem_t *name_elem = mp_map_lookup(name_map, name, MP_MAP_LOOKUP);
    
    if ( (name_elem != NULL) && (name_elem->value != NULL) )
    {
        return name_elem->value;
    }
    return NULL;
}

其中,machine_pin_board_pins[]和machine_pin_board_pins_locals_dict[]在“ports/mm32/board/MB_F3270/machine_pin_board_pins.c”文件中定义。

const uint32_t machine_pin_board_pins_num = 3;

const machine_pin_obj_t pin_PA1 = { .base = { &machine_pin_type }, .name = MP_QSTR_PA1, .gpio_port = GPIOA, .gpio_pin = 1 };
const machine_pin_obj_t pin_PA2 = { .base = { &machine_pin_type }, .name = MP_QSTR_PA2, .gpio_port = GPIOA, .gpio_pin = 2 };
const machine_pin_obj_t pin_PA3 = { .base = { &machine_pin_type }, .name = MP_QSTR_PA3, .gpio_port = GPIOA, .gpio_pin = 3 };

const machine_pin_obj_t *machine_pin_board_pins[] = 
{
    &pin_PA1,
    &pin_PA2,
    &pin_PA3,
};

STATIC const mp_rom_map_elem_t pin_board_pins_locals_dict_table[] =
{
    { MP_ROM_QSTR(MP_QSTR_PA1), MP_ROM_PTR(&pin_PA1) },
    { MP_ROM_QSTR(MP_QSTR_PA2), MP_ROM_PTR(&pin_PA2) },
    { MP_ROM_QSTR(MP_QSTR_PA3), MP_ROM_PTR(&pin_PA3) },
};
MP_DEFINE_CONST_DICT(machine_pin_board_pins_locals_dict, pin_board_pins_locals_dict_table);

是的,我还是创建了“machine_pin.h”。

引入“machine_pin.h”是为了解决在通用machine_pin和板级machine_pin之间共享machine_pin_obj_t的问题,顺便把hal_gpio.h中配置PinMode选项的枚举类型用mp的方式映射出来。

typedef enum
{
    PIN_MODE_IN_ANALOG = 0u,
    PIN_MODE_IN_FLOATING,
    PIN_MODE_IN_PULLDOWN,
    PIN_MODE_IN_PULLUP,
    PIN_MODE_OUT_OPENDRAIN,
    PIN_MODE_OUT_PUSHPULL,
    PIN_MODE_AF_OPENDRAIN,
    PIN_MODE_AF_PUSHPULL,
} machine_pin_mode_t;

在machine_pin.c还有:

    static const GPIO_PinMode_Type machine_pin_modes[] = 
    {
        GPIO_PinMode_In_Analog    ,
        GPIO_PinMode_In_Floating  ,
        GPIO_PinMode_In_PullDown  ,
        GPIO_PinMode_In_PullUp    ,
        GPIO_PinMode_Out_OpenDrain,
        GPIO_PinMode_Out_PushPull ,
        GPIO_PinMode_AF_OpenDrain ,
        GPIO_PinMode_AF_PushPull  ,
    };

 这样就可以通过mp中的顺序索引访问GPIO配置驱动中的不连续的设定值了。

machine_pin_modes[PIN_MODE_IN_PULLUP] = GPIO_PinMode_In_PullUp

同时,这些PinMode配置值还要变成关键字,才能被用户从脚本中调用到。

/* class locals_dict_table. */
STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] =
{
    /* Class instance methods. */
    { MP_ROM_QSTR(MP_QSTR_low),     MP_ROM_PTR(&machine_pin_low_obj) },
    { MP_ROM_QSTR(MP_QSTR_high),    MP_ROM_PTR(&machine_pin_high_obj) },
    { MP_ROM_QSTR(MP_QSTR_value),   MP_ROM_PTR(&machine_pin_value_obj) },
    { MP_ROM_QSTR(MP_QSTR_init),    MP_ROM_PTR(&machine_pin_init_obj) },

    /* Class constants. */
    { MP_ROM_QSTR(MP_QSTR_IN_ANALOG    ), MP_ROM_INT(PIN_MODE_IN_ANALOG    ) },
    { MP_ROM_QSTR(MP_QSTR_IN_FLOATING  ), MP_ROM_INT(PIN_MODE_IN_FLOATING  ) },
    { MP_ROM_QSTR(MP_QSTR_IN_PULLDOWN  ), MP_ROM_INT(PIN_MODE_IN_PULLDOWN  ) },
    { MP_ROM_QSTR(MP_QSTR_IN_PULLUP    ), MP_ROM_INT(PIN_MODE_IN_PULLUP    ) },
    { MP_ROM_QSTR(MP_QSTR_OUT_OPENDRAIN), MP_ROM_INT(PIN_MODE_OUT_OPENDRAIN) },
    { MP_ROM_QSTR(MP_QSTR_OUT_PUSHPULL ), MP_ROM_INT(PIN_MODE_OUT_PUSHPULL ) },
    { MP_ROM_QSTR(MP_QSTR_AF_OPENDRAIN ), MP_ROM_INT(PIN_MODE_AF_OPENDRAIN ) },
    { MP_ROM_QSTR(MP_QSTR_AF_PUSHPULL  ), MP_ROM_INT(PIN_MODE_AF_PUSHPULL  ) },

};
STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);

准备了这么多,最后才能开始写make_new()函数:

/* return an instance of machine_pin_obj_t. */
mp_obj_t machine_pin_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
{
    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);

    const machine_pin_obj_t *pin = pin_find(args[0]);

    if ( (n_args > 1) || (n_kw > 0) )
    {
        mp_map_t kw_args;
        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); /* 将关键字参数从总的参数列表中提取出来,单独封装成kw_args。 */
        machine_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
    }

    return (mp_obj_t)pin;
}

 其中machine_pin_obj_init_helper()的实现如下:

typedef enum
{
    PIN_INIT_ARG_MODE = 0,
    PIN_INIT_ARG_VALUE,
} machine_pin_init_arg_t;

STATIC mp_obj_t machine_pin_obj_init_helper (
    const machine_pin_obj_t *self, /* machine_pin_obj_t类型的变量,包含硬件信息 */
    size_t n_args, /* 位置参数数量 */
    const mp_obj_t *pos_args, /* 位置参数清单 */
    mp_map_t *kw_args ) /* 关键字参数清单结构体 */
{
    static const mp_arg_t allowed_args[] = 
    {
        [PIN_INIT_ARG_MODE] { MP_QSTR_mode , MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = PIN_MODE_IN_PULLUP} },
        [PIN_INIT_ARG_VALUE]{ MP_QSTR_value, MP_ARG_KW_ONLY  | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
        //{ MP_QSTR_drive, MP_ARG_KW_ONLY  | MP_ARG_INT, {.u_int = PIN_DRIVE_POWER_3}},
    };

    /* 解析参数 */
    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

    static const GPIO_PinMode_Type machine_pin_modes[] = 
    {
        GPIO_PinMode_In_Analog    ,
        GPIO_PinMode_In_Floating  ,
        GPIO_PinMode_In_PullDown  ,
        GPIO_PinMode_In_PullUp    ,
        GPIO_PinMode_Out_OpenDrain,
        GPIO_PinMode_Out_PushPull ,
        GPIO_PinMode_AF_OpenDrain ,
        GPIO_PinMode_AF_PushPull  ,
    };

    GPIO_Init_Type gpio_init;
    gpio_init.Speed = GPIO_Speed_50MHz;
    gpio_init.Pins = (1u << self->gpio_pin);
    gpio_init.PinMode = machine_pin_modes[args[PIN_INIT_ARG_MODE].u_int];

    GPIO_Init(self->gpio_port, &gpio_init);

    if (args[PIN_INIT_ARG_VALUE].u_obj != MP_OBJ_NULL)
    {
        if ( mp_ojb_is_true(args[PIN_INIT_ARG_VALUE].u_obj) )
        {
            GPIO_WriteBit(self->gpio_port, 1u << self->gpio_pin, 1u);
        }
        else
        {
            GPIO_WriteBit(self->gpio_port, 1u << self->gpio_pin, 0u);
        }
    }

    return mp_const_none;
}

pin_init()天然复用了init_helper()函数好,不用额外代码了。

pin_low()和pin_high()


STATIC mp_obj_t machine_pin_high(mp_obj_t self_in)
{
    /* self_in is machine_pin_obj_t. */
    machine_pin_obj_t * pin = (machine_pin_obj_t *)self_in;

    GPIO_WriteBit(pin->gpio_base, 1u << pin->gpio_pin, 1u);

    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high);


STATIC mp_obj_t machine_pin_low(mp_obj_t self_in)
{
    /* self_in is machine_pin_obj_t. */
    machine_pin_obj_t * pin = (machine_pin_obj_t *)self_in;

    GPIO_WriteBit(pin->gpio_base, 1u << pin->gpio_pin, 0u);
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_low_obj, machine_pin_low);

到此为止,就可以试着编一下,然后下载程序试着运行一下了。


MicroPython v1.16 on 2021-08-23; MB_F3270 with MM32F3277G7P
>>> import machine
>>> dir(machine)
['__name__', 'Pin', 'freq', 'mem16', 'mem32', 'mem8']
>>> from machine import Pin
>>> dir(Pin)
['value', 'AF_OPENDRAIN', 'AF_PUSHPULL', 'IN_ANALOG', 'IN_FLOATING', 'IN_PULLDOWN', 'IN_PULLUP', 'OUT_OPENDRAIN', 'OUT_PUSHPULL', 'high', 'init', 'low']
>>> pin0 = Pin(0)
>>> pin0.init(mode=OUT_PUSHPULL)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name not defined
>>> Pin.OUT_PUSHPULL
5
>>> pin0.init(mode=Pin.OUT_PUSHPULL)
>>> pin0.low()
>>> pin0.high()
>>>

通过试用可以看到,即使定义了“OUT_PUSHPULL”,也不能直接用,必须使用“Pin.OUT_PUSHPULL”。

想来如果使用了“from Pin import *”,就有可能直接用“OUT_PUSHPULL”

>>> from Pin import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: module not found
>>> from machine.Pin import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: module not found
>>>

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值