ESP32 FreeRTOS 튜토리얼 가이드 6부작 3
FreeRTOS를 사용하여 ESP32에서 실시간 애플리케이션을 구축하는 방법을 배워보세요. 태스크 생성, 우선순위 처리, 메모리 관리, 태스크 간 통신에 관한 실용적인 튜토리얼을 살펴보세요. 각 예제는 실제 하드웨어에서 테스트되어 멀티태스킹을 숙달하고 ESP32의 듀얼 코어 성능을 최대한 활용할 수 있도록 도와줍니다.
ESP32 FreeRTOS(1부): FreeRTOS 및 작업 관리 소개
ESP32 FreeRTOS(2부): 스케줄러 및 작업 관리 이해
ESP32 FreeRTOS(3부): 작업 우선순위 및 스택 관리 설명
ESP32 FreeRTOS(4부): 작업 간 통신 설명 | 큐, 세마포어 및 이벤트 그룹
ESP32 FreeRTOS(5부): 소프트웨어 타이머 및 작업 알림 설명
ESP32 FreeRTOS(6부): ESP-IDF에서 작업을 일시 중지, 재개 및 삭제하는 방법
ESP32 FreeRTOS 작업 우선 순위 및 스택 관리
ESP32 FreeRTOS 시리즈 3부 에 오신 것을 환영합니다 !
첫 번째 튜토리얼에서는 ESP-IDF를 사용하여 FreeRTOS에서 작업을 생성, 삭제 및 제어하는 방법, 즉 작업 관리 의 기본 사항을 살펴보았습니다. 2부에서는 작업 스케줄러를 살펴보고 FreeRTOS가 멀티태스킹을 효율적으로 관리하기 위해 작업 간을 전환하는 방법을 살펴보았습니다.
이 부분에서는 작업 우선순위와 스택 관리에 대해 더 자세히 알아보겠습니다. 이 두 가지 측면은 ESP32가 여러 작업을 동시에 처리하는 방식을 결정하는 중요한 측면입니다.
작업 우선순위가 스케줄링에 미치는 영향 , 우선순위를 할당하고 변경하는 방법 , 그리고 안정적인 성능을 보장하기 위해 스택 크기를 관리하는 방법을 알아봅니다 . 또한 스택 최적화, 스택 사용량 모니터링 , 그리고 프로그램 충돌을 유발할 수 있는 메모리 문제 방지에 대해서도 다룹니다 .

ESP32 FreeRTOS 작업 우선 순위 및 스택 관리
목차
- ESP32 FreeRTOS에서 작업 우선순위 이해하기
- ESP32 FreeRTOS에서 작업 우선 순위 설정
- ESP32 FreeRTOS의 스택 관리
- 스택 사용 최적화 및 메모리 문제 방지
- 결론
ESP32 FreeRTOS에서 작업 우선순위 이해하기
FreeRTOS에서 여러 작업을 생성하면 모든 작업이 CPU의 관심을 필요로 합니다. 하지만 ESP32는 각 코어에서 한 번에 하나의 작업만 실행할 수 있습니다. 그렇다면 FreeRTOS는 어떤 작업을 먼저 실행해야 할지 어떻게 결정할까요?
바로 여기서 작업 우선순위가 중요합니다.
작업 우선순위는 스케줄러가 어떤 작업이 더 중요하고 다른 작업보다 먼저 CPU 시간을 할당받아야 하는지 결정하는 데 도움이 됩니다. 작업 우선순위가 어떻게 작동하는지 알아보겠습니다.
작업 우선순위란 무엇인가요?
FreeRTOS의 모든 작업에는 우선순위 수준이 있으며, 이는 xTaskCreate() 또는 xTaskCreatePinnedToCore()를 사용하여 작업을 생성할 때 정의됩니다.
- 숫자 가 높을수록 우선순위가 높습니다.
- 우선순위 가 높은 작업은 항상 우선순위가 낮은 작업보다 먼저 실행됩니다.
- 두 작업의 우선순위가 같으면 FreeRTOS는 두 작업 사이를 전환합니다(타임 슬라이싱).
예:
작업 A의 우선순위가 2 이고 작업 B의 우선순위가 1 인 경우 스케줄러는 작업 A가 대기 중이거나 차단되지 않는 한 항상 작업 A를 먼저 실행합니다.
간단히 말해서, 작업 우선순위는 어떤 작업이 CPU 시간과 주의를 더 많이 받는지를 정의합니다.
작업 우선 순위가 일정에 미치는 영향
FreeRTOS는 선점형 스케줄링 시스템을 사용합니다. 즉, 우선순위가 높은 작업이 실행될 준비가 되면 현재 실행 중인 우선순위가 낮은 작업을 즉시 선점 (인터럽트)합니다. 비 선점형 스케줄링 시스템은 현재 작업이 끝날 때까지 기다렸다가 선점하는 방식의 스케줄링입니다.
단계별로 진행되는 내용은 다음과 같습니다.
- 스케줄러는 실행할 준비가 된 모든 작업을 확인합니다.
- 가장 높은 우선순위를 가진 작업 을 선택합니다.
- 해당 작업은 차단될 때까지(예: 지연이나 대기열을 기다리는 경우) 실행됩니다.
- 그런 다음 스케줄러는 다음으로 준비된 작업으로 전환합니다.
이를 통해 센서 판독, 인터럽트 처리, 네트워크 작업과 같은 중요한 작업이 먼저 CPU 시간을 할당받고 로깅이나 LED 깜박임과 같은 덜 중요한 작업은 차례를 기다리게 됩니다.
팁: 모든 작업에 높은 우선순위를 부여하지 마세요. 우선순위가 낮은 작업이 전혀 실행되지 않아 시스템 정지 또는 워치독 재설정이 발생할 수 있습니다.
ESP32의 기본 작업 우선 순위
ESP32 FreeRTOS 환경에서 우선 순위 범위는 일반적으로 0에서 (configMAX_PRIORITIES – 1)까지 입니다 .
기본적으로:
- 0 → 가장 낮은 우선순위
- tskIDLE_PRIORITY (0) → 유휴 작업
- 숫자가 높을수록(예: 5, 10 등) 우선순위가 더 높습니다.
ESP-IDF는 기본적으로 configMAX_PRIORITIES를 25로 설정합니다. 즉, 0부터 24까지의 우선순위를 할당할 수 있습니다.
참고: 유휴 작업은 항상 우선순위 0 으로 실행됩니다 . 다른 작업이 실행될 준비가 되지 않았을 때만 실행됩니다.
실제 작업 우선순위 적용 사례
두 가지 작업이 있는 간단한 예를 살펴보겠습니다.
void Task1(void *pvParameters)
{
while (1)
{
printf("Task 1 is running\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void Task2(void *pvParameters)
{
while (1)
{
printf("Task 2 is running\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main()
{
xTaskCreate(Task1, "Task 1", 2048, NULL, 1, NULL);
xTaskCreate(Task2, "Task 2", 2048, NULL, 2, NULL);
}
이 예에서는:
- Task2 는 Task1 ( 1 )보다 우선순위( 2 ) 가 높습니다.
- 스케줄러는 항상 Task2를 먼저 실행합니다.
- Task1은 Task2가 지연 또는 차단 상태일 때만 실행됩니다.
두 작업의 우선순위가 같으면 FreeRTOS는 이를 시간 분할 하여 각 작업에 차례로 CPU 시간을 제공합니다.
아래 이미지는 ESP-IDE 콘솔에서 위 코드의 출력을 보여줍니다.

ESP32 기반 FreeRTOS에서는 우선순위가 높은 작업이 먼저 실행됩니다. 다른 작업은 우선순위가 높은 작업이 차단된 경우에만 실행됩니다.
그림에서 볼 수 있듯이 Task2가 먼저 실행되고 그 다음에 Task1이 실행됩니다 .
이 현상은 Task2의 우선순위(2)가 Task1(1)보다 높기 때문에 발생합니다. FreeRTOS 스케줄러는 항상 실행 준비가 된 태스크 중 가장 높은 우선순위를 가진 태스크에 CPU를 할당합니다.
Task2가 지연 상태(vTaskDelay())로 진입하면 해당 기간 동안 차단됩니다. 이 기간 동안 스케줄러는 다음 준비 상태 작업(이 경우 Task1)을 찾아 CPU 시간을 할당합니다.
Task2의 지연이 완료되면 다시 준비 상태가 되고, 우선순위가 더 높으므로 Task1보다 먼저 실행되어 즉시 실행을 시작합니다.
이 간단한 예제는 FreeRTOS에서 작업 우선순위가 실행 순서를 어떻게 제어하는지 명확하게 보여줍니다 . 두 작업의 지연 시간이 같더라도, 우선순위가 높은 작업이 실행 준비가 되면 항상 우선권을 갖습니다.
ESP32 FreeRTOS에서 작업 우선 순위 설정
FreeRTOS에서 적절한 작업 우선순위를 설정하면 ESP32가 여러 작업을 원활하게 처리하는 데 도움이 됩니다. 작업 생성 시 우선순위를 지정할 수 있으며, 나중에 런타임 중에 우선순위를 변경할 수도 있습니다. 어떻게 하는지 살펴보겠습니다.
xTaskCreate() 우선순위 매개변수와 함께 사용
작업 우선순위를 지정하는 가장 일반적인 방법은 작업 생성 시 xTaskCreate() 또는 xTaskCreatePinnedToCore() 함수를 사용하는 것입니다.
함수 형식은 다음과 같습니다.
xTaskCreate(
TaskFunction_t pvTaskCode, // Function that implements the task
const char * const pcName, // Name of the task
const uint16_t usStackDepth, // Stack size in words
void *pvParameters, // Parameters passed to the task
UBaseType_t uxPriority, // Task priority
TaskHandle_t *pxCreatedTask // Handle to the created task
);
매개 uxPriority 변수는 작업의 중요도를 결정합니다.
예를 들면 다음과 같습니다.
xTaskCreate(Task1, "Task1", 2048, NULL, 1, NULL);
xTaskCreate(Task2, "Task2", 2048, NULL, 3, NULL);
- Task2 는 Task1(1) 보다 우선 순위가 3 입니다 .
- 스케줄러는 항상 Task2를 먼저 실행하고 , Task1은 Task2가 지연되거나 차단될 때만 실행됩니다.
듀얼 코어 ESP32를 사용하는 경우 특정 코어에 작업을 고정할 수도 있습니다.
xTaskCreatePinnedToCore(Task1, "Task1", 2048, NULL, 2, NULL, 1);
이렇게 하면 우선순위 2 의 Core 1 에 Task1이 생성됩니다 .
팁: 항상 우선순위를 균형 있게 정하세요. 모든 작업에 높은 우선순위를 부여하지 마세요. 그렇지 않으면 우선순위가 낮은 작업이 CPU 시간을 할당받지 못할 수 있습니다.
동적으로 작업 우선 순위 변경 vTaskPrioritySet()
때로는 프로그램 실행 중에 작업의 우선순위를 변경 해야 할 수 있습니다 . 예를 들어, 실시간 데이터를 처리할 때는 작업의 우선순위가 더 높고, 유휴 작업 중에는 우선순위가 낮아야 할 수 있습니다.
.vTaskPrioritySet()을 사용하면 쉽게 이 작업을 수행할 수 있습니다.
vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority);
예를 들면 다음과 같습니다.
TaskHandle_t myTaskHandle;
void TaskA(void *pvParameters)
{
while (1)
{
printf("Running Task A\n");
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
void app_main()
{
xTaskCreate(TaskA, "TaskA", 2048, NULL, 1, &myTaskHandle);
// Change priority after 5 seconds
vTaskDelay(5000 / portTICK_PERIOD_MS);
vTaskPrioritySet(myTaskHandle, 3);
}
이 예에서는:
- TaskA는 우선순위 1 로 시작합니다 .
- 5초 후에는 우선순위가 3 으로 바뀌어 다른 낮은 우선순위의 작업보다 중요해집니다.
- 스케줄러는 즉시 다시 평가하여 TaskA에 더 많은 CPU 시간을 제공합니다.
참고: 작업의 우선순위를 높이면, 해당 작업이 현재 실행 중인 작업 중 가장 높은 우선순위의 준비 상태 작업이 될 경우 해당 작업을 선점할 수 있습니다.
우선순위 지정을 위한 모범 사례
ESP32 FreeRTOS 프로젝트를 안정적이고 효율적으로 만들려면 다음 우선순위 관리 모범 사례를 따르세요.
중요도에 따라 우선순위를 정하세요
높은 우선순위 → 시간에 민감한 작업(예: 센서 읽기, 통신).
중간 우선순위 → 정기적인 작업.
낮은 우선순위 → 로깅 또는 백그라운드 작업.
불필요하게 높은 우선순위를 피하세요.
모든 작업에 높은 우선순위를 부여하면 다른 작업이 차단되고 워치독 재설정이 발생할 수 있습니다.
유휴 작업을 비워 두세요.
유휴 작업(우선순위 0)은 백그라운드 정리를 처리합니다. 바쁜 루프로 이를 차단하지 마세요.
성능 모니터링
디버깅 도구나 FreeRTOS 추적 기능을 사용하여 모든 작업에 충분한 CPU 시간이 확보되는지 확인하세요.
다양한 우선순위로 테스트하기
때로는 우선순위를 약간만 변경해도 애플리케이션의 응답성이 향상될 수 있습니다.
ESP32 FreeRTOS의 스택 관리
FreeRTOS의 모든 작업은 임시 데이터, 로컬 변수, 함수 호출 정보를 저장하기 위해 자체 스택 메모리가 필요합니다 . 스택이 너무 작으면 ESP32가 충돌하거나 예기치 않게 작동할 수 있습니다. 스택이 너무 크면 귀중한 RAM을 낭비하게 됩니다.
안정적이고 효율적인 FreeRTOS 애플리케이션 작성에 스택 관리가 중요한 이유입니다 . 스택 관리의 작동 방식과 모니터링 및 최적화 방법을 알아보겠습니다.
스택이란 무엇이고 왜 중요한가
FreeRTOS에서 각 작업은 독립적으로 실행되며 자체적인 전용 스택을 갖습니다 . 이 스택에는 다음이 포함됩니다.
- 함수 내부의 지역 변수
- 함수 호출 중 반환 주소
- 컨텍스트 및 임시 데이터 중단
작업이 할당된 것보다 많은 스택을 사용하려고 하면 스택 오버플로가 발생합니다. 이는 FreeRTOS에서 시스템 충돌이 발생하는 가장 일반적인 이유 중 하나입니다.
간단히 말해서,
스택은 작업의 작업 메모리 입니다. 스택이 오버플로우되면 프로그램이 다시 시작되거나 제대로 작동하지 않을 수 있습니다.
각 작업에 대한 스택 크기 할당
xTaskCreate() 또는 xTaskCreatePinnedToCore()를 사용하여 작업을 생성할 때는 매개변수 중 하나로 스택 크기를 지정해야 합니다.
xTaskCreate(Task1, "Task1", 2048, NULL, 1, NULL);
여기서 2048은 스택 깊이입니다 — 스택의 크기를 바이트가 아닌 워드로 나타낸 값입니다.
ESP32는 4바이트 워드를 사용하므로, 이는 2048 * 4 = 8192바이트(8KB의 스택)에 해당합니다.
2048 * 4 = 8192 bytes
팁:
작업에서 큰 로컬 변수, 중첩 함수 또는 문자열 버퍼를 사용하는 경우 더 큰 스택이 필요합니다.
작은 계산만 수행하거나 데이터를 출력하는 경우 스택을 더 작게 유지할 수 있습니다.
2048개의 단어로 시작한 후 나중에 스택 사용 모니터링을 기반으로 조정할 수 있습니다.
스택 사용량 모니터링 uxTaskGetStackHighWaterMark()
FreeRTOS는 작업이 실제로 사용한 스택 양을 확인하는 데 매우 유용한 함수인 uxTaskGetStackHighWaterMark()를 제공합니다.
이 함수는 작업 수행 시간 동안 남아 있던 최소 여유 스택을 반환합니다 . 즉, 스택 오버플로에 얼마나 가까운지 알려줍니다.
예:
void Task1(void *pvParameters)
{
while (1)
{
printf("Task1 is running\n");
// Check stack usage
UBaseType_t watermark = uxTaskGetStackHighWaterMark(NULL);
printf("Task1 Stack High Water Mark: %u words\n", watermark);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
void app_main()
{
xTaskCreate(Task1, "Task1", 2048, NULL, 1, NULL);
}
이것이 의미하는 바는 다음과 같습니다.
- 큰 워터마크 값 = 사용하지 않은 스택이 충분히 있다는 의미(안전함).
- 작은 워터마크 값 = 스택이 거의 소진됨(위험).
모니터링 작업 스택 사용 예
아래 이미지는 위 코드의 출력을 보여줍니다.

위의 출력에서, 우리는 uxTaskGetStackHighWaterMark()를 사용하여 Task1의 스택 사용량을 모니터링하고 있습니다.
- 각 줄은 스택의 현재 "하이 워터마크"를 보여줍니다.Task1 Stack High Water Mark: 316 words
- 하이 워터 마크는 작업이 시작된 이후 남아 있는 최소 여유 스택 공간을 나타냅니다 .
- 이 경우 316개의 단어가 여전히 사용 가능 하므로 Task1에는 충분한 스택 메모리가 남아 있습니다.
큰 하이 워터 마크는 작업이 할당된 스택 내에 있음을 의미합니다. 하이 워터 마크가 매우 낮거나 0이면 작업이 스택 오버플로에 가까워 졌음을 나타내므로 스택 크기를 늘려야 합니다.
이 방법은 스택 할당을 최적화하여 충돌과 메모리 낭비를 방지하는 데 도움이 됩니다.
스택 사용 최적화 및 메모리 문제 방지
스택 메모리 관리는 ESP32에서 안정적인 FreeRTOS 애플리케이션을 구축하는 데 가장 중요한 부분 중 하나입니다. 스택 할당의 작은 실수는 시스템 충돌, 임의 재설정 또는 워치독 오류로 이어질 수 있습니다.
이 섹션에서는 FreeRTOS에서 적절한 스택 크기를 계산하는 방법, 일반적인 스택 관련 문제를 식별하는 방법, 효율적인 메모리 관리를 위한 모범 사례를 따르는 방법을 살펴보겠습니다.
최적의 스택 크기를 계산하는 방법
FreeRTOS의 모든 작업은 자체 스택을 필요로 합니다. 목표는 너무 크지도 작지도 않은 적당한 양의 메모리를 할당하는 것입니다.
각 작업에 맞는 최적의 스택 크기를 찾는 방법은 다음과 같습니다 .
1. 합리적인 기본값으로 시작합니다.
대부분의 간단한 작업의 경우 2048단어 (≈8KB)의 스택 크기로 시작합니다 .
2. 애플리케이션을 실행하고 사용량을 모니터링합니다.
각 작업의 남은 스택을 확인하려면 uxTaskGetStackHighWaterMark() 함수를 사용하십시오.
UBaseType_t watermark = uxTaskGetStackHighWaterMark(NULL); printf("Task Stack Free Space: %u words\n", watermark);
워터마크 값이 높으면 스택 이 너무 큰 것입니다. 안전하게 스택 크기를 줄일 수 있습니다.
매우 낮거나 0 이라면 스택이 너무 작다는 뜻입니다. 스택을 늘리세요.
3. 스택 크기를 점진적으로 조정합니다.
각 작업의 스택 크기를 안전한 균형에 도달할 때까지 조정합니다. 즉, 오버플로를 피할 수 있을 만큼 여유가 있지만 메모리를 낭비하지 않아야 합니다.
팁: 안전을 위해 항상 최소 100~200단어 의 여유 스택 공간을 남겨 두세요.
일반적인 스택 문제 및 해결 방법
FreeRTOS 프로젝트에서는 스택 관련 문제가 흔히 발생합니다. 다음은 발생할 수 있는 몇 가지 문제와 해결 방법입니다.
1. 스택 오버플로우
작업이 할당된 스택 크기를 초과할 때 발생합니다.
수정 방법:
configCHECK_FOR_STACK_OVERFLOW 2를 사용하여 스택 오버플로우 검사를 활성화하십시오.
vApplicationStackOverflowHook()을 사용하여 오버플로우를 감지하십시오.
영향을 받는 작업의 스택 크기를 늘리십시오.
2. 워치독 타이머 재설정
작업이 너무 오래 실행되거나 중단되면 워치독이 ESP32를 재설정할 수 있습니다.
해결 방법:
다른 작업에 시간을 할당하려면 vTaskDelay() 또는 vTaskDelayUntil()을 추가하십시오.
지연 없이 무한 루프를 피하십시오.
3. 힙 또는 메모리 조각화
작업을 자주 생성하고 삭제하면 시간이 지남에 따라 힙이 조각화될 수 있습니다.
해결 방법:
작업 생성 및 삭제를 반복하지 마십시오 — 대신 작업 일시 중지 기능을 사용하십시오 (vTaskSuspend() / vTaskResume()).
가능한 경우 정적 작업 할당을 사용하여 메모리를 미리 확보하십시오.
4. 새로운 작업을 위한 RAM이 부족합니다.
힙 메모리가 충분하지 않으면 xTaskCreate() 실패합니다.
수정 방법:
xPortGetFreeHeapSize()로 사용 가능한 힙을 확인하십시오.
다른 작업의 스택 크기를 줄이거나 menuconfig에서 힙을 늘리십시오.
결론
이 튜토리얼에서는 작업 우선순위 와 스택 관리가 ESP32 FreeRTOS 애플리케이션의 성능과 안정성에 어떤 영향을 미치는지 살펴보았습니다. 작업 우선순위를 설정 및 변경하고, 적절한 스택 크기를 할당하고, 스택 사용량을 모니터링하고, 스택 오버플로를 감지하여 충돌을 방지하는 방법을 살펴보았습니다.
적절한 우선순위 설정과 최적화된 스택 사용을 통해 ESP32 프로젝트가 더 빠르고, 원활하고, 안정적으로 실행될 것입니다 .
이 시리즈의 다음 부분에서는 태스크 간 통신을 살펴보겠습니다 . 큐, 세마포어, 뮤텍스를 사용하여 태스크 간에 데이터를 안전하게 공유하는 방법을 알아봅니다 .
'ESP32' 카테고리의 다른 글
| ESP32 FreeRTOS 튜토리얼 가이드 6부작 5 (1) | 2025.11.21 |
|---|---|
| ESP32 ESP-NOW 양방향 커뮤니케이션 (0) | 2025.11.20 |
| esp32 및 esp8266 Dallas ds18b20 네트워크 연결 (0) | 2025.11.19 |
| ESP32 FreeRTOS 튜토리얼 가이드 6부작 4 (1) | 2025.11.19 |
| ESP32 ADXL345 Accelerometer Interfacing (0) | 2025.11.18 |
| ESP32 FreeRTOS 튜토리얼 가이드 6부작 2 (0) | 2025.11.18 |
| ESP32 FreeRTOS 튜토리얼 가이드 6부작 1 (0) | 2025.11.18 |
| ESP-IDF vs Arduino 개발 환경 비교 (0) | 2025.11.18 |
취업, 창업의 막막함, 외주 관리, 제품 부재!
당신의 고민은 무엇입니까? 현실과 동떨어진 교육, 실패만 반복하는 외주 계약,
아이디어는 있지만 구현할 기술이 없는 막막함.
우리는 알고 있습니다. 문제의 원인은 '명확한 학습, 실전 경험과 신뢰할 수 있는 기술력의 부재'에서 시작됩니다.
이제 고민을 멈추고, 캐어랩을 만나세요!
코딩(펌웨어), 전자부품과 디지털 회로설계, PCB 설계 제작, 고객(시장/수출) 발굴과 마케팅 전략으로 당신을 지원합니다.
제품 설계의 고수는 성공이 만든 게 아니라 실패가 만듭니다. 아이디어를 양산 가능한 제품으로!
귀사의 제품을 만드세요. 교육과 개발 실적으로 신뢰할 수 있는 파트너를 확보하세요.
지난 30년 여정, 캐어랩이 얻은 모든 것을 함께 나누고 싶습니다.
귀사가 성공하기까지의 긴 고난의 시간을 캐어랩과 함께 하세요.
캐어랩