rt_hw_usart_init函数干了些什么??
之前写了一篇pin设备框架分析pin设备框架分析,简单理了一下pin设备框架实现的思想,其实今天要说的串口基本类似,今天咱们就长话短说,我介绍几个重要的部分。
首先就是标题的这个函数。包括上一节内容的**int rt_hw_pin_init(void)**函数。我们都是围绕这个进行介绍的。
int rt_hw_usart_init(void)
{
rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct stm32_uart);/* 当前的串口设备数量 */
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;/* 串口的默认参数(包括波特率,数据长度,停止位等) */
rt_err_t result = 0;
stm32_uart_get_dma_config(); /* 配置串口DMA */
for (int i = 0; i < obj_num; i++)
{
uart_obj[i].config = &uart_config[i]; /* 串口的底层配置(包括寄存器句柄,中断相关,和设备名字) */
uart_obj[i].serial.ops = &stm32_uart_ops;/* 将serial.ops集和底层的操作函数绑定 */
uart_obj[i].serial.config = config; /* 配置默认参数RT_SERIAL_CONFIG_DEFAULT */
/* register UART device */
result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name,
RT_DEVICE_FLAG_RDWR
| RT_DEVICE_FLAG_INT_RX
| RT_DEVICE_FLAG_INT_TX
| uart_obj[i].uart_dma_flag
, NULL);
RT_ASSERT(result == RT_EOK);
}
return result;
}
rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
const char *name,
rt_uint32_t flag,
void *data)
{
rt_err_t ret;
struct rt_device *device;
RT_ASSERT(serial != RT_NULL);
device = &(serial->parent);
device->type = RT_Device_Class_Char;/* 设备类型为RT_Device_Class_Char */
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
device->ops = &serial_ops;
#else
device->init = rt_serial_init; /* 设备的init操作绑定在sensor.c的rt_serial_init函数 */
device->open = rt_serial_open; /* 设备的open操作绑定在sensor.c的rt_serial_open函数 */
device->close = rt_serial_close; /* 设备的close操作绑定在sensor.c的rt_serial_close函数 */
device->read = rt_serial_read; /* 设备的read操作绑定在sensor.c的rt_serial_read函数 */
device->write = rt_serial_write; /* 设备的write操作绑定在sensor.c的rt_serial_write函数 */
device->control = rt_serial_control;/* 设备的control操作绑定在sensor.c的rt_serial_control函数 */
#endif
device->user_data = data;/* 私有数据 */
/* register a character device */
ret = rt_device_register(device, name, flag);
#if defined(RT_USING_POSIX)
/* set fops */
device->fops = &_serial_fops;
#endif
return ret;
}
基本上必要的注释,我都在代码上写了,大家这么看可能不太直观,我还是上个图:
上层接口是如何对接的??
隐藏宏定义
#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_err_t rt_device_close(rt_device_t dev)
->result = device_close(dev);/* result = (dev->close)(dev); */
=>rt_serial_close(struct rt_device *dev)/* 根据上面图,dev->close和rt_serial_close绑定 */
-> serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
等等,到这儿就有一个重点了!!!!!!!!!!!!!!!!!!!!
在前面的注册函数和初始过程中,我们似乎没有对rt_serial_init、rt_serial_open与(drv_usart.cart.c)里面的stm32_uart_ops里面的操作函数对接,那这里为什么可以直接调用serial->ops->control呢?????
大家仔细观察会发现,在rt_serial_init、rt_serial_open、rt_serial_write等函数中,前面会有这么几条语句!
static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
{
rt_uint16_t stream_flag = 0;
struct rt_serial_device *serial;
RT_ASSERT(dev != RT_NULL);
serial = (struct rt_serial_device *)dev;
……
}
这个函数我们传进去的参数是一个struct rt_device*结构类型的变量dev,在函数里面做了一个类型转换:
struct rt_serial_device *serial;
serial = (struct rt_serial_device *)dev;
这里大家可能得回顾一个知识点:
结构体成员的第一个元素的地址和结构体的首地址相同。
我们再看这个struct rt_serial_device结构体
struct rt_serial_device
{
struct rt_device parent;
const struct rt_uart_ops *ops;
struct serial_configure config;
void *serial_rx;
void *serial_tx;
};
所以通过前面一转换,虽然我们在注册的时候只是注册了device设备,但是我们可以根据这个“父亲(rt_serial_device)”来找到他的“孩子(rt_serial_device)”,然后通过调用serial->ops去对接device设备的操作函数。
同理,大家去仔细观察一下其他device操作函数,都是这样一层一层的调用的。
补充
如果大家是新作一个bsp的话,在配置各种各样的驱动的时候,我们都需要使用CubeMX工具去生成一个驱动,获得如下这个函数
void HAL_XXX_MspInit(XXX_HandleTypeDef* huart)
这个函数是关于外设时钟和引脚配置的,大家有没有想过,本节的**void HAL_UART_MspInit(UART_HandleTypeDef* huart)**这个函数又是在哪儿调用的呢????
static rt_err_t rt_serial_init(struct rt_device *dev)
{
rt_err_t result = RT_EOK;
struct rt_serial_device *serial;
RT_ASSERT(dev != RT_NULL);
serial = (struct rt_serial_device *)dev;
/* initialize rx/tx */
serial->serial_rx = RT_NULL;
serial->serial_tx = RT_NULL;
/* apply configuration */
if (serial->ops->configure)
result = serial->ops->configure(serial, &serial->config);
return result;
}
在这个函数中serial->ops->configure
static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
……
……
if (HAL_UART_Init(&uart->handle) != HAL_OK)
{
return -RT_ERROR;
}
return RT_EOK;
}
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
{
……
HAL_UART_MspInit(huart);
……
}