本文主要是介绍rtt的io设备框架面向对象学习-pin设备,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 1.pin设备基类
- 2.pin设备基类的子类
- 3.初始化/构造流程
- 3.1设备驱动层
- 3.2 设备驱动框架层
- 3.3 设备io管理层
- 4.总结
- 5.gpio的pin映射
- 6.使用
1.pin设备基类
此层处于设备驱动框架层。
在/ components / drivers / include / drivers 下的pin.h定义了如下pin设备基类
struct rt_device_pin
{
struct rt_device parent;
const struct rt_pin_ops *ops;
};
pin设备基类的方法定义如下
struct rt_pin_ops
{
void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_uint8_t mode);
void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_uint8_t value);
rt_int8_t (*pin_read)(struct rt_device *device, rt_base_t pin);
rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_base_t pin,
rt_uint8_t mode, void (*hdr)(void *args), void *args);
rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_base_t pin);
rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled);
0rt_base_t (*pin_get)(const char *name);
};
抽象出来所有pin设备的共性成为pin设备基类的方法。
pin设备比较特殊,它在/ components / drivers / misc / pin.c实例化了pin设备基类对象如下:
static struct rt_device_pin _hw_pin;
2.pin设备基类的子类
无。pin设备比较特殊,没有pin设备基类的子类。
3.初始化/构造流程
以stm32为例,从设备驱动层、设备驱动框架层到设备io管理层从下到上的构造/初始化流程如下
3.1设备驱动层
此层是bsp层,pin设备比较特殊,没有定义驱动层的pin设备对象,在设备驱动层是直接定义了pin设备基类的方法,用以重写在/ components / drivers / misc / pin.c实例化了pin设备基类对象_hw_pin的基类方法。
在/ bsp / stm32 / libraries / HAL_Drivers / drivers 下drv_gpio.c的rt_hw_pin_init中开启stm32的pin设备的初始化/构造流程——并重写了pin设备基类对象的ops方法:
static const struct rt_pin_ops _stm32_pin_ops =
{
stm32_pin_mode,
stm32_pin_write,
stm32_pin_read,
stm32_pin_attach_irq,
stm32_pin_dettach_irq,
stm32_pin_irq_enable,
stm32_pin_get,
};
然后调用/ components / drivers / misc 下rt_pin.c中rt_device_pin_register函数来初始化pin设备基类对象。
3.2 设备驱动框架层
rt_device_pin_register是pin设备驱动框架层的入口,开启pin设备基类的构造/初始化流程。
其主要是重写设备基类对象的方法,如下
/ components / drivers / misc 下的pin.c实现了设备驱动框架层接口。
重写pin设备基类的父类设备基类的方法如下
_hw_pin.parent.init = RT_NULL; _hw_pin.parent.open = RT_NULL; _hw_pin.parent.close = RT_NULL; _hw_pin.parent.read = _pin_read; _hw_pin.parent.write = _pin_write; _hw_pin.parent.control = _pin_control;
同时,重写pin设备基类的方法。
_hw_pin.ops = ops;
并最终调用设备基类的初始化/构造函数rt_device_register。
3.3 设备io管理层
在/ components / drivers / core 下的device.c中实现了rt_device_register,它是io管理层的入口。
它将设备框架层pin设备基类对象放到对象容器里管理。
4.总结
整个设备对象的构造/初始化流程其实是对具体设备对象也就是结构体进行初始化赋值——它这个结构体是包含一个个的结构体——模拟的是面向对象的继承机制。跟套娃似的,层层进行初始化。这样的好处是什么?每层有每层的初始化(构造)函数,就模拟了面向对象的构造函数——按照先调用子类构造/初始化函数,再调用父类的构造/初始化函数方式——其实也是子类构造/初始化函数调用父类构造/初始化函数的流程,来完成设备对象的初始化/构造。最终放到对象容器里来管理。
这样的好处是可扩展,如搭积木似的,也是对内封闭,对外开放,扩展性好,模拟的是面向对象的继承多态机制。
其实每个类的注册函数模拟的是面向对象的构造函数。
5.gpio的pin映射
pin设备gpio计算原理,由设备驱动层即各个bsp根据各自芯片厂家gpio的寄存器地址映射规则,来实现pin设备基类的方法。
实例
以stm32为例,在/ bsp / stm32 / libraries / HAL_Drivers / drivers 下drv_gpio.c定义了如下宏
#define PIN_NUM(port, no) (((((port)&0xFu) << 4) | ((no)&0xFu)))
#define PIN_PORT(pin) ((uint8_t)(((pin) >> 4) & 0xFu))
#define PIN_NO(pin) ((uint8_t)((pin)&0xFu))
PIN_NUM是计算引脚编号,和芯片引脚号无关,自己抽象的,其实是对芯片引脚端口和引脚号的映射或者说再编码或者说降维(多维变低维)的概念。
PIN_PORT是根据引脚编号反推出芯片引脚端口(如PA~PZ),和芯片手册相一致。
PIN_NO是根据引脚编号反推出芯片引脚号(如推算Px.y中的y),和芯片手册相一致。
stm32_pin_get就通过调用PIN_NUM宏实现了芯片端口和引脚号到rtt的引脚编号的转换,其原理就是
PA.0 映射为 引脚编号0
PA.1 映射为 引脚编号1
…
PB.0 映射为 引脚编号16
…
PZ.0 映射为 引脚编号176
…
下面这两个是将引脚编号重新解算为stm32的寄存器地址——根据芯片手册找到正确的映射公式,仅取如下宏举例
#define PIN_STPORT(pin) ((GPIO_TypeDef *)(GPIOA_BASE + (0x400u * PIN_PORT(pin))))
#define PIN_STPIN(pin) ((uint16_t)(1u << PIN_NO(pin)))
PIN_STPORT宏解算出端口的寄存器地址
PIN_STPIN宏解算出对应引脚号的寄存器值
有了寄存器地址,那么设置gpio的模式,高低电平就不再话下,如此这般,这般如此,不再赘诉。
6.使用
文档
这篇关于rtt的io设备框架面向对象学习-pin设备的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!