티스토리 뷰

반응형

안녕하세요. 09LABS 입니다.
지난 강의에서는 ESP-IDF 빌드 시스템 구축 후 기본 코드를 작성하는 방법에 대해 알아봤습니다.
이번 강의에서는 멀티태스킹과 유사한 Task API에 대해 알아보겠습니다.

멀티태스킹은 동시에 여러 작업을 수행하는 것을 의미하는데요, 싱글코어 MCU에서는 한 번에 하나의 Task를 실행할 수 있습니다.
따라서 싱글코어 MCU의 경우 Task를 여러개 생성하면 동시에 처리되는 것 처럼 보이지만 스케쥴러에 의해 순차적으로 처리됩니다.

그림1. 싱글코어 멀티태스킹 (위키백과)

위 그림과 같이 프로그램을 3개 실행한다고 했을 때 우선순위가 높은 순서에 따라 프로그램이 실행되는 순서가 결정됩니다.
만약 듀얼코어 MCU를 사용한다면 멀티태스킹이 어떻게 실행될까요?

제가 사용하는 ESP32-S3 MCU는 듀얼코어 CPU로 구성되어있습니다.
총 2개의 Task를 생성한다고 하면 코어 하나에 하나의 Task를 할당시켜 동시에 두 개의 Task를 실행시킬 수 있습니다.
ESP-IDF Task API 문서를 보면 xTaskCreatePinnedToCore 라는 함수를 사용하여 Task를 실행시킬 Core를 지정할 수 있습니다.

만약 동시에 실행되어서 실시간으로 데이터를 처리하는 Task와 데이터를 수신하는 Task 두 개를 생성한다고 하면 Core를 나눠서 실행시키면 가장 효과적인 성능을 보여줄 것입니다.
이번 강의에서는 멀티태스킹을 구성하는 방법에 대해 알아보고 0부터 10까지 숫자를 세는 Task를 두 개 생성하여 어떻게 동작하는지 알아보겠습니다.


xTaskCreate 함수 정의

ESP-IDF 문서에 정의된 내용에 따르면 xTaskCreate 함수는 다음과 같이 Parameter를 입력하게 되어있습니다.

static inline BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pxCreatedTask)

Parameter 정의

  • pvTaskCode – Pointer to the task entry function. Tasks must be implemented to never return (i.e. continuous loop), or should be terminated using vTaskDelete function.
  • pcName – A descriptive name for the task. This is mainly used to facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN - default is 16.
  • usStackDepth – The size of the task stack specified as the number of bytes. Note that this differs from vanilla FreeRTOS.
  • pvParameters – Pointer that will be used as the parameter for the task being created.
  • uxPriority – The priority at which the task should run. Systems that include MPU support can optionally create tasks in a privileged (system) mode by setting bit portPRIVILEGE_BIT of the priority parameter. For example, to create a privileged task at priority 2 the uxPriority parameter should be set to ( 2 | portPRIVILEGE_BIT ).
  • pxCreatedTask – Used to pass back a handle by which the created task can be referenced.

- pvTaskCode : 실행하고자 하는 함수의 포인터. Task는 절대 반환되지 않도록 구현되거나(무한 루프) xTaskDelete 함수를 사용하여 종료되어야 한다.
- pcName : Task를 설명하는 이름. 디버깅할 때 유용하게 사용되며 최대 길이는 16 Byte이다.
- usStackDepth : Byte로 지정된 Task의 Stack 크기.
- pvParameters : 생성되는 Task의 매개변수(Parameter)로 사용될 포인터
- uxPriority : Task의 우선순위. portPRIVILEGE_BIT를 설정하여 우선순위를 지정할 수 있다.
- pxCreatedTask : 생성된 Task를 참조할 수 있는 Handler

xTaskCreate 기본 예제

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

TaskHandle_t taskHandle = NULL;

void counterTask(void *args) {
    int count = 0;
    printf("counter Task Start...\n");

    while(1) {
        printf("count : %d\n", count);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        count++;
        if (count > 10) {
            count = 0;
        }
    }
}

void app_main(void) {
    xTaskCreate(counterTask, "CounterTask", 4096, NULL, 10, &taskHandle);
}


이전 강의에서는 app_main 함수에 무한 루프를 생성하여 0부터 10까지 증가시키는 예제를 작성했습니다.
이번 강의에서는 app_main 함수에 구현한 내용을 counterTask라는 함수에 포함시키고 while(1) 문을 사용하여 무한루프로 실행시켰습니다.

app_main 함수에서 달라진 점은 xTaskCreate 함수를 사용하여 counterTask를 실행시킨다는 점인데요, 위에서 설명한 것과 같이 counterTask 함수를 Task로 생성하는 것입니다.

void app_main(void) {
    xTaskCreate(counterTask, "CounterTask", 4096, NULL, 10, &taskHandle);
}

위 내용을 살펴보면
xTaskCreate 함수를 사용하여 counterTask 함수를 실행시키고 Task의 이름은 CounterTask로 설정하였습니다.
Stack의 크기는 4096, 우선순위는 10, Task Handler는 taskHandle로 지정하였습니다.

I (0) cpu_start: App cpu up.
I (187) cpu_start: Pro cpu start user code
I (187) cpu_start: cpu freq: 160000000 Hz
I (187) cpu_start: Application information:
I (190) cpu_start: Project name:     count_number
I (195) cpu_start: App version:      1
I (200) cpu_start: Compile time:     Feb 17 2024 02:13:07
I (206) cpu_start: ELF file SHA256:  d5dd2f5179dd4e8a...
I (212) cpu_start: ESP-IDF:          v5.1-dirty
I (217) cpu_start: Min chip rev:     v0.0
I (222) cpu_start: Max chip rev:     v0.99 
I (227) cpu_start: Chip rev:         v0.1
I (231) heap_init: Initializing. RAM available for dynamic allocation:
I (239) heap_init: At 3FC94448 len 000552C8 (340 KiB): DRAM
I (245) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (251) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (258) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM
I (265) spi_flash: detected chip: gd
I (268) spi_flash: flash io: dio
W (272) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (285) sleep: Configure to isolate all GPIO pins in sleep state
I (292) sleep: Enable automatic switching of GPIO sleep configuration
I (299) app_start: Starting scheduler on CPU0
I (304) app_start: Starting scheduler on CPU1
I (304) main_task: Started on CPU0
I (314) main_task: Calling app_main()
counter Task Start...
count : 0
I (324) main_task: Returned from app_main()
count : 1
count : 2
count : 3
count : 4
count : 5
count : 6
count : 7
count : 8
count : 9
count : 10
count : 0

코드를 빌드하여 ESP32-S3 DevModule에 업로드한 결과 위와 같이 숫자가 0부터 10까지 순차적으로 증가하는 것을 볼 수 있습니다.

위와 같이 사용하고자 하는 기능을 함수로 구현한 다음 xTaskCreate 함수를 사용하면 원하는만큼 멀티태스킹을 수행할 수 있습니다.
다음 강의에서는 멀티태스킹 활용 + Queue API에 대해 알아보겠습니다.

반응형

'코딩하자 > ESP-IDF' 카테고리의 다른 글

[ESP-IDF] 2. 빌드 시스템 구축하기  (0) 2023.08.15
[ESP-IDF] 1. ESP32 개발환경 구축  (0) 2023.08.15
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함