购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第1章
RT-Thread与设备框架简介

本章主要为大家介绍RT-Thread及其设备框架。

1.1 RT-Thread概述

RT-Thread(Real Time-Thread)是一个嵌入式实时多线程操作系统。它的基本属性之一是支持多任务,而允许多个任务同时运行并不意味着处理器在同一时刻真的执行了多个任务。事实上,一个处理器核心在某一时刻只能运行一个任务,由于每次处理器对一个任务的执行时间很短,任务与任务之间通过任务调度器进行非常快速的切换(调度器根据优先级决定此刻该执行的任务),因此给人造成一种多个任务在同一时刻同时运行的错觉。在RT-Thread系统中,任务是通过线程实现的,RT-Thread中的线程调度器就是以上提到的任务调度器。

RT-Thread主要采用C语言编写,浅显易懂,方便移植。它把面向对象的设计方法应用到实时系统设计中,使得代码风格优雅,架构清晰,系统模块化,且可裁剪性非常好。RT-Thread目前有3个版本:完整版、Nano版以及Smart版。针对资源受限的MCU(微控制器)系统,可通过方便易用的工具裁剪出仅需要3KB Flash、1.2KB RAM内存资源的Nano版。资源丰富的物联网设备可使用RT-Thread完整版。RT-Thread完整版通过在线的软件包管理工具、系统配置工具,可实现直观、快速的模块化裁剪,无缝地导入丰富的软件功能包,实现类似Android的图形界面以及触摸滑动效果,还具有智能语音交互等复杂功能。带有MMU,且基于ARM9、ARM11甚至Cortex-A系列CPU的应用处理器,可以使用Smart版本。该版本可以在RT-Thread操作系统的基础上启用独立、完整的进程,同时以混合微内核模式去执行。

相较于Linux操作系统,RT-Thread体积小,成本低,功耗低,启动快。除此以外,RT-Thread还具有实时性高、占用资源少等特点,非常适用于各种资源受限(如成本、功耗限制等)的场合。

1.许可协议

RT-Thread系统完全开源,遵循Apache License 2.0开源许可协议,可以免费在商业产品中使用,并且不需要公开私有代码。

2.架构

近年来,物联网(Internet of Things, IoT)概念广为普及,物联网市场发展迅猛,嵌入式设备的联网已是大势所趋。终端联网使得软件复杂性大幅增加,传统的RTOS内核已经越来越难以满足市场的需求。在这种情况下,物联网操作系统(IoT OS)的概念应运而生。物联网操作系统是指以操作系统内核(可以是RTOS、Linux等)为基础,包括如文件系统、图形库等较为完整的中间件组件,具备低功耗、安全特性,支持通信协议和云端连接能力的软件平台,RT-Thread就是一个物联网操作系统。

RT-Thread与其他很多RTOS(如FreeRTOS、uC/OS)的主要区别之一是,它不仅有实时内核,还具备丰富的中间层组件,如图1-1所示。

图1-1 RT-Thread架构

RT-Thread架构具体包括以下部分。

1)硬实时内核层:RT-Thread内核,这是RT-Thread的核心部分,包括了内核系统中对象的实现,例如多线程及其调度、信号量、邮箱、消息队列、内存管理、定时器等。另外内核层还包括libcpu/BSP(芯片移植相关文件/板级支持包),它与硬件密切相关,由外设驱动和CPU移植文件构成。

2)组件与服务层:组件是基于RT-Thread内核之上的上层软件,例如虚拟文件系统、FinSH命令行界面、网络框架、设备框架等。采用模块化设计,能够做到组件内部高内聚,组件之间低耦合。

3)软件包层:运行于RT-Thread物联网操作系统平台上,是面向不同应用领域的通用软件组件,由描述信息、源代码或库文件组成。RT-Thread提供了开放的软件包平台。平台上存放了官方提供或开发者提供的软件包,为开发者提供了众多可重用软件包,是RT-Thread生态的重要组成部分。这些软件包具有很强的可重用性,模块化程度很高,可让应用开发者在最短时间内打造出自己想要的系统。

RT-Thread支持的软件包数量已经达到400多个,举例如下。

1)物联网相关的软件包:Paho MQTT、WebClient、mongoose、WebTerminal等。

2)脚本语言相关的软件包:目前支持JerryScript、MicroPython、Lua、PikaScript。

3)多媒体相关的软件包:LVGL、Openmv、mupdf、STemWin、TinyJPEG等。

4)工具类软件包:CmBacktrace、EasyFlash、EasyLogger、SystemView。

5)系统相关的软件包:FlashDB、littlefs、MCUboot、lwext4、partition、SQLite等。

6)外设库与驱动类软件包:各类传感器、rosserial、Nordic nRF5_SDK等。

7)嵌入式AI软件包:ONNX、TensorFlow Lite、μLAPack、libann、NNoM等。

3.RT-Thread源码获取

RT-Thread源码获取有几种途径。

❏GitHub: https://github.com/RT-Thread/rt-thread。

❏Gitee: https://gitee.com/rtthread/rt-thread。

另外,读者还可通过RT-Thread Studio创建RT-Thread工程,通过IDE下载源码并将其加入工程中。

4.芯片对接RT-Thread流程

当有一款芯片想要对接RT-Thread时,可以根据图1-2中的流程进行对接。

第1步: 查看是否是RT-Thread支持的架构,如果是,可以开始BSP移植;如果不是,可参照文档中心的libcpu移植教程进行移植,网址如下:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/porting/porting。

第2步: 进行BSP移植需要完成的基本工作如下。

1)初始化CPU内部寄存器,设定RAM工作时序。

2)实现时钟驱动及中断控制器驱动,完善中断管理。

3)实现串口和GPIO驱动。

4)初始化动态内存堆,实现动态堆内存管理。

此时还要注意一种情况,判断是否为STM32系列,若是,则进行STM32 BSP移植。可以参考STM32 BSP制作教程进行移植,教程链接如下:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/stm32-bsp/stm32-bsp。

第3步: 驱动移植,即参考本书中的驱动教程完成相应的驱动移植,最后进行驱动验证。

图1-2 芯片对接RT-Thread流程

1.2 RT-Thread I/O设备框架

之前没有接触过驱动开发的人,看到“设备框架”这个名词可能会感到迷茫。大家不妨先思考这样一个问题:“为什么不同厂家、不同价格、不同形状的鼠标,插到电脑上之后都能正常工作?”这是因为各家生产的鼠标都遵循同一套标准,操作系统只要按照这个标准去操作鼠标就可以得到它想要的效果。

“设备框架”就是针对某一类外设,抽象出来一套统一的操作方法以及接入标准。有了这一层抽象,框架上层的应用要访问具体外设(比如摄像头)时,就不用关心具体的厂家或者产地了。只要按照框架提供的操作方法,就可以控制摄像头拍照、摄像了。这套设备框架也为生产厂家提供了方便,他们不需要关心应用具体会怎么使用,只要按照设备框架提供的接入标准设计产品,生产出来就可以在市面上销售了。

在嵌入式领域,RT-Thread也提供了这样的一层抽象,用于屏蔽嵌入式上的硬件差异,为应用层提供统一的操作方法,也为底层硬件提供统一的接入标准。

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

图1-3 RT-Thread I/O设备框架

应用程序通过I/O设备管理接口获得正确的设备驱动,然后通过这个设备驱动与底层I/O硬件设备进行数据(或控制)交互。

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

设备驱动框架层 是对同类硬件设备驱动的抽象,将不同厂家的同类硬件设备驱动中相同的部分抽取出来,将不同部分留出接口,由驱动程序实现。

设备驱动层 是一组驱使硬件设备工作的程序,实现了访问硬件设备的功能,它负责创建和注册I/O设备。设备驱动层注册设备有以下两种方式。

第一种方式 ,使用I/O设备管理接口直接注册,在设备驱动文件中通过rt_device_register()接口注册到I/O设备管理器中。这种方式是针对操作逻辑简单的设备,可以不经过设备驱动框架层,直接将设备注册到I/O设备管理器中。这类设备的注册与使用序列图如图1-4所示,其主要步骤如下。

图1-4 I/O设备注册与使用序列图

1)设备驱动根据设备模型定义,创建出具备硬件访问能力的设备实例,将该设备通过rt_device_register()接口注册到I/O设备管理器中。

2)应用程序通过rt_device_find()接口查找到设备,然后使用I/O设备管理接口来访问硬件。

第二种方式 ,通过设备驱动框架层提供的注册函数进行注册,注册函数名一般命名为rt_hw_xxx_register(),设备驱动框架层的注册函数又调用了I/O设备管理接口的注册函数rt_device_register(),从而进行设备注册。此种注册方式是针对一些不能使用I/O设备管理接口完成操作的设备,如看门狗等。看门狗设备注册的主要步骤如下。

1)看门狗设备驱动程序根据看门狗设备模型定义,创建出具备硬件访问能力的看门狗设备实例,并将该看门狗设备通过rt_hw_watchdog_register()接口注册到看门狗设备驱动框架中。

2)看门狗设备驱动框架通过rt_device_register()接口将看门狗设备注册到I/O设备管理器中。

3)应用程序通过rt_device_find()接口查找到设备,然后使用I/O设备管理接口来访问看门狗设备硬件。

看门狗设备注册与使用序列如图1-5所示。

当然,有的设备驱动框架也会给应用层提供接口,此时应用层可以调用设备驱动框架层的接口对硬件进行操作。

图1-5 看门狗设备注册与使用序列

1.2.1 I/O设备模型与分类

RT-Thread的I/O设备模型(以下简称“设备模型”)是建立在内核对象模型基础之上的,设备被认为是一类对象,被纳入对象管理器的范畴。每个设备对象都是由基对象派生而来的,每个具体设备都可以继承其父类对象的属性,并派生出其私有属性。图1-6是设备对象的继承和派生关系示意。

图1-6 设备对象的继承和派生关系

设备对象struct rt_device的具体定义如下所示:

rt_device_class_type用于RT-Thread对设备进行分类,在每类设备执行注册后,系统会将它们注册为相应类别的设备。rt_device_class_type类型枚举如下。

其中,字符设备、块设备是常用的设备类型,它们的分类依据是设备与系统之间的数据传输处理方式。字符设备允许非结构化的数据传输,通常数据传输采用串行的形式,每次一字节。字符设备通常是一些简单设备,如串口、按键。

块设备每次传输一个数据块,例如每次传输512字节数据。这个数据块大小是硬件强制性要求的,数据块可能使用某类数据接口或某些强制性的传输协议,否则就可能发生错误。因此,有时块设备驱动程序进行读/写操作时必须执行附加的工作,如图1-7所示。

图1-7 块设备操作

当系统服务需要进行大量数据的写操作时,设备驱动程序必须将数据划分为多个包,每个包采用设备指定的数据尺寸。而在实际操作中,最后一部分数据尺寸有可能小于正常的设备块尺寸。如图1-7中每个块使用单独的写请求写入到设备中,前3个块直接进行写操作。但最后一个数据块尺寸小于设备块尺寸,设备驱动程序必须使用不同的方式处理最后的数据块。通常情况下,设备驱动程序需要首先执行相对应的设备块(块4)的读操作,然后把写入数据覆盖到读出数据上,然后把这个“合成”的数据块作为一整个块写回到设备中。

1.2.2 I/O设备管理接口

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

图1-8 I/O设备管理接口与I/O设备的操作方法的映射关系

在执行过程中,若未得到正常结果,则需返回相应的错误码,错误码表如下所示。一般来说,在RT-Thread代码中,当返回错误码时,除RT_EOK之外的所有错误码都要加负号。

代码清单1-1 错误码表

1.查找设备

应用程序根据设备名称查找设备,查找接口(即函数)会返回设备的句柄,进而可以操作设备。查找设备的接口rt_device_find如下所示:

rt_device_find接口的参数及返回值如表1-1所示。

表1-1 rt_device_find接口的参数及返回值

2.初始化设备

获得设备句柄后,应用程序可使用rt_device_init接口对设备进行初始化操作:

rt_device_init接口的参数及返回值如表1-2所示。

表1-2 rt_device_init接口的参数及返回值

注意,当一个设备已经初始化成功后,调用这个接口将不再重复进行初始化。

3.打开和关闭设备

通过设备句柄,应用程序可以打开和关闭设备。打开设备时,系统会检测设备是否已经初始化,若没有初始化,会默认调用初始化接口来初始化设备,可通过rt_device_open接口打开设备:

rt_device_open接口的参数及返回值如表1-3所示。

表1-3 rt_device_open接口的参数及返回值

oflags支持以下参数:

注意:如果上层应用程序需要设置设备的接收回调函数,则必须以RT_DEVICE_FLAG_INT_RX或者RT_DEVICE_FLAG_DMA_RX的方式打开设备。

应用程序打开设备完成读写等操作后,如果不需要再对设备进行操作,就可以关闭设备,可通过rt_device_close接口完成:

rt_device_close接口的参数及返回值如表1-4所示。

表1-4 rt_device_close接口的参数及返回值

注意:关闭设备接口和打开设备接口需配对使用,打开一次设备对应要关闭一次设备,这样设备才会被完全关闭,否则设备仍处于未关闭状态。

4.控制设备

通过命令控制字,应用程序也可以对设备进行控制,通过rt_device_control接口完成:

rt_device_control接口的参数及返回值如表1-5所示。

参数cmd的通用设备命令可取如下宏定义:

表1-5 rt_device_control接口的参数及返回值

5.读写设备

应用程序从设备中读取数据可以通过rt_device_read接口完成:

rt_device_read接口的参数及返回值如表1-6所示。

表1-6 rt_device_read接口的参数及返回值

调用这个接口,会从dev中读取数据,并存放在缓冲区中。这个缓冲区的最大长度是size, pos根据不同的设备类别有不同的意义。

如果向设备中写入数据,可以通过rt_device_write接口完成:

rt_device_write接口的参数及返回值如表1-7所示。

表1-7 rt_device_write接口的参数及返回值

调用这个接口,会把缓冲区中的数据写入dev中,写入数据的最大长度是size, pos根据不同的设备类别有不同的意义。

6.数据收发回调

数据收发回调的意思是当硬件设备接收到数据或者发送数据时,可以设置一个回调函数作为数据发送或者接收的通知。当RT-Thread的设备进行数据收发时,也可以通过rt_device_set_rx_indicate接口回调另一个函数来设置数据接收指示,通知上层应用线程有数据到达:

rt_device_set_rx_indicate接口的参数及返回值如表1-8所示。

表1-8 rt_device_set_rx_indicate接口的参数及返回值

该接口的回调函数由调用者提供。当硬件设备接收到数据时,会回调这个接口并把收到的数据长度放在size参数中传递给上层应用。上层应用线程应在收到指示后,立刻从设备中读取数据。

在应用程序调用rt_device_write写入数据时,如果底层硬件能够支持自动发送,那么上层应用可以设置一个回调函数。这个回调函数会在底层硬件数据发送完成后(例如DMA传送完成或FIFO写入完毕产生完成中断时)调用。我们可以通过rt_device_set_tx_complete接口设置设备发送完成指示,接口参数及返回值如下:

rt_device_set_tx_complete接口参数及返回值如表1-9所示。

表1-9 rt_device_set_tx_complete接口参数及返回值

调用这个接口时,回调函数由调用者提供,当硬件设备发送完数据时,由驱动程序回调这个接口并把发送完成的数据块地址buffer作为参数传递给上层应用。上层应用(线程)在收到指示时会根据发送buffer的情况,释放buffer内存块或将其作为下一个写数据的缓存。

7.设备访问示例

下面代码为用程序访问设备的示例,首先通过rt_device_find()查找到看门狗设备,获得设备句柄,然后通过rt_device_init()初始化设备,并通过rt_device_control()设置看门狗设备溢出时间。

1.2.3 驱动编写流程与规范

驱动编写流程是本书中所有设备都要用到的,如图1-9所示。

图1-9 驱动编写流程

RT-Thread设备对应的设备驱动框架源码在rt-thread/components/drivers文件夹中。在该文件夹中查看代码,找到对应框架的注册函数和操作方法即(ops),如图1-10所示。

图1-10 RT-Thread设备驱动框架源码位置

在驱动中完成驱动框架提供的设备结构、操作函数和注册函数,然后进行驱动验证。

编写好的驱动代码风格可以参考RT-Thread代码规范进行格式化。若要提交到RT-Thread仓库,则代码风格必须遵守RT-Thread代码规范:https://gitee.com/rtthread/rt-thread/blob/master/documentation/contribution_guide/coding_style_cn.md。

1.3 本章小结

本章对RT-Thread进行了介绍,讲解了以下内容。

1)RT-Thread的版本、特性、芯片对接流程与架构等。

2)RT-Thread I/O设备框架。 NiP+xykkeJ11hR+Oq05Tpfzx7l1+w6jw1FkiZDUwEgatKjEDhL5AnaygxPT6pmFY

点击中间区域
呼出菜单
上一章
目录
下一章
×