赞
踩
内核的许多方面都是可配置的,并在适用的情况下提及配置选项。
由于 main 不再是一个线程,RTX5 在到达 main 之前不会干扰系统启动。一旦执行到达 main(),建议初始化硬件并启动内核。这也反映在随 RTX5 组件提供的用户代码模板文件 “CMSIS-RTOS2” 主 “功能” 中。
你的应用程序的 main()应该按给定的顺序至少实现以下内容:
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 对象。
代码示例:对于没有浮点单元的 Cortex-M 处理器,线程上下文在本地堆栈上需要 64 个字节。
每个线程都有一个单独的堆栈,为自动变量和函数调用嵌套返回地址保存线程上下文和堆栈空间。RTX 线程的堆栈大小可以灵活配置,如线程配置部分所述。RTX 提供了一个可配置的检查堆栈溢出和堆栈利用率。
系统线程 osRtxIdleThread 可用于将系统切换至低功耗模式。进入低功耗模式的最简单形式是执行 __WFE 功能,使处理器进入休眠模式,等待事件。
代码示例:
__WFE()不是在每个 Cortex-M 实现中都是可用的。检查设备手册的可用性。
RTX 使用通用 OS Tick API 来配置和控制其周期性内核刻度。
要使用替代定时器作为内核刻度定时器,只需实现 OS Tick API 的自定义版本即可。
RTX5 为无滴答操作提供了扩展,对于使用 SysTick 定时器也被禁用的广泛低功耗模式的应用非常有用。为了在这种省电模式下提供时间标记,使用唤醒定时器来导出定时器间隔。CMSIS-RTOS2 函数 osKernelSuspend 和 osKernelResume 控制无滴答的操作。
使用这个函数允许 RTX5 线程调度器停止周期性内核刻度中断。当所有活动线程挂起时,系统进入掉电模式,并计算在这个掉电模式下可以停留多长时间。在省电模式下,处理器和外设可以关闭。只有唤醒定时器必须保持上电状态,因为该定时器负责在断电周期到期后唤醒系统。
无滴答操作由 osRtxIdleThread 线程控制。唤醒超时值在系统进入掉电模式之前设置。函数 osKernelSuspend 计算在 RTX Timer Ticks 中测量的唤醒超时; 该值用于设置在系统掉电模式下运行的唤醒定时器。
一旦系统恢复运行(通过唤醒超时或其他中断),RTX5 线程调度程序将以函数 osKernelResume 启动。参数 sleep_time 指定系统处于掉电模式的时间(在 RTX Timer Ticks 中)。
代码示例:
__WFE()不是在每个 ARM Cortex-M 实现中都是可用的。检查设备手册的可用性。使用 __WFI()的替代方案还有其他问题,请注意http://www.keil.com/support/docs/3591.htm 。
CMSIS-RTOS2 API 的每个实现都可以带来自己的附加功能。RTX5 增加了一些空闲功能,用于错误通知和特殊的系统定时器功能。 它也使用宏来控制块和内存大小。
如果您的应用程序代码中需要一些 RTX 特定功能,请包括头文件 rtx_os.h:
超时值是多个 osXxx 函数的参数,以便有时间解析请求。超时值为 0 意味着即使没有资源可用,RTOS 也不会立即等待并立即返回。osWaitForever 的超时值意味着 RTOS 无限等待,直到资源可用。或者迫使线程恢复使用 osThreadResume,这是不鼓励的。
超时值指定在时间延迟消逝之前定时器滴答的数量。该值是一个上限,取决于自上次计时器滴答后所经过的实际时间。
例子:
可以从线程和中断服务程序(ISR)调用以下 CMSIS-RTOS2 函数:
无法从 ISR 调用的函数正在验证中断状态并返回状态码 osErrorISR,以防从 ISR 上下文中调用它们。在某些实现中,可能会使用 HARD_FAULT 向量捕获此条件。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。