기술 가이드

FreeRTOS ISR 작업 알림: pdTRUE·pdFALSE와 누적 이벤트 처리

ISR에서 작업으로 직접 알림을 전달하고 ulTaskNotifyTake의 두 소비 방식이 누적 이벤트에 주는 차이를 검증합니다.

목차

GPIO 인터럽트가 짧은 시간에 여러 번 발생할 때 작업을 깨우는 방법을 정해야 합니다. FreeRTOS의 직접 작업 알림은 별도 큐 없이 ISR에서 특정 작업에 이벤트를 전달할 수 있습니다. 다만 ulTaskNotifyTake()의 첫 인자에 따라 쌓인 알림을 한 번에 비우거나 하나씩 소비하므로, 이벤트 수를 세어야 하는지 먼저 결정해야 합니다. 아래 내용은 FreeRTOS의 Task Notifications 장과 커널 API 선언을 기준으로 합니다.

1. ISR에서 작업으로 전달하는 순서

작업 핸들을 초기화하고 작업을 만든 다음에 해당 인터럽트를 활성화하세요. ISR에서는 BaseType_t higher = pdFALSE;로 시작하여 vTaskNotifyGiveFromISR(task_handle, &higher)를 호출합니다. higher가 pdTRUE이면 사용하는 포트에 맞는 portYIELD_FROM_ISR(higher) 방식으로 ISR 종료 전에 스케줄 전환을 요청합니다. 호출 가능한 인터럽트 우선순위 범위는 사용 중인 MCU 포트의 FreeRTOS 설정과 맞아야 합니다.

작업에서는 ulTaskNotifyTake(pdTRUE, portMAX_DELAY) 또는 ulTaskNotifyTake(pdFALSE, portMAX_DELAY)로 기다립니다. 반환값은 호출 직전의 알림 값이며, 타임아웃으로 받을 알림이 없으면 0입니다. 알림은 단일 수신 작업에 전달됩니다. 여러 작업에 배포하거나 이벤트마다 별도 데이터가 필요하면 큐 등 다른 구조를 선택하세요.

작업 호출 세 번의 알림 뒤 반환값 다음에 남는 값 용도
ulTaskNotifyTake(pdTRUE, ...) 3 0 깨움 신호를 한 묶음으로 처리
ulTaskNotifyTake(pdFALSE, ...) 3 2 알림을 하나씩 소비하며 누적 횟수 처리

pdTRUE를 사용해도 반환값 3을 읽어 세 번으로 집계할 수 있습니다. 하지만 작업 본문을 한 번 실행하면 이벤트 하나를 처리한 것으로 간주하는 설계라면, 세 알림이 한 번의 실행으로 합쳐집니다. 이벤트마다 실제 센서 샘플이나 메시지를 따로 보관해야 한다면 알림 카운트만으로는 데이터가 보존되지 않습니다.

2. PC에서 카운트 동작을 확인하는 C 예제

아래 코드는 FreeRTOS 커널을 흉내 내는 단일 스레드 상태 모델입니다. 하드웨어 ISR·스케줄 지연은 시험하지 않습니다. notify_count_model.c로 저장하고 gcc -std=c11 -Wall -Wextra -Werror notify_count_model.c -o notify_count_model로 빌드해 실행하세요. 첫 번째 시퀀스는 세 알림을 한 번에 비우고, 두 번째는 하나씩 소비합니다.

#include <assert.h>
#include <stdint.h>
#include <stdio.h>

static uint32_t pending;

static void give_from_isr_model(void) {
assert(pending < UINT32_MAX);
++pending;
}

static uint32_t take_model(int clear_on_exit) {
uint32_t before = pending;
if (before != 0) {
pending = clear_on_exit ? 0 : before - 1;
}
return before;
}

int main(void) {
give_from_isr_model();
give_from_isr_model();
give_from_isr_model();
assert(take_model(1) == 3);
assert(take_model(1) == 0);
puts("clear mode: 3, then 0");

give_from_isr_model();
give_from_isr_model();
give_from_isr_model();
assert(take_model(0) == 3);
assert(take_model(0) == 2);
assert(take_model(0) == 1);
assert(take_model(0) == 0);
puts("count mode: 3, 2, 1, then 0");
return 0;
}

예상 출력:

clear mode: 3, then 0
count mode: 3, 2, 1, then 0

3. 보드에 적용할 때 점검할 항목

  1. 작업 핸들이 유효해진 뒤 인터럽트를 켜고, ISR에서는 알림 전송과 필요한 하드웨어 인터럽트 플래그 처리만 짧게 수행합니다.
  2. 깨움만 필요하면 pdTRUE로 대기하고, 반환값이 0인지 확인해 타임아웃과 정상 이벤트를 구분합니다.
  3. 이벤트 횟수가 의미 있으면 반환값을 기록하거나 pdFALSE로 하나씩 소비합니다. 장시간 작업 정지 뒤의 누적량과 32비트 값의 한계를 설계에 포함합니다.
  4. 입력 데이터 자체가 필요하면 큐·스트림 버퍼 등에 데이터를 넣고 알림은 깨움 용도로만 사용합니다.
  5. 로직 애널라이저 또는 GPIO 토글로 ISR 진입, 작업 시작, 처리 종료 시각을 측정합니다. PC 예제는 카운트 규칙만 검증했으므로 실기의 우선순위와 지연은 별도 확인이 필요합니다.

공식 근거: FreeRTOS Task Notifications, FreeRTOS task.h, 공식 알림 데모.

관련 글

댓글

첫 댓글을 남겨 보세요.

관리자 확인 후 게시됩니다.

처리 중입니다...

잠시만 기다려주세요.