程序小白
认证:优质创作者
所在专题目录 查看专题
单片机应用与驱动开发之路:这时的你只需要扣动扳机。
RT-Thread驱动之路:stm32设备驱动开发之uart注册①
RT-Thread驱动之路:stm32设备驱动开发之uart设备创建②
RT-Thread驱动之路:stm32设备驱动开发之uart操作方法③
RT-Thread驱动之路:stm32设备驱动开发之uart中断处理④
RT-Thread驱动之路:stm32设备驱动开发之浅析注册机制⑤
作者动态 更多
电子元器件那些事儿:三极管工作区的判断如此简单①
4天前
RT-Thread驱动之路:stm32设备驱动开发之SPI原理①
1星期前
RT-Thread驱动之路:stm32设备驱动开发之浅析注册机制⑤
2星期前
RT-Thread驱动之路:stm32设备驱动开发之uart中断处理④
2星期前
电子元器件那些事儿:继电器电路驱动设计②
2星期前

RT-Thread驱动之路:stm32设备驱动开发之uart注册①


      开篇分割线,驱动开发和应用是完全两条路子,系统里面应用程序想要通过名称或者句柄找到驱动的必要条件就是,驱动已经被注册到了系统里了,那么我们的第一篇就聊聊他是如何被注册到系统里面的,直接上图看下其调用关系:

      首先我们看到系统初始化过程中,需要对板载硬件进行初始化,调用rt_hw_board_init,而内部使用大量的预编译宏进行开关控制各个硬件部分是不是需要进行初始化,接下来看下函数rt_hw_usart_init:

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();

    for (int i = 0; i < obj_num; i++)
    {
        uart_obj[i].config = &uart_config[i];
        uart_obj[i].serial.ops    = &stm32_uart_ops;
        uart_obj[i].serial.config = config;
        /* 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_hw_serial_register,它是你理解注册的第一步接下来我们看下这个函数的原形:

/*
 * serial register
 */
rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct serial_device *serial)
{
    RT_ASSERT(device != RT_NULL);

    device->type        = RT_Device_Class_Char;
    device->rx_indicate = RT_NULL;
    device->tx_complete = RT_NULL;
    device->init        = rt_serial_init;
    device->open        = rt_serial_open;
    device->close       = rt_serial_close;
    device->read        = rt_serial_read;
    device->write       = rt_serial_write;
    device->control     = rt_serial_control;
    device->user_data   = serial;

    /* register a character device */
    return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
}

      我们注意下它的输入参数,这非常重要,第一个就是一个对象实体(当然C语言中就是一个结构体变量),第二个参数我们得给这个对象起个名字,这样方便我们的应用更好的找到我们的对象,第三个参数是对象的人设(举个例子它可以进行那些操作的合集,比如或者读or写),四个参数则是这个对象的私有数据(user_data,也就是我和别人不一样的点),这个函数的主要任务就是,定义设备的类型:RT_Device_Class_Char,并且设备的动作赋真实可操作的值:初始化/打开/关闭/读/写/控制操作。

      最后的最后它需要调用系统提供的rt_device_register完成最终的注册,原型如下:

      最后的最后我们倒序的方式回忆一下,设备注册都做了什么:

rt_device_register:设备对象dev  与设备name 建立联系,并赋值挣得操作flag类型。

rt_hw_serial_register:设备对象dev的操作方法具体赋值,私有数据赋值和类型赋值,丰富dev对象,然后调用rt_device_register。

rt_hw_usart_init:传入真实的设备操作方法,比如我们用的是stm32芯片,这里就需要将真实的硬件驱动操作方法,串口配置参数传入到serial结构体中,下一章我们会基于这个API讲讲设备驱动的详细实现细节。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 2
收藏 4
关注 135
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧