FreeRTOS任务切换

发布时间:2023年12月28日

一、PendSV 异常

PendSV(Pended Service Call,可挂起服务调用),PendSV的中断优先级是可以编程的,用户可以根据实际的需求,对其进行配置。PendSV 与 SVC 不同,PendSV 的中断是非实时的,即 PendSV 的中断可以在更高优先级的中断中触发,但是在更高优先级中断结束后才执行。

任务切换概念:在典型的 RTOS 中,任务的处理时间被分为多个时间片,OS 内核的执行可以有两种触发方式,一种是通过在应用任务中通过 SVC 指令触发,例如在应用任务在等待某个时间发生而需要停止的时候,那么就可以通过 SVC 指令来触发 OS内核的执行,以切换到其他任务;第二种方式是,SysTick 周期性的中断,来触发 OS 内核的执行。


二、PendSV 中断服务函数

????????FreeRTOS 在 PendSV 的中断中,完成任务切换,PendSV 的中断服务函数由 FreeRTOS 编
写,将 PendSV 的中断服务函数定义成函数 xPortPendSVHandler()。

? ? ? ? 针 对 ARM Cortex-M3 和 针 对 ARM Cortex-M4 和 ARM Cortex-M7 内 核 的 函 数xPortPendSVHandler()稍有不同,其主要原因在于 ARM Cortex-M4 和 ARM Cortex-M7 内核具有
浮点单元,因此在进行任务切换的时候,还需考虑是否保护和恢复浮点寄存器的值

任务切换的大概内容:(1)保存上文。(2)恢复下文。

具体流程如下:

  1. 触发任务切换异常(PendSV中断)后,硬件自动使用PSP堆栈指针将寄存器xPSR、PC、LR、R12、R3-R0压入任务对战
  2. 进入异常后,CPU使用MSP。
  3. 寄存器R11-R4,通过软件使用PSP压栈。
  4. 进入临界区。
  5. 调用vTaskSwitchContext()函数找出下一个要执行的任务更新到pxCurrentTCB
  6. 退出临界。
  7. 通过pxCurrentTCB获取到新的任务栈顶。
  8. 使用新的任务栈顶指针出栈R11-R4。
  9. 更新当前任务栈顶指针到PSP。
  10. 退出异常,硬件使用PSP出栈xPSR、PC、LR、R12、R3-R0。
  11. 进入新的任务了。

? ?
三、FreeRTOS 确定下一个要运行的任务

在 PendSV 的中断服务函数中,调用了函数 vTaskSwitchContext()来确定写一个要运行的任务。


四、PendSV 异常何时触发

调用函数 portYIELD()

#define portYIELD() \
{  \
/* 设置中断控制状态寄存器,以触发 PendSV 异常 */  \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
__dsb( portSY_FULL_READ_WRITE );  \
__isb( portSY_FULL_READ_WRITE );  \
}

五、溢出检查

任务切换时会对任务栈进行检查,是否溢出。taskCHECK_FOR_STACK_OVERFLOW();

有两种方案可检查栈溢出,可同时使用:(以堆栈向下生长为例)

  1. 方案1:检查任务栈顶指针。如果任务上文压栈后,任务栈顶pxCurrentTCB->pxTopOfStack比栈起始pxCurrentTCB->pxStack还小,说明已经栈溢出了。

  2. 方案2:栈起始内容检查。初始化时,把任务栈其实pxCurrentTCB->pxStack一部分栈内存初始化为特定的值。在每次任务切换时,检查下这几个值是否为原有值,如果不是,说明被踩栈了;如果不是,可初步判断任务栈安全(不能绝对判断当前任务栈安全)

文章来源:https://blog.csdn.net/m0_61973119/article/details/135261348
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。