FreeRTOS-任务调度

230 阅读4分钟

1. 开启任务调度器

vTaskStartScheduler(),用于启动任务调度器,任务调度器启动后,FreeRTOS便会开始进行任务调度。 该函数内部实现:

  1. 创建空闲任务

  2. 如果使能软件定时器,则创建定时器任务

  3. 关闭中断,防止调度器开启之前或过程中,受中断干扰,会在运行第一个任务时打开中断

  4. 初始化全局变量,并将任务调度器的运行标志设置为已运行

  5. 初始化任务运行时间统计功能的时基定时器

  6. 调用函数xPortStartScheduler()

     作用:该函数用于完成启动任务调度器中与硬件架构相关的配置部分,
     以及启动第一个任务该函数内部实现,如下:
     1. 检测用户在FreeRTOSConfig.h文件中对中断的相关配置是否有误
     2. 配置PendSV和SysTick的中断优先级为最低优先级
     3. 调用函数vPortSetupTimerlnterrupt()配置SysTick
     4. 初始化临界区嵌套计数器为O
     5. 调用函数prvEnableVFP()使能FPU
     6. 调用函数prvStartFirstTask()启动第一个任务
    

2. 启动第一个任务

prvStartFirstTask()  /*开启第一个任务*/
vPortSVCHandler()     /*SVC中断服务函数*/

2.1 怎么启动第一个任务

  1. 找到优先级最高的任务
  2. 将该任务的寄存器值恢复到CPU寄存器中

2.2 prvStartFirstTask()

  1. 该函数用于初始化启动第一个任务前的环境,主要是重新设置MSP指针,并使能全局中断。
  • MSP指针:主堆栈指针,由OS内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。
  • PSP指针:进程堆栈指针,用于常规的应用程序代码(不处于异常服用例程中时)。

特别注意:在FreeRTOS中,中断使用MSP(主堆栈),中断以外使用PSP(进程堆栈)。

  1. 为什么是OxEOOOEDO8?

因为需从OxEO0OED08获取向量表的偏移。

为啥要获得向量表呢?

因为向量表的第一个是MSP指针!取MSP的初始值的思路是先根据向量表的位置寄存器VTOR(OxEO00ED08)来获取向量表存储的地址;

在根据向量表存储的地址,来访问第一个元素,也就是初始的MSP。

CM3允许向量表重定位——从其它地址处开始定位各异常向量这个就是向量表偏移量寄存器,向量表的起始地址保存的就是主栈指针MSP的初始值

2.3 vPortSVCHandler()

SVC中断只在启动第一次任务时会调用一次,以后均不调用。

  1. 通过pxCurrentTCB 获取优先级最高的就绪态任务的任务栈地址,优先级最高的就绪态任务是系统将要运行的任务。
  2. 通过任务的栈顶指针,将任务栈中的内容出栈到CPU寄存器中,任务栈中的内容在调用任务创建函数的时候,已初始化,然后设置PSP指针。
  3. 通过往BASEPRI寄存器中写0,允许中断。
  4. 执行 bx R14,告诉处理器ISR完成,需要返回,此刻处理器便会使用PSP做为堆栈指针,进行出栈操作,将xPSR、PC、LR、R12、R3~RO出栈,初始化的时候,PC被我们赋值成为了执行任务的函数的入口,所以呢,就正常跳入到了优先级最高的就绪状态的第一个任务的入口函数了

3. 任务切换

任务切换的本质就是CPU寄存器的切换。 例如:

当由任务A切换到任务B时,分为两步,整个过程被称为上下文切换

  1. 暂停任务A的执行,并将此时任务A的寄存器保存到任务堆栈,称为保存现场
  2. 将任务B的各个寄存器值(被存于任务堆栈中 )恢复到CPU寄存器中,称为恢复现场

3.1 vTaskSwitchContext()

通过该函数查找最优先级任务,

利用函数taskSELECT_HIGHEST_PRIORITY_TASK(),前导置零指令找到最高优先级;

利用函数listGET_OWNER_OF_NEXT_ENTRY(),获取最高优先级的任务句柄。

3.2 任务切换流程

触发PendSV中断(任务切换的过程在PendSV中断服务函数里边完成),执行任务切换,主要途径有:

  • 滴答定时器中断触发
  • 调用FreeRTOS的API函数触发,如portYIELD()
  1. 当前的psp是正在运行的任务的栈指针,读取当前psp进程指针,存入rO
  2. 压栈(保存现场)
  3. 获取当前最高优先级任务的任务控制块
  4. 出栈(恢复现场)
  5. 更新切换后的任务的的栈指针给PSP
  6. bx r14执行新任务函数