Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
学习笔记
【rtthread设备驱动】第零篇:io设备模型
发布于 2021-05-14 23:01:22 浏览:1967
订阅该版
[tocm] # 一、IO设备概念 rtthread提供的IO设备模型分为三层 * IO设备管理层:提供一组通用的IO操作:open、read、control等,连接着应用程序和底层硬件。 * 设备驱动框架层:rtthread对同一类外设的抽象,对不同厂家的soc提供接口。 * 设备驱动层:soc外设驱动,操作底层硬件。 rtthread将设备抽象成rt_device。 ``` /** * Device structure */ struct rt_device { struct rt_object parent; /**< inherit from rt_object */ enum rt_device_class_type type; /**< device type */ rt_uint16_t flag; /**< device flag */ rt_uint16_t open_flag; /**< device open flag */ rt_uint8_t ref_count; /**< reference count */ rt_uint8_t device_id; /**< 0 - 255 */ /* device call back */ rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size); rt_err_t (*tx_complete)(rt_device_t dev, void *buffer); #ifdef RT_USING_DEVICE_OPS const struct rt_device_ops *ops; #else /* 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); #endif #if defined(RT_USING_POSIX) const struct dfs_file_ops *fops; struct rt_wqueue wait_queue; #endif void *user_data; /**< device private data */ }; ``` # 二、IO设备api 在调用设备管理器操作设备之前,需要先创建和注册设备到设备管理器,在应用程序里调用rt_device_find根据设备名称获得设备句柄,根据设备句柄可以处理: * 初始化设备 * 打开关闭设备 * 对设备进行读写和控制 * 设置读写回调。 ``` //创建设备 /* type:设备类型,可取4.1中的设备类型 attach_size:用户数据大小 */ rt_device_t rt_device_create(int type, int attach_size); //销毁设备 /* device:设备句柄 */ void rt_device_destroy(rt_device_t device); //注册设备 /* dev:设备句柄 name:设备名称 flags:设备模式标志,可取4.2中的设备模式 */ rt_err_t rt_device_register(rt_device_t dev, const char* name, rt_uint8_t flags); //注销设备 /* dev:设备句柄 */ rt_err_t rt_device_unregister(rt_device_t dev); //查找设备 /* name:设备名称 返回:设备句柄 */ rt_device_t rt_device_find(const char* name); //初始化设备 /* dev:设备句柄 */ rt_err_t rt_device_init(rt_device_t dev); //打开设备,若设备为初始化则执行初始化 /* dev:设备句柄 oflags:打开模式,可取4.3中设备打开模式 */ rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags); //关闭设备 /* dev:设备句柄 */ rt_err_t rt_device_close(rt_device_t dev); //控制设备 /* dev:设备句柄 cmd:控制命令,可取4.4中的控制命令 arg:控制命令参数 */ rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg); //读设备 /* dev:设备句柄 pos:读取数据偏移 buffer:读取数据缓冲区 size:读取数据大小 */ rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos,void* buffer, rt_size_t size) //写设备 /* dev:设备句柄 pos:数据偏移 buffer:写数据缓冲区 size:写入数据大小 */ rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size); //设置数据接收回调 /* dev:设备句柄 rx_ind:接收回调函数 size:接收到数据大小 */ rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_tdev, rt_size_t size)); //设置发送完成回调 /* dev:设备句柄 tx_done:发送完成回调 buffer:发送完成的数据缓冲区 */ rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_device_tdev, void *buffer)); ``` # 三、IO设备示例 ``` /* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-09-25 misonyo first edition. */ /* * 程序清单:这是一个独立看门狗设备使用例程 * 例程导出了 iwdg_sample 命令到控制终端 * 命令调用格式:iwdg_sample iwg * 命令解释:命令第二个参数是要使用的看门狗设备名称,为空则使用例程默认的看门狗设备。 * 程序功能:程序通过设备名称查找看门狗设备,然后初始化设备并设置看门狗设备溢出时间。 * 然后设置空闲线程回调函数,在回调函数里会喂狗。 */ #include
#include
#define IWDG_DEVICE_NAME "iwg" /* 看门狗设备名称 */ static rt_device_t wdg_dev; /* 看门狗设备句柄 */ static void idle_hook(void) { /* 在空闲线程的回调函数里喂狗 */ rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, NULL); rt_kprintf("feed the dog!\n "); } static int iwdg_sample(int argc, char *argv[]) { rt_err_t ret = RT_EOK; rt_uint32_t timeout = 1000; /* 溢出时间 */ char device_name[RT_NAME_MAX]; /* 判断命令行参数是否给定了设备名称 */ if (argc == 2) { rt_strncpy(device_name, argv[1], RT_NAME_MAX); } else { rt_strncpy(device_name, IWDG_DEVICE_NAME, RT_NAME_MAX); } /* 根据设备名称查找看门狗设备,获取设备句柄 */ wdg_dev = rt_device_find(device_name); if (!wdg_dev) { rt_kprintf("find %s failed!\n", device_name); return RT_ERROR; } /* 初始化设备 */ ret = rt_device_init(wdg_dev); if (ret != RT_EOK) { rt_kprintf("initialize %s failed!\n", device_name); return RT_ERROR; } /* 设置看门狗溢出时间 */ ret = rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &timeout); if (ret != RT_EOK) { rt_kprintf("set %s timeout failed!\n", device_name); return RT_ERROR; } /* 设置空闲线程回调函数 */ rt_thread_idle_sethook(idle_hook); return ret; } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(iwdg_sample, iwdg sample); ``` # 四、IO设备知识点 ## 4.1 IO设备类型 ``` enum rt_device_class_type { 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_PM, /**< PM pseudo device */ RT_Device_Class_Pipe, /**< Pipe device */ RT_Device_Class_Portal, /**< Portal device */ RT_Device_Class_Timer, /**< Timer device */ RT_Device_Class_Miscellaneous, /**< Miscellaneous device */ RT_Device_Class_Sensor, /**< Sensor device */ RT_Device_Class_Unknown /**< unknown device */ }; ``` ## 4.2 设备模式 ``` #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 发 送 */ ``` ## 4.3 设备打开模式 ``` #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 发 送 模 式 打 开 */ ``` ## 4.4 控制命令 ``` #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 /* 获 取 中 断 状 态 */ ```
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
happycode999
这家伙很懒,什么也没写!
文章
28
回答
6
被采纳
0
关注TA
发私信
相关文章
推荐文章
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组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
三世执戟
7
个答案
1
次被采纳
KunYi
5
个答案
1
次被采纳
RTT_逍遥
4
个答案
1
次被采纳
xiaorui
1
个答案
1
次被采纳
JonasWen
1
个答案
1
次被采纳
本月文章贡献
出出啊
1
篇文章
3
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部