前提条件:在创建完成任务后,需要调用vTaskStartSchedule函数,只有开启了任务调度器,rtos才会去调度任务函数。
开启任务调度器——vTaskStartSchedule()过程分析(动态和静态分析)
a.创建空闲任务(动态创建任务可以忽略,静态创建任务需要开发者自行提供相应的栈空间和TCB存储空间)
b.创建定时计数器任务(该任务是选择性创建的,如果动态创建也可以忽略,静态创建则需要提供相应的存储空间——栈空间和TCB空间)
c.屏蔽中断(在启动第一个任务时,会使能中断)
d.初始化一些全局变量(下次阻塞超时时间为最大,并且标记任务调度器的运行标志位已运行)
e.初始化任务运行时间统计功能的时基定时器
f.调用xPortStartScheduler()函数(启动任务调度器,以及启动第一个任务)
xPortStartScheduler()函数详解:
a.检查配置是否有误
b.配置PendSV和Systick的中断优先级为15(为最低中断优先级,可以切换任务与计时作为心跳,并且优先相应其他中断)
c.调用vPortSetupTimerInterrupt()配置Systick的重装载值,以及时钟来源,使能中断和开启Systick
d.初始化临界区嵌套中断计数器为0;(与临界区嵌套有关在此初始化)
e.调用prvStartFirstTask()函数启动第一个任务(即将任务栈空间的寄存器赋值到CPU的寄存器中)
prvStartFirstTask()函数分析:
a.八字节对齐(不知道为何要八字节对齐,为什么不可以是四字节)
b.获取向量表偏移量寄存器的地址并且保存到r0中
c.获取r0指向的地址内容存储在r0中(存储的内容就是MSP的地址)
d.获取r0地址里面的内容存储在r0中(存储的内容是MSP的值)
e.将r0的值赋值给MSP指针
f.使能中断
g.触发SVC中断(开启第一个任务)
vPortSVCHandler()中断函数详解:
a.八字节对齐(不知道为何要八字节对齐,为什么不可以是四字节)
b.获取当前任务控制块的地址并且保存到r0中(在创建任务是当前任务控制块就是优先级最高的任务控制块)
c.获取r0指向的地址内容存储在r0中(存储的内容就是当前任务控制块的内容(栈顶指针的地址))
d.获取r0地址里面的内容存储在r0中(存储的内容是栈顶指针指向的内容)
e.手动出栈r4-r11(就是将内存中的值赋值到CPU的寄存器中)
f.开启中断(对应开启任务调度器中的屏蔽中断)
g.CPU中的PC指针已经是当前最高优先级的任务函数地址,直接跳转执行
注意:只有在启动第一个任务的时候会调用SVC中断,任务切换是调用PendSV中断来进行任务的上下文切换的(就是将正在运行任务CPU中的寄存器保存到该任务的栈空间中,然后在将要运行的任务的相关寄存器赋值到CPU寄存器中)
最后作者有一个问题:stm32中进入中断前为何八字节对齐(不知道为何要八字节对齐,为什么不可以是四字节)希望大家解答