TI-RTOS概述
TI-RTOS是CC2640R2F设备上低功耗蓝牙项目的运行环境。TI-RTOS内核是传统SYS/BIOS内核的定制版本,是一个具有驱动程序,同步和调度工具的实时抢占式多线程操作系统。
线程模块
TI-RTOS内核管理线程执行的四个不同的任务级别,如图21所示。线程模块列表如下图所示,按照优先级降序排列。
- 硬件中断
- 软件中断
- 任务
- 后台空闲功能的空闲任务
这一节将要介绍四个执行线程以及整个TI-RTOS中用于消息传递和同步的各种结构。在大多数情况下,TI-RTOS函数在util.c(Util)中已被抽象为更高级别的函数。较低级的TI-RTOS函数在TI-RTOS Kernel API Guide中有描述,你可以在TI-RTOS内核用户指南中查看。本文档还定义了TI-RTOS包含的软件包和模块。
硬件中断(Hwi)
Hwi线程(也称为中断服务程序或ISR)是TI-RTOS应用程序中具有最高优先级的线程。Hwi线程用于执行有严格时间限制的关键任务。它们被触发以响应在实时环境中发生的外部异步事件(中断)。Hwi线程总是运行至完成,但是如果有其他的Hwi中断使能,它也可以暂时地被其他中断触发的Hwi线程抢占,这就是所谓的中断嵌套。有关中断嵌套,向导和功能的具体信息,可以在CC26XX技术参考手册中查看。
一般来说中断服务程序运行时间较短,不影响硬实时系统的要求。另外,由于Hwis总是运行至完成,所以在在其上下文中不会调用阻塞API。
中断的TI-RTOS驱动程序将初始化分配的外设所需的中断。有关详细信息,请参阅外设驱动。
注意:
外部资源(External Resources)提供了使用GPIO和Hwis的示例。虽然SDK包含一个外设驱动程序库抽象了对硬件寄存器的访问,但建议使用线程>安全的TI-RTOS驱动程序,如外设驱动中所述。
CC2640R2F的Hwi模块还支持零延迟中断。这些中断不通过TI-RTOS Hwi调度程序,因此比标准中断更灵敏,但是该功能禁止其中断服务程序直接调用任何TI-RTOS内核API。ISR要保护自己的上下文防止它干扰内核的调度程序。
为了能让低功耗蓝牙协议栈满足RF严格的时序要求,所有应用程序定义的Hwis都要以最低优先级执行。TI向系统添加新的Hwis时,建议不要修改默认的Hwi优先级。为了不破坏低功耗蓝牙协议栈中TI-RTOS的严格时序,应用程序中定义了临界段代码。执行临界段代码时中断会被关闭,在临界段代码执行完毕之后才会重新启用中断。
软件中断(Swi)
软件中断线程(Swis)是在Hwi线程和任务线程之间提供的一个额外的优先级。与Hwis由硬件中断触发不同,Swis是通过在程序编写过程中调用某些Swi模块的API来触发中断。由于时间限制,Swis中断服务程序不能作为任务来运行,其截止时间不如硬件中断服务程序那么严格。Swi也总是运行至完成,它允许Hwis将不太重要的中断处理放到较低优先级的线程来处理,从而最小化CPU在中断服务程序中花费的时间。Swis需要足够的空间来保存每个Swi中断优先级的上下文,它的每个线程都使用单独的堆栈。
与Hwis类似,Swis需要保持简短,它不应该包含任何阻塞API的调用。这保证了诸如无线协议栈等高优先级任务能根据需要执行。在Swis中建议发布某些TI-RTOS同步对象,然后把具体处理放在任务上下文中。图22说明了这种用例。
图22. 抢占情景
Swi上下文中常常会由时钟模块调用,对于Swi服务函数,不调用阻塞API,保证较短的执行时间是很重要的。
任务
任务线程的优先级高于空闲任务线程,低于软件中断。任务与软件中断的不同之处在于,任务可以在执行期间等待(阻塞),直到有必要的资源可用。每个任务线程都有一个独立的堆栈。TI-RTOS提供了可用于任务间通信和同步的多种机制。这些包括信号量,事件,消息队列和邮箱。
有关详细信息,可以在本文后面的任务中查看。
空闲任务
空闲任务线程在TI-RTOS应用程序中优先级最低,它会执行一个空闲循环。在主函数返回之后,TI-RTOS应用程序会调用每个TI-RTOS模块的启动程序,然后进入空闲循环。每个线程在被再次调用之前都必须等待所有其他线程执行完成。空闲循环在没有更高优先级的任务需要执行的时候会一直执行。只有没有严格截止期限的函数才能在空闲循环中执行。
对于CC2640R2F设备,空闲任务支持电源策略管理器设置为允许的最低功率节省模式。
内核配置
TI-RTOS应用程序可以使用工程中的.cfg
文件来配置TI-RTOS内核。在IAR和CCS工程中,配置文件在应用程序项目工作区中的TOOLS
文件夹下。
该配置通过选择性地包括或使用可用于内核的RTSC模块来实现。.cfg
中通过调用xdc.useModule()
函数来设置TI-RTOS内核用户指南中定义的各种选项来启用一个模块。
注意:
BLE5-Stack中的项目(如simple_peripheral
)通常会包含一个app_ble.cfg配置文件。
可以在.cfg
文件中配置的一些选项(但不限于这些):
- 启动选项
- Hwi,Swi和任务优先级的数量
- 异常和错误处理
- 系统刻度的持续时间(TI-RTOS内核中最基本的时间单位)。
- 定义应用程序的入口点和中断向量
- TI-RTOS堆和堆栈(不要与其他堆管理器混淆!)
- 包括预编译的内核和TI-RTOS驱动程序库
- 系统配置(for
System_printf()
)
一旦.cfg
文件发生变动时,您需要重新运行XDCTools的configuro
工具。在IAR和CCS提供的示例中这一步作为预构建步骤已经为您提供。
注意:
.cfg
的名称并不重要。但是项目只能包含一个.cfg
文件。
对于CC2640R2F,TI-RTOS内核存储在ROM中。通常为了节省Flash的访问足迹,.cfg
也会包含在内核的ROM模块中,如清单1所示。
清单1. 如何把TI-RTOS内核包含到ROM中
/ * ================ ROM configuration================ * /
/ *
*To use BIOS in flash, comment out the code block below.
* /
if (typeof NO_ROM == 'undefined' ||(typeof NO_ROM != 'undefined' && NO_ROM == 0 ))
{
var ROM = xdc.useModule('ti.sysbios.rom.ROM');
if(program.cpu.deviceName .match(/CC26/)){
ROM.romName = ROM.CC2640R2F;
}
else if(Program.cpu.deviceName.match(/CC13/)){
ROM.romName = ROM.CC1350;
}
}
ROM中的TI-RTOS内核针对性能进行了优化。如果您的应用程序需要额外的工具(通常用于调试),则必须将TI-RTOS内核包含在Flash中,这将增加Flash消耗。下面显示的是在ROM
中使用TI-RTOS内核的简要列表。
BIOS.assertsEnabled
必须设置为false
BIOS.logsEnabled
必须设置为false
BIOS.taskEnabled
必须设置为true
BIOS.swiEnabled
必须设置为true
BIOS.runtimeCreatesEnabled
必须设置为true
- BIOS必须使用该
ti.sysbios.gates.GateMutex
模块 Clock.tickSource
必须设置为Clock.TickSource_TIMER
Semaphore.supportsPriority
一定是false
- Swi,Task和Hwi hooks不容许
- Swi,Task和Hwi name instances不容许
- 任务堆栈检查被禁用
Hwi.disablePriority
必须设置为0x20
Hwi.dispatcherAutoNestingSupport
必须设置为true
- 默认的Heap instance必须设置为
ti.sysbios.heaps.HeapMem
管理者
有关上述列表外的其他文档,可以在TI-RTOS内核用户指南中查看。
创造与构建
大多数TI-RTOS模块通常都有_create()
和_construct()
APIs用来初始化最初的例程。这两个API之间运行时的主要差异是内存分配和错误处理。
在初始化之前,创建API会从默认的TI-RTOS堆执行内存分配。因此,应用程序必须在继续之前检查有效句柄的返回值。
清单2. 创建一个信号量
1 Semaphore_Handle sem;
2 Semaphore_Params semParams;
3 Semaphore_Params_init(&semParams);
4 sem = Semaphore_create(0,&semParams,NULL);/*Memory allocated in here*/
5 if (sem == NULL) /* Check if the handle is valid */
6 {
7 System_abort("Semaphore could not be created");
8 }
9
10
构造API提供了一个用于存储实例变量的数据结构。由于内存已被预先分配给实例,构建后不再需要进行错误检查。
清单3. 构造一个信号量
1 Semaphore_Handle SEM ;