打印
[其他ST产品]

RTT中IO设备驱动的抽象学习

[复制链接]
732|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
stormwind123|  楼主 | 2023-4-28 16:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
RTT中对于IO设备的抽象是很有特点一个地方,是类似ucos,freertos都没有的一个地方。RTT提供了一个简单的IO设备管理框架,希望所有的IO设备驱动都通过这个框架编写,实现统一的管理,目前这框架还相对比较简陋,最重要的是缺少规范文档,随着兼容的设备越来越多,整个框架的规范文档势必需要给出,否则程序将变得越来越不干净。

应用程序通过RT-Thread的设备操作接口获得正确的设备驱动,然后通过这个设备驱动与底层I/O硬件设备进行数据(或控制)交互。RT-Thread提供给上层应用的是一个抽象的设备接口,给下层设备提供的是底层驱动框架。从系统整体位置来说I/O设备模块相当于设备驱动程序和上层应用之间的一个中间层。

I/O设备模块实现了对设备驱动程序的封装。应用程序通过I/O设备模块提供的标准接口访问底层设备,设备驱动程序的升级、更替不会对上层应用产生影响。这种方式使得设备的硬件操作相关的代码能够独立于应用程序而存在,双方只需关注各自的功能实现,从而降低了代码的耦合性、复杂性,提高了系统的可靠性。


现在我们就来看看与rt_device这个类的成员以及相关函数把。
```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 */
};```

1.parent rt_object的实例化,因为rt_device也是继承于rt_object

2.type设备的类型,RTT中支持以下一些设备类型的定义:
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_Unknown /**< unknown device */ };

使用特权

评论回复
沙发
stormwind123|  楼主 | 2023-4-28 16:11 | 只看该作者
3.flag rt_device的标志位,有如下取值
```#define RT_DEVICE_FLAG_DEACTIVATE 0x000 /*< device is not not initialized /

define RT_DEVICE_FLAG_RDONLY 0x001 /*< read only /
define RT_DEVICE_FLAG_WRONLY 0x002 /*< write only /
define RT_DEVICE_FLAG_RDWR 0x003 /*< read and write /
define RT_DEVICE_FLAG_REMOVABLE 0x004 /*< removable device /
define RT_DEVICE_FLAG_STANDALONE 0x008 /*< standalone device /
define RT_DEVICE_FLAG_ACTIVATED 0x010 /*< device is activated /
define RT_DEVICE_FLAG_SUSPENDED 0x020 /*< device is suspended /
define RT_DEVICE_FLAG_STREAM 0x040 /*< stream mode /
define RT_DEVICE_FLAG_INT_RX 0x100 /*< INT mode on Rx /
define RT_DEVICE_FLAG_DMA_RX 0x200 /*< DMA mode on Rx /
define RT_DEVICE_FLAG_INT_TX 0x400 /*< INT mode on Tx /
define RT_DEVICE_FLAG_DMA_TX 0x800 /*< DMA mode on Tx /```
4.open_flag 标志位,有如下取值
```#define RT_DEVICE_OFLAG_CLOSE 0x000 /*< device is closed /

define RT_DEVICE_OFLAG_RDONLY 0x001 /*< read only access /
define RT_DEVICE_OFLAG_WRONLY 0x002 /*< write only access /
define RT_DEVICE_OFLAG_RDWR 0x003 /*< read and write /
define RT_DEVICE_OFLAG_OPEN 0x008 /*< device is opened /
define RT_DEVICE_OFLAG_MASK 0xf0f /*< mask of open flag /```
5.ref_count 引用计数,当device_open调用之后会使得其增加1

6.device_id 好像没被使用

7.rx_indicate 设备收到数据后的回调函数指针

8.tx_complete设备写入数据完成后的回调函数指针

init 设备初始化函数接口

open 设备打开函数接口

close 设备关闭函数接口

read 设备读数据函数接口

write 设备写数据函数接口

control 设备控制函数接口

10.user_data 用户保留数据

rt_device这个类中的所有成员都解释清楚了。

下面便是与rt_device相关的函数。
```rt_device_t rt_device_find(const char *name);

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

rt_device_t rt_device_create(int type, int attach_size);
void rt_device_destroy(rt_device_t device);

rt_err_t rt_device_init_all(void);

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

rt_err_t rt_device_init (rt_device_t dev);
rt_err_t rt_device_open (rt_device_t dev, rt_uint16_t oflag);
rt_err_t rt_device_close(rt_device_t dev);
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_control(rt_device_t dev, int cmd, void *arg);```

这些函数的功能都相当的直白,且实现方式都与thread,或者timer类似一样。

rt_device_register就是把rt_device类添加到对象容器中管理起来。

其他诸如init,open,close,read,write,control基本可以看成是仅仅给出一个抽象接口,需要具体在对应的设备驱动中一一实现。

其实最后看来rt_device其实类似一个接口类,各种设备都应该包含这个接口中的所有函数,并在自身的驱动中重写这些函数。

使用特权

评论回复
板凳
cooldog123pp| | 2023-4-29 13:51 | 只看该作者
楼主讲的很详细,非常感谢楼主的讲解,mark一下,收藏学习,受教受教。

使用特权

评论回复
地板
shizaigaole| | 2023-4-30 20:19 | 只看该作者
简单的RTOS驱动非得搞得不伦不类,模仿linux,作茧自缚

使用特权

评论回复
5
Pulitzer| | 2024-6-16 07:06 | 只看该作者

STM32芯片中有多个工作时钟源的外设很常见

使用特权

评论回复
6
童雨竹| | 2024-6-16 09:02 | 只看该作者

CPU借助于APB总线访问相关寄存器达到对I2C1工作模块的控制

使用特权

评论回复
7
Wordsworth| | 2024-6-16 10:05 | 只看该作者

ART2固定使用PCLK时钟,只有开启和关闭的问题,不存在其它时钟源选择

使用特权

评论回复
8
Clyde011| | 2024-6-16 11:08 | 只看该作者

一部分是I2C1的工作模块,另外一部分是其控制模块

使用特权

评论回复
9
公羊子丹| | 2024-6-16 12:01 | 只看该作者

控制模块的时钟仍然由外设时钟PCLK提供

使用特权

评论回复
10
万图| | 2024-6-16 13:04 | 只看该作者

USART1可以有多个时钟源

使用特权

评论回复
11
Uriah| | 2024-6-16 14:07 | 只看该作者

STM32CUBEMX配置生成初始化代码

使用特权

评论回复
12
帛灿灿| | 2024-6-16 16:03 | 只看该作者

通过访问寄存器来控制I2C1工作时钟的开启。

使用特权

评论回复
13
Bblythe| | 2024-6-16 17:06 | 只看该作者

I2C1的时钟可以自行选择HSI或者SYSCLK

使用特权

评论回复
14
周半梅| | 2024-6-16 19:02 | 只看该作者

I2C1工作时钟源选择;I2C1模块工作时钟的开启使能。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

417

主题

2169

帖子

2

粉丝