FreeRTOS 在Tricore上的三種任務切換方式


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 )

  使用場合:每次進入中斷,都會檢查是否有延時任務超時,若有,則進行一次任務切換

 

三種方式的區別在於:跳轉到執行任務切換的處理函數的方式,但三者的上下文保存與切換代碼完全一致。① SysTick中斷方式周期性地檢查並進行任務切換,該中斷優先級被設置為2,防止其搶占正在執行的中斷處理而引發錯誤(若SysTick中斷通過搶占其他中斷而進入,那么在進行上下文切換時,會把被其打斷的中斷處理函數的上下文CSA地址保存到最近一次運行的任務TCB.TopOfStack中,而將PCX指向新任務的CSA地址,因此SysTick中斷退出時會將新任務的上下文恢復到寄存器中從而執行新任務,而不是返回到被搶占的中斷中繼續執行,於是整個系統都會亂掉。進入SysTick中斷后的CSA情況為:PCX->Breaked Int's CSA -> 最近一個任務的CSA);② 任務中調用的任務切換的方式為立即進行任務切換(陷阱的優先級高於中斷);③ 而中斷中調用的任務切換方式為觸發一個可掛起的軟件中斷,其優先級被設置為1,原因和SysTick中斷一樣。實際上,ARM-CM3中使用PendSV進行任務切換也是基於這個原因(CM3中的FreeRTOS任務切換方式有兩種:SysTick(Trap)和PendSV(SW Int),其實SysTick也是用了PendSV,Pend是指可被懸起的意思)。三種方式對應的任務切換處理函數在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();
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM