FreeRTOS兩種任務切換觸發方式
執行系統調用
普通任務可以使用taskYIELD()強制任務切換
正在執行的任務讀取隊列失敗,再執行下去沒有意義,決定通知排程器切換到其他任務,自己進入阻塞
(比如,目前的任務執行xSemaphoreTake—>xQueueGenericReceive,從隊列中讀取信号量,發現為空,xQueueGenericReceive就會進行傳回errQUEUE_FULL,也就是得知讀取不成功 !=pdPASS,這是這個任務就可以執行taskYIELD來強制任務切換了)
xTaskCreate—>xTaskGenericCreate,建立任務時,如果建立的這個任務的優先級高于目前運作的任務,切換任務。
if( xReturn == pdPASS )
{
if( xSchedulerRunning != pdFALSE )
{
/** If the created task is of a higher priority than the current task
then it should run now. */
if( pxCurrentTCB->uxPriority < uxPriority )
{
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#if( configUSE_PREEMPTION == )
/** If the cooperative scheduler is being used then a yield should not be
performed just because a higher priority task has been woken. */
#define taskYIELD_IF_USING_PREEMPTION()
#else
#define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
#endif
#ifndef portYIELD_WITHIN_API
#define portYIELD_WITHIN_API portYIELD
#endif
#define portYIELD() vPortYieldFromISR()
中斷服務程式中使用portYIELD_FROM_ISR()強制任務切換
系統節拍時鐘中斷
#if (configCOMPILER==configCOMPILER_ARM_KEIL)
#if configPEX_KINETIS_SDK /** the SDK expects different interrupt handler names */
void SysTick_Handler(void) {
#else
void vPortTickHandler(void) {
#endif
#if configUSE_TICKLESS_IDLE ==
TICK_INTERRUPT_FLAG_SET();
#endif
portSET_INTERRUPT_MASK(); /** disable interrupts */
if (xTaskIncrementTick()!=pdFALSE) { /** increment tick count */
taskYIELD();
}
portCLEAR_INTERRUPT_MASK(); /** enable interrupts again */
}
#endif
taskYIELD()—>portYIELD() —>vPortYieldFromISR(void)
—>*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET_BIT;
void vPortYieldFromISR(void) {
/** Set a PendSV to request a context switch. */
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET_BIT;
/** Barriers are normally not required but do ensure the code is completely
within the specified behavior for the architecture. */
__asm volatile("dsb");
__asm volatile("isb");
}
從上面的代碼中可以看出,PendSV中斷的産生是通過代碼:portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT實作的,它向中斷狀态寄存器bit28位寫入1,将PendSV中斷設定為挂起狀态,等到優先級高于PendSV的中斷執行完成後,PendSV中斷服務程式将被執行,進行任務切換工作。
總結
對于Cortex-M3平台,這兩種方法的實質是一樣的,都會使能一個PendSV中斷,在PendSV中斷服務程式中,找到最高優先級的就緒任務,然後讓這個任務獲得CPU運作權,進而完成任務切換。