RT Thread I/O设备模型与分层

5 篇文章 0 订阅

在这里插入图片描述
RT Thread 设备模型的思路是继承了Linux驱动的思想。
一般 RTOS 用于深度定制的嵌入式系统当中,深度定制就是系统用于特定的环境执行特定的任务。
在深度定制的嵌入式系统一般选择功耗较低成本较低的方案。例如ARM M系列架构的MCU,这种环境下RTOS扮演的角色很有限
一般是提供有限的服务给应用层,并且引入虚拟化并行特性的线程(任务),把不方便或者不适合在ISR中运行的代码封装成任务。同样提供软件定时器,任务间的同步和数据通信,调度器功能。没有去对底层驱动有过多的要求。

RT Thread 的设备模型,相当于提供了设备管理的API给应用层软件使用。RTOS规定了统一的命名规则给应用层使用。应用层使用这些API进行相应的任务开发。这种架构下,应用层去调用RTOS 的设备管理API 去使用设备,通过RTOS统一命名的用户接口函数。

通俗的说就是RT THread在 底层和应用层中介插了一手。在RTOS层面规定了底层接口。那么底层驱动就要按照规定的结构去实现。
直接带来的最大优点是解耦,并且引入强烈的软件分层。
在这里插入图片描述
设备驱动,需要按在RT Thread 框架来写驱动程序。
设备的逻辑实体,由驱动程序创建。然后注册到IO设备管理器。
应用程序调用发现设备(RTOS service )以此获取设备。再通过一些列的标准API访问和控制设备。

设备的定义如下
rt_object 是操作系统管理的内核对象,thread,timer,信号量等等都是所为的内核对象

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

/* 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);
设备的操作函数
在这里插入图片描述

app应用层最后通过调用这些函数来使用设备。

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_t rt_device_create(int type, int attach_size);

创建device是申请sizeof(struct rt_device)空间大小的内存,用于构建设备实体。这里可以静态创建出来。
动态创建的目的是在于节省内存空间

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

设备添加至系统容器内。
在这里插入图片描述
flag变量的值代表设备的属性。
在这里插入图片描述
在这里插入图片描述

rt_device_t rt_device_find(const char *name)
{
    return (rt_device_t)rt_object_find(name, RT_Object_Class_Device);
}

查找设备用过name索引,在系统中气中查找,获取设备控制款的首地址-设备句柄。
rt_err_t rt_device_init(rt_device_t dev);
调用设备句柄,执行init

rt_device_open
调用设备句柄,执行open

已GPIO PIN为例

rtthread_startup->rt_hw_board_init->rt_hw_pin_init->rt_device_pin_register—rt_device_pin_register(“pin”, &_stm32_pin_ops, RT_NULL);
在这里插入图片描述_hw_pin 为静态定义的rt_device_pin 类型变量

struct rt_device_pin
{
    struct rt_device parent;
    const struct rt_pin_ops *ops;
};

注册后在容器的设备裂变里面就有了 name “pin”

_hw_pin.parent.write = _pin_write;
_hw_pin.parent. 是rt thread为每个设备定义的基础结构
在基础结构之外定义ops用于存放PIN特殊的基本API入口
在components\drivers\misc 文件夹中有PIN.C
组件的意思是操作系统组建,代表设备管理层。
在这里插入图片描述
这里调用的_hw_pin.ops执行写入功能。
在这里插入图片描述
stm32_pin_write 对应PIN Write 来说 dev 对于写入来说是一个无用参数,也就是它不需要控制句柄。
应为PIN的传入参数是PIN地址,PIN地址本身是绝对地址,有类似句柄的作用。
所以PIN 没有device find的步骤,应为使用PIN的时候PIN脚名称已经是句柄。

static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
{
    GPIO_TypeDef *gpio_port;
    uint16_t gpio_pin;

    if (PIN_PORT(pin) < PIN_STPORT_MAX)
    {
        gpio_port = PIN_STPORT(pin);
        gpio_pin = PIN_STPIN(pin);

        HAL_GPIO_WritePin(gpio_port, gpio_pin, (GPIO_PinState)value);
    }
}

最后调用HAL库的GPIO Write。

梳理一次

rtthread_startup->rt_hw_board_init->rt_hw_pin_init->rt_device_pin_register—rt_device_pin_register(“pin”, &_stm32_pin_ops, RT_NULL);

rt_pin_write 作为rt thread提供的设备函数,存在于conponents -->pin.c中属于RTOS 组建中的PIN设备管理层

设备管理层会调用底层驱动的函数执行
_hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);

ops 的stm32_pin_write 对应的是 底层驱动层 也就是HAL层 bsp\stm32\libraries\HAL_Drivers
STM的HAL层又进行了一层分层 第一层是不分处理器的,实现的是底层逻辑层也就是board 抽象,然后调用和MCU寄存器相关的hal函数
bsp\stm32\libraries\STM32F1xx_HAL\STM32F1xx_HAL_Driver\Src

所以使用RTOS 系统调用的设备输入输入输出函数,其调用深度就有3~4层
APP-> RT_device_->ops->hal_obj->hal_LL
作用应用层开发只要关注RTOS设备层即可,可以高效的开发应用。
但是层数多了,必然会消耗一部分实时性,这部分是双刃剑,依照项目需求来看吧

UART 设备

在这里插入图片描述

在这里插入图片描述
回头看看 rt_device
1.容器标准的结构体 rt_object
2.设备的类型
3.设备的回调函数
4.通用设备接口
operations set for device object 就是ops

驱动编写需要做的是根据设备的类型编写好 ops 接口。

按照面向对象的思考方式
使用串口就是一个设备对象

1 要使用对象我就先注册
2 注册后打开它
3 ops操作获得设备的使用

这是应用层的思路
Low level BSP层需要考虑的是MCU上有很多ADC模块,我要用哪个

设备层 需要考虑的是配置串口

rtconfig.h RT Thread用于配置具体工程的文件,在文档最后

/* On-chip Peripheral Drivers */

#define BSP_USING_GPIO
#define BSP_USING_UART
#define BSP_USING_LPUART1
#define BSP_LPUART1_RX_USING_DMA

配置 On-chip Peripheral Drivers

这样在 bsp\stm32\libraries\HAL_Drivers 对STM32 chip做了驱动接口 IO管理层或者设备管理层。也就是说设备管理层是按照RTT的方式定义的硬件中间层,中间层 去对接最底层的驱动程序,最底层的驱动程序是根据各种型号的MCU来定的。
整个过程还是比较复杂的。
在这里插入图片描述
A 部分 component.c作为系统初始化组建的开端。调用函数 rt_hw_board_init 对硬件进行初始化
drv_common.c,drv_uart.c (B) 位于bsp\stm32\libraries\HAL_Drivers 是RT thread 写的BSP层用于适配ST HAL库©,用于对接IO设备模型(D),IO设备管理层(E)使用通用模型管理设备。E对OS 提供OPS operations set for device object。
APP只需要关心 operations set for device object。通用的API函数
底层驱动C,按照基本需求完成设备的驱动编写。
LL中间层(B) 下接底层驱动,上接D设备模型。所以RT Thread如果开发驱动程序,主要是BC两个部分。需要对RT Thread 设备模型和MCU底层还有硬件配置都有了解。

换一种角度来看
在这里插入图片描述
应用程序使用rt_device_xxxx API访问IO设备管理器。定义该过程的是RTT,RTT把设备进行了分类并且建立了专门的模型
\components\drivers

├─audio
├─can
├─cputime
├─hwcrypto
├─hwtimer
├─i2c
├─include
│  ├─drivers
│  └─ipc
├─ipc
├─misc
├─mtd
├─phy
├─pm
├─rtc
├─sdio
├─sensors
├─serial
├─spi
│  └─sfud
│      ├─inc
│      └─src
├─touch
├─usb
│  ├─usbdevice
│  │  ├─class
│  │  └─core
│  └─usbhost
│      ├─class
│      └─core
├─watchdog
└─wlan

这些模型由RT Thread 所定义,属于IO管理器。

\bsp\stm32\libraries\HAL_Drivers
也是按照RT Thread 所定义 的方式构建的板级支持包。

BSP的目的是在驱动和设备模型中间建立桥梁,解除耦合。无论是RTOS还是底层变化,只要修改BSP即可。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值