FreeRTOS笔记(八)任务切换


上一文链接:FreeRTOS笔记(七)开启调度器

  在上一文中,提到了pxCurrentTCB会在任务创建和任务切换的时候被改变,并且查看了任务创建,现在再来查看任务切换,FreeRTOS的任务切换依赖一个PendSV中断,提到PendSV,不得不提一个相关的中断SVC

01 - SVC和PendSV

1.1 - SVC中断

  SVC是系统服务调用,这是一个改名,在ARM7~ARM11这些系列中,系统服务调用称为SWI,可以进入ARM处理器的其中一个异常模式,操作系统特权模式,在这个模式下可以操作任何硬件资源。
  在ARM针对高性能低功耗的新系列CM3/4中,SWI被改名为SVC,只是名字变了,其余内容都一样。

1.2 - PendSV中断

  与SVC相关的是PendSV中断,称为可悬起的系统调用。两者不同之处在于响应速度,SVC中断是要求被立刻得到响应的,而PendSV中断则可以延迟被响应,也就是PendSV中断可以先“悬起”,待其它重要中断被执行完成后再处理它。

  悬起PendSV的方法是:手工往NVIC的PendSV悬起寄存器中写1,悬起后,如果优先级不够其它中断高,则将延迟等待执行

  PendSV中断这种可以被延迟执行的特性,非常适合用于任务切换。原因很简单,当一个外部中断正在被执行的时候,如果此时进行任务切换,意味着要先执行任务,而中断要被延迟执行,这违背了FreeRTOS实时操作系统的概念,所以绝不允许在中断活跃期进行任务切换。
  一个简单的解决办法是使用SysTick周期性中断进行任务切换,而在切换之前检查是否有中断执行,但是弊端在于,如果这个中断的频率和SysTick中断几乎一样,那么任务切换将很长一段时间得不到执行.
  改良的办法是在SysTick中断里面悬起PendSV中断,等这些重要的中断执行完成后,再进行任务切换,《M3 权威指南》中的一个图片很好地解释了这个过程

02 - 任务切换

2.1 - 上下文

  任务切换的本质是任务上下文的切换,上文其实就是待切出任务(当前正在运行)的TCB和相关寄存器状态,下文就是待切入(抢占)任务的TCB和相关寄存器状态。
  寄存器是宝贵资源,某个时刻只能储存某个任务的值,要使得当前任务的寄存器状态得到保留,需要把当前的寄存器压栈,恢复的时候再弹出到寄存器,这样一个寄存器就可以不断使用了。

2.2 - 切换场合

  发生任务切换的场合有2个,一个是优先级抢占,另一个是时间片轮转。在FreeRTOS中的表达为:
  系统调用 ⇌ 优先级抢占
  SysTick中断 ⇌ 时间片轮转
  其中优先级抢占不一定是高优先级抢占,可能的情况还有任务调用系统API主动放弃CPU,让其它任务先行等等。而时间片轮转发生在相同优先级的任务中,SysTick中断是FreeRTOS的周期性中断,每隔一段时间就会发生中断,调度器需要在里面执行一些自身的程序。

  无论是哪个场合,最终都需要PendSV中断的处理,比如系统调用taskYIELD(),跟踪源码可以发现设置如下

扫描二维码关注公众号,回复: 4721772 查看本文章
taskYIELD()
	portYIELD()
		portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; 

  而跟踪SysTick中断服务函数最终也会发现有一样的设置

SysTick_Handler()
	xPortSysTickHandler();
		portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; 

  最终都是portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT意思是手工往NVIC的PendSV悬起寄存器中写1

2.3 - PendSV_Handler

  因为任务切换最终都会发生PendSV中断,在PendSV中断服务函数中进行,中断服务函数为PendSV_Handler,但是在FreeRTOSConfig.h中被改名为xPortPendSVHandler,内容使用汇编编写的,它主要的工作如下

  比较关心的是改变pxCurrentTCB回顾上一文),用到了一个函数vTaskSwitchContext(),调用层次下

vTaskSwitchContext()
	taskSELECT_HIGHEST_PRIORITY_TASK()
		portGET_HIGHEST_PRIORITY()		//得到高优先级任务
		listGET_OWNER_OF_NEXT_ENTRY()	//设置pxCurrentTCB

  到此,在PendSV_Handler中断服务函数中,就完成了任务的切换。

03 - 总结

  • SVC中断就是软中断,给用户提供一个访问硬件的接口
  • PendSV中断相对SVC来说,是可以被延迟执行的,用于任务切换
  • 任务切换可以发生在系统调用中,也可以发生在时间片轮转中
  • 无论哪个情况,任务切换最终都会进入PendSV中断服务函数
  • 任务切换的过程为:保存现场、跳转到下一个任务、恢复现场

猜你喜欢

转载自blog.csdn.net/Hxj_CSDN/article/details/85290249