重要结构体介绍
rt_device_pin结构体
struct rt_device_pin
{
struct rt_device parent; /* 父类 */
const struct rt_pin_ops *ops; /* 操作函数集 */
};
rt_device结构体
struct rt_device
{
struct rt_object parent; /**< inherit from rt_object */
enum rt_device_class_type type; /**< device type */
rt_uint16_t flag; /**< device flag */
rt_uint16_t open_flag; /**< device open flag */
rt_uint8_t ref_count; /**< reference count */
rt_uint8_t device_id; /**< 0 - 255 */
/* device call back */
rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);
#ifdef RT_USING_DEVICE_OPS
const struct rt_device_ops *ops;
#else
/* common device interface */
rt_err_t (*init) (rt_device_t dev);
rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close) (rt_device_t dev);
rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void *args);
#endif
#if defined(RT_USING_POSIX)
const struct dfs_file_ops *fops;
struct rt_wqueue wait_queue;
#endif
void *user_data; /**< device private data */
};
rt_pin_ops结构体
struct rt_pin_ops
{
void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
int (*pin_read)(struct rt_device *device, rt_base_t pin);
/* TODO: add GPIO interrupt */
rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
rt_uint32_t mode, void (*hdr)(void *args), void *args);
rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);
rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
};
重要的C文件介绍
drv_gpio.c
/* drv_gpio.c里面的函数 */
static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
static int stm32_pin_read(rt_device_t dev, rt_base_t pin)
static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
rt_inline rt_int32_t bit2bitno(rt_uint32_t bit)
rt_inline const struct pin_irq_map *get_pin_irq_map(uint32_t pinbit)
static rt_err_t stm32_pin_attach_irq(struct rt_device *device, rt_int32_t pin,
rt_uint32_t mode, void (*hdr)(void *args), void *args)
static rt_err_t stm32_pin_dettach_irq(struct rt_device *device, rt_int32_t pin)
static rt_err_t stm32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
rt_uint32_t enabled)
const static 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,
};
int rt_hw_pin_init(void)
我们可以看出,drv_gpio.c这个文件里面主要是完成了 rt_pin_ops 结构体里面函数的实现,并且这些函数基本上也就是通过HAL库底层驱动来实现的,即这个文件是最接近底层的文件,当然官方HAL除外。
底层驱动函数
static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
{
const struct pin_index *index;
index = get_pin(pin);
if (index == RT_NULL)
{
return;
}
HAL_GPIO_WritePin(index->gpio, index->pin, (GPIO_PinState)value);
}
static int stm32_pin_read(rt_device_t dev, rt_base_t pin)
{
int value;
const struct pin_index *index;
value = PIN_LOW;
index = get_pin(pin);
if (index == RT_NULL)
{
return value;
}
value = HAL_GPIO_ReadPin(index->gpio, index->pin);
return value;
}
这里展示其中两个代码,HAL_GPIO_WritePin(index->gpio, index->pin, (GPIO_PinState)value)、HAL_GPIO_ReadPin(index->gpio, index->pin)这两个函数相信大家学习过stm32都应该知道。
rt_hw_pin_init(重要)
int rt_hw_pin_init(void)
{
#if defined(__HAL_RCC_GPIOA_CLK_ENABLE)
__HAL_RCC_GPIOA_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOB_CLK_ENABLE)
__HAL_RCC_GPIOB_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOC_CLK_ENABLE)
__HAL_RCC_GPIOC_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOD_CLK_ENABLE)
__HAL_RCC_GPIOD_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOE_CLK_ENABLE)
__HAL_RCC_GPIOE_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOF_CLK_ENABLE)
__HAL_RCC_GPIOF_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOG_CLK_ENABLE)
#ifdef SOC_SERIES_STM32L4
HAL_PWREx_EnableVddIO2();
#endif
__HAL_RCC_GPIOG_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOH_CLK_ENABLE)
__HAL_RCC_GPIOH_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOI_CLK_ENABLE)
__HAL_RCC_GPIOI_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOJ_CLK_ENABLE)
__HAL_RCC_GPIOJ_CLK_ENABLE();
#endif
#if defined(__HAL_RCC_GPIOK_CLK_ENABLE)
__HAL_RCC_GPIOK_CLK_ENABLE();
#endif
return rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
}
上面代码主要实现了打开对应gpio的时钟以及调用rt_device_pin_register函数。&_stm32_pin_ops这个参数很重要,看一下这个函数原型:
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data);
注册PIN设备
此函数可以注册PIN设备到PIN驱动框架中。
参数
- name PIN设备名称
- ops PIN设备操作函数对象指针
- user_data 用户数据,一般设为RT_NULL
返回
- RT_EOK 注册成功;-RT_ERROR 注册失败,已有其他驱动使用该name注册。
pin.c
/* pin.c里面的函数 */
static struct rt_device_pin _hw_pin;
static rt_size_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
static rt_size_t _pin_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
static rt_err_t _pin_control(rt_device_t dev, int cmd, void *args)
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode,
void (*hdr)(void *args), void *args)
rt_err_t rt_pin_detach_irq(rt_int32_t pin)
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled)
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
oid rt_pin_write(rt_base_t pin, rt_base_t value)
int rt_pin_read(rt_base_t pin)
现在我们再来看看上面说的 rt_device_pin_register 函数
static struct rt_device_pin _hw_pin;
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{
_hw_pin.parent.type = RT_Device_Class_Miscellaneous;/* 声明为杂类设备类型 */
_hw_pin.parent.rx_indicate = RT_NULL;
_hw_pin.parent.tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
_hw_pin.parent.ops = &pin_ops;
#else
_hw_pin.parent.init = RT_NULL;
_hw_pin.parent.open = RT_NULL;
_hw_pin.parent.close = RT_NULL;
_hw_pin.parent.read = _pin_read; /* 把设备的read操作绑定在pin.c的_pin_read函数 */
_hw_pin.parent.write = _pin_write; /* 把设备的write操作绑定在pin.c的_pin_write函数 */
_hw_pin.parent.control = _pin_control; /* 把设备的control操作绑定在pin.c的_pin_control函数 */
#endif
_hw_pin.ops = ops; /* 把drv_gpio.c所实现的_stm32_pin_ops绑定在_hw_pin.ops上 */
_hw_pin.parent.user_data = user_data; /* 私有数据 */
/* register a character device */
rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);/* 将其注册进device设备框架中 */
return 0;
}
当程序运行到这儿的时候,设备框架里面已经注册了一个名为"pin"的设备。然后也初始化好了_hw_pin这个结构体:
如何实现对接
pin设备框架提供的接口:
rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode,
void (*hdr)(void *args), void *args)
rt_err_t rt_pin_detach_irq(rt_int32_t pin)
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled)
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
oid rt_pin_write(rt_base_t pin, rt_base_t value)
int rt_pin_read(rt_base_t pin)
在这里我就拿最简单的mode函数做讲解了:
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
_hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
}
分析如下
rt_pin_mode(rt_base_t pin, rt_base_t mode)
->_hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
->stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
综上,pin设备框架的流程大概如下:
- 先实现底层的gpio驱动函数
- 把这些函数通过rt_device_pin_register注册进pin设备驱动框架
- 最后就可以调用pin设备框架提供访问api进行操作了。
一些补充
看到这儿,大家可能会有疑问
static rt_size_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
static rt_size_t _pin_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
static rt_err_t _pin_control(rt_device_t dev, int cmd, void *args)
这几个函数有什么作用????
_hw_pin.parent.read = _pin_read; /* 把设备的read操作绑定在pin.c的_pin_read函数 */
_hw_pin.parent.write = _pin_write; /* 把设备的write操作绑定在pin.c的_pin_write函数 */
_hw_pin.parent.control = _pin_control; /* 把设备的control操作绑定在pin.c的_pin_control函数 */
这里我们可以看出来,这些函数被绑定在device框架的标准设备操作函数,那说明我们也是可以通过rtthread提供的I/O设备模型的标准device操作函数去访问pin设备。
关于device设备框架和pin设备提供的这三个接口的绑定,其实和上面pin和drv_gpio提供的底层操作接口绑定很类似。这里我说一下device是如何调用到底层pin的:
rt_size_t rt_device_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t size)
{
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
if (dev->ref_count == 0)
{
rt_set_errno(-RT_ERROR);
return 0;
}
/* call device_read interface */
if (device_read != RT_NULL)
{
return device_read(dev, pos, buffer, size);
}
/* set error code */
rt_set_errno(-RT_ENOSYS);
return 0;
}
一些隐藏宏定义:
#define device_init (dev->init)
#define device_open (dev->open)
#define device_close (dev->close)
#define device_read (dev->read)
#define device_write (dev->write)
#define device_control (dev->control)
分析如下:
rt_device_read
->device_read(dev, pos, buffer, size);//(dev->read(dev, pos, buffer, size);)
->_pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
->pin->ops->pin_read(dev, status->pin);
->stm32_pin_read(rt_device_t dev, rt_base_t pin)
总结
无论RT-Thread写的多么花花,都是想尽一切办法去调用底层代码,慢慢分析!!!