@(嵌入式)
简述
前面文章 < FreeRTOS 任务调度 任务创建 > 介绍了 FreeRTOS 中如何创建任务以及其具体实现。
一般来说, 我们会在程序开始先创建若干个任务, 而此时任务调度器还没又开始运行,因此每一次任务创建后都会依据其优先级插入到就绪链表,同时保证全局变量 pxCurrentTCB
指向当前创建的所有任务中优先级最高的一个,但是任务还没开始运行。
当初始化完毕后,调用函数 vTaskStartScheduler
启动任务调度器开始开始调度,此时,pxCurrentTCB
所指的任务才开始运行。
所以, 本章,介绍任务调度器启动以及如何进行任务切换。
调度器涉及平台底层硬件操作,本文以Cotex-M3 架构为例, 具体可以参考 《Cortex-M3权威指南》(文末附)
分析的源码版本是 v9.0.0
(为了方便查看,github 上保留了一份源码Source目录下的拷贝)
启动调度器
创建任务后,系统不会自动启动任务调度器,需要用户调用函数 vTaskStartScheduler 启动调度器。 该函数被调用后,会先创建系统自己需要用到的任务,比如空闲任务 prvIdleTask
,定时器管理的任务等。 之后, 调用移植层提供的函数 xPortStartScheduler
。
代码解析如下,
void vTaskStartScheduler( void )
{
BaseType_t xReturn;
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
// 采用静态内存创建空闲任务
StaticTask_t *pxIdleTaskTCBBuffer = NULL;
StackType_t *pxIdleTaskStackBuffer = NULL;
uint32_t ulIdleTaskStackSize;
// 获取静态内存地址/参数
vApplicationGetIdleTaskMemory(
&pxIdleTaskTCBBuffer,
&pxIdleTaskStackBuffer,
&ulIdleTaskStackSize );
// 创建任务
// 空闲任务优先级为 0, 也就是其优先级最低
// !! 但是, 设置了特权位, 所以其运行在 特权模式
xIdleTaskHandle = xTaskCreateStatic(prvIdleTask, "IDLE",
ulIdleTaskStackSize, (void *) NULL,
(tskIDLE_PRIORITY | portPRIVILEGE_BIT),
pxIdleTaskStackBuffer,
pxIdleTaskTCBBuffer);
if( xIdleTaskHandle != NULL )
{
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
}
#else
{
// 动态申请内存创建任务
xReturn = xTaskCreate(prvIdleTask,
"IDLE", configMINIMAL_STACK_SIZE,
(void *)NULL,
(tskIDLE_PRIORITY | portPRIVILEGE_BIT),
&xIdleTaskHandle );
}
#endif
// 如果工程使用了软件定时器, 需要创建定时器任务进行管理
#if ( configUSE_TIMERS == 1 )
{
if( xReturn == pdPASS )
{
xReturn = xTimerCreateTimerTask();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
if( xReturn == pdPASS )
{
// 关闭中断, 避免调度器运行前节拍定时器产生中断
// 中断在第一个任务启动时恢复
portDISABLE_INTERRUP