目录
- 简介
- TI-RTOS
- FreeRTOS
- POSIX
- 运行时对象查看器 (Runtime Object Viewer)
- TI-POSIX 介绍
- 在源代码中使用 POSIX
- TI-POSIX支持的函数摘要
- 线程函数调用的前后关系
- 线程管理
- 线程属性
- 线程同步
- 障碍属性
- 条件变量
- 条件变量属性
- 互斥锁
- 互斥属性
- 读写锁定
- 读写锁属性
- 辅助函数调用的前后关系
- 时钟
- 消息队列
- 信号量
- 睡眠
- 计时器
- 注意事项
- 线程默认堆栈大小和线程默认优先级
- 线程调度策略
- FreeRTOS上的TI-POSIX
- 二进制信号量
平台:Code Composer Studio 10.4.0
MSP432P401R SimpleLink™ 微控制器 LaunchPad™ 开发套件
(MSP-EXP432P401R)
本文内容机翻自
SimpleLink™ MCU SDKs: RTOS and POSIX 和 TI-POSIX User’s Guide
简介
SimpleLinkTM 微控制器(MCU)平台的软件开发工具包(sdk)具有通用组件和特定于设备的中间件,加快了上市时间,并提供了有线和无线设备的 SimpleLink 整个 MCU 组合的统一开发经验。关于 SimpleLink SDK 的框图,请参阅下图。在本文中,我将更深入地探讨 SimpleLink SDK 中包含的组件如何使您能够使用实时操作系统(RTOS)创建确定的、高效的、可伸缩的应用程序。
TI-RTOS
TI-RTOS SimpleLink SDK 集成了 TI-RTOS,一个功能齐全的实时操作系统。所有 TI SimpleLink sdk 都预先安装了 TI-rtos 内核,并且与 Portable Operating System Interface (POSIX)兼容。TI-RTOS 是一个您可以信任的健壮解决方案,已经部署在各种 TI 嵌入式解决方案的数千个应用程序中。内核是开放源码的(开源 BSD [ BSD ]许可证) ,与 TI 的硅组合同步开发,以实现非常低的延迟,高效的代码占用。TI-RTOS 帮助您优化您的应用程序的功耗,性能和代码大小,以满足您的独特需求。具体地说,TI-RTOS 的电源管理功能使您能够以最小的努力和直观的应用程序编程接口(api)为应用程序实现积极的功耗节省。
TI-RTOS 内核的中心是调度程序,它确保最高优先级的线程正在运行。这提供了确定性和快速的运算。TI-RTOS 支持四种不同类型的线程: 硬件中断(Hwis)、软件中断(Swis)、任务和空闲,如下面的图2所示。TI-RTOS 提供了几种线程通信机制,如信号量、邮箱、队列、门和事件。此外,TI-RTOS 包括系统级的计时服务和内存管理器,以确保您的应用程序尽可能高效和精简。
FreeRTOS
开发 SimpleLink SDK 是模块化的,允许您在 ti-RTOS 之外使用可选的 RTOS 内核。除了 TI-RTOS,MSP432™ 和 Wi-Fi ® CC3220软件开发包(sdk)还包括使用流行的 FreeRTOS 的能力。SimpleLink sdk 的模块性使您可以轻松插入首选的操作系统/内核,从而获得最大的灵活性。
POSIX
POSIX The SimpleLink SDK 还提供了与 POSIX 兼容的 api。POSIX 是一个电气和电子工程师协会(IEEE)的操作系统兼容性 API 行业标准。POSIX 层抽象了应用程序使用的 RTOS 内核功能。在典型的应用程序中,POSIX 层只需要少于2KB 的代码,因此可以重用示例和用户应用程序,并将其移植到不同的内核。使用这个层是可选的,但是这意味着你可以使用任何你目前熟悉的或者将来想要移动到的操作系统。POSIX 兼容性还允许 TI 第三方合作伙伴与 SimpleLink SDK 设备进行接口,以增加对其内核的支持,从而为包括 FreeRTOS 在内的任何操作系统的设计提供完全自由。
运行时对象查看器 (Runtime Object Viewer)
运行时对象查看器为了帮助您优化启用 rtos 的应用程序,TI 提供了强大的工具来帮助您调试和监视代码。具体来说,Runtime Object Viewer (ROV2)提供了一个强大的可视化和检测界面,可以帮助您监视线程状态、堆使用情况和中央处理器(CPU)负载。下面的图3显示了一些可用的仪表板,以帮助您进行调试。尽管 ROV2可以为您支持 RTOS 的应用程序提供有用的洞察力,但 ROV2工具具有足够的灵活性,可以在应用程序中显示与任何库、 RTOS 或其他相关的高级信息。
TI-POSIX 介绍
在源代码中使用 POSIX
在源代码中使用 Open Group Specification 定义的文件名包含 POSIX 头文件。例如,使用以下命令创建一个 POSIX 线程:
#include <pthread.h>void *start_fxn(void *arg);
pthread_t thread;
int arg = 1;pthread_create(&thread, NULL, start_fxn, (void *)&arg);
在 SYS/BIOS 的以前版本中,POSIX 头文件使用包限定的路径名包含在内。这已经不再受支持了。不要使用下列包括语句:
#include <ti/sysbios/posix/pthread.h> INCORRECT
#include <ti/sysbios/posix/sys/types.h> INCORRECT
使用以下包括语句:
#include <pthread.h>
#include <sys/types.h>
TI-POSIX支持的函数摘要
在实时操作系统前后关系中,有三种前后关系:
main
在main()函数中,在调用RTOS调度器之前
task
在本地RTOS线程中(即不是从pthread中)
interrupt
在中断服务程序中
线程函数调用的前后关系
线程管理
函数名 | 用途 | main | task |
---|---|---|---|
pthread_cancel | 向线程发送取消请求 | No | Yes |
pthread_cleanup_pop | 弹出线程取消清理处理程序 | No | Yes |
pthread_cleanup_push | 推取消线程清理处理程序 | No | No |
pthread_create | 创建一个新线程 | Yes | Yes |
pthread_detach | 分离一个线程 | No | Yes |
pthread_equal | 比较线程 id | Yes | Yes |
pthread_exit | 终止调用线程 | No | No |
pthread_getconcurrency | 不支持 | ||
pthread_getcpuclockid | 不支持 | ||
pthread_getschedparam | 用于获取 pthread 的优先级 | No | Yes |
pthread_getspecific | 获取调用线程的线程特定数据 | No | No |
pthread_join | 用终止线程连接 | No | Yes |
pthread_key_create | 创建特定于线程的数据键 | No | No |
pthread_key_delete | 删除线程特定的数据键 | No | No |
pthread_once | 运行一次初始化例程 | No | Yes |
pthread_self | 获取调用线程的 ID | No | No |
pthread_setcancelstate | 设置取消能力状态和类型 | No | No |
pthread_setcanceltype | 不支持。只支持异步取消 | ||
pthread_setconcurrency | 不支持 | ||
pthread_setschedparam | 用于设置线程的优先级 | No | No |
pthread_setschedprio | 不支持。使用 pthread_setschedparam 来设置优先级 | ||
pthread_setspecific | 设置调用线程的线程特定数据 | No | No |
pthread_testcancel | 不支持 |
线程属性
函数名 | 用途 | main | task |
---|---|---|---|
pthread_attr_destroy | 销毁线程属性对象 | Yes | Yes |
pthread_attr_getdetachstate | 获取属性对象中的分离状态 | Yes | Yes |
pthread_attr_getguardsize | 获取属性对象中的保护大小 | Yes | Yes |
pthread_attr_getinheritsched | 不支持的内核调度策略是固定的 | ||
pthread_attr_getschedparam | 获取属性对象中的调度参数 | Yes | Yes |
pthread_attr_getschedpolicy | 不支持的内核调度策略是固定的 | ||
pthread_attr_getscope | 不支持的内核没有进程的概念 | ||
pthread_attr_getstack | 获取堆栈大小和地址属性 | Yes | Yes |
pthread_attr_getstacksize | 获取属性对象中的堆栈大小 | Yes | Yes |
pthread_attr_init | 初始化线程属性 | Yes | Yes |
pthread_attr_setdetachstate | 在属性对象中设置分离状态 | Yes | Yes |
pthread_attr_setguardsize | 在属性对象中设置保护大小 | Yes | Yes |
pthread_attr_setinheritsched | 不支持的内核调度策略是固定的 | ||
pthread_attr_setschedparam | 在属性对象中设置调度参数 | Yes | Yes |
pthread_attr_setschedpolicy | 不支持的内核调度策略是固定的 | ||
pthread_attr_setscope | 不支持的内核没有进程的概念 | ||
pthread_attr_setstack | 设置堆栈大小和地址 | Yes | Yes |
pthread_attr_setstacksize | 设置堆栈大小 | Yes | Yes |
线程同步
函数名 | 用途 | main | task |
---|---|---|---|
pthread_barrier_destroy | 摧毁一个障碍物 | Yes | Yes |
pthread_barrier_init | 初始化一个障碍物体 | Yes | Yes |
pthread_barrier_wait | 在屏障处同步 | No | Yes |
障碍属性
函数名 | 用途 | main | task |
---|---|---|---|
pthread_barrierattr_destroy | 破坏 barrier 属性对象 | Yes | Yes |
pthread_barrierattr_getpshared | 不支持的内核没有进程的概念 | ||
pthread_barrierattr_init | 初始化 barrier 属性对象 | Yes | Yes |
pthread_barrierattr_setpshared | 不支持的内核没有进程的概念 |
条件变量
函数名 | 用途 | main | task |
---|---|---|---|
pthread_cond_broadcast | 取消阻止条件变量上阻塞的所有线程 | No | Yes |
pthread_cond_destroy | 为条件变量分配的可用资源 | Yes | Yes |
pthread_cond_init | 分配和初始化条件变量 | Yes | Yes |
pthread_cond_signal | 取消阻止等待条件变量的线程 | No | Yes |
pthread_cond_timedwait | 使用超时等待条件变量 | No | Yes |
pthread_cond_wait | 等待条件变量 | No | Yes |
条件变量属性
函数名 | 用途 | main | task |
---|---|---|---|
pthread_condattr_destroy | 销毁条件变量属性对象 | Yes | Yes |
pthread_condattr_getclock | 不支持 | ||
pthread_condattr_getpshared | 不支持 | ||
pthread_condattr_init | 初始化条件变量属性对象 | Yes | Yes |
pthread_condattr_setclock | 不支持 | ||
pthread_condattr_setpshared | 不支持 |
互斥锁
函数名 | 用途 | main | task |
---|---|---|---|
pthread_mutex_destroy | 为互斥对象分配的自由资源 | Yes | Yes |
pthread_mutex_getprioceiling | 获取互斥锁的优先级上限 | Yes | Yes |
pthread_mutex_init | 分配和初始化互斥对象 | Yes | Yes |
pthread_mutex_lock | 锁定互斥锁 | No | No |
pthread_mutex_setprioceiling | 设置互斥锁的优先级上限 | No | Yes |
pthread_mutex_timedlock | 等待带超时的互斥对象 | No | No |
pthread_mutex_trylock | 锁定一个互斥锁,如果它是可用的,不阻塞返回 | No | No |
pthread_mutex_unlock | 解锁调用线程拥有的互斥对象 | No | No |
互斥属性
函数名 | 用途 | main | task |
---|---|---|---|
pthread_mutexattr_destroy | 销毁互斥属性对象 | Yes | Yes |
pthread_mutexattr_getprioceiling | 获取互斥锁属性对象的优先级上限 | Yes | Yes |
pthread_mutexattr_getprotocol | 获取互斥锁属性对象的协议 | Yes | Yes |
pthread_mutexattr_getpshared | 不支持 | ||
pthread_mutexattr_gettype | 获取互斥类型属性 | Yes | Yes |
pthread_mutexattr_init | 初始化互斥属性对象 | Yes | Yes |
pthread_mutexattr_setprioceiling | 设置互斥对象的优先级上限 | Yes | Yes |
pthread_mutexattr_setprotocol | 设置互斥锁属性对象的协议 | Yes | Yes |
pthread_mutexattr_setpshared | 不支持 | ||
pthread_mutexattr_settype | 设置互斥类型属性 | Yes | Yes |
读写锁定
函数名 | 用途 | main | task |
---|---|---|---|
pthread_rwlock_destroy | 销毁一个读写锁对象 | Yes | Yes |
pthread_rwlock_init | 初始化一个读写锁对象 | Yes | Yes |
pthread_rwlock_rdlock | 锁定读写锁对象进行读取 | No | No |
pthread_rwlock_timedrdlock | 锁定一个读写锁对象,用于超时读取 | No | No |
pthread_rwlock_timedwrlock | 使用超时锁定写入的读写锁定 | No | No |
pthread_rwlock_tryrdlock | 尝试读写锁以进行读取(非阻塞) | No | No |
pthread_rwlock_trywrlock | 尝试使用读写锁进行写入(非阻塞) | No | No |
pthread_rwlock_unlock | 解锁一个读写锁对象 | No | No |
pthread_rwlock_wrlock | 锁定一个读写锁对象进行写入 | No | No |
读写锁属性
函数名 | 用途 | main | task |
---|---|---|---|
pthread_rwlockattr_destroy | 销毁读写锁属性对象 | Yes | Yes |
pthread_rwlockattr_getpshared | 不支持 | ||
pthread_rwlockattr_init | 初始化读写锁属性对象 | Yes | Yes |
pthread_rwlockattr_setpshared | 不支持 |
辅助函数调用的前后关系
时钟
函数名 | 用途 | main | task |
---|---|---|---|
clock_gettime | 获取当前时间 | Yes | Yes |
clock_nanosleep | 高分辨率睡眠,可指定时钟 | No | Yes |
clock_settime | 为CLOCK REALTIME时钟设置当前时间 | Yes | Yes |
消息队列
函数名 | 用途 | main | task |
---|---|---|---|
mq_close | 关闭消息队列 | Yes | Yes |
mq_getattr | 获取消息队列属性 | Yes | Yes |
mq_open | 打开一个消息队列 | Yes | Yes |
mq_receive | 从消息队列接收消息 | No | Yes |
mq_send | 向消息队列发送消息 | No | Yes |
mq_setattr | 设置消息队列属性 | Yes | Yes |
mq_timedreceive | 接收来自消息队列的消息,带有超时 | No | Yes |
mq_timedsend | 使用超时向消息队列发送消息 | No | Yes |
mq_unlink | 删除消息队列 | Yes | Yes |
信号量
函数名 | 用途 | main | task |
---|---|---|---|
sem_destroy | 销毁一个信号量 | Yes | Yes |
sem_getvalue | 获取信号量计数 | Yes | Yes |
sem_init | 初始化信号量 | Yes | Yes |
sem_post | 解锁一个信号量(即增加信号量计数) | Yes | Yes |
sem_timedwait | 带超时锁定信号量 | No | Yes |
sem_trywait | 尝试锁定信号量(非阻塞) | No | Yes |
sem_wait | 锁定信号量 | No | Yes |
睡眠
函数名 | 用途 | main | task |
---|---|---|---|
nanosleep | 高分辨率睡眠 | No | Yes |
计时器
函数名 | 用途 | main | task |
---|---|---|---|
timer_create | 创建一个计时器 | Yes | Yes |
timer_delete | 删除计时器 | Yes | Yes |
timer_gettime | 获取计时器到期之前的时间 | Yes | Yes |
timer_settime | 设置计时器下一次到期的时间 | Yes | Yes |
注意事项
线程默认堆栈大小和线程默认优先级
int pthread_attr_init(pthread_attr_t *attr)
pthread_attr_init()使用默认值初始化所指向的对象,其中包括堆栈大小和线程优先级。pthread_attr_t、attr
在 TI-RTOS 上,默认堆栈大小在配置脚本中定义。
var Task = xdc.useModule('ti.sysbios.knl.Task');
Task.defaultStackSize = 0x800;
在 FreeRTOS 上,使用 FreeRTOS.config.h 和 portmacro.h 头文件中定义的值计算默认堆栈大小如下。
configPOSIX_STACK_SIZE * sizeof(portSTACK_TYPE)
注意,这是一个自定义符号,定义在SDK中的FreeRTOSConfig.h头文件中。h头文件是在FreeRTOS发行版中附带的。configPOSIX_STACK_SIZE
优先级设置为1,这是Idle任务之外允许的最低优先级,Idle任务的优先级为0。
线程调度策略
int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param)
int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param)
RTOS 内核使用了一个基于优先级的调度程序
FreeRTOS上的TI-POSIX
我们已经尽最大努力在TI-RTOS和FreeRTOS之间提供同样的支持。然而,这里也有一些例外。
没有办法将堆栈传递给xTaskCreate()。
pthread_attr_setstack() // - not supported on FreeRTOS
互斥锁的优先级继承由 FreeRTOS 处理。如果优先级较高的任务试图获取互斥锁,则拥有互斥的任务的优先级会暂时提高。因此,FreeRTOS 不支持互斥协议。
pthread_mutexattr_getprotocol() //- not supported for FreeRTOS
pthread_mutexattr_setprotocol() //- not supported for FreeRTOS
pthread_mutexattr_getprioceiling() //- not supported for FreeRTOS
pthread_mutexattr_setprioceiling() //- not supported for FreeRTOS
只有CLOCK_REALTIME被clock_settime()支持
timer_settime() 这是一个阻塞调用,与 TI-RTOS 不同
任务清理由 FreeRTOS 中的 Idle 任务完成。如果 pthreads 被删除,请确保 Idle 任务有机会运行到已删除线程的空闲分配内存中。
二进制信号量
. POSIX不支持二进制信号量。也就是说,一个信号量可以被传递多次,但计数不能大于1。下一个等待将计数减少到0
幸运的是,使用互斥量和条件变量很容易构建二进制信号量。下面是一个伪代码示例。
struct binary_semaphore {pthread_mutex_t mutex;pthread_cond_t cvar;int v;
};void mysem_post(struct binary_semaphore *p)
{pthread_mutex_lock(&p->mutex);p->v = 1;pthread_cond_signal(&p->cvar);pthread_mutex_unlock(&p->mutex);
}void mysem_pend(struct binar_semaphore *p)
{pthread_mutex_lock(&p->mutex);while (!p->v) {pthread_cond_wait(&p->cvar, &p->mutex);}p->v = 0;pthread_mutex_unlock(&p->mutex);
}