目录
RTOS 系统的核心是任务管理,而任务管理的核心是任务切换,任务切换决定了任务的执行顺序,任务切换效率的高低也决定了一款系统的性能,尤其是对于实时操作系统;如果我们想要深入的了解 FreeRTOS 的运行过程,那么任务切换是必须要掌握的。
1. RendSV 异常
PendSV(可挂起的系统调用)异常对 OS 操作非常重要,其优先级可以通过编程设置。可以通过将中断控制和状态寄存器 ICSR 的 bit28,也就是 PendSV 的挂起位置 1 来触发 PendSV 中断。与 SVC 异常不同,PendSV 是不精确的,因此它的挂起状态可在更高优先级异常处理内设置,且会在高优先级处理完成后执行。
这里首先介绍几个定义:
SVC:
在 FreeRTOS 中,SVC 代表 Supervisor Call,它是一种特殊的指令或中断,用于实现操作系统的服务调用。当应用程序需要操作系统提供的特权功能时,可以通过 SVC 指令触发一个软中断,并将参数传递给操作系统内核。操作系统接收到 SVC 中断后,会根据参数执行相应的服务,并返回结果给应用程序。
SVC 指令通常用于实现操作系统的系统调用和任务切换等功能。通过 SVC,应用程序可以请求操作系统进行资源分配、任务管理、中断处理等操作,从而实现多任务协作和资源管理。在 FreeRTOS 中,SVC 指令的实现可以是硬件相关的,在不同的平台上可能存在差异。
PendSV:
在 FreeRTOS 中,PendSV(Pending Supervisor Call)是一个与任务调度相关的中断。它是由 ARM Cortex-M 处理器架构提供的一种中断请求。PendSV 中断用于实现任务切换和任务调度,通常与 SysTick 定时器一起使用。当 PendSV 中断触发时,它会被操作系统内核用于执行任务切换和调度的相关操作。在 FreeRTOS 中,当一个任务的时间片用完或发生更高优先级的任务就绪时,操作系统会通过 PendSV 中断来触发任务切换。PendSV 中断的优先级要设置为最低优先级,这样可以确保 PendSV 中断始终处于最低优先级,不会被其他中断打断。
当 PendSV 中断发生时,操作系统会保存当前任务的上下文信息,包括任务的寄存器值、堆栈指针等,然后加载下一个要执行的任务的上下文信息,切换到新的任务继续执行。这样实现了任务的切换和调度。
需要注意的是,PendSV 中断的执行是由操作系统内核负责的,应用程序开发者一般无需直接操作 PendSV 中断,而是使用 FreeRTOS 提供的任务管理接口和调度器来进行任务的创建、删除和切换。
系统调用:
在 FreeRTOS 中,系统调用是通过特定的函数接口来访问操作系统提供的功能和服务。通过系统调用,应用程序可以请求操作系统执行特定的操作,如任务管理、资源管理、时间管理等。系统调用函数是操作系统内核中提供的 API,用于与应用程序进行交互。
FreeRTOS 中常见的系统调用包括但不限于以下几类:
任务管理:通过系统调用函数可以创建任务、删除任务、挂起任务、恢复任务、设置任务优先级等。
资源管理:系统调用函数可以申请和释放内存、信号量、消息队列、事件标志组等资源,进行资源的分配和管理。
中断管理:通过系统调用函数可以使能和禁用中断,配置中断优先级,注册中断处理程序等。
时间管理:系统调用函数可以获取当前时钟值、延时指定时间、延时等待事件等。
具体的系统调用接口和函数名称可以参考 FreeRTOS 的官方文档或相关的编程指南。
利用该特性,若将 PendSV 设置为最低的异常优先级,可以让 PendSV 异常处理在所有其他中断处理完成后执行,这对于上下文切换非常有用,也是各种 OS 设计中的关键。将 PendSV 设置为最低优先级以后,PendSV 是不会被打断的。
在具有嵌入式 OS 的典型系统中,处理时间被划分为了多个时间片。倘若系统只有两个任务,则这两个任务会交替执行,如下图所示:

上述图片的意思就是:线程任务 A ,在系统滴答定时器中断 SysTick 中进行上下文切换,每次都会切换到另外一个任务;因为上图只有两个任务,所以这两个任务进行循环切换。
上下文切换被触发的场合可以是:
- 执行一个系统调用
- 系统滴答定时器(SysTick)中断
在 OS 中,任务调度器决定是否应该执行上下文切换,正如上图所示:任务切换都是由 SysTick 中断中执行的,每次它都会决定切换到一个不同的任务中。
SysTick 中断:
在 FreeRTOS 中,SysTick 是一个系统定时器,它是在硬件层面上提供的一个计时器。SysTick 定时器通常用于操作系统的时间管理和任务调度。
SysTick 定时器在 FreeRTOS 中常用于两个方面:
任务调度:SysTick 定时器可以被配置为以固定时间间隔中断的方式运行。每当 SysTick 定时器中断发生时,操作系统内核会进行调度,检查任务优先级、任务状态和时间片等信息,从而决定下一个要执行的任务。这样可以实现多任务的时间共享和调度。
操作系统节拍:SysTick 定时器还可以被配置为以一定频率产生中断,作为操作系统的节拍信号。这个节拍信号在操作系统的时间管理中起关键作用,用于计算任务的延时时间、超时判断和时间片轮转等。
在 FreeRTOS 中,通过配置 SysTick 定时器的初始化参数,可以设置定时器的中断频率和工作模式。
若中断请求(IRQ)在 SysTick 异常前产生,则 SysTick 异常可能会抢占 IRQ 的处理,在这种情况下,OS 不应该执行上下文切换,否则中断请求 IRQ 就会被延迟(之所以被延迟是很好理解的,如果中断请求 IRQ 在 SysTick 异常前产生,那么 SysTick 异常会抢占 IRQ 的处理,那么线程无法进入 IRQ 中断,会直接进入 SysTick 异常,这样中断请求 IRQ 会被延迟),而且在真实系统中延迟时间还往往不可预知——任何有一丁点实时要求的系统都决不能容忍这种事。
对于 Cortex-M3 和 Cortex-M4 处理器来说,当存在活跃的异常服务时,设计默认不允许返回到线程模式,若存在活跃中断服务,且 OS 试图返回到线程模式,则将触发用法 fault,如下图所示:

意思是:
在 Cortex-M3 和 Cortex-M4 处理器中,当存在活跃的异常服务(包括中断服务和其他异常处理)时,按照设计,默认情况下不允许返回到线程模式。
活跃的异常服务是指当前正在执行的中断服务例程或其他异常处理例程。这些例程通常会使用堆栈储存相关的寄存器值和局部变量。当处理器处于异常服务状态时,不允许在异常服务例程执行完毕后返回到线程模式。
当操作系统(OS)试图将处理器从异常服务状态切换回线程模式时,如果仍存在活跃的中断服务,即还未完成或返回到线程模式,则会触发用法错误(Usage Fault)。用法错误是一种处理器异常,指示了不合法的指令或操作。
这种设计决策是为了确保异常服务的完整性和可靠性。因为线程模式可能对栈帧有不同的管理需求,与异常服务模式存在区别,因此当存在活跃中断服务时,不允许直接返回到线程模式。在遇到这种情况时,需要确保中断服务完全执行完毕或返回到线程模式后才能进行任务的切换和调度。此外,开发者还可以通过使用特定的操作系统机制(如临界区保护)来保证中断服务和线程模式之间的同步和正确性。
在一些 OS 设计中,要解决这个问题,可以在运行中断服务时不执行上下文切换,此时可以检查栈帧中的压栈 xPSR 或 NVIC 中的中断活跃状态寄存器。

文章详细阐述了FreeRTOS操作系统中的任务切换原理,包括PendSV异常在任务调度中的作用,如何通过系统调用和SysTick中断触发任务切换,以及PendSV中断服务函数如何执行上下文切换。此外,还介绍了时间片调度的概念和实验,展示了在特定优先级任务下的执行情况。
最低0.47元/天 解锁文章
1869

被折叠的 条评论
为什么被折叠?



