xsemaphoretake返回_干货 | FreeRTOS学习笔记——中断与任务切换

原标题:干货 | FreeRTOS学习笔记——中断与任务切换

EEWorld

在FreeRTOS具备了任务的内存资源——堆栈管理机制,能根据任务状态和优先级进行CPU执行的上下文切换,并提供了任务间通信渠道以实现必要的任务同步和互斥之后,多个任务可以协同起来工作了。不过,既然名称叫做 Real-Time (实时)的操作系统,还需要能对外部(硬件)事件作出快速的响应。尤其是对于单片机上的应用,在一个硬件中断(IRQ)产生以后,立即唤醒某个任务来处理这个事件是操作系统必须要支持的。从任务的角度来看,其实有很多任务是需要根据硬件上的事件(比如传输完成,设备就绪,接收到数据等)来被调度的,否则它将不停测试硬件设备状态寄存器标志位,浪费CPU时间。

FreeRTOS 的时间片管理,其实背后就是借用了定时器中断。不然不可能一个任务执行时没有申请调度就被打断,去执行其它同一优先级的任务。类似的,任何硬件中断发生时都会执行相应的中断服务程序(Interrupt Service Routine, ISR, 又叫IRQ Handler),在ISR执行完之后是返回当前任务,还是调度执行其它任务?这完全由ISR来决定。

1. ISR 独立于所有任务

尽管从效果上看,ISR,即中断服务程序是为了某个任务的功能在服务的,务必先强调一下:ISR 的代码不属于 FreeRTOS 任何一个任务代码的部分。每个 ISR 都是一个C语言函数,但它不是一个任务,也不会被任何一个任务所调用。

ISR对堆栈的使用与任务不同。前面的连载中已经介绍过,FreeRTOS 对每个任务分配了独立的堆栈空间,用于保存函数的局部变量等等。在发生中断时,CPU的某些寄存器会被保存到当前的堆栈里(而不是指定某任务的堆栈),然后开始执行ISR程序。如果当前是某个任务的代码正被执行,则会占用该任务的堆栈;如果当前是另外一个 ISR 的代码正在执行即发生中断嵌套,那么可能继续用更早被中断的任务的堆栈(注:这与平台有关。对于 ARM Cortex-m 系列平台上的实现,FreeRTOS 让任务运行在 thread mode, 使用PSP作堆栈指针,而 ISR 会切换到 handler mode, 使用MSP作为堆栈指针,于是所有 ISR 会共享一个堆栈)。

ISR的执行可以与FreeRTOS内核无关。只要在 ISR 中不使用 FreeRTOS 的API,那么 FreeRTOS 不会知道这个中断的发生,因为它不论当前堆栈在哪里,都能保存现场并在执行后恢复现场。同样,ISR 的执行本身也不会引起任何的任务切换。在将 FreeRTOS 代码引入到现有的工程时,原有的 ISR 不需要经过修改仍然可以运作。

ISR不改变当前任务的状态。尽管 IRQ 发生以后,当前运行着的任务执行被暂停,CPU转而执行 ISR 的代码,但当前任务的状态仍然是 Running,并不是变成其它状态——这与任务被抢占明显不同。哪怕是在 ISR 里面调用了 FreeRTOS 的 API, 使其它具有比当前任务更高优先级的任务被唤醒(变为Ready状态),在 ISR 返回之后才会经过任务切换操作,重新选择运行的任务。其实,ISR 也不知道当前运行的任务是什么,去主动改变当前任务状态没有意义。

2. Critical Section 概念

前面我在分析 FreeRTOS 实现细节的时候,多次遇到 taskENTER_CRITICAL() 和 taskEXIT_CRITICAL() 这两个调用。从名称来理解就是说,这时要做一个很要紧的操作,不允许被打断,比如要对任务状态列表进行访问。如果不这样处理的话,有可能中途要访问的数据被改写了,或者是数据改动未完成被其它任务或者 FreeRTOS 内核访问,都会造成错误的结果。于是,定义一段代码为 critical section, 前后用taskENTER_CRITICAL()和taskEXIT_CRITICAL() 保护起来,禁止任务调度,以

你可能感兴趣的:(xsemaphoretake返回_干货 | FreeRTOS学习笔记——中断与任务切换)