FreeRTOS 시리즈
FreeRTOS Documentation - FreeRTOS™
이 문서에서 제공하는 PDF를 읽고 정리한 글입니다.
생성 일 : 2026-07-25 최종 수정일 : 2026-07-25
절전 모드
전력 소모량을 낮추기 위해 FreeRTOS는 유휴 태스크 훅을 사용하여 MCU를 절전 모드로 동작하게 할 수 있다. 그러나 이런 효과는 주기적으로 틱 인터럽트를 처리하기 위해 절전 모드를 해제했다가 다시 들어오는 작업에 의해 감소된다. 틱 인터럽트가 자주 발생하도록 주기를 짧게 설정하는 경우 절전 모드를 해제하고 다시 들어오는 작업이 빈번해지므로 절전 효과가 크지 않다(정말 가벼운 절전 모드는 예외일 수 있음).
FreeRTOS는 위와 같은 일반적인 절전 모드(매 틱마다 깨어나는 Idle Hook 방식)를 지원하고, 틱 인터럽트를 처리하지 않는 Tickless Idle 방식도 지원한다. Tickless Idle 방식은 다른 실행 가능한 태스크가 없을 때 주기적인 틱 인터럽트를 중단하고 MCU가 깊은 절전 모드로 들어가게 한다. 이 때 MCU는 외부에서 인터럽트가 발생하지 않거나 태스크가 실행 가능한 상태로 바뀌지 않는 한 깊은 절전 모드를 유지한다. 깊은 절전 모드를 탈출할 때 틱 인터럽트를 다시 시작하며 틱 카운트 값을 갱신한다.
슬립 모드 상태
FreeRTOS는 세 가지 슬립 모드 상태를 제공한다.
-
eAbortSleep태스크가 실행 가능하거나, 컨택스트 스위칭이 지연되었거나, 스케줄러가 정지되어 있어 틱 인터럽트가 지연되었다는 것을 나타낸다. 슬립 모드로 진입하는 것을 막기 위해 FreeRTOS에게 알린다.
-
eStandardSleep예측되는 유휴 시간보다 짧은 시간동안 슬립 모드에 진입할 수 있게 한다.
-
eNoTasksWaitingTimeout일정 시간만큼 기다렸을 때 아무 태스크도 실행 가능하지 않은 상태라면 슬립 모드에 진입하고, 외부 인터럽트나 리셋 신호가 와야지만 슬립 모드에서 탈출한다.
Tickless Idle 방식 사용
Tickless Idle 방식은 configUSE_TICKLESS_IDLE매크로를 1로 설정해야 사용할 수 있다. configUSE_TICKLESS_IDLE 매크로가 2라면 사용자 정의 Tickless Idle 방식을 쓰는 것을 의미한다. 이 방식은 모든 port에서 사용 가능하다.
FreeRTOS는 두 가지 조건을 만족할 때 portSUPPRESS_TICKS_AND_SLEEP()을 호출하여 Tickless Idle 구간에 들어간다.
-
유휴 태스크가 실행 가능한 유일한 태스크여야 한다. 다른 태스크들은 Blocked 또는 Suspend 상태여야 한다.
-
최소
n번의 틱이 발생하는 동안 Blocked 상태의 태스크가 Ready 상태로 바뀌는 일이 없어야 한다.n값은configEXPECTED_IDLE_TIME_BEFORE_SLEEP매크로에 의해 정해진다.
portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime )
xExpectedIdleTime: 절전 모드를 유지할 수 있는 시간, 다시 말해 Blocked 상태에서 Ready 상태로 전환되기까지 남아있는 틱 주기의 개수
인자로 전해지는 시간만큼 Tickless Idle 구간에 들어간다.
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );이 함수도 Tickless Idle 상태에 진입하는 함수인데 Cortex-M 시리즈의 port에만 정의되어 있다.
eSleepModeStatus eTaskConfirmSleepModeStatus( void );
슬립 모드로 들어가도 괜찮은 상황인지 확인하는 함수다.
반환값이 eNoTasksWaitingTimeout이면, Tickless Idle 구간에서 이 함수가 호출되었다는 것이며 MCU는 깊은 절전 상태를 무기한으로 유지한다. 이 상태는 두 가지를 의미한다.
- 실행해야할 소프트웨어 타이머가 없다.
- 모든 애플리케이션 태스크 상태가 Suspend 상태이거나 Blocked 상태(portMAX_DELAY만큼 기다리는 중)여서 스케줄러가 일정 시간 이후 상태를 바꾸는 일이 없는 것을 의미한다.
이 함수를 호출하여 슬립 모드에 진입할 수 있는지 조건을 검사하는데, 그동안 인터럽트가 발생해서 태스크가 Ready 상태가 되면 안되므로, 틱 타이머가 멈추고 슬립 모드에 진입하기 전까지는 크리티컬 섹션이어야 한다.
슬립 모드 진입 전/후 이벤트 매크로
configPRE_SLEEP_PROCESSING( xExpectIdleTime )
configPOST_SLEEP_PROCESSING( xExpectIdleTime )
각각 슬립 모드 진입 전 후에 호출되며 페리퍼럴을 끄거나 클럭을 낮추는 등 작업을 할 수 있다.
직접 매크로 구현하기
FreeRTOS port가 portSUPPRESS_TICKS_AND_SLEEP() 함수를 제공하지 않는다면 직접 구현할 수 있다. 만약 기본 구현을 제공하더라도 사용자가 직접 구현한다면 덮어쓰기가 된다.
#if ( configUSE_TICKLESS_IDLE == 1 )
__attribute__( ( weak ) ) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
^^^^^^^^^^^^^^^^^^^^^^^^^~~~ weak 키워드가 붙어 있다!
{
...
#define portSUPPRESS_TICKS_AND_SLEEP( xIdleTime ) vApplicationSleep( xIdleTime )
void vApplicationSleep( TickType_t xExpectedIdleTime )
{
unsigned long ulLowPowerTimeBeforeSleep, ulLowPowerTimeAfterSleep;
eSleepModeStatus eSleepStatus;
ulLowPowerTimeBeforeSleep = ulGetExternalTime();
/*
1. 틱 인터럽트 타이머 정지
2. 인터럽트 비활성화( = 크리티컬 섹션 진입)
3. 슬립 모드 진입 가능 여부 확인
4-1. eAbortSleep이면 틱 타이머 재개, 인터럽트 활성화
4-2. eNoTaskWaitingTimeout이면, 무한히 슬립
4-3. eStandardSleep이라면, 일정 시간만 슬립 후 깨어났을 때 틱 카운트 갱신
5. 슬립 모드 탈출 시 인터럽트 활성화 후 틱 타이머 재개
*/
prvStopTickInterruptTimer();
disable_interrupts();
eSleepStatus = eTaskConfirmSleepModeStatus();
if( eSleepStatus == eAbortSleep )
{
prvStartTickInterruptTimer();
enable_interrupts();
}
else
{
if( eSleepStatus == eNoTasksWaitingTimeout )
{
prvSleep();
}
else
{
vSetWakeTimeInterrupt( xExpectedIdleTime );
prvSleep();
ulLowPowerTimeAfterSleep = ulGetExternalTime();
vTaskStepTick( ulLowPowerTimeAfterSleep - ulLowPowerTimeBeforeSleep );
}
enable_interrupts();
prvStartTickInterruptTimer();
}
}
유휴 태스크 훅 함수
유휴 태스크 훅이 호출된다는건 유휴 태스크가 실행 가능한 유일한 태스크라는 것을 의미한다. 그러므로