RT-Thread OS 设备模型

设备驱动层是一组驱使硬件设备工作的程序,实现访问硬件设备的功能。它负责创建和注册 I/O 设备,对于操作逻辑简单的设备,可以不经过设备驱动框架层,直接将设备注册到 I/O 设备管理器中,使用序列图如下图所示,主要有以下 2 点:

  • 设备驱动根据设备模型定义,创建出具备硬件访问能力的设备实例,将该设备通过 rt_device_register() 接口注册到 I/O 设备管理器中。

  • 应用程序通过 rt_device_find() 接口查找到设备,然后使用 I/O 设备管理接口来访问硬件。

设备创建: 

rt_device_t rt_device_create(int type, int attach_size);

type包括:

RT_Device_Class_Char             /* 字符设备       */
RT_Device_Class_Block            /* 块设备         */
RT_Device_Class_NetIf            /* 网络接口设备    */
RT_Device_Class_MTD              /* 内存设备       */
RT_Device_Class_RTC              /* RTC 设备        */
RT_Device_Class_Sound            /* 声音设备        */
RT_Device_Class_Graphic          /* 图形设备        */
RT_Device_Class_I2CBUS           /* I2C 总线设备     */
RT_Device_Class_USBDevice        /* USB device 设备  */
RT_Device_Class_USBHost          /* USB host 设备   */
RT_Device_Class_SPIBUS           /* SPI 总线设备     */
RT_Device_Class_SPIDevice        /* SPI 设备        */
RT_Device_Class_SDIO             /* SDIO 设备       */
RT_Device_Class_Miscellaneous    /* 杂类设备        */
attach_size用户数据大小

返回值: 

设备句柄创建成功
RT_NULL创建失败,动态内存分配失败

 销毁设备,释放内存

void rt_device_destroy(rt_device_t device);

设备被创建后,需要注册到 I/O 设备管理器中,应用程序才能够访问,注册设备的函数如下所示:

rt_err_t rt_device_register(rt_device_t dev, const char* name, rt_uint8_t flags);

 

flags 参数支持下列参数 (可以采用或的方式支持多种参数):

#define RT_DEVICE_FLAG_RDONLY       0x001 /* 只读 */
#define RT_DEVICE_FLAG_WRONLY       0x002 /* 只写  */
#define RT_DEVICE_FLAG_RDWR         0x003 /* 读写  */
#define RT_DEVICE_FLAG_REMOVABLE    0x004 /* 可移除  */
#define RT_DEVICE_FLAG_STANDALONE   0x008 /* 独立   */
#define RT_DEVICE_FLAG_SUSPENDED    0x020 /* 挂起  */
#define RT_DEVICE_FLAG_STREAM       0x040 /* 流模式  */
#define RT_DEVICE_FLAG_INT_RX       0x100 /* 中断接收 */
#define RT_DEVICE_FLAG_DMA_RX       0x200 /* DMA 接收 */
#define RT_DEVICE_FLAG_INT_TX       0x400 /* 中断发送 */
#define RT_DEVICE_FLAG_DMA_TX       0x800 /* DMA 发送 */

当设备注销后的,设备将从设备管理器中移除,也就不能再通过设备查找搜索到该设备。注销设备不会释放设备控制块占用的内存。注销设备的函数如下所示:

rt_err_t rt_device_unregister(rt_device_t dev);

 访问I/O设备

 

应用程序通过 I/O 设备管理接口来访问硬件设备,当设备驱动实现后,应用程序就可以访问该硬件。I/O 设备管理接口与 I/O 设备的操作方法的映射关系下图所示:

 查找设备

应用程序根据设备名称获取设备句柄,进而可以操作设备。查找设备函数如下所示:

rt_device_t rt_device_find(const char* name);

初始化设备 

获得设备句柄后,应用程序可使用如下函数对设备进行初始化操作:

rt_err_t rt_device_init(rt_device_t dev);

 打开设备

通过设备句柄,应用程序可以打开和关闭设备,打开设备时,会检测设备是否已经初始化,没有初始化则会默认调用初始化接口初始化设备。通过如下函数打开设备:

rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);

 

oflags 支持以下的参数:

#define RT_DEVICE_OFLAG_CLOSE 0x000   /* 设备已经关闭(内部使用)*/
#define RT_DEVICE_OFLAG_RDONLY 0x001  /* 以只读方式打开设备 */
#define RT_DEVICE_OFLAG_WRONLY 0x002  /* 以只写方式打开设备 */
#define RT_DEVICE_OFLAG_RDWR 0x003    /* 以读写方式打开设备 */
#define RT_DEVICE_OFLAG_OPEN 0x008    /* 设备已经打开(内部使用)*/
#define RT_DEVICE_FLAG_STREAM 0x040   /* 设备以流模式打开 */
#define RT_DEVICE_FLAG_INT_RX 0x100   /* 设备以中断接收模式打开 */
#define RT_DEVICE_FLAG_DMA_RX 0x200   /* 设备以 DMA 接收模式打开 */
#define RT_DEVICE_FLAG_INT_TX 0x400   /* 设备以中断发送模式打开 */
#define RT_DEVICE_FLAG_DMA_TX 0x800   /* 设备以 DMA 发送模式打开 */

 关闭设备

应用程序打开设备完成读写等操作后,如果不需要再对设备进行操作则可以关闭设备,通过如下函数完成:

rt_err_t rt_device_close(rt_device_t dev);

控制设备

通过命令控制字,应用程序也可以对设备进行控制,通过如下函数完成:

rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);

 参数 cmd 的通用设备命令可取如下宏定义:

#define RT_DEVICE_CTRL_RESUME           0x01   /* 恢复设备 */
#define RT_DEVICE_CTRL_SUSPEND          0x02   /* 挂起设备 */
#define RT_DEVICE_CTRL_CONFIG           0x03   /* 配置设备 */
#define RT_DEVICE_CTRL_SET_INT          0x10   /* 设置中断 */
#define RT_DEVICE_CTRL_CLR_INT          0x11   /* 清中断 */
#define RT_DEVICE_CTRL_GET_INT          0x12   /* 获取中断状态 */

读写设备

应用程序从设备中读取数据可以通过如下函数完成:

rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos,void* buffer, rt_size_t size);

 

参数描述
dev设备句柄
pos读取数据偏移量
buffer内存缓冲区指针,读取的数据将会被保存在缓冲区中
size读取数据的大小
返回——
读到数据的实际大小如果是字符设备,返回大小以字节为单位,如果是块设备,返回的大小以块为单位
0需要读取当前线程的 errno 来判断错误状态

调用这个函数,会从 dev 设备中读取数据,并存放在 buffer 缓冲区中,这个缓冲区的最大长度是 size,pos 根据不同的设备类别有不同的意义。

向设备中写入数据,可以通过如下函数完成:

rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos,const void* buffer, rt_size_t size);复制错误复制成功
参数描述
dev设备句柄
pos写入数据偏移量
buffer内存缓冲区指针,放置要写入的数据
size写入数据的大小
返回——
写入数据的实际大小如果是字符设备,返回大小以字节为单位;如果是块设备,返回的大小以块为单位
0需要读取当前线程的 errno 来判断错误状态

调用这个函数,会把缓冲区 buffer 中的数据写入到设备 dev 中,写入数据的最大长度是 size,pos 根据不同的设备类别存在不同的意义。

创建一个简单的应用实例

在driver文件夹下创建drv_demo.c

#include <rtdevice.h>
#include <rtdbg.h>
#include <drv_log.h>

rt_device_t drv_demo;
/*
    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);
*/
rt_err_t  drv_demo_init(rt_device_t dev)
{
    rt_kprintf("drv_demo_init\n");
    return 0;
}
rt_err_t drv_demo_open(rt_device_t dev, rt_uint16_t oflag)
{
    rt_kprintf("drv_demo_open\n");
    return 0;
}
rt_err_t  drv_demo_close(rt_device_t dev)
{
    rt_kprintf("drv_demo_close\n");
    return 0;
}
int rt_drv_demo_init()
{
    rt_kprintf("rt_drv_demo_init...\n");
    drv_demo = rt_device_create(RT_Device_Class_Char, 32);
    if(drv_demo == RT_NULL){
        LOG_E("rt_device_create falied...\n");
        return RT_ENOMEM;
    }
    LOG_D("rt_device_create successed...\n");
    drv_demo->init = drv_demo_init;
    drv_demo->open = drv_demo_open;
    drv_demo->close = drv_demo_close;
    rt_device_register(drv_demo,"demo",RT_DEVICE_FLAG_RDWR );
  return 0;
}

//板级初始化,在系统上电后自动调用该函数初始化

INIT_BOARD_EXPORT(rt_drv_demo_init);

在main.c中访问创建的设备

#include <rtthread.h>
#include <rtdevice.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

rt_device_t demo;

int main(void)
{
    demo = rt_device_find("demo");//通过设备名字获取设备句柄
    if(demo == RT_NULL){
        LOG_E("rt_device_find failed...\n");
        return RT_EEMPTY;
    }
    rt_device_init(demo);
    rt_device_open(demo,RT_DEVICE_OFLAG_RDWR );
    rt_device_close(demo);
    return RT_EOK;
}

 运行结果:

[2022-10-27_18:14:58:592]rt_drv_demo_init...

[2022-10-27_18:14:58:592] \ | /
[2022-10-27_18:14:58:592]- RT -     Thread Operating System
[2022-10-27_18:14:58:592] / | \     4.0.3 build Oct 24 2022
[2022-10-27_18:14:58:592] 2006 - 2020 Copyright by rt-thread team
[2022-10-27_18:14:58:592]drv_demo_init
[2022-10-27_18:14:58:592]drv_demo_open
[2022-10-27_18:14:58:592]drv_demo_close
[2022-10-27_18:14:58:592]msh >
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值