任务调度由SysTick_Handler和 PendSV_Handler两个中断接管
系统时钟计数器按给定频率倒计时,至0触发SysTick_Handler中断,此中断函数为宏中对xPortSysTickHandler的重命名。
增加计数,置位可挂起中断。
void xPortSysTickHandler( void )
{portDISABLE_INTERRUPTS();{if( xTaskIncrementTick() != pdFALSE ){portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;}}portENABLE_INTERRUPTS();
}
xTaskIncrementTick 以设定频率增加计数,处理延时任务。
BaseType_t xTaskIncrementTick( void )
{TCB_t * pxTCB; TickType_t xItemValue;BaseType_t xSwitchRequired = pdFALSE;if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ){const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;xTickCount = xConstTickCount;if( xConstTickCount == ( TickType_t ) 0U ){taskSWITCH_DELAYED_LISTS(); //计数溢出 交换延时链表与溢出链表}if( xConstTickCount >= xNextTaskUnblockTime ) //处理延时链表{for( ; ; ){if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) //空{xNextTaskUnblockTime = portMAX_DELAY;break;}else //非空{pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );if( xConstTickCount < xItemValue ){ xNextTaskUnblockTime = xItemValue;break;}listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); //延时已过if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ){listREMOVE_ITEM( &( pxTCB->xEventListItem ) );}prvAddTaskToReadyList( pxTCB ); //添至就绪链表#if ( configUSE_PREEMPTION == 1 ){if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ){xSwitchRequired = pdTRUE; //优先级大于现运行任务需切换}}#endif}}}#if ( configUSE_PREEMPTION == 1 ){if( xYieldPending != pdFALSE ){xSwitchRequired = pdTRUE;}}#endif}else{++xPendedTicks; // 增加计数}return xSwitchRequired;
}
listLIST_IS_EMPTY宏定义
#define listLIST_IS_EMPTY( pxList ) ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
可挂起中断,此中断函数在宏中重命名为PendSV_Handler。系统时钟中断中对其置位,以低优先级运行,无高于其优先级时会调入对任务进行切换。
void xPortPendSVHandler( void )
{__asm volatile(" mrs r0, psp \n"" isb \n"" ldr r3, pxCurrentTCBConst \n" //当前运行任务" ldr r2, [r3] \n" " stmdb r0!, {r4-r11} \n" //保存r4-r11 psp" str r0, [r2] \n" //保存当前栈顶pxTopOfStack " stmdb sp!, {r3, r14} \n" //保存r3 r14至msp" mov r0, %0 \n" // 优先级" msr basepri, r0 \n" " bl vTaskSwitchContext \n" // 在就绪链表寻找最高优先级设为当前切换任务" mov r0, #0 \n"" msr basepri, r0 \n"" ldmia sp!, {r3, r14} \n" // 恢复 r3 lr" ldr r1, [r3] \n" //当前TCB指针 TCB已切换" ldr r0, [r1] \n" //当前TCB栈顶pxTopOfStack" ldmia r0!, {r4-r11} \n" //从TCB栈恢复 r4-r11 变动后指向任务参数" msr psp, r0 \n" //psp栈指向tcb栈 " isb \n" // " bx r14 \n" // 中断返回从PSP栈恢复寄存器值,任务回调函数指针载入PC,完成任务切换。" \n"" .align 4 \n""pxCurrentTCBConst: .word pxCurrentTCB \n"::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ));
}
参考创建任务时,任务堆栈设置
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters )
{pxTopOfStack--; *pxTopOfStack = portINITIAL_XPSR; //thumb pxTopOfStack--;*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; //task回调函数指针pxTopOfStack--;*pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */pxTopOfStack -= 5; /* R12, R3, R2 and R1. */*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */return pxTopOfStack;
}