FreeRTOS 在Tricore上的三种任务切换方式如下:
(1)任务中调用任务切换
切换函数:portYIELD()/portYIELD_WITHIN_API()/taskYEILD()
处理器资源:Trap_class6_TIN0
触发方式:_syscall(0)
处理函数:void prvTrapYield( int iTrapIdentification )
使用场合:例如 ①任务调用vTaskDelay()时,其内部会执行portYIELD_WITHIN_API()进行任务切换;②调用xQueueSend()函数时,会检查是否使某一阻塞态任务解阻塞,若是,则调用portYIELD_WITHIN_API()进行任务切换
(2)普通中断中调用任务切换
切换函数:portYIELD_FROM_ISR()/taskYEILD_FROM_ISR()
处理器资源:GPSRx0
触发方式:GPSRx0.B.SETR = 1或INT_SRB0.B.TRIG0 = 1
处理函数:static void prvInterruptYield( int iId )
使用场合:在中断中调用进行任务切换,例如在中断中向队列中写数据xQueueSendFromISR( xQueue, &xHigherPriorityTaskWoken );,然后使用portYIELD_FROM_ISR( xHigherPriorityTaskWoken )进行任务切换。
(3)systick中断中的任务切换
切换函数:在StmISR中进行
处理器资源:SysTimerx
触发方式:SysTimerx COMP0计数器溢出触发中断
处理函数:static void prvSystemTickHandler( int iArg )
使用场合:每次进入中断,都会检查是否有延时任务超时,若有,则进行一次任务切换
三种方式对应的处理函数在port.c中定义,代码如下:
(1)
void prvTrapYield( int iTrapIdentification ) { uint32_t *pxUpperCSA = NULL; uint32_t xUpperCSA = 0UL; extern volatile uint32_t *pxCurrentTCB; switch( iTrapIdentification ) { case portSYSCALL_TASK_YIELD:
_disable(); _dsync(); xUpperCSA = _mfcr( CPU_PCXI ); pxUpperCSA = portCSA_TO_ADDRESS( xUpperCSA ); *pxCurrentTCB = pxUpperCSA[ 0 ]; vTaskSwitchContext(); pxUpperCSA[ 0 ] = *pxCurrentTCB; SRC_GPSR00.B.SRR = 0; _isync(); break; default: /* Unimplemented trap called. */ configASSERT( ( ( volatile void * ) NULL ) ); break; } }
(2)
static void prvInterruptYield( int iId ) { uint32_t *pxUpperCSA = NULL; uint32_t xUpperCSA = 0UL; extern volatile uint32_t *pxCurrentTCB; /* Just to remove compiler warnings. */ ( void ) iId; _disable(); _dsync(); xUpperCSA = _mfcr( CPU_PCXI ); pxUpperCSA = portCSA_TO_ADDRESS( xUpperCSA ); *pxCurrentTCB = pxUpperCSA[ 0 ]; vTaskSwitchContext(); pxUpperCSA[ 0 ] = *pxCurrentTCB; SRC_GPSR00.B.SRR = 0; _isync(); }
(3)
static void prvSystemTickHandler( int iArg ) { uint32_t ulSavedInterruptMask; uint32_t *pxUpperCSA = NULL; uint32_t xUpperCSA = 0UL; extern volatile uint32_t *pxCurrentTCB; int32_t lYieldRequired; /* Clear the interrupt source. */ IfxStm_clearCompareFlag( &MODULE_STM0, IfxStm_Comparator_0 ); /* Reload the Compare Match register for X ticks into the future. IfxStm_increaseCompare( &MODULE_STM0, IfxStm_Comparator_0, ulCompareMatchValue ); /* Kernel API calls require Critical Sections. */ ulSavedInterruptMask = portSET_INTERRUPT_MASK_FROM_ISR(); { /* Increment the Tick. */ lYieldRequired = xTaskIncrementTick(); } portCLEAR_INTERRUPT_MASK_FROM_ISR( ulSavedInterruptMask ); if( lYieldRequired != pdFALSE ) { _disable(); _dsync(); xUpperCSA = _mfcr( CPU_PCXI ); pxUpperCSA = portCSA_TO_ADDRESS( xUpperCSA ); *pxCurrentTCB = pxUpperCSA[ 0 ]; vTaskSwitchContext(); pxUpperCSA[ 0 ] = *pxCurrentTCB; SRC_GPSR00.B.SRR = 0; _isync(); } }