Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
内核学习营
I/O设备模型 基本函数整理
发布于 2020-03-17 11:29:22 浏览:1191
订阅该版
[tocm] #### 设备与驱动 1. I/O设备模型 基本函数整理 设备驱动层是一组驱使硬件设备工作的程序,实现访问硬件设备的功能。它负责创建和注册 I/O 设备,对于操作逻辑简单的设备,可以不经过设备驱动框架层,直接将设备注册到 I/O 设备管理器中,使用序列图如下图所示,主要有以下 2 点: 设备驱动根据设备模型定义,创建出具备硬件访问能力的设备实例,将该设备通过 rt_device_register() 接口注册到 I/O 设备管理器中。 应用程序通过 rt_device_find() 接口查找到设备,然后使用 I/O 设备管理接口来访问硬件。 ![enter description here](./images/1584409633442.png) 设备对象定义 ``` c struct rt_device { struct rt_object parent; /* 内核对象基类 */ enum rt_device_class_type type; /* 设备类型 */ rt_uint16_t flag; /* 设备参数 */ rt_uint16_t open_flag; /* 设备打开标志 */ rt_uint8_t ref_count; /* 设备被引用次数 */ rt_uint8_t device_id; /* 设备 ID,0 - 255 */ /* 数据收发回调函数 */ rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size); rt_err_t (*tx_complete)(rt_device_t dev, void *buffer); const struct rt_device_ops *ops; /* 设备操作方法 */ /* 设备的私有数据 */ void *user_data; }; typedef struct rt_device *rt_device_t; ``` rt_device_class_type所支持的I/O设备 ```c 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 /* 杂类设备 */ ``` 其中字符设备、块设备是常用的设备类型,它们的分类依据是设备数据与系统之间的传输处理方式。 字符模式设备允许非结构的数据传输,即通常数据传输采用*串行的形式*,每次一个字节。字符设备通常是一些简单设备,如串口、按键。 块设备每次传输一个数据块,例如每次传输 512 个字节数据。这个数据块是硬件强制性的,数据块可能使用某类数据接口或某些强制性的传输协议,否则就可能发生错误。因此,有时块设备驱动程序对读或写操作必须执行附加的工作。而在实际过程中,最后一部分数据尺寸有可能小于正常的设备块尺寸。如上图中每个块使用单独的写请求写入到设备中,头 3 个直接进行写操作。但最后一个数据块尺寸小于设备块尺寸,设备驱动程序必须使用不同于前 3 个块的方式处理最后的数据块。通常情况下,设备驱动程序需要首先执行相对应的设备块的读操作,然后把写入数据覆盖到读出数据上,然后再把这个 “合成” 的数据块作为一整个块写回到设备中。 驱动层负责创建设备实例,并注册到 I/O 设备管理器中,动态创建方式: rt_device_t rt_device_create(int type, int attach_size); ```c struct rt_device_ops {//设备操作方法 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); }; ``` 当一个动态创建的设备不再需要使用时可以通过如下函数来销毁: 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所支持的宏 ```c #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); 查找设备: rt_device_t rt_device_find(const char* name); 初始化设备:(当一个设备已经初始化成功后,调用这个接口将不再重复做初始化 0。) rt_err_t rt_device_init(rt_device_t dev); 打开和关闭 rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags); ```c //打开模式标志 #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); ```c //基本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); rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos,const void* buffer, rt_size_t size); 数据收发回调 rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev,rt_size_t size)); rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_device_t dev,void *buffer)); ```c //源码中使用回调函数的例子 void finsh_set_device(const char *device_name) { rt_device_t dev = RT_NULL; RT_ASSERT(shell != RT_NULL); dev = rt_device_find(device_name); if (dev == RT_NULL) { rt_kprintf("finsh: can not find device: %s
", device_name); return; } /* check whether it's a same device */ if (dev == shell->device) return; /* open this device and set the new device in finsh shell */ if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | \ RT_DEVICE_FLAG_STREAM) == RT_EOK) { if (shell->device != RT_NULL) { /* close old finsh device */ rt_device_close(shell->device); rt_device_set_rx_indicate(shell->device, RT_NULL); } /* clear line buffer before switch to new device */ memset(shell->line, 0, sizeof(shell->line)); shell->line_curpos = shell->line_position = 0; shell->device = dev; rt_device_set_rx_indicate(dev, finsh_rx_ind); } } static rt_err_t finsh_rx_ind(rt_device_t dev, rt_size_t size) { RT_ASSERT(shell != RT_NULL); /* release semaphore to let finsh thread rx data */ rt_sem_release(&shell->rx_sem); return RT_EOK; } ```
查看更多
0
个回答
默认排序
按发布时间排序
暂无答案,快来添加答案吧
撰写答案
登录
注册新账号
关注者
0
被浏览
1.2k
关于作者
水蜜桃菌
这家伙很懒,什么也没写!
提问
9
回答
10
被采纳
0
关注TA
发私信
相关问题
1
【内核学习】rtthread内核移植记录-STM32F103ZET6-HAL库
2
《内核学习营》+水一方+自用STM32F103VC 板RT-Thread内核移植分享
3
《内核学习营》+水一方+项目中创建标准的 RT-Thread工程
4
内核学习营+坦然+探索者stm32f407板子RT-thread循环点亮led灯
5
<内核学习营>+坦然+探索者stm32f407板子RT-thread串口字符点灯
6
<内核学习营>+坦然+探索者stm32f407板子RT-thread的pwm点灯实验
7
<内核学习营>+坦然+探索者stm32f407板子RT-thread串口实验
8
<内核学习营>+坦然+野火stm32f103板子RT-thread读写SD卡实验
9
<内核学习营>+坦然+探索者stm32f407板子RT-thread的RTC闹钟实验
10
【内核学习营】+王秀峰+led_rgb
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
7
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部