任务调度器的挂起与恢复:_SuspendAll 见 5C。SysTick_Handler(源) 经 xTaskIncrementTick(源码)触发任务调度 pendSV)
59ppt脑图 pdf补充最后一部分60任务调度始于 SysTick_HandlervoidSysTick_Handler(void)// 正点原子自定义的 delay.c 文件中{HAL_IncTick();// 意思是只要调度器启动了无论调度器是否又被挂起都执行下面的 if 内容if(xTaskGetSchedulerState()!taskSCHEDULER_NOT_STARTED)// taskSCHEDULER_NOT_STARTED 1xPortSysTickHandler();/* OS开始跑了,才执行正常的调度处理 */}61SysTick_Handler 调用了下面的变量与函数 xTaskGetSchedulerState__IOuint32_tuwTick;// stm32f1xx_hal.c 68 行 这是全局变量uint32_tuwTickPrio(1UL__NVIC_PRIO_BITS);/* Invalid PRIO */HAL_TickFreqTypeDef uwTickFreqHAL_TICK_FREQ_DEFAULT;/* 1KHz */__weakvoidHAL_IncTick(void)// 本函数其实并没有被重写 // stm32f1xx_hal.c 293 行{uwTickuwTickFreq;// __IO uint32_t uwTick; 全局变量}BaseType_txTaskGetSchedulerState(void)// tasks.c 3727{BaseType_t xReturn;if(xSchedulerRunningpdFALSE)xReturntaskSCHEDULER_NOT_STARTED;// 1else{if(uxSchedulerSuspended(UBaseType_t)pdFALSE)xReturntaskSCHEDULER_RUNNING;// 2elsexReturntaskSCHEDULER_SUSPENDED;// 0}returnxReturn;}62SysTick_Handler 也调用了下面的变量与函数 xPortSysTickHandlervoidxPortSysTickHandler(void)// port.c 429{//SysTick 以最低内部中断优先级运行因此当此中断执行时必须解除屏蔽所有中断。//因此无需保存和恢复中断屏蔽值因为其值已知//一一因此使用稍快的 vPortRaiseBASEPRI 函数来替代 portSET_INTERRUPT_MASK_FROM_ISR()//static portFORCE_INLINE void vPortRaiseBASEPRI( void )vPortRaiseBASEPRI();// 此函数有返回值返回 BASEPRI 里原来的值{/* Increment the RTOS tick. */if(xTaskIncrementTick()!pdFALSE){/* A context switch is required. * Context switching is performed in the PendSV interrupt. Pend the PendSV interrupt. */portNVIC_INT_CTRL_REGportNVIC_PENDSVSET_BIT;// * 0xE000ED04 1 28 // SCR_ICSR 寄存器的 bit28 置 1 就会触发 pendSV 中断}}vPortClearBASEPRIFromISR();// msr basepri, # 0}63xPortSysTickHandler 调用了下面的 xTaskIncrementTickBaseType_txTaskIncrementTick(void)// tasks.c 2482{TCB_t*pxTCB;TickType_t xItemValue;BaseType_t xSwitchRequiredpdFALSE;//返回值表是否需要发起任务切换 T 表需要调度任务traceTASK_INCREMENT_TICK(xTickCount);// #define traceTASK_INCREMENT_TICK( xTickCount ) 统计测试//此 if 里有 150 行是 tick 调度任务的逻辑最复杂的情况有 150 行。else 表调度器挂起的情况if(uxSchedulerSuspended(UBaseType_t)pdFALSE)// uxSchedulerSuspended 是计数器{/* Minor optimisation. The tick count cannot change in this block. */constTickType_t xConstTickCountxTickCount(TickType_t)1;/* Increment the RTOS tick, switching the delayed and overflowed * delayed lists if it wraps to 0. */xTickCountxConstTickCount;//FreeRTOS 32bit tick1ms 节拍约 49.7 天 tick 溢出采用双延时链表轮换if(xConstTickCount(TickType_t)0U){taskSWITCH_DELAYED_LISTS();// 这是很短的宏记录在下面}elsemtCOVERAGE_TEST_MARKER();/* See if this tick has made a timeout expire. Tasks are stored in * the queue in the order of their wake time - meaning once one task * has been found whose block time has not expired there is no need to * look any further down the list. */// 这是处理阻塞任务与唤醒暂时略if(xConstTickCountxNextTaskUnblockTime){for(;;){if(listLIST_IS_EMPTY(pxDelayedTaskList)!pdFALSE){/* The delayed list is empty. Set xNextTaskUnblockTime * to the maximum possible value so it is extremely * unlikely that the * if( xTickCount xNextTaskUnblockTime ) test will pass * next time through. */xNextTaskUnblockTimeportMAX_DELAY;break;}else{/* The delayed list is not empty, get the value of the * item at the head of the delayed list. This is the time * at which the task at the head of the delayed list must * be removed from the Blocked state. */pxTCBlistGET_OWNER_OF_HEAD_ENTRY(pxDelayedTaskList);xItemValuelistGET_LIST_ITEM_VALUE((pxTCB-xStateListItem));if(xConstTickCountxItemValue){/* It is not time to unblock this item yet, but the * item value is the time at which the task at the head * of the blocked list must be removed from the Blocked * state - so record the item value in * xNextTaskUnblockTime. */xNextTaskUnblockTimexItemValue;break;}elsemtCOVERAGE_TEST_MARKER();/* It is time to remove the item from the Blocked state. */listREMOVE_ITEM((pxTCB-xStateListItem));/* Is the task waiting on an event also? If so remove * it from the event list. */if(listLIST_ITEM_CONTAINER((pxTCB-xEventListItem))!NULL)listREMOVE_ITEM((pxTCB-xEventListItem));elsemtCOVERAGE_TEST_MARKER();/* Place the unblocked task into the appropriate ready * list. */prvAddTaskToReadyList(pxTCB);/* A task being unblocked cannot cause an immediate * context switch if preemption is turned off. */#if(configUSE_PREEMPTION1){/* Preemption is on, but a context switch should * only be performed if the unblocked task has a * priority that is equal to or higher than the * currently executing task. */if(pxTCB-uxPrioritypxCurrentTCB-uxPriority)xSwitchRequiredpdTRUE;elsemtCOVERAGE_TEST_MARKER();}#endif/* configUSE_PREEMPTION */}//if( listLIST_IS_EMPTY( pxDelayedTaskList ) ! pdFALSE )}//for( ; ; )}//if( xConstTickCount xNextTaskUnblockTime )//1如果抢占功能已开启且应用程序编写者未显式关闭时间片// 则与当前运行任务具有相同优先级的任务将共享处理时间(时间片)//2FreeRTOS 的抢占式调度是高优先级任务永远不会让 CPU 给低优先级任务除非自己睡眠// 但多个最高优先级任务之间会共享轮转时间片轮转时间就是一个滴答 1ms。内核是 9MHz。//3这不同于 linux linux 是所有任务都能得到时间片只是高优先级的任务得到的时间片长一些而已。#if((configUSE_PREEMPTION1)(configUSE_TIME_SLICING1)){if(listCURRENT_LIST_LENGTH((pxReadyTasksLists[pxCurrentTCB-uxPriority]))(UBaseType_t)1)xSwitchRequiredpdTRUE;elsemtCOVERAGE_TEST_MARKER();}#endif#if(configUSE_TICK_HOOK1)// 本项目里不成立//.....#endif/* configUSE_TICK_HOOK */#if(configUSE_PREEMPTION1){if(xYieldPending!pdFALSE)xSwitchRequiredpdTRUE;elsemtCOVERAGE_TEST_MARKER();}#endif/* configUSE_PREEMPTION */}else//当调度器被挂起的时候仅递增下面的计数值并返回 false{xPendedTicks;//这是全局量 static volatile TickType_t xPendedTicks ( TickType_t ) 0U;/* The tick hook gets called at regular intervals, even if the scheduler is locked. */#if(configUSE_TICK_HOOK1)// configUSE_TICK_HOOK 0本 if 不成立vApplicationTickHook();#endif}returnxSwitchRequired;// BaseType_t xSwitchRequired pdFALSE; 此局部变量的默认值是 False}// BaseType_t xTaskIncrementTick( void ) 返回值是是否需要发起任务切换64用于交换延时链表的宏 taskSWITCH_DELAYED_LISTS/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick count overflows. */#definetaskSWITCH_DELAYED_LISTS()\{\List_t*pxTemp;\\/* The delayed tasks list should be empty when the lists are switched. */\configASSERT((listLIST_IS_EMPTY(pxDelayedTaskList)));\\pxTemppxDelayedTaskList;\pxDelayedTaskListpxOverflowDelayedTaskList;\pxOverflowDelayedTaskListpxTemp;\xNumOfOverflows;\prvResetNextTaskUnblockTime();\}65谢谢