【嵌入式——FreeRTOS】启动任务调度器
开启任务调度器
用于启动任务调度器,任务调度器启动后,FreeRTOS便会开始进行任务调度。
//启动任务,开启调度
vTaskStartScheduler();
xTaskCreate((TaskFunction_t)start_thread,
(const char *)"Initialize all task",
(uint16_t)START_THREAD_STKSZ,
(void *)NULL,
(UBaseType_t)(START_THREAD_PRIO),
(TaskHandle_t *)&start_tid);
vTaskStartScheduler();
vTaskStartScheduler()
内部实现
- 创建空闲任务;
- 如果使能软件定时器,则创建定时器任务;
- 关闭中断,防止调度器开启之前或过程中受中断干扰,会在运行第一个任务时打开中断;
- 初始化全局变量,并将任务调度器的运行标志设置为已运行;
- 初始化任务运行时间统计功能的时基定时器;
- 调用函数xPortStartScheduler()。
xPortStartScheduler()
该函数用于完成启动任务调度器中与硬件架构相关的配置部分,以及启动第一个任务。
内部实现
- 检测用户在FreeRTOSConfig.h文件中对中断的相关配置是否有误;
- 配置PendSV和SysTick的中断优先级为最低优先级;
- 调用函数vPortSetupTimerInterrupt()配置SysTick;
- 初始化临界区嵌套计数器为0;
- 调用函数prvEnableVFP()使能FPU;
- 调用函数prvStartFirstTask()启动第一个任务。
prvStartFirstTask()
- 复位MSP初始值;
- 使能中断;
- 触发SVC中断
- 获取当前优先级最高的任务控制块pxCurrentTCB
- 将该任务的寄存器值出栈至CPU寄存器中
- 设置PSP
- 返回R14,执行第一个任务函数
启动第一个任务
prvStartFirstTask()用于初始化启动第一个任务前的环境,主要是重新设置MSP指针,并使能全局中断。
MSP指针:程序在运行过程中需要一定的栈空间来保存局部变量等一些信息,当有信息保存到栈中时,MCU会自动更新SP指针,ARM Cortex-M内核提供了两个栈空间;
主堆栈指针(MSP):由OS内核、异常服务例程以及所有需要特权访问的应用程序代码来使用;
进程堆栈指针(PSP):用于常规的应用程序代码(不处于异常服务例程中时)。
在FreeRTOS中,中断使用MSP,中断以外使用PSP。
使用时间片调度需要把宏configUSE_TIME_SLICING和configUSE_PREEMPTION置为1