FreeRTOS任务调度与任务切换 | FreeRTOS八

目录

说明:

一、任务调度器

1.1、开启任务调度器函数

1.2、任务调度器实现步骤

1.3、xPortStartScheduler()函数

二、启动一个任务

2.1、prvStartFirstTask()函数

2.2、vPortSVCHandler()函数

三、任务切换

3.1、任务切换触发途径

3.2、PendSV中断触发任务切换步骤


说明:

关于内容:

1)以下内容多为概念了解与步骤分析

2)暂无个人示例代码,使用的是FreeRTOS的官方示例代码

3)若想移植代码测试的,请移步其它地方寻找,下文内容暂无个人示例代码供测试

关于其它:

1)操作系统:win 10

2)平台:keil 5 mdk

3)语言:c语言

4)板子:STM32系列移植FreeRTOS

一、任务调度器

1.1、开启任务调度器函数

名称:vTaskStartScheduler(),作用:启动任务调度器,当任务调度器启动后,FreeRTOS会开始进行任务的调度。

1.2、任务调度器实现步骤

1)创建空闲任务:prvldelTask

如下图1:

 图1

2)创建软件定时器任务:xTimerCreateTimerTask(可选,不配置宏定义则不创建)

如下图2:

 图2

3)关中断(会在启动第一个任务时开启)

如下图3:

图3

4)初始化全局变量

如下图4,因为刚启动任务调度器,此时没有任务在运行,给等待时间为最大值8个F,如下图5:

 图4

 图5

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

如下图6,实际上并没有实现功能,只是定义了一个接口:

图 6

6)调用函数xPortStartScheduler完成任务调度器

如下图7:

图7

1.3、xPortStartScheduler()函数

作用:完成启动任务调度器中与硬件框架相关的配置部分,以及启动第一个任务。

1)检测用户在FreeRTOSConfig.h文件中对中断的相关配置是否有误

如下图8,内容较多,截取部分:

图8

2)配置PendSV和SysTick的中断优先级为最低优先级

如下图9,通过给寄存器赋值给优先级:

图9

3)调用vPortSetupTimerlnterrupt()函数配置SysTick

图下图10:

 图10

4)初始化临界区嵌套计数器为 0

如下图11:

图11

5)调用函数prvStartFirstTask()函数启动第一个任务

如下图12:

 图12

二、启动一个任务

如何启动一个任务?

        找到优先级最高的任务,将最高优先级任务的寄存器值放到CPU的寄存器中,就相当于启动了最高优先级的任务。

        例如:要启动的第一个任务是A,任务A的寄存器值,在创建时就保存在申请的任务堆栈中,将任务A堆栈的寄存器值取出,放到CPU寄存器上,即可。

注意:

1)中断产生时,硬件自动将PSR,PC(R15,程序计算器PC),LR(R14,连接寄存器),R12,R3-R0保存和恢复,而R4-R11需要手动保存和恢复。R12(MSP主栈堆指针–>中断、PSP进程栈堆指针)

2)进入中断后,硬件会强制使用MSP指针,此时LR(R14,连接寄存器)的值将会被自动更新为特殊的EXC_RETURN

2.1、prvStartFirstTask()函数

作用:初始化启动第一个任务前的环境,主要是重新设置MSP指针,并使能全局中断(开启PendSV)

什么是MSP指针?

        程序在运行过程需要一定的栈空间来保存局部变量等信息。当有信息保持到栈里面时,MCU会自动更新SP指针,ARM Cortex-M内核提供了两个栈空间。

MSP(主堆栈指针):由OS内核、异常服务例程以及需要所有特权访问的应用程序代码来使用;

PSP(进程堆栈指针):用于常规的应用程序代码(不处于异常服务例程中时);

在FreeRTOS中,中断使用MSP(主堆栈),中断以外使用PSP(进程堆栈)。

1)复位MSP初始值

如下图13:

 图13

2)使能中断(开启中断)

如下图14:

 图14

3)触发SVC中断(获取当前优先级最高的任务控制块pxCurrentTCP;将该任务的寄存器值出栈至CPU寄存器中;设置PSP;返回r14,执行第一个任务)

如下图15:

 图15

2.2、vPortSVCHandler()函数

1)通过pxCurrentTCP获取优先级最高的就绪态任务的任务栈地址,优先级最高的就绪态任务是系统将要运行的任务

如下图16:

图16

2)通过任务栈顶指针,将任务栈中的内容出栈到CPU寄存器中,任务栈中的内容在调用任务函数时已初始化,设置PSP值

图下图17:

图17

3)设置控制中断寄存器值写0,允许中断

如下图18:

 图18

4)R14在ISR中,记录了异常返回值EXC_RETURN

异常返回值EXC_RETURN合法值如下图19:

 

图19

三、任务切换

任务切换的本质是?

        CPU寄存器的切换(切换到那个任务的寄存器值,就是在运行那个任务)。

       

3.1、任务切换触发途径

相当于触发PnedSV中断的途径,如下:

1)滴答定时器触发

2)调用FreeRTOS的API函数触发,例如:portYIELD()

本质上是通过向中断控制和状态寄存器ICSR的bit28写入1挂起PendSV来启动PendSV中断。

3.2、PendSV中断触发任务切换步骤

1)当前PSP是正在运行的任务的栈指针,读取当前PSP进程指针,存入r0

2)压栈(也叫保存现场,从r0开始往下)

如下图20:

 图20

3)获取当前最高优先级任务控制块

4)出栈(也叫恢复现场,把寄存器的值给CPU寄存器)

如下图21:

 图21

5)更新切换后的任务栈指针给PSP(也就是把r0给PSP)

6)bx r14执行更新任务函数

3.3、任务切换实现函数

名称:__asm void xPortPendSVHandler( void ),作用:实现任务切换

实现步骤如下:

1)手动8字节对齐,给PSP,r0的值

如下图22:

 图22

2)获取当前最高优先级任务

如下图23:

 图23

3)获取当前任务最高优先级

如下图24:

  图24

4)开中断

如下图25:

5)压栈

如下图26:

 图26

6)把栈顶给PSP

如下图27:

 图27

物联沃分享整理
物联沃-IOTWORD物联网 » FreeRTOS任务调度与任务切换 | FreeRTOS八

发表评论