1,FreeRTOS详解
1:FreeRTOS任务调度器开启
vTaskStartScheduler
1、创建空闲任务
2、如果使能了软件定时器,创建软件定时器
3、关中断
4、初始化一些静态全局变量
5、xPortStartScheduler
xPortStartScheduler
1、设置PendSV和Systick中断优先级
2、初始化嘀嗒定时器,中断周期,中断使能,systick使能
3、如果MCU有FPU的话,开启FPU
4、如果使用FPU的话,开启惰性压栈
5、prvStartFirstTask,开启第一个任务
6、SVC 0;引起SVC中断
2:FreeRTOS任务创建
xTaskCreate()
1、申请堆栈内存
2、申请任务控制块内存
3、调用prvInitialiseNewTask()初始化任务
prvInitialiseNewTask()
1、初始化堆栈为0xa5,可选功能
2、获取栈顶,保存在pxTopOfStack。
3、保存任务名字,到pxNewTCB->pcTaskName
4、保存任务优先级到pxNewTCB->uxPriority
5、初始化两个列表项xStateListItem和xEventListItem
6、初始化各种任务控制块成员变量
7、调用pxPortInitialiseStack(),初始化堆栈
8、保存/记录任务句柄,其实就是任务控制块。
prvAddNewTaskToReadyList()
1、uxCurrentNumberOfTasks加一,记录系统中有多少个任务
2、如果创建的是第一个任务,初始化相关列表,使用函数uxCurrentNumberOfTasks()
3、调用prvAddTaskToReadyList,将任务添加到就序列表中
4、如果新创建的任务优先级比当前任务优先级高,那么调用taskYIELD_IF_USING_PREEMPTION()进行任务切换
prvAddTaskToReadyList()
1、将uxTopReadyPriority相应的bit置1,表示相应优先级有就序任务
2、将新创建的任务添加到对应的就序列表中去,末尾插入。比如优先级5,pxReadyTasksLists[5]
3:任务删除、挂起和恢复过程
任务删除
vTaskDelete(TaskHandle_t xTaskToDelete)
1、根据任务句柄获取任务控制块,如果任务句柄为NULL,表示删除任务自身
2、将要删除的任务从就序列表中移除,并且如果相应的优先级下只有这一个任务那么复位相应的优先级位
3、如果任务等待某些事件的话那就将此任务从相应的时间列表中移除
4、如果删除的是任务自身,那么将任务添加到列表xTasksWaitingTermination中。任务堆栈,控制块的内存释放在空闲任务中完成
5、uxCurrentNumberOfTasks减一,表示当前系统任务减一。如果删的不是任务自身
6、释放任务控制块和任务堆栈内存
7、如果删除的是任务自身,最后需要主动发起任务切换
任务挂起
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
1、根据任务句柄获取任务控制块,如果任务句柄为NULL,表示删除任务自身
2、将要挂起的任务从相应的状态列表和事件中移除
3、将要挂起的任务添加到挂起任务列表xSuspendedTaskList里面去
4、如果挂起的是任务自身,而且任务调度器正在运行,那么需要进行一次任务切换
任务恢复
void vTaskResume(TaskHandle_t xTaskToResume)
1、判断要恢复的任务是否为挂起任务?
2、将要恢复的任务从挂起任务列表xSuspendTaskList移除
3、调用函数prvAddTaskToReadyList()将任务添加到就序列表中。
4、如果刚刚恢复的任务优先级比当前正在运行的任务优先级高,那么进行一次任务切换。
4:FreeRTOS任务切换
PendSV异常
1、任务切换具体过程是在PendSV中断服务函数里面
2、如何一起PendSV中断,ICSR寄存器bit28置1。
3、关于PendSV具体的内容,建议大家参考权威指南相关章节
任务切换场合
1、执行系统调用如:taskYILED(),vTaskDelay()->portYIELD_WIRHIN_API()->portYIELD()
2、systick中断服务函数
PendSV_Handler()或xPortPendSVHandler()
1、判断是否使用FPU。如果使用的话将S16-S31入栈。EXC_RETURN当处理异常的时候bit4会被CONTROL的FPCA位替代。判断EXC_RETURN的bit4是否为1,如果为1需要保存浮点寄存器。
2、R4-R11 R14入栈
3、关闭中断
4、调用vTaskSwitchContext,获取下一个要运行任务
5、打开中断
6、获取要切换的任务的栈顶指针
7、R4-R11,R14出栈
8、判断是否使用FPU,如果使用的话S16-S31出栈
9、任务切换完成
2,按键事件
stm8用定时器中断代替轮询读取GPIO监听cortex-m3主板是否休眠