开启调度器
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 );
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, // 空闲任务函数名
configIDLE_TASK_NAME, // 任务名称,用于调试
ulIdleTaskStackSize, // 空闲任务堆栈大小
( void * ) NULL, // 空闲任务参数
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), // 空闲任务优先级,最低
pxIdleTaskStackBuffer, // 空闲任务堆栈地址
pxIdleTaskTCBBuffer ); // 空闲任务控制块
if( xIdleTaskHandle != NULL ) // 任务创建成功,任务控制块不为空
{
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
}
#else
{ // 动态创建任务
xReturn = xTaskCreate( prvIdleTask, // 空闲任务函数名
configIDLE_TASK_NAME, // 空闲任务名称,用于调试
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 ) // 空闲任务创建成功,并且定时器任务创建成功
{
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
{
freertos_tasks_c_additions_init();
}
#endif
// 关闭中断,确保不会发生中断。开启任务调度器之前,或期间,堆栈的创建任务包含打开中断的状态,当第一个任务时,中断将自动重启开始运行
portDISABLE_INTERRUPTS();
#if ( configUSE_NEWLIB_REENTRANT == 1 )
{
_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
}
#endif
xNextTaskUnblockTime = portMAX_DELAY; // 下一任务唤醒任务的时间,本次计时不会唤醒任务
xSchedulerRunning = pdTRUE; // 为pdTRUE表示调度器在运行
xTickCount = ( TickType_t ) 0U; // 用于记录系统运行时长
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); // 配置定时器的时基
if( xPortStartScheduler() != pdFALSE ) // 开启调度器,启动系统节拍,启动后直接开始执行第一个任务
{
// 启动成功,则不会到达此处,直接执行第一个任务
}
else
{
// 除非调用 xTaskEndScheduler 函数才可到达此处
}
}
else
{
// 只有在内核无法启动时才会运行到达慈航,因为没有足够的堆内存创建空闲任务或计时器任务
configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ); // 断言函数输出错误信息,定位错误位置
}
( void ) xIdleTaskHandle;
}
BaseType_t xPortStartScheduler( void )
{
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) );
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; // 设置pendsv中断优先级,为最低优先级
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; // 设置systick中断优先级,为最低优先级
prvSetupMPU();
prvSetupTimerInterrupt(); // 调用 vPortSetupTimerInterrupt 设置滴答定时周期,使能滴答中断
uxCriticalNesting = 0; // 初始化临界区嵌套计数器
vPortEnableVFP(); // 调用函数使能FPU
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS; // 设置FPCCR的bit31和bit30为1
prvStartFirstTask(); // 启动第一个任务
return 0;
}
__asm void prvStartFirstTask( void )
{
PRESERVE8 // 8位对齐
ldr r0, =0xE000ED08 // 读取 向量表偏移量寄存器的值,也就是向量表保存位置,MSP 地址
ldr r0, [r0] // 读取 向量表偏移量寄存器的值 ,读取MSP
ldr r0, [r0] // 读取最先压栈的数据
msr msp, r0 // msp指针写入msp寄存器中
mov r0, #0 // 目前 R0 = MSP,清空R0寄存器的值
cpsie i // primask寄存器
cpsie f // faultmask寄存器
dsb // 数据操作完毕后,同步数据和命令
isb
svc 0 // 调用SVC指令触发SVC中断
nop
nop
}