xPortPendSVHandler( void ) //任务切换函数
函数是由汇编代码实现的,下面是实现任务切换的源码:
以上代码都是对寄存器直接操作,首先,获取当前任务的TCB,与其他需要入栈的寄存器一起存入任务堆栈。其次,调用vTaskSwitchContext()函数查找下一个要运行的任务,并将全局变量pxCurrentTCB指向这个要运行的任务。最后,获取新任务的堆栈地址,相关寄存器出栈,PC寄存器恢复为新任务的任务函数,完成任务切换
1.将当前任务地址存入r3寄存器
获取当前激活任务的TCB任务控制块地址,将其存入到r2寄存器。
2.内核寄存器入栈![](https://img-blog.csdnimg.cn/bb6d988966574d20babc4912cf47347a.png)
3.将新的栈顶保存到任务TCB的第一个成员中![](https://img-blog.csdnimg.cn/75759f4f4cef408a95e529cc3b44d100.png)
4.寻找就绪列表中最高优先级任务![](https://img-blog.csdnimg.cn/47300c00d76a433893951d92162e22e7.png)
这里直接使用的是一个宏定义的函数进行查找就绪列表中最高优先级的任务
这个宏函数主要调用了两个函数,其中调用了portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities )函数,这里使用的是优化方法uxTopReadyPriority 的每个位号对应的是任务的优先级,任务就绪时,则将对应 的位置 1,反之则清零。列如:优先级 0、优先级 24 和优先级 25 这三个任务就绪,其中优先级为 25的任务优先级最高。利用前导零计算指令可以很快计算出就绪任务 中的最高优先级为:( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) ) = ( 31UL - ( uint32_t ) 6 ) = 25。
5.当前激活的任务TCB第一项中保存了任务堆栈的栈顶![](https://img-blog.csdnimg.cn/6806cdc05f4e41068908dd743b45b6b3.png)
6.内核寄存器出栈![](https://img-blog.csdnimg.cn/bdb2586e07fc4185980898ab61a48737.png)
7.跳转指令![](https://img-blog.csdnimg.cn/a4d38ab0fb56497f823d808c20d9721a.png)
参看:《FreeRTOS 内核实现与应用开发实战指南—基于野火 STM32 全系列(M3/4/7)开发板》
《嵌入式实时操作系统FreeROTS原理及应用》