系统启动
您的应用程序的main()应至少按照给定的顺序执行以下操作:
- 硬件的初始化和配置,包括外设,内存,引脚,时钟和中断系统。
- 使用相应的CMSIS-CORE功能更新系统内核时钟。
- 使用osKernelInitialize初始化CMSIS-RTOS内核。
- (可选)创建一个新线程app_main,该线程用作使用osThreadNew的主线程。 或者,可以直接在main()中创建线程。
- 使用osKernelStart启动RTOS调度程序。 在执行成功的情况下,此函数不返回。 osKernelStart之后的任何应用程序代码将不被执行,除非osKernelStart失败。
注意
内核使用的中断(例如SVC)在osKernelInitialize中初始化。 如果NVIC中的优先级和分组在上述顺序之后被应用程序改变,则可能需要再次调用osKernelInitialize。
内存分配
RTX5对象(线程,互斥体,信号量,定时器,消息队列,线程和事件标志以及内存池)都需要专用的RAM内存。 可以使用osobjectNew()调用创建对象,并使用osobjectDelete()调用进行删除。 相关对象内存需要在对象的生命周期内可用。
RTX5为对象提供了三种不同的内存分配方法:
- 全局内存池为所有对象使用单个全局内存池。 容易配置,但是当创建和销毁具有不同大小的对象时,可能存在内存碎片的缺点。
- 对象特定的内存池对于每个对象类型使用固定大小的内存池。 该方法是时间确定性的,避免了内存碎片。
- 静态对象内存在编译期间保留内存,完全避免了系统内存不足。 这通常是一些安全关键系统所必需的。
可以在同一应用程序中混合所有的内存分配方法。
全局内存池
全局内存池从内存区域分配所有对象。 这种内存分配方式是RTX5的默认配置设置。
全局内存池为所有对象
当内存池没有提供足够的内存时,对象的创建失败,相关的osobjectNew()函数返回NULL。
在系统配置中启用。
对象特定的内存池
对象特定的内存池通过针对每种对象类型的专用固定大小的内存管理来避免内存碎片。 这种类型的内存池是完全时间确定性的,这意味着对象创建和销毁总是保持相同的固定时间长度。 由于固定大小的内存池特定于对象类型,因此简化了对内存不足情况的处理。
每个对象类型有一个内存池
每个对象类型都有选择地启用对象特定的内存池,例如:使用RTX配置文件的mutex或线程:
- 在线程配置中为线程对象启用。
- 在定时器对象的定时器配置中启用。
- 在事件对象的事件标志配置中启用。
- 在互斥体对象的Mutex配置中启用。
- 在信号量的信号量配置中启用。
- 在内存池的内存池配置中启用。
- 在消息对象的消息队列配置中启用。
- 当内存池没有提供足够的内存时,对象的创建失败,相关的osobjectNew()函数返回NULL。
静态对象内存
与动态内存分配相反,静态内存分配需要编译时分配对象内存。
静态分配所有对象的内存
以下代码示例显示如何使用静态内存创建OS对象。
Code Example:
#include "RTE_Components.h"
#include CMSIS_device_header
void worker(void *arg)
{
while(1)
{
}
}
uint64_t worker_thread_stk_1[64];
"wrk1",
&worker_thread_tcb_1,
sizeof(worker_thread_tcb_1),
&worker_thread_stk_1[0],
sizeof(worker_thread_stk_1),
0
};
void app_main (void *argument) {
uint32_t param = NULL;
for (;;) {}
}
int main (void) {
SystemCoreClockUpdate();
for (;;) {}
}
线程堆栈管理
对于没有浮点单元的Cortex-M处理器,线程上下文在本地堆栈上需要64个字节。
注意
对于具有FP的Cortex-M4 / M7,线程上下文在本地堆栈上需要200字节。 对于这些设备,默认堆栈空间应增加至少300个字节。
每个线程都提供一个单独的堆栈,它保存线程上下文和堆栈空间,用于自动变量和函数调用嵌套的返回地址。 RTX线程的堆栈大小可灵活配置,如"线程配置"部分所述。 RTX提供了对堆栈溢出和堆栈利用率的可配置检查。
低功耗操作
系统线程osRtxIdleThread可用于将系统切换到低功耗模式。 进入低功耗模式的最简单的形式是执行__WFE功能,使处理器进入等待事件的睡眠模式。
Code Example:
#include "RTE_Components.h"
#include CMSIS_device_header
for (;;) {
__WFE();
}
}
注意
每个Cortex-M实现中__WFE()都不可用。 检查设备手册的可用性。
RTX内核定时器Tick
默认情况下,RTX5使用Cortex-M SysTick定时器为RTX内核定时器tick生成周期性中断。 CMSIS-RTOS提供定时器管理功能,多个CMSIS-RTOS功能具有超时参数。 这个周期性的RTX内核定时器中断是用来导出所需的时间间隔。 RTX5还提供了替代计时器和无勾选操作的配置选项。
为了处理线程的超时和时间延迟,RTX5线程管理由RTX内核定时器刻度中断控制。 线程上下文包含所有CPU寄存器(R0 - R12),返回地址(LR),程序计数器(PC)和处理器状态寄存器(xPSR)。 对于Cortex-M4 / M7 FPU,浮点状态和寄存器(S0 - S32,FPSCR)也是线程上下文的一部分。
发生线程切换时:
当前运行的线程的线程上下文存储在该线程的本地堆栈上。
堆栈指针被切换到下一个正在运行的线程。
这个下一个运行的线程的线程上下文被还原,并且这个线程开始运行。
超时值
超时值是几个osXxx函数的一个参数,以便能够解决请求的时间。 超时值为0意味着即使没有资源可用,RTOS也不会等待功能立即返回。 osWaitForever的超时值意味着RTOS无限等待直到资源变为可用。
超时值指定到时间延迟过去之前的定时器滴答数。 该值是上限,取决于自上次计时器计时以来经过的实际时间。
例子:
超时值0:系统不等待,即使没有资源可用,RTOS功能立即返回。
超时值1:系统等待直到下一个计时器出现; 取决于之前的计时器滴答,它可能是非常短的等待时间。
超时值2:实际等待时间在1到2个定时器之间。
超时值osWaitForever:系统等待无限直到资源变为可用。

使用osDelay()的超时举例
来自中断服务程序的调用
可以从线程和中断服务程序(ISR)调用以下CMSIS-RTOS2函数,
- osKernelGetSysTimerCount, osKernelGetSysTimerFreq
- osThreadFlagsSet
- osEventFlagsSet, osEventFlagsClear, osEventFlagsGet, osEventFlagsWait
- osSemaphoreAcquire, osSemaphoreRelease, osSemaphoreGetCount
- osMemoryPoolAlloc, osMemoryPoolFree, osMemoryPoolGetCapacity, osMemoryPoolGetBlockSize, osMemoryPoolGetCount, osMemoryPoolGetSpace
- osMessageQueuePut, osMessageQueueGet, osMessageQueueGetCapacity, osMessageQueueGetMsgSize, osMessageQueueGetCount, osMessageQueueGetSpace
不能从ISR调用的函数正在验证中断状态,并返回状态代码osErrorISR,以防它们从ISR上下文中调用。 在某些实现中,可能会使用HARD_FAULT向量来捕获此条件。
Tick-less 低功耗操作
RTX5提供了tick-less操作的扩展,对于使用SysTick定时器也被禁用的广泛低功耗模式的应用程序,这是非常有用的。 为了在这种省电模式下提供时间戳,使用唤醒定时器来导出定时器间隔。 CMSIS-RTOS2功能osKernelSuspend和osKernelResume控制tick-less操作。
使用此功能允许RTX5线程调度程序停止周期性内核中断。 当所有活动线程暂停时,系统进入掉电状态,并计算在此掉电模式下可以停留多长时间。 在掉电模式下,处理器和外围设备可以关闭。 只有唤醒定时器必须保持供电,因为该定时器负责在断电时间到期后唤醒系统。
tick-less操作由osRtxIdleThread线程控制。 唤醒超时值在系统进入掉电模式前设置。 函数osKernelSuspend计算在RTX Timer Ticks中测得的唤醒超时时间; 该值用于设置在系统掉电模式下运行的唤醒定时器。
一旦系统恢复运行(通过唤醒超时或其他中断),RTX5线程调度程序将以osKernelResume函数启动。 参数sleep_time指定系统处于掉电模式的时间(在RTX Timer Ticks中)。
Code Example:
#include "msp.h"
staticvoid MSP432_LP_Entry(void) {
PCM->CTL1 = PCM_CTL1_KEY_VAL | PCM_CTL1_FORCE_LPM_ENTRY;
SYSCTL->SRAM_BANKRET |= SYSCTL_SRAM_BANKRET_BNK7_RET;
__enable_interrupt();
NVIC_EnableIRQ(RTC_C_IRQn);
SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk);
}
staticvolatile unsigned int tc;
staticvolatile unsigned int tc_wakeup;
void RTC_C_IRQHandler(void)
{
if (tc++ > tc_wakeup)
{
SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;
NVIC_DisableIRQ(RTC_C_IRQn);
NVIC_ClearPendingIRQ(RTC_C_IRQn);
return;
}
if (RTC_C->PS0CTL & RTC_C_PS0CTL_RT0PSIFG)
{
RTC_C->CTL0 = RTC_C_KEY_VAL;
RTC_C->PS0CTL &= ~RTC_C_PS0CTL_RT0PSIFG;
RTC_C->CTL0 = 0;
SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk);
}
}
uint32_t g_enable_sleep = 0;
for (;;) {
if (tc_wakeup > 0) {
tc = 0;
MSP432_LP_Entry();
__WFI();
}
}
}
注意
每个ARM Cortex-M实现中__WFI()不可用。 检查设备手册的可用性。
RTX5头文件
CMSIS-RTOS2 API的每个实现都可以带来自己的附加功能。 RTX5增加了一些空闲功能,用于错误通知和特殊的系统定时器功能。 它也是使用宏控制块和内存大小。
如果您在应用程序代码中需要一些RTX特定功能,#包含头文件rtx_os.h
#ifndef RTX_OS_H_
#define RTX_OS_H_
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern"C"
{
#endif
#define osRtxVersionAPI 20010000
#define osRtxVersionKernel 50010000
#define osRtxKernelId "RTX V5.1.0"
#define osRtxIdInvalid 0x00U
#define osRtxIdThread 0x01U
#define osRtxIdTimer 0x02U
#define osRtxIdEventFlags 0x03U
#define osRtxIdMutex 0x04U
#define osRtxIdSemaphore 0x05U
#define osRtxIdMemoryPool 0x06U
#define osRtxIdMessage 0x07U
#define osRtxIdMessageQueue 0x08U
#define osRtxObjectInactive 0x00U
#define osRtxObjectActive 0x01U
#define osRtxFlagSystemObject 0x01U
#define osRtxFlagSystemMemory 0x02U
#define osRtxKernelInactive ((uint8_t)osKernelInactive)
#define osRtxKernelReady ((uint8_t)osKernelReady)
#define osRtxKernelRunning ((uint8_t)osKernelRunning)
#define osRtxKernelLocked ((uint8_t)osKernelLocked)
#define osRtxKernelSuspended ((uint8_t)osKernelSuspended)
#define osRtxThreadStateMask 0x0FU
#define osRtxThreadInactive ((uint8_t)osThreadInactive)
#define osRtxThreadReady ((uint8_t)osThreadReady)
#define osRtxThreadRunning ((uint8_t)osThreadRunning)
#define osRtxThreadBlocked ((uint8_t)osThreadBlocked)
#define osRtxThreadTerminated ((uint8_t)osThreadTerminated)
#define osRtxThreadWaitingDelay (osRtxThreadBlocked | 0x10U)
#define osRtxThreadWaitingJoin (osRtxThreadBlocked | 0x20U)
#define osRtxThreadWaitingThreadFlags (osRtxThreadBlocked | 0x30U)
#define osRtxThreadWaitingEventFlags (osRtxThreadBlocked | 0x40U)
#define osRtxThreadWaitingMutex (osRtxThreadBlocked | 0x50U)
#define osRtxThreadWaitingSemaphore (osRtxThreadBlocked | 0x60U)
#define osRtxThreadWaitingMemoryPool (osRtxThreadBlocked | 0x70U)
#define osRtxThreadWaitingMessageGet (osRtxThreadBlocked | 0x80U)
#define osRtxThreadWaitingMessagePut (osRtxThreadBlocked | 0x90U)
#define osRtxThreadFlagDefStack 0x10U
#define osRtxStackMagicWord 0xE25A2EA5U
#define osRtxStackFillPattern 0xCCCCCCCCU
typedefstruct osRtxThread_s {
uint8_t id;
uint8_t state;
uint8_t flags;
uint8_t attr;
constchar *name;
structosRtxThread_s *thread_next;
structosRtxThread_s *thread_prev;
structosRtxThread_s *delay_next;
structosRtxThread_s *delay_prev;
structosRtxThread_s *thread_join;
uint32_t delay;
int8_t priority;
int8_t priority_base;
uint8_t stack_frame;
uint8_t flags_options;
uint32_t wait_flags;
uint32_t thread_flags;
structosRtxMutex_s *mutex_list;
void *stack_mem;
uint32_t stack_size;
uint32_t sp;
uint32_t thread_addr;
uint32_t tz_memory;
#define osRtxTimerInactive 0x00U
#define osRtxTimerStopped 0x01U
#define osRtxTimerRunning 0x02U
#define osRtxTimerPeriodic ((uint8_t)osTimerPeriodic)
typedefstruct {
void *fp;
void *arg;
typedefstruct osRtxTimer_s {
uint8_t id;
uint8_t state;
uint8_t flags;
uint8_t type;
constchar *name;
structosRtxTimer_s *prev;
structosRtxTimer_s *next;
uint32_t tick;
uint32_t load;
typedefstruct osRtxEventFlags_s {
uint8_t id;
uint8_t state;
uint8_t flags;
uint8_t reserved;
constchar *name;
uint32_t event_flags;
typedefstruct osRtxMutex_s {
uint8_t id;
uint8_t state;
uint8_t flags;
uint8_t attr;
constchar *name;
structosRtxMutex_s *owner_prev;
structosRtxMutex_s *owner_next;
uint8_t lock;
uint8_t padding[3];
typedefstruct osRtxSemaphore_s {
uint8_t id;
uint8_t state;
uint8_t flags;
uint8_t reserved;
constchar *name;
uint16_t tokens;
uint16_t max_tokens;
typedefstruct osRtxMpInfo_s {
uint32_t max_blocks;
uint32_t used_blocks;
uint32_t block_size;
void *block_base;
void *block_lim;
void *block_free;
typedefstruct osRtxMemoryPool_s {
uint8_t id;
uint8_t state;
uint8_t flags;
uint8_t reserved;
constchar *name;
typedefstruct osRtxMessage_s {
uint8_t id;
uint8_t state;
uint8_t flags;
uint8_t priority;
structosRtxMessage_s *prev;
structosRtxMessage_s *next;
typedefstruct osRtxMessageQueue_s {
uint8_t id;
uint8_t state;
uint8_t flags;
uint8_t reserved;
constchar *name;
uint32_t msg_size;
uint32_t msg_count;
typedefstruct osRtxObject_s {
uint8_t id;
uint8_t state;
uint8_t flags;
uint8_t reserved;
constchar *name;
typedefstruct {
constchar *os_id;
uint32_t version;
struct{
uint8_t state;
volatile uint8_t blocked;
uint8_t pendISR;
uint8_t pendSV;
uint32_t sys_freq;
uint64_t tick;
} kernel;
int32_t tick_irqn;
struct{
struct{
} run;
struct{
uint32_t tick;
uint32_t timeout;
} robin;
} thread;
struct{
} timer;
struct{
uint16_t max;
uint16_t cnt;
uint16_t in;
uint16_t out;
void **data;
} isr_queue;
struct{
} post_process;
struct{
void *stack;
void *mp_data;
void *mq_data;
void *common;
} mem;
struct{
} mpi;
#define osRtxThreadFlagsLimit 31U
#define osRtxEventFlagsLimit 31U
#define osRtxMutexLockLimit 255U
#define osRtxSemaphoreTokenLimit 65535U
#define osRtxThreadCbSize sizeof(osRtxThread_t)
#define osRtxTimerCbSize sizeof(osRtxTimer_t)
#define osRtxEventFlagsCbSize sizeof(osRtxEventFlags_t)
#define osRtxMutexCbSize sizeof(osRtxMutex_t)
#define osRtxSemaphoreCbSize sizeof(osRtxSemaphore_t)
#define osRtxMemoryPoolCbSize sizeof(osRtxMemoryPool_t)
#define osRtxMessageQueueCbSize sizeof(osRtxMessageQueue_t)
#define osRtxMemoryPoolMemSize(block_count, block_size) \
(4*(block_count)*(((block_size)+3)/4))
#define osRtxMessageQueueMemSize(msg_count, msg_size) \
(4*(msg_count)*(3+(((msg_size)+3)/4)))
#define osRtxErrorStackUnderflow 1U
#define osRtxErrorISRQueueOverflow 2U
#define osRtxErrorTimerQueueOverflow 3U
#define osRtxErrorClibSpace 4U
#define osRtxErrorClibMutex 5U
#define osRtxConfigPrivilegedMode (1UL<<0)
#define osRtxConfigStackCheck (1UL<<1)
#define osRtxConfigStackWatermark (1UL<<2)
typedefstruct {
uint32_t flags;
uint32_t tick_freq;
uint32_t robin_timeout;
struct{
void **data;
uint16_t max;
uint16_t padding;
} isr_queue;
struct{
void *stack_addr;
uint32_t stack_size;
void *mp_data_addr;
uint32_t mp_data_size;
void *mq_data_addr;
uint32_t mq_data_size;
void *common_addr;
uint32_t common_size;
} mem;
struct{
} mpi;
uint32_t thread_stack_size;
const
const
const
uint32_t timer_mq_mcnt;
#ifdef __cplusplus
}
#endif
#endif // RTX_OS_H_