CMSIS-RTOS2 文档翻译 之 RTX v5 实现(操作理论)

操作理论

内核的许多方面都是可配置的,并在适用的情况下提及配置选项。

系统启动

由于 main 不再是一个线程,RTX5 在到达 main 之前不会干扰系统启动。一旦执行到达 main(),建议初始化硬件并启动内核。这也反映在随 RTX5 组件提供的用户代码模板文件 “CMSIS-RTOS2” 主 “功能” 中。

你的应用程序的 main()应该按给定的顺序至少实现以下内容:

  1. 硬件的初始化和配置,包括外设,存储器,引脚,时钟和中断系统。
  2. 使用相应的 CMSIS-Core(Cortex-M)或 CMSIS-Core(Cortex-A)功能更新系统内核时钟。
  3. 使用 osKernelInitialize 初始化 CMSIS-RTOS 内核。
  4. 或者,创建一个新线程 app_main,该线程将作为使用 osThreadNew 的主线程使用。或者,可以直接在 main()中创建线程。
  5. 使用 osKernelStart 启动 RTOS 调度程序。如果执行成功,该函数不会返回。除非 osKernelStart 失败,否则 osKernelStart 之后的任何应用程序代码都不会执行。
注意
内核使用的中断(如 SVC)在 osKernelInitialize 中初始化。如果在上述顺序之后 NVIC 中的优先级和分组被更改,则可能需要再次调用osKernelInitialize。您可能会观察到可能由 osRtxErrorNotify 捕获或导致硬故障的奇怪的不当行为。
滴答定时器在 osKernelStart 期间配置。滴答间隔是基于 SystemCoreClock 变量计算的。

调度

RTX5 实现了一个低延迟预先调度器。RTX5 的主要部分在处理器模式下执行,例如

为了在 ISR 执行方面具有低延迟,这些系统例外被配置为使用可用的最低优先级组。优先级被配置为使得它们之间不发生抢占。因此,不需要中断关键部分(即中断锁)来保护调度器。

线程调度和中断执行

调度程序结合了基于优先级和循环的上下文切换。上图中描述的示例包含四个线程(1, 2, 3 和 4)。 线程 1 和 2 共享相同的优先级,线程 3 具有较高的优先级,线程 4 最高(osThreadAttr_t :: priority)。只要线程 3 和 4 被阻塞,调度程序就会按时间片(循环)在线程 1 和线程 2 之间切换。可以配置循环调度的时间片,请参阅系统配置中的循环超时。

线程 2 在时间索引 2 时通过任意 RTOS 调用(在 SVC 处理程序模式下执行)解除对线程 3 的阻塞。由于线程 3 具有高优先级,因此调度程序立即切换到线程 3。线程 4 仍然被阻塞。

在索引 4 时间发生中断(ISR)并抢占 SysTick_Handler 。 RTX 不会为中断服务执行添加任何延迟。ISR 例程使用解除线程 4 的RTOS调用,而不是立即切换到线程 4,PendSV 标志被设置为推迟上下文切换。PendSV_Handler 在 SysTick_Handler 返回之后立即执行,并且将被拒绝的上下文切换到线程 4。一旦最高优先级线程 4 通过使用阻塞 RTOS 调用执行再次阻塞,在时间索引 5 期间立即切换回线程 3 。

在索引 5 时,线程 3 也使用阻塞 RTOS 调用。因此,调度程序切换回线程 2 以获得时间索引 6 。在索引 7 时,调度程序使用循环机制切换到线程1,依此类推。

内存分配

RTX5 对象(线程,互斥锁,信号量,定时器,消息队列,线程和事件标志以及内存池)需要专用的 RAM 存储器。可以使用 osObjectNew()调用创建对象,并使用 osObjectDelete()调用删除对象。相关的对象内存需要在对象的生命周期中可用。

RTX5 为对象提供了三种不同的内存分配方法:

  • 全局内存池 为所有对象使用单个全局内存池。它很容易配置,但是当创建并销毁具有不同大小的对象时,可能存在内存碎片的缺点。
  • 特定于对象的内存池 为每个对象类型使用固定大小的内存池。该方法是时间确定性的,避免了内存碎片。
  • 静态对象内存 在编译期间保留内存并完全避免系统可能内存不足。这对于一些安全关键系统通常是必需的。

有可能在同一个应用程序中混合所有内存分配方法。

全局内存池

全局内存池分配内存区域中的所有对象。这种内存分配方法是 RTX5 的默认配置设置。

全局内存池用于所有对象

当内存池没有提供足够的内存时,对象的创建失败,并且相关的 osObjectNew()函数返回 NULL 。

在系统配置中启用。

特定于对象的内存池

特定于对象的内存池可避免内存碎片,并为每种对象类型提供专用固定大小的内存管理。这种类型的内存池是完全时间确定性的,这意味着对象创建和销毁总是需要相同的固定时间。由于固定大小的内存池是特定于对象类型的,因此可以简化对内存不足情况的处理。

每个对象类型一个内存池

特定于对象的内存池可针对每种对象类型启用,例如:使用 RTX 配置文件的互斥锁或线程:

  • 在线程对象的线程配置中启用。
  • 在定时器对象的定时器配置中启用。
  • 在事件标志配置中为事件对象启用。
  • 在互斥对象的互斥体配置中启用。
  • 在信号量的信号量配置中启用。
  • 在内存池的内存池配置中启用。
  • 在消息队列的消息队列配置中启用。

当内存池没有提供足够的内存时,对象的创建失败,并且相关的 osObjectNew()函数返回 NULL 。

静态对象内存

与动态内存分配相比,静态内存分配需要编译时分配对象内存。

为所有对象静态分配内存

静态内存分配可以通过在对象创建时使用属性提供用户定义的内存来实现,请参见手动用户定义的分配。请特别注意以下限制:

内存类型 要求
控制块 (osXxxAttr_t::cb_mem) 4 字节对齐。 osRtxThreadCbSize, osRtxTimerCbSize, osRtxEventFlagsCbSize, osRtxMutexCbSize, osRtxSemaphoreCbSize, osRtxMemoryPoolCbSize, osRtxMessageQueueCbSize 定义的大小。
线程堆栈 (osThreadAttr_t::stack_mem) 8 字节对齐。大小是应用程序特定的,即堆栈变量和帧的数量。
内存池 (osMemoryPoolAttr_t::mp_mem) 4 字节对齐。 使用 osRtxMemoryPoolMemSize 计算大小。
消息队列(osMessageQueueAttr_t::mq_mem) 4 字节对齐。 使用 osRtxMessageQueueMemSize 计算大小。

为了允许 RTX5 知道调试,即组件查看器识别控制块,这些块需要放置在单独的存储器部分中,即使用__attribute __((section(...)))。

RTX 对象 链接器部分
线程 .bss.os.thread.cb
定时器 .bss.os.timer.cb
事件标志 .bss.os.evflags.cb
互斥锁 .bss.os.mutex.cb
信号量 .bss.os.semaphore.cb
内存池 .bss.os.mempool.cb
消息队列 .bss.os.msgqueue.cb

以下代码示例显示如何使用静态内存创建 OS 对象。

代码示例:
/*----------------------------------------------------------------------------
* CMSIS-RTOS 'main' function template
*---------------------------------------------------------------------------*/
#include "RTE_Components.h"
#include CMSIS_device_header
#include "cmsis_os2.h"
//include rtx_os.h for types of RTX objects
#include "rtx_os.h"
//The thread function instanced in this example
void worker( void *arg)
{
while(1)
{
//work
osDelay(10000);
}
}
// Define objects that are statically allocated for worker thread 1
__attribute__((section( ".bss.os.thread.cb")))
osRtxThread_t worker_thread_tcb_1;
// Reserve two areas for the stacks of worker thread 1
// uint64_t makes sure the memory alignment is 8
uint64_t worker_thread_stk_1[64];
// Define the attributes which are used for thread creation
// Optional const saves RAM memory and includes the values in periodic ROM tests
const osThreadAttr_t worker_attr_1 = {
"wrk1",
&worker_thread_tcb_1,
sizeof(worker_thread_tcb_1),
&worker_thread_stk_1[0],
sizeof(worker_thread_stk_1),
0
};
// Define ID object for thread
/*----------------------------------------------------------------------------
* Application main thread
*---------------------------------------------------------------------------*/
void app_main ( void *argument) {
uint32_t param = NULL;
// Create an instance of the worker thread with static resources (TCB and stack)
th1 = osThreadNew(worker, &param, &worker_attr_1);
for (;;) {}
}
int main ( void) {
// System Initialization
SystemCoreClockUpdate();
// ...
osKernelInitialize(); // Initialize CMSIS-RTOS
osThreadNew(app_main, NULL, NULL); // Create application main thread
osKernelStart(); // Start thread execution
for (;;) {}
}

线程堆栈管理

对于没有浮点单元的 Cortex-M 处理器,线程上下文在本地堆栈上需要 64 个字节。

注意
对于带有FPU 的 Cortex-M4 / M7,线程上下文在本地堆栈上需要 200 个字节。 对于这些设备,默认堆栈空间应该增加到最小 300 字节。

每个线程都有一个单独的堆栈,为自动变量和函数调用嵌套返回地址保存线程上下文和堆栈空间。RTX 线程的堆栈大小可以灵活配置,如线程配置部分所述。RTX 提供了一个可配置的检查堆栈溢出和堆栈利用率。

低功耗操作

系统线程 osRtxIdleThread 可用于将系统切换至低功耗模式。进入低功耗模式的最简单形式是执行 __WFE 功能,使处理器进入休眠模式,等待事件。

代码示例:

#include "RTE_Components.h"
#include CMSIS_device_header /* Device definitions */
void osRtxIdleThread ( void) {
/* The idle demon is a system thread, running when no other thread is */
/* ready to run. */
for (;;) {
__WFE(); /* Enter sleep mode */
}
}
注意
__WFE()不是在每个 Cortex-M 实现中都是可用的。检查设备手册的可用性。

RTX 内核定时器节拍

RTX 使用通用 OS Tick API 来配置和控制其周期性内核刻度。

要使用替代定时器作为内核刻度定时器,只需实现 OS Tick API 的自定义版本即可。

注意
所提供的 OS Tick 实现必须确保所使用的定时器中断使用与服务中断相同(低)的优先级组,即 RTX 使用的中断不能相互抢占。 有关更多详细信息,请参阅计划程序部分。

无滴答低功耗操作

RTX5 为无滴答操作提供了扩展,对于使用 SysTick 定时器也被禁用的广泛低功耗模式的应用非常有用。为了在这种省电模式下提供时间标记,使用唤醒定时器来导出定时器间隔。CMSIS-RTOS2 函数 osKernelSuspend 和 osKernelResume 控制无滴答的操作。

使用这个函数允许 RTX5 线程调度器停止周期性内核刻度中断。当所有活动线程挂起时,系统进入掉电模式,并计算在这个掉电模式下可以停留多长时间。在省电模式下,处理器和外设可以关闭。只有唤醒定时器必须保持上电状态,因为该定时器负责在断电周期到期后唤醒系统。

无滴答操作由 osRtxIdleThread 线程控制。唤醒超时值在系统进入掉电模式之前设置。函数 osKernelSuspend 计算在 RTX Timer Ticks 中测量的唤醒超时; 该值用于设置在系统掉电模式下运行的唤醒定时器。

一旦系统恢复运行(通过唤醒超时或其他中断),RTX5 线程调度程序将以函数 osKernelResume 启动。参数 sleep_time 指定系统处于掉电模式的时间(在 RTX Timer Ticks 中)。

代码示例:

#include "msp.h" // Device header
/*----------------------------------------------------------------------------
* MSP432 Low-Power Extension Functions
*---------------------------------------------------------------------------*/
static void MSP432_LP_Entry( void) {
/* Enable PCM rude mode, which allows to device to enter LPM3 without waiting for peripherals */
PCM->CTL1 = PCM_CTL1_KEY_VAL | PCM_CTL1_FORCE_LPM_ENTRY;
/* Enable all SRAM bank retentions prior to going to LPM3 */
SYSCTL->SRAM_BANKRET |= SYSCTL_SRAM_BANKRET_BNK7_RET;
__enable_interrupt();
NVIC_EnableIRQ(RTC_C_IRQn);
/* Do not wake up on exit from ISR */
SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
/* Setting the sleep deep bit */
SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk);
}
static volatile unsigned int tc;
static volatile 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; // Unlock RTC key protected registers
RTC_C->PS0CTL &= ~RTC_C_PS0CTL_RT0PSIFG;
RTC_C->CTL0 = 0;
SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk);
}
}
uint32_t g_enable_sleep = 0;
void osRtxIdleThread ( void) {
for (;;) {
tc_wakeup = osKernelSuspend();
/* Is there some time to sleep? */
if (tc_wakeup > 0) {
tc = 0;
/* Enter the low power state */
MSP432_LP_Entry();
__WFE();
}
/* Adjust the kernel ticks with the amount of ticks slept */
}
}
注意
__WFE()不是在每个 ARM Cortex-M 实现中都是可用的。检查设备手册的可用性。使用 __WFI()的替代方案还有其他问题,请注意http://www.keil.com/support/docs/3591.htm 。

RTX5 头文件

CMSIS-RTOS2 API 的每个实现都可以带来自己的附加功能。RTX5 增加了一些空闲功能,用于错误通知和特殊的系统定时器功能。 它也使用宏来控制块和内存大小。

如果您的应用程序代码中需要一些 RTX 特定功能,请包括头文件 rtx_os.h:

/*
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -----------------------------------------------------------------------------
*
* Project: CMSIS-RTOS RTX
* Title: RTX OS definitions
*
* -----------------------------------------------------------------------------
*/
#ifndef RTX_OS_H_
#define RTX_OS_H_
#include <stdint.h>
#include <stddef.h>
#include "cmsis_os2.h"
#ifdef __cplusplus
extern "C"
{
#endif
/// Kernel Information
#define osRtxVersionAPI 20010002 ///< API version (2.1.2)
#define osRtxVersionKernel 50030000 ///< Kernel version (5.3.0)
#define osRtxKernelId "RTX V5.3.0" ///< Kernel identification string
// ==== Common definitions ====
/// Object Identifier definitions
#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
/// Object State definitions (except for Threads and Timers)
#define osRtxObjectInactive 0x00U
#define osRtxObjectActive 0x01U
/// Object Flags definitions
#define osRtxFlagSystemObject 0x01U
#define osRtxFlagSystemMemory 0x02U

// ==== Kernel definitions ====
/// Kernel State definitions
#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)
// ==== Thread definitions ====
/// Thread State definitions (extending osThreadState)
#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 ((uint8_t)(osRtxThreadBlocked | 0x10U))
#define osRtxThreadWaitingJoin ((uint8_t)(osRtxThreadBlocked | 0x20U))
#define osRtxThreadWaitingThreadFlags ((uint8_t)(osRtxThreadBlocked | 0x30U))
#define osRtxThreadWaitingEventFlags ((uint8_t)(osRtxThreadBlocked | 0x40U))
#define osRtxThreadWaitingMutex ((uint8_t)(osRtxThreadBlocked | 0x50U))
#define osRtxThreadWaitingSemaphore ((uint8_t)(osRtxThreadBlocked | 0x60U))
#define osRtxThreadWaitingMemoryPool ((uint8_t)(osRtxThreadBlocked | 0x70U))
#define osRtxThreadWaitingMessageGet ((uint8_t)(osRtxThreadBlocked | 0x80U))
#define osRtxThreadWaitingMessagePut ((uint8_t)(osRtxThreadBlocked | 0x90U))
/// Thread Flags definitions
#define osRtxThreadFlagDefStack 0x10U ///< Default Stack flag
/// Stack Marker definitions
#define osRtxStackMagicWord 0xE25A2EA5U ///< Stack Magic Word (Stack Base)
#define osRtxStackFillPattern 0xCCCCCCCCU ///< Stack Fill Pattern
/// Thread Control Block
typedef struct osRtxThread_s {
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
uint8_t attr; ///< Object Attributes
const char *name; ///< Object Name
struct osRtxThread_s *thread_next; ///< Link pointer to next Thread in Object list
struct osRtxThread_s *thread_prev; ///< Link pointer to previous Thread in Object list
struct osRtxThread_s *delay_next; ///< Link pointer to next Thread in Delay list
struct osRtxThread_s *delay_prev; ///< Link pointer to previous Thread in Delay list
struct osRtxThread_s *thread_join; ///< Thread waiting to Join
uint32_t delay; ///< Delay Time
int8_t priority; ///< Thread Priority
int8_t priority_base; ///< Base Priority
uint8_t stack_frame; ///< Stack Frame (EXC_RETURN[7..0])
uint8_t flags_options; ///< Thread/Event Flags Options
uint32_t wait_flags; ///< Waiting Thread/Event Flags
uint32_t thread_flags; ///< Thread Flags
struct osRtxMutex_s *mutex_list; ///< Link pointer to list of owned Mutexes
void *stack_mem; ///< Stack Memory
uint32_t stack_size; ///< Stack Size
uint32_t sp; ///< Current Stack Pointer
uint32_t thread_addr; ///< Thread entry address
uint32_t tz_memory; ///< TrustZone Memory Identifier
// ==== Timer definitions ====
/// Timer State definitions
#define osRtxTimerInactive 0x00U ///< Timer Inactive
#define osRtxTimerStopped 0x01U ///< Timer Stopped
#define osRtxTimerRunning 0x02U ///< Timer Running
/// Timer Type definitions
#define osRtxTimerPeriodic ((uint8_t)osTimerPeriodic)
/// Timer Function Information
typedef struct {
osTimerFunc_t func; ///< Function Pointer
void *arg; ///< Function Argument
/// Timer Control Block
typedef struct osRtxTimer_s {
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
uint8_t type; ///< Timer Type (Periodic/One-shot)
const char *name; ///< Object Name
struct osRtxTimer_s *prev; ///< Pointer to previous active Timer
struct osRtxTimer_s *next; ///< Pointer to next active Timer
uint32_t tick; ///< Timer current Tick
uint32_t load; ///< Timer Load value
osRtxTimerFinfo_t finfo; ///< Timer Function Info
// ==== Event Flags definitions ====
/// Event Flags Control Block
typedef struct {
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
uint8_t reserved;
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Waiting Threads List
uint32_t event_flags; ///< Event Flags
// ==== Mutex definitions ====
/// Mutex Control Block
typedef struct osRtxMutex_s {
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
uint8_t attr; ///< Object Attributes
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Waiting Threads List
osRtxThread_t *owner_thread; ///< Owner Thread
struct osRtxMutex_s *owner_prev; ///< Pointer to previous owned Mutex
struct osRtxMutex_s *owner_next; ///< Pointer to next owned Mutex
uint8_t lock; ///< Lock counter
uint8_t padding[3];
// ==== Semaphore definitions ====
/// Semaphore Control Block
typedef struct {
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
uint8_t reserved;
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Waiting Threads List
uint16_t tokens; ///< Current number of tokens
uint16_t max_tokens; ///< Maximum number of tokens
// ==== Memory Pool definitions ====
/// Memory Pool Information
typedef struct {
uint32_t max_blocks; ///< Maximum number of Blocks
uint32_t used_blocks; ///< Number of used Blocks
uint32_t block_size; ///< Block Size
void *block_base; ///< Block Memory Base Address
void *block_lim; ///< Block Memory Limit Address
void *block_free; ///< First free Block Address
/// Memory Pool Control Block
typedef struct {
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
uint8_t reserved;
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Waiting Threads List
osRtxMpInfo_t mp_info; ///< Memory Pool Info
// ==== Message Queue definitions ====
/// Message Control Block
typedef struct osRtxMessage_s {
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
uint8_t priority; ///< Message Priority
struct osRtxMessage_s *prev; ///< Pointer to previous Message
struct osRtxMessage_s *next; ///< Pointer to next Message
/// Message Queue Control Block
typedef struct {
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
uint8_t reserved;
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Waiting Threads List
osRtxMpInfo_t mp_info; ///< Memory Pool Info
uint32_t msg_size; ///< Message Size
uint32_t msg_count; ///< Number of queued Messages
osRtxMessage_t *msg_first; ///< Pointer to first Message
osRtxMessage_t *msg_last; ///< Pointer to last Message
// ==== Generic Object definitions ====
/// Generic Object Control Block
typedef struct {
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
uint8_t reserved;
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Threads List
// ==== OS Runtime Information definitions ====
/// OS Runtime Information structure
typedef struct {
const char *os_id; ///< OS Identification
uint32_t version; ///< OS Version
struct { ///< Kernel Info
uint8_t state; ///< State
volatile uint8_t blocked; ///< Blocked
uint8_t pendSV; ///< Pending SV
uint8_t reserved;
uint32_t tick; ///< Tick counter
} kernel;
int32_t tick_irqn; ///< Tick Timer IRQ Number
struct { ///< Thread Info
struct { ///< Thread Run Info
osRtxThread_t *curr; ///< Current running Thread
osRtxThread_t *next; ///< Next Thread to Run
} run;
osRtxObject_t ready; ///< Ready List Object
osRtxThread_t *idle; ///< Idle Thread
osRtxThread_t *delay_list; ///< Delay List
osRtxThread_t *wait_list; ///< Wait List (no Timeout)
osRtxThread_t *terminate_list; ///< Terminate Thread List
struct { ///< Thread Round Robin Info
osRtxThread_t *thread; ///< Round Robin Thread
uint32_t tick; ///< Round Robin Time Tick
uint32_t timeout; ///< Round Robin Timeout
} robin;
} thread;
struct { ///< Timer Info
osRtxTimer_t *list; ///< Active Timer List
osRtxThread_t *thread; ///< Timer Thread
osRtxMessageQueue_t *mq; ///< Timer Message Queue
void (*tick)(void); ///< Timer Tick Function
} timer;
struct { ///< ISR Post Processing Queue
uint16_t max; ///< Maximum Items
uint16_t cnt; ///< Item Count
uint16_t in; ///< Incoming Item Index
uint16_t out; ///< Outgoing Item Index
void **data; ///< Queue Data
} isr_queue;
struct { ///< ISR Post Processing functions
void (*thread)( osRtxThread_t*); ///< Thread Post Processing function
void (*event_flags)( osRtxEventFlags_t*); ///< Event Flags Post Processing function
void (*semaphore)( osRtxSemaphore_t*); ///< Semaphore Post Processing function
void (*memory_pool)( osRtxMemoryPool_t*); ///< Memory Pool Post Processing function
void (*message)( osRtxMessage_t*); ///< Message Post Processing function
} post_process;
struct { ///< Memory Pools (Variable Block Size)
void *stack; ///< Stack Memory
void *mp_data; ///< Memory Pool Data Memory
void *mq_data; ///< Message Queue Data Memory
void *common; ///< Common Memory
} mem;
struct { ///< Memory Pools (Fixed Block Size)
osRtxMpInfo_t *stack; ///< Stack for Threads
osRtxMpInfo_t *thread; ///< Thread Control Blocks
osRtxMpInfo_t *timer; ///< Timer Control Blocks
osRtxMpInfo_t *event_flags; ///< Event Flags Control Blocks
osRtxMpInfo_t *mutex; ///< Mutex Control Blocks
osRtxMpInfo_t *semaphore; ///< Semaphore Control Blocks
osRtxMpInfo_t *memory_pool; ///< Memory Pool Control Blocks
osRtxMpInfo_t *message_queue; ///< Message Queue Control Blocks
} mpi;
extern osRtxInfo_t osRtxInfo; ///< OS Runtime Information
/// OS Runtime Object Memory Usage structure
typedef struct {
uint32_t cnt_alloc; ///< Counter for alloc
uint32_t cnt_free; ///< Counter for free
uint32_t max_used; ///< Maximum used
/// OS Runtime Object Memory Usage variables
// ==== OS API definitions ====
// Object Limits definitions
#define osRtxThreadFlagsLimit 31U ///< number of Thread Flags available per thread
#define osRtxEventFlagsLimit 31U ///< number of Event Flags available per object
#define osRtxMutexLockLimit 255U ///< maximum number of recursive mutex locks
#define osRtxSemaphoreTokenLimit 65535U ///< maximum number of tokens per semaphore
// Control Block sizes
#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)
/// Memory size in bytes for Memory Pool storage.
/// \param block_count maximum number of memory blocks in memory pool.
/// \param block_size memory block size in bytes.
#define osRtxMemoryPoolMemSize(block_count, block_size) \
(4*(block_count)*(((block_size)+3)/4))
/// Memory size in bytes for Message Queue storage.
/// \param msg_count maximum number of messages in queue.
/// \param msg_size maximum message size in bytes.
#define osRtxMessageQueueMemSize(msg_count, msg_size) \
(4*(msg_count)*(3+(((msg_size)+3)/4)))
// ==== OS External Functions ====
// OS Error Codes
#define osRtxErrorStackUnderflow 1U ///< Stack overflow, i.e. stack pointer below its lower memory limit for descending stacks.
#define osRtxErrorISRQueueOverflow 2U ///< ISR Queue overflow detected when inserting object.
#define osRtxErrorTimerQueueOverflow 3U ///< User Timer Callback Queue overflow detected for timer.
#define osRtxErrorClibSpace 4U ///< Standard C/C++ library libspace not available: increase \c OS_THREAD_LIBSPACE_NUM.
#define osRtxErrorClibMutex 5U ///< Standard C/C++ library mutex initialization failed.
/// OS Error Callback function
extern uint32_t osRtxErrorNotify (uint32_t code, void *object_id);
/// OS Idle Thread
extern void osRtxIdleThread ( void *argument);
/// OS Exception handlers
extern void SVC_Handler ( void);
extern void PendSV_Handler ( void);
extern void SysTick_Handler ( void);
// ==== OS External Configuration ====
/// OS Configuration flags
#define osRtxConfigPrivilegedMode (1UL<<0) ///< Threads in Privileged mode
#define osRtxConfigStackCheck (1UL<<1) ///< Stack overrun checking
#define osRtxConfigStackWatermark (1UL<<2) ///< Stack usage Watermark
/// OS Configuration structure
typedef struct {
uint32_t flags; ///< OS Configuration Flags
uint32_t tick_freq; ///< Kernel Tick Frequency
uint32_t robin_timeout; ///< Round Robin Timeout Tick
struct { ///< ISR Post Processing Queue
void **data; ///< Queue Data
uint16_t max; ///< Maximum Items
uint16_t padding;
} isr_queue;
struct { ///< Memory Pools (Variable Block Size)
void *stack_addr; ///< Stack Memory Address
uint32_t stack_size; ///< Stack Memory Size
void *mp_data_addr; ///< Memory Pool Memory Address
uint32_t mp_data_size; ///< Memory Pool Memory Size
void *mq_data_addr; ///< Message Queue Data Memory Address
uint32_t mq_data_size; ///< Message Queue Data Memory Size
void *common_addr; ///< Common Memory Address
uint32_t common_size; ///< Common Memory Size
} mem;
struct { ///< Memory Pools (Fixed Block Size)
osRtxMpInfo_t *stack; ///< Stack for Threads
osRtxMpInfo_t *thread; ///< Thread Control Blocks
osRtxMpInfo_t *timer; ///< Timer Control Blocks
osRtxMpInfo_t *event_flags; ///< Event Flags Control Blocks
osRtxMpInfo_t *mutex; ///< Mutex Control Blocks
osRtxMpInfo_t *semaphore; ///< Semaphore Control Blocks
osRtxMpInfo_t *memory_pool; ///< Memory Pool Control Blocks
osRtxMpInfo_t *message_queue; ///< Message Queue Control Blocks
} mpi;
uint32_t thread_stack_size; ///< Default Thread Stack Size
const
osThreadAttr_t *idle_thread_attr; ///< Idle Thread Attributes
const
osThreadAttr_t *timer_thread_attr; ///< Timer Thread Attributes
const
osMessageQueueAttr_t *timer_mq_attr; ///< Timer Message Queue Attributes
uint32_t timer_mq_mcnt; ///< Timer Message Queue maximum Messages
extern const osRtxConfig_t osRtxConfig; ///< OS Configuration
#ifdef __cplusplus
}
#endif
#endif // RTX_OS_H_

超时值

超时值是多个 osXxx 函数的参数,以便有时间解析请求。超时值为 0 意味着即使没有资源可用,RTOS 也不会立即等待并立即返回。osWaitForever 的超时值意味着 RTOS 无限等待,直到资源可用。或者迫使线程恢复使用 osThreadResume,这是不鼓励的。

超时值指定在时间延迟消逝之前定时器滴答的数量。该值是一个上限,取决于自上次计时器滴答后所经过的实际时间。

例子:

  • 超时值0:即使没有资源可用,系统也不会等待 RTOS 功能立即返回。
  • 超时值1:系统等待直到发生下一个定时器滴答; 取决于先前的定时器滴答,这可能是一个非常短的等待时间。
  • 超时值2:实际等待时间在 1 到 2 个定时器滴答声之间。
  • 超时值 osWaitForever:系统等待无限,直到资源变为可用。
使用 osDelay()的超时示例

来自中断服务例程的调用

可以从线程和中断服务程序(ISR)调用以下 CMSIS-RTOS2 函数:

无法从 ISR 调用的函数正在验证中断状态并返回状态码 osErrorISR,以防从 ISR 上下文中调用它们。在某些实现中,可能会使用 HARD_FAULT 向量捕获此条件。

猜你喜欢

转载自blog.csdn.net/u012325601/article/details/80082039