| 切换代码: 
 void xPortPendSVHandler( void )
 {
 /* This is a naked function. */
 
 __asm volatile
 (
 "        mrs r0, psp                                                        \n"
 "                                                                                \n"
 "        ldr        r3, pxCurrentTCBConst                        \n" /* Get the location of the current TCB. */
 "        ldr        r2, [r3]                                                \n"
 "                                                                                \n"
 "        stmdb r0!, {r4-r11}                                        \n" /* Save the remaining registers. */
 "        str r0, [r2]                                                \n" /* Save the new top of stack into the first member of the TCB. */
 "                                                                                \n"
 "        stmdb sp!, {r3, r14}                                \n"
 "        mov r0, %0                                                        \n"
 "        msr basepri, r0                                                \n"
 "        bl vTaskSwitchContext                                \n"
 "        mov r0, #0                                                        \n"
 "        msr basepri, r0                                                \n"
 "        ldmia sp!, {r3, r14}                                \n"
 "                                                                                \n"        /* Restore the context, including the critical nesting count. */
 "        ldr r1, [r3]                                                \n"
 "        ldr r0, [r1]                                                \n" /* The first item in pxCurrentTCB is the task top of stack. */
 "        ldmia r0!, {r4-r11}                                        \n" /* Pop the registers. */
 "        msr psp, r0                                                        \n"
 "        bx r14                                                                \n"
 "                                                                                \n"
 "        .align 2                                                        \n"
 "pxCurrentTCBConst: .word pxCurrentTCB        \n"
 ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
 );
 }
 
 见 FreeRTOS V6.0.4 port.c, 其中的 vTaskSwitchContext 函数
 
 void vTaskSwitchContext( void )
 {
 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
 {
 /* The scheduler is currently suspended - do not allow a context
 switch. */
 xMissedYield = pdTRUE;
 return;
 }
 
 traceTASK_SWITCHED_OUT();
 
 #if ( configGENERATE_RUN_TIME_STATS == 1 )
 {
 unsigned long ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
 
 /* Add the amount of time the task has been running to the accumulated
 time so far.  The time the task started running was stored in
 ulTaskSwitchedInTime.  Note that there is no overflow protection here
 so count values are only valid until the timer overflows.  Generally
 this will be about 1 hour assuming a 1uS timer increment. */
 pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
 ulTaskSwitchedInTime = ulTempCounter;
 }
 #endif
 
 taskFIRST_CHECK_FOR_STACK_OVERFLOW();
 taskSECOND_CHECK_FOR_STACK_OVERFLOW();
 
 /* Find the highest priority queue that contains ready tasks. */
 while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
 {
 --uxTopReadyPriority;
 }
 
 /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
 same priority get an equal share of the processor time. */
 listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
 
 traceTASK_SWITCHED_IN();
 vWriteTraceToBuffer();
 }
 
 见 FreeRTOS V6.0.4 tasks.c
 |