FreeRTOS的“启动调度器”到底干啥什么?

发布时间:2026/7/22 10:49:34

FreeRTOS的“启动调度器”到底干啥什么? 一、启动调度器的流程具体做了这几件事1. 创建空闲任务Idle Task这是调度器做的第一件事。空闲任务优先级最低0当没有任何就绪任务时 CPU 就跑它。代码根据编译配置走两条路静态分配用户提供内存调 xTaskCreateStatic动态分配内核自己分配调 xTaskCreate。创建失败则 xReturn pdFAIL。2. 创建定时器任务Timer Task如果 configUSE_TIMERS 1 且空闲任务创建成功就调用 xTimerCreateTimerTask() 创建软件定时器服务任务。这个任务负责处理所有软件定时器的回调。3. 启动前的最终准备全部成功才走到这里依次执行关闭全局中断防止启动过程中被 tick 打断→ 设置 TLS 块可选→ 初始化调度器状态变量xSchedulerRunning pdTRUE、tick 计数归零→ 配置运行时统计定时器 → 调用 xPortStartScheduler()。4. 启动硬件调度器xPortStartScheduler() 是端口层函数负责配置 SysTick、所以初始化的时候不要使用利用SysTick进行delay_us()的函数否则卡死。设置 PendSV 中断、恢复第一个任务的上下文并跳过去执行。这个函数正常情况下永远不会返回——一旦调用CPU 就开始跑任务了。5. 失败路径如果内存不够创建空闲任务或定时器任务触发 configASSERT 断言系统停死。二. 代码void vTaskStartScheduler( void ) { BaseType_t xReturn; /* Add the idle task at the lowest priority. */ #if ( configSUPPORT_STATIC_ALLOCATION 1 ) { StaticTask_t * pxIdleTaskTCBBuffer NULL; StackType_t * pxIdleTaskStackBuffer NULL; uint32_t ulIdleTaskStackSize; /* The Idle task is created using user provided RAM - obtain the * address of the RAM then create the idle task. */ vApplicationGetIdleTaskMemory( pxIdleTaskTCBBuffer, pxIdleTaskStackBuffer, ulIdleTaskStackSize ); xIdleTaskHandle xTaskCreateStatic( prvIdleTask, configIDLE_TASK_NAME, ulIdleTaskStackSize, ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ pxIdleTaskStackBuffer, pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ if( xIdleTaskHandle ! NULL ) { xReturn pdPASS; } else { xReturn pdFAIL; } } #else /* if ( configSUPPORT_STATIC_ALLOCATION 1 ) */ { /* The Idle task is being created using dynamically allocated RAM. */ xReturn xTaskCreate( prvIdleTask, configIDLE_TASK_NAME, configMINIMAL_STACK_SIZE, ( void * ) NULL, portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ } #endif /* configSUPPORT_STATIC_ALLOCATION */ #if ( configUSE_TIMERS 1 ) { if( xReturn pdPASS ) { xReturn xTimerCreateTimerTask(); } else { mtCOVERAGE_TEST_MARKER(); } } #endif /* configUSE_TIMERS */ if( xReturn pdPASS ) { /* freertos_tasks_c_additions_init() should only be called if the user * definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is * the only macro called by the function. */ #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT { freertos_tasks_c_additions_init(); } #endif /* Interrupts are turned off here, to ensure a tick does not occur * before or during the call to xPortStartScheduler(). The stacks of * the created tasks contain a status word with interrupts switched on * so interrupts will automatically get re-enabled when the first task * starts to run. */ portDISABLE_INTERRUPTS(); #if ( ( configUSE_NEWLIB_REENTRANT 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT 1 ) ) { /* Switch C-Runtimes TLS Block to point to the TLS * block specific to the task that will run first. */ configSET_TLS_BLOCK( pxCurrentTCB-xTLSBlock ); } #endif xNextTaskUnblockTime portMAX_DELAY; xSchedulerRunning pdTRUE; xTickCount ( TickType_t ) configINITIAL_TICK_COUNT; /* If configGENERATE_RUN_TIME_STATS is defined then the following * macro must be defined to configure the timer/counter used to generate * the run time counter time base. NOTE: If configGENERATE_RUN_TIME_STATS * is set to 0 and the following line fails to build then ensure you do not * have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your * FreeRTOSConfig.h file. */ portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); traceTASK_SWITCHED_IN(); /* Setting up the timer tick is hardware specific and thus in the * portable interface. */ xPortStartScheduler(); /* In most cases, xPortStartScheduler() will not return. If it * returns pdTRUE then there was not enough heap memory available * to create either the Idle or the Timer task. If it returned * pdFALSE, then the application called xTaskEndScheduler(). * Most ports dont implement xTaskEndScheduler() as there is * nothing to return to. */ } else { /* This line will only be reached if the kernel could not be started, * because there was not enough FreeRTOS heap to create the idle task * or the timer task. */ configASSERT( xReturn ! errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ); } /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0, * meaning xIdleTaskHandle is not used anywhere else. */ ( void ) xIdleTaskHandle; /* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority * from getting optimized out as it is no longer used by the kernel. */ ( void ) uxTopUsedPriority; }

相关新闻