[FreeRTOS] Interrupt

ISR (인터럽트 서비스 루틴) 내에서 시간이 오래 소요되는 작업을 처리하게 되면, 그 동안 다른 인터럽트를 받지 못하고 놓치게 되는 문제가 발생한다.

따라서 ISR 에서는 인터럽트 발생 여부만 체크하고, 실제 작업을 처리하는건 Task에서 수행하도록 하면 인터럽트를 놓치지 않을 수 있다.

간단하게 비교하자면 다음과 같다.


코드레벨에서는 다음과 같이 구현 할 수 있다.

TaskHandle_t xHandlingTask;

void vHandlingTask( void *pvParameters )
{
    uint32_t ulNotifiedValue;
        
	xHandlingTask = xTaskGetCurrentTaskHandle(); /* Store the handle of the calling task. */

    while(1)
    {
        ulNotifiedValue = ulTaskNotifyTake(pdTRUE, portMAX_DELAY /* Block indefinitely. */ );

        while(ulNotifiedValue > 0)
        {
            처리해야 할 작업( );

            ulNotifiedValue--;
        }
    }
}


void vANInterruptHandler( void )
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    vTaskNotifyGiveFromISR(xHandlingTask, &xHigherPriorityTaskWoken); /* Unblocking Task */
    portYIELD_FROM_ISR(&xHigherPriorityTaskWoken); /* Context Switch */
}



TaskHandle_t xHandlingTask;

void vHandlingTask( void *pvParameters )
{
    uint32_t ulNotifiedValue;
        
	xHandlingTask = xTaskGetCurrentTaskHandle(); /* Store the handle of the calling task. */

    while(1)
    {
        ulNotifiedValue = ulTaskNotifyTake(pdTRUE, portMAX_DELAY /* Block indefinitely. */ );

        while(ulNotifiedValue > 0)
        {
            처리해야 할 작업( );

            ulNotifiedValue--;
        }
    }
}


void vANInterruptHandler( void )
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    vTaskNotifyGiveFromISR(xHandlingTask, &xHigherPriorityTaskWoken); /* Unblocking Task */
    portYIELD_FROM_ISR(&xHigherPriorityTaskWoken); /* Context Switch */
}



# vTaskNotifyGiveFromISR

"인터럽트 서비스 루틴" (ISR) 에서 호출 할 수 있는 xTaskNotifyGive( ) 버전.

각 task 에는 task가 create 될 때 0으로 초기화 되는 32-bit짜리 notification value가 있다.

"Task Notification"은 blocked된 task를 unblocked 시키고 notification 값을 업데이트 하도록 task에 전달되는 이벤트다.

#include “FreeRTOS.h”
#include “task.h”

void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, 
                             BaseType_t *pxHigherPriorityTaskWoken );


[Parameters]

  • xTaskToNotify

"Task Notification" 이벤트를 받게 될 task의 핸들.


  • pxHigherPriorityTaskWoken

*pxHigherPriorityTaskWoken 은 pdFALSE 로 초기화 되어야 함.

vTaskNotifyGiveFromISR( )은 대상 task를 blocked 상태에서, unblocked 상태로 만들고, notification 을 받은 task의 우선순위가 현재 실행 중인 task보다 우선 순위보다 높을 경우 *pxHigherPriorityTaskWoken 을 pdTRUE 로 설정 함.

vTaskNotifyGiveFromISR( )이 *pxHigherPriorityTaskWoken 값을 pdTRUE로 설정하면, 인터럽트가 종료되기 전에 Context-Switching을 요청 해야 함.



# ulTaskNotifyTake

#include “FreeRTOS.h”
#include “task.h”

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, 
                           TickType_t xTicksToWait );



[Parameters]

  • xClearCountOnExit

pdFALSE : ulTaskNotifyTake( ) 가 종료되기 전에 task의 notification value가 감소 함.

pdTRUE : ulTaskNotifyTake( ) 가 종료되기 전에 task의 notification value가 0(zero)으로 재설정 됨.


  • xTicksToWait

ulTaskNotifyTake( ) 가 호출될 때 notification이 아직 pending 중이 아닌 경우 notification 이벤트가 수신될 때 까지 blocked 상태에서 대기하는 최대 시간.

RTOS task는 blocked 상태에서 CPU 시간을 소모하지 않음.

단위는 RTOS tick 이며, pdMS_TO_TICKS( ) 매크로를 사용하여 원하는 밀리세컨드 기간을 tick으로 변환 할 수 있음.


[Return Value]

감소되거나 0으로 클리어 되기 전의 task의 notification value 값



아래와 같이 Task1, Task2 가 있고, 외부 인터럽트를 받아 처리하는 ISR이 있다고 할 때, 

현재 진행중인 Task가 무엇인지, 우선순위가 무엇인지에 따라 상황이 달라진다.

( 항상 ISR에서 외부인터럽트를 받으면 Task1에게 Notification 이벤트를 준다고 하자 )

TaskHandle_t xTaskHandle1, xTaskHandle2;

void Task1(void *pvParameters)
{
    uint32_t ulNotifiedValue;

    while(1)
    {
        ulNotifiedValue = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
    }
}

void Task2(void *pvParameters)
{
    while(1)
    {
    	// DO Something...
    }
}

void ISR( void )
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    vTaskNotifyGiveFromISR(xTaskHandle1, &xHigherPriorityTaskWoken); /* Unblocking Task */
    
    portYIELD_FROM_ISR(&xHigherPriorityTaskWoken); /* Context Switch */
}​


Case #1 ) 우선순위가 Task1 이 높을 때

task1의 우선순위가 높지만 시작하자마자 ulTaskNotifyTake( )를 호출 하였기 때문에, 인터럽트가 발생 할 때 까지 Blocked 상태로 대기하게 되며, 그 동안 Task2가 CPU를 선점하게 된다.


Case #2 ) Task1이 선점하고 있고, 시간이 오래걸리는 작업 중 인터럽트를 받는 경우


Case #3 ) 우선순위가 Task2 가 높을 때



이 블로그의 인기 게시물

Crusader Kings 3 - Converting DNA code using Portrait Editor