RTT(RT-Thread)IO设备模型

news2024/12/23 1:43:19

目录

IO设备模型

模型框架原理

IO设备类型

创建和注册IO设备

RTT设备管理程序实现原理

访问IO设备

查找设备

初始化设备

打开设备

关闭设备

 控制设备

 读写设备

数据收发回调

数据接收回调

数据发送回调

设备模型实例


IO设备模型

        RT-Thread 提供了一套简单的 I/O 设备模型框架,如下图所示,它位于硬件和应用程序之间,共分成三层,从上到下分别是 I/O 设备管理层、设备驱动框架层、设备驱动层。

  • 应用程序通过 I/O 设备管理接口获得正确的设备驱动,然后通过这个设备驱动与底层 I/O 硬件设备进行交互。
  • I/O 设备管理层实现了对设备驱动程序的封装
  • 设备驱动框架层是对同类硬件设备驱动的抽象,将不同厂家的同类硬件设备驱动中相同的部分抽取出来,将不同部分留出接口,由驱动程序实现。
  • 设备驱动层是一组驱使硬件设备工作的程序,实现访问硬件设备的功能。

简单设备的注册不经过设备驱动框架层,直接将设备注册到I/O设备管理器中

  • 设备驱动根据设备模型定义,创建出具备硬件访问能力的设备实例,将该设备通过rt_device_register()接口注册到 I/O 设备管理器中
  • 应用程序通过 rt_device_find()接口查找到设备,然后使用 I/O 设备管理接口来访问硬件

模型框架原理

图中:在左边是应用层代码,在右边是设备驱动代码,设备驱动层是与硬件最接近的(用于直接访问硬件)。而设备驱动和应用程序通过同一的IO设备管理器来统一管理起来。

如何去管理呢?设备驱动在要操作硬件的时候,要向IO设备管理器去注册,一旦注册完之后,设备管理器就知道了哪个设备的驱动注册到系统里面了。当注册成功以后,当应用层想要访问硬件的时候,通过调用rt_device_find函数来找到相应的设备驱动,一旦找到以后,就可以打开设备,接着进行读写操作,最后要记得关闭设备。

应用层想要去访问硬件的时候,只需要查找到相应的设备驱动,然后调用统一的接口就能对硬件设备进行操作,不需要关注硬件的实现原理。而对应硬件驱动来讲,我们只需要提供对硬件的访问方法。具体如何去访问,以及访问到的数据如何去处理也跟设备驱动没有关系。也就是说将不同的事情交给不同的层去完成,实现解耦(高内聚、低耦合)

对于一些复杂设备,需要使用到对应的设备驱动框架层,进行注册,它们拥有自己专属的注册函数 如:看门狗定时器

  • 看门狗设备驱动程序根据看门狗设备模型定义,创建出具备硬件访问能力的看门狗设备实例,并将该看门狗设备通过特定的函数 rt_hw_watchdog_register()接口注册到看门狗设备驱动框架中
  • 看门狗设备驱动框架通过 rt_device_register()接口将看门狗设备注册到 I/O 设备管理器中
  • 应用程序通过 I/O 设备管理接口来访问看门狗设备硬件

IO设备类型

  • RT-Thread 支持多种 I/O 设备类型,主要设备类型如下所示

RT_Device_Class_Char = 0, /**< character device */

RT_Device_Class_Block, /**< block device */

RT_Device_Class_NetIf, /**< net interface */

RT_Device_Class_MTD, /**< memory device */

RT_Device_Class_CAN, /**< CAN device */

RT_Device_Class_RTC, /**< RTC device */

RT_Device_Class_Sound, /**< Sound device */

RT_Device_Class_Graphic, /**< Graphic device */

RT_Device_Class_I2CBUS, /**< I2C bus device */

RT_Device_Class_USBDevice, /**< USB slave device */

RT_Device_Class_USBHost, /**< USB host bus */

RT_Device_Class_SPIBUS, /**< SPI bus device */

RT_Device_Class_SPIDevice, /**< SPI device */

RT_Device_Class_SDIO, /**< SDIO bus device */

RT_Device_Class_Timer, /**< Timer device */

RT_Device_Class_Miscellaneous, /**< misc device */

RT_Device_Class_Sensor, /**< Sensor device */

RT_Device_Class_Touch, /**< Touch device */

RT_Device_Class_Unknown /**< unknown device */

创建和注册IO设备

  • 驱动层负责创建设备实例,并注册到 I/O 设备管理器中
/**
 * This function creates a device object with user data size.
 *
 * @param type, the kind type of this device object.
 * @param attach_size, the size of user data.
 *
 * @return the allocated device object, or RT_NULL when failed.
 */
rt_device_t rt_device_create(int type, int attach_size)
  • 当一个动态创建的设备不再需要使用时可以通过如下函数来销毁
/**
 * This function destroy the specific device object.
 *
 * @param dev, the specific device object.
 */
void rt_device_destroy(rt_device_t dev)
  • 设备被创建后,需要实现它访问硬件的操作方法
struct rt_device_ops
{
    /* 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);
};
  • 设备被创建后,需要注册到 I/O 设备管理器中,应用程序才能够访问
/**
 * This function registers a device driver withspecified name.
 *
 * @param dev the pointer of device driverstructure
 * @param name the device driver's name
 * @param flags the capabilities flag ofdevice   设备模式标志
 *
 * @return the error code, RT_EOK oninitialization successfully.
 */
rt_err_t rt_device_register(rt_device_t dev,
                            const char *name,
                            rt_uint16_t flags)
                            
#define RT_DEVICE_FLAG_RDONLY 0x001/*只读*/
#define RT_DEVICE_FLAG_WRONLY 0x002/*只写*/
#define RT_DEVICE_FLAG_RDWR 0x003 /*读写*/
#define RT_DEVICE_FLAG_REMOVABLE0x004 /*可移除*/
#define RT_DEVICE_FLAG_STANDALONE0x008 /*独立*/
#define RT_DEVICE_FLAG_SUSPENDED0x020 /*挂起*/
#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发送*/
  • 设备注销后的,设备将从设备管理器中移除,也就不能再通过设备查找搜索到该设备。注销设备不会释放设备控制块占用的内存
/**
 * This function removes a previouslyregistered device driver
 *
 * @param dev the pointer of device driverstructure
 *
 * @return the error code, RT_EOK onsuccessfully.
 */
rt_err_t rt_device_unregister(rt_device_t dev)

RTT设备管理程序实现原理

当我们创建一个设备的时候,系统会使用一个结构体描述这个设备的所有信息。当我们创建并注册多个设备的时候,系统就会通过列表的方式将这些结构体统一管理起来。当我们应用层想要找到某个设备的时候,就会调用find函数来找到列表头来根据name遍历查找,找到以后就会调用相应的方法来操作设备。当设备不用的时候,调用unregister函数来移除(将结构体变量从列表中移除),但结构体的空间依然存在,如果我们想要将结构体的空间释放掉,就需要调用destroy函数来进行删除释放。

访问IO设备

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

相应接口函数在设备句柄结构体中

使用应用层接口前,首先要查找到设备

查找设备

返回值为设备句柄指针

/**
 * This function finds a device driver byspecified name.
 *
 * @param name the device driver's name
 *
 * @return the registered device driver onsuccessful, or RT_NULL on failure.
 */
rt_device_t rt_device_find(const char*name)

操作接口如下:

初始化设备

/**
 * This function will initialize the specified device
 *
 * @param dev the pointer of device driver structure
 *
 * @return the result
 */
rt_err_t rt_device_init(rt_device_t dev)

打开设备

/**
 * This function will open a device
 *
 * @param dev the pointer of device driver structure
 * @param oflag the flags for device open
 *
 * @return the result
 */
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)

注:RT_DEVICE_FLAG_STREAM:流模式用于向串口终端输出字符串:当输出的字符是 "\n"(对应 16 进制值为 0x0A)时,自动在前面输出一个 "\r"(对应 16 进制值为 0x0D)做分行。

流模式 RT_DEVICE_FLAG_STREAM 可以和接收发送模式参数使用或 “|” 运算符一起使用

关闭设备

/**
 * This function will close a device
 *
 * @param dev the pointer of device driver structure
 *
 * @return the result
 */
rt_err_t rt_device_close(rt_device_t dev)

 控制设备

/**
 * This function will perform a variety of control functions on devices.
 *
 * @param dev the pointer of device driver structure
 * @param cmd the command sent to device
 * @param arg the argument of command
 *
 * @return the result
 */
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)

 读写设备

/**
 * This function will read some data from adevice.
 *
 * @param dev the pointer of device driverstructure
 * @param pos the position of reading
 * @param buffer the data buffer to save read data
 * @param size the size of buffer
 *
 * @return the actually read size onsuccessful, otherwise negative returned.
 *
 * @note since 0.4.0, the unit of size/pos is ablock for block device.
 */
rt_size_t rt_device_read(rt_device_tdev,
                         rt_off_t    pos,
                         void       *buffer,
                         rt_size_t   size)
/**
 * This function will write some data to adevice.
 *
 * @param dev the pointer of device driverstructure
 * @param pos the position of written
 * @param buffer the data buffer to be writtento device
 * @param size the size of buffer
 *
 * @return the actually written size onsuccessful, otherwise negative returned.
 *
 * @note since 0.4.0, the unit of size/pos is ablock for block device.
 */
rt_size_trt_device_write(rt_device_t dev,
                          rt_off_t    pos,
                          const void *buffer,
                          rt_size_t   size)

数据收发回调

当硬件设备收到数据时,可以通过如下函数回调另一个函数来设置数据接收指示,通知上层应用线程有数据到达

原理:通过设置数据的收发回调来通知我们的应用层某个线程来接收数据。这样就不需要再接收数据的时候写一个while循环一直去读。让它在没有数据的时候去休眠阻塞,一旦有数据的时候,这个函数就会被回调去通知相应线程唤醒去读写,这样可以减少系统的调用,提高系统调用效率。

数据接收回调

/**
 * This function will set the receptionindication callback function. 
 * This callback function
 * is invoked when this device receives data.
 *
 * @param dev the pointer of device driverstructure
 * @param rx_ind the indication callbackfunction
 *
 * @return RT_EOK
 */
rt_err_t
rt_device_set_rx_indicate(rt_device_tdev,
      rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size))

数据发送回调

/**
 * This function will set the indicationcallback function when device has
 * written data to physical hardware.
 *
 * @param dev the pointer of device driverstructure
 * @param tx_done the indication callbackfunction
 *
 * @return RT_EOK
 */
rt_err_t
rt_device_set_tx_complete(rt_device_tdev,
        rt_err_t (*tx_done)(rt_device_t dev,void *buffer))

设备模型实例

(1)首先在drivers下创建一个drv_demo.c的驱动文件

(2)然后刷新工程目录,打开drv_demo.c

(3)我们可以参考drv_wdt.c的设备驱动模型来写

在文件最后我们可以发现有一个板级初始化的导出函数:我们使用INIT_BOARD_EXPORT宏将rt_wdt_init函数导出,那么在板级初始化的时候就会调用rt_wdt_init函数

我们再drv_demo.c中导出自己的设备初始化函数,并编写设备初始化函数

(4)接着我们创建设备,使用rt_device_create函数

第一个参数是设备类型,这里用字符设备

第二个参数是用户的数据大小,如果要传入用户数据的话,我们就根据用户数据的大小来传参。因为我们不需要传入用户数据,因此大小可以随便写一个,如32。

返回值为指针类型rt_device_t

(5)设备创建成功以后,我们需要对设备编写相应的接口函数,我们以init、open、close为例

我们可以按F3跳转到rt_device_t中,并将相应接口函数指针复制到我们自己的设备驱动文件下

(6)将函数进行简单完善

并对接口进行赋值

(7)然后我们以读写的方式注册我们的设备模型

(8)最后我们在main函数中使用,首先查找设备,如果查找成功,返回一个设备对象指针,如果查找失败,我们返回错误:变量无效

然后调用相应的应用层接口函数

(10)编译之后发现有一个警告LOG_E未定义

我们需要将添加调试头文件#include

(11)运行结果

通过列举设备,可以查看到demo是我们自己创建的设备;uart2是用来监控当前STM32单片机的,用作用户的调试接口;pin是GPIO引脚。(其中要注意串口也是属于字符设备类型的)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/874268.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

穿透防线:泛微E-Office任意文件上传漏洞解析

子曰&#xff1a;“学天时习之&#xff0c;不亦说乎&#xff1f;有朋自远方来&#xff0c;不亦乐乎&#xff1f;人不知而不愠&#xff0c;不亦君子乎&#xff1f;” 漏洞复现 访问漏洞url&#xff1a; 构造漏洞利用payload ​POST /general/index/UploadFile.php?muploadP…

Kettle系列(二)smart-kettle本地离线部署

Kettle系列&#xff08;二&#xff09;smart-kettle本地离线部署 说明一、概述二、代码下载&#xff08;1&#xff09;后端代码依赖下载&#xff08;2&#xff09;前端代码依赖下载 三、创建数据库&#xff08;mysql8&#xff09;四、修改配置文件五、mysql8数据库配置六、其他…

Python学习笔记第五十七天(Pandas 数据清洗)

Python学习笔记第五十七天 Pandas 数据清洗Pandas 清洗空值isnull() Pandas替换单元格mean()median()mode() Pandas 清洗格式错误数据Pandas 清洗错误数据Pandas 清洗重复数据duplicated()drop_duplicates() 后记 Pandas 数据清洗 数据清洗是对一些没有用的数据进行处理的过程…

最强自动化测试框架Playwright(19)- 事件

Playwright允许收听网页上发生的各种类型的事件&#xff0c;例如网络请求&#xff0c;创建子页面&#xff0c;专用工作人员等。有几种方法可以订阅此类事件&#xff0c;例如等待事件或添加或删除事件侦听器。 等待事件 大多数情况下&#xff0c;脚本需要等待特定事件的发生。…

实训一 :Linux的启动、关机及登录

实训一 &#xff1a;Linux的启动、关机及登录 2017 年 2 月 22 日 今日公布 实训目标 完成本次实训&#xff0c;将能够&#xff1a; 描述Linux的开机过程。在图形模式和文本模式下登录Linux。关闭和重启Linux 实训准备 一台已安装RHEL6的虚拟计算机&#xff0c;Linux虚拟…

【嵌入式环境下linux内核及驱动学习笔记-(19)LCD驱动框架2-FrameBuffer】

目录 1、 Frmebuffer(帧缓冲&#xff09;操作介绍1.1 显示设备的抽象1.2 内存映像1.3 输出画面数据1.4 用户态下操作屏显1.4.1 用文件I / O 操作屏显1.4.2 mmap() 函数1.4.3 ioctl()函数1.4.5 用命令操作屏1.4.6 测试程序 2、Framebuffer总体框架2.1 框架要点2.2 fbmem.c分析2.…

中小企业项目管理软件推荐:选择适合的工具提升项目效率!

中小企业项目管理软件有哪些&#xff1f;Zoho Projects是一款好用无广告的项目管理软件。当个小创业者是真的不容易&#xff0c;不仅要管理团队&#xff0c;还要管理团队项目。很多团队之前用了好多项目管理的软件&#xff0c;但是都不太满意。但是如果你经常参加创业者聚会上&…

安装cuda/cudann和pytorch

一、查看驱动信息 # 进入CMD输入命令 nvidia-smi 也可以右下角图标打开NVIDIA 设置进行查看 二、下载安装CUDA 1、下载 下载地址 https://developer.nvidia.com/ 2、安装 推荐自定义安装。建议只勾选Cuda&#xff0c;只安装这一个就好&#xff0c;以免报错安装失败。 3、验证…

泰卦-地天卦

前言&#xff1a;否极泰来&#xff0c;但在易经里是泰卦在前&#xff0c;让我们分析下在否所期待否极后的泰卦是什么样的&#xff1f;本篇博客分析泰卦的卦辞和爻辞。 卦辞 小往大来&#xff0c;吉&#xff0c;亨。 篆曰&#xff1a;泰&#xff0c;小往大来&#xff0c;吉亨。…

7-8 计算存款利息

本题目要求计算存款利息&#xff0c;计算公式为interestmoney(1rate)year−money&#xff0c;其中interest为存款到期时的利息&#xff08;税前&#xff09;&#xff0c;money是存款金额&#xff0c;year是存期&#xff0c;rate是年利率。 输入格式&#xff1a; 输入在一行中…

035_小驰私房菜_Qualcomm账号注册以及提case流程

全网最具价值的Android Camera开发学习系列资料~ 作者:8年Android Camera开发,从Camera app一直做到Hal和驱动~ 欢迎订阅,相信能扩展你的知识面,提升个人能力~ 一、账号注册 1)登陆高通网站Wireless Technology & Innovation | Mobile Technology | Qualcomm, 采用…

Ceph Reef版本 RBD 性能测试:80万写IOPS(10节点、60个NVMe SSD)

2023-05-16 08:30 发表于上海 摘自&#xff1a;https://mp.weixin.qq.com/s/mKkPElmCktoZaRk0m0IbqA 1、背景 Ceph 社区最近冻结了即将发布的 Ceph Reef 版本&#xff0c;今天我们研究一下 Ceph Reef 版本在 10 个节点、60 个 NVMe 磁盘的集群上的 RBD 性能。 在确保硬件没有…

16收16发ARINC429模块

6通道发送&#xff0c; 16通道接收 发送通道: 每路发送通道FIFO大小为&#xff1a;511 x 32bit(CHR32216/32316) &#xff0c;缓存256条发送消息(CHR32216-EX/32316-EX) 发送FIFO可设置复位 可设置消息间隔&#xff0c; 字间隔和发送帧的预定数呈 发送波特率100Kbps、50Kbps、…

春秋云镜 CVE-2020-0784

春秋云镜 CVE-2020-0784 wordpress插件 Title Experiments Free < 9.0.1 SQLI 靶标介绍 wordpress插件 Title Experiments Free < 9.0.1 没有对用户输入进行过滤和转义&#xff0c;导致了SQL注入。 启动场景 漏洞利用 exp POST /wp-admin/admin-ajax.php HTTP/1.1 H…

NeuralNLP-NeuralClassifier的使用记录(二),训练预测自己的【中文文本多分类】

NeuralNLP-NeuralClassifier的使用记录&#xff0c;训练预测自己的【中文文本多分类】 数据准备&#xff1a; ​ 与英文的训练预测一致&#xff0c;都使用相同的数据格式&#xff0c;将数据通过代码处理为JSON格式&#xff0c;以下是我使用的一种&#xff0c;不同的原数据情况…

关于配电室升级为智能运维模式的问题

配电室安全稳定运行、电能使用高效节能是每个企业关注的问题&#xff0c;然而&#xff0c;由于供用电系统的运行维护又是一项复杂而且专业性很强的工程&#xff0c;如果没有先进的技术手段&#xff0c;靠人工值班、人工操作的运行方式&#xff0c;运行管理成本大&#xff0c;安…

【什么是摆线减速器?设计、3D 打印和测试】

【什么是摆线减速器&#xff1f;设计、3D 打印和测试】 1. 什么是摆线驱动&#xff1f;2. 如何设计摆线驱动器3. DIY摆线驱动3D模型4. 三维设计5. 3D打印制造6. 组装摆线齿轮箱7. 测试摆线驱动器 在本教程中&#xff0c;我们将学习什么是摆线驱动器&#xff0c;它是如何工作的&…

React Native 图片组件基础知识

在 React Native 中使用图片其实跟 HTML 中使用图片一样简单&#xff0c;在 React Native 中我们使用Image组件来呈现图片的内容&#xff0c;其中主要的属性有&#xff1a;source。这个属性主要是设置图片的内容&#xff0c;它可以是网络图像地址、静态资源、临时本地图像以及本…

电气测试相关

项目&#xff1a; 长期过电压 瞬态过电压 瞬态欠压 跳跃启动 卸载 纹波电压 电源电压缓慢下降和上升 电源电压缓慢下降、快速上升 复位行为 短暂中断 启动脉冲 带电气系统控制的电压曲线 引脚中断 连接器中断 反极性 信号线和负载电路短路 启动行为 对分流不…

【数据结构系列】链表

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…