๐Ÿ˜Ž ๊ณต๋ถ€ํ•˜๋Š” ์ง•์ง•์•ŒํŒŒ์นด๋Š” ์ฒ˜์Œ์ด์ง€?

์‹ค์‹œ๊ฐ„(Real Time) ์šด์˜์ฒด์ œ(OS) ์˜ RTOS์™€ FreeRTOS ์‚ฌ์šฉํ•ด๋ณด๊ธฐ ๋ณธ๋ฌธ

๐Ÿ‘ฉ‍๐Ÿ’ป IoT (Embedded)/Arduino

์‹ค์‹œ๊ฐ„(Real Time) ์šด์˜์ฒด์ œ(OS) ์˜ RTOS์™€ FreeRTOS ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

์ง•์ง•์•ŒํŒŒ์นด 2023. 11. 29. 11:43
728x90
๋ฐ˜์‘ํ˜•

<๋ณธ ๋ธ”๋กœ๊ทธ๋Š” ์ฝฉ์ด์˜ ์ผ์ƒ๊ณผ ์ž„๋ฒ ๋””๋“œ blogEmbeddedJune์˜ Festival  ๋ธ”๋กœ๊ทธ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๊ณต๋ถ€ํ•˜๋ฉฐ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค :-)>

 

โญ RTOS

์‹ค์‹œ๊ฐ„(Real Time) ์šด์˜์ฒด์ œ(Operating System)์˜ ์•ฝ์ž

์ œํ•œ๋œ ์‹œ๊ฐ„๋‚ด์— ์›ํ•˜๋Š” ์ž‘์—…์„ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ•˜๋Š”๊ฒƒ์„ ๋ณด์žฅํ•˜๋Š” ์šด์˜์ฒด์ œ

๋ฉ€ํ‹ฐํƒœ์Šคํ‚น ํ™˜๊ฒฝ์—์„œ Task ์ฒ˜๋ฆฌ์‹œ๊ฐ„์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„๋กœ ์‚ฌ์šฉ

์‹œ๋ถ„ํ•  ์‹œ์Šคํ…œ ํ•˜์—์„œ ์šฐ์„ ์ˆœ์œ„ ๊ธฐ๋ฐ˜ ์Šค์ผ€์ค„๋ง์„ ํ†ตํ•ด ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ task๊ฐ€ ๋จผ์ € ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ

์Šค์ผ€์ค„๋ง : ํ”„๋กœ์„ธ์Šค๋“ค์—๊ฒŒ CPU ๋“ฑ ์ž์›์„ ๋ฐฐ์ •ํ•˜๋Š” ๊ฒƒ์„ ๋งํ•จ

 

๋™์‹œ์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋ฉด ์ฒ˜๋ฆฌ์†๋„๊ฐ€ ์ง€์—ฐ๋˜๊ฑฐ๋‚˜ ํ”„๋กœ๊ทธ๋žจ์‹คํ–‰์ด 1์ดˆ ์ด์ƒ ์ง€์—ฐ๋จ

RTOS๋ฅผ ์‚ฌ์šฉํ•œ ๊ธฐ๊ธฐ๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ์ตœ๋Œ€ 1์ดˆ์•ˆ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•œ๋‹ค

์œˆ๋„์šฐ๋‚˜ ๋ฆฌ๋ˆ…์Šค์—์„œ๋Š” millisecond, microsecond ๋‹จ์œ„๋กœ ํ”„๋กœ๊ทธ๋žจ์„ ์ œ์–ดํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ต์ง€๋งŒ, RTOS์—์„œ๋Š” ๊ฐ€๋Šฅ

 

โญ FreeRTOS

RTOS์˜ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋Š”๋ฐ RTOS์•ž์— Free ๋ผ๋Š” ์ˆ˜์‹์–ด๊ฐ€ ๋ถ™์€ ์ด์œ ๋Š” ๋ˆ„๊ตฌ๋‚˜ ์‚ฌ์šฉ๊ฐ€๋Šฅ

์†Œํ˜• ์ €์ถœ๋ ฅ ์—ฃ์ง€ ๋””๋ฐ”์ด์Šค๋ฅผ ์‰ฝ๊ฒŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ, ๋ฐฐํฌ, ๋ณดํ˜ธ, ์—ฐ๊ฒฐ ๋ฐ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋งˆ์ดํฌ๋กœ ์ปจํŠธ๋กค๋Ÿฌ์šฉ ์‹ค์‹œ๊ฐ„ ์˜คํ”ˆ ์†Œ์Šค ์šด์˜ ์ฒด์ œ

2003๋…„ Richard Barry๊ฐ€ ๋งŒ๋“  ANSI C ๊ธฐ๋ฐ˜ RTOS

์•„๋งˆ์กด AWS IoT ์„œ๋น„์Šค ํ™•์žฅ์„ ์œ„ํ•ด 2017๋…„ 11์›”์— ์ธ์ˆ˜

 

 - ๊ธฐํƒ€ ๊ณ ์„ฑ๋Šฅ OS(Linux, Windows, iOS, Android ๋“ฑ)์™€๋Š” ๋‹ค๋ฅด๊ฒŒ 1์ดˆ ๋‚ด์— Task์˜ ์ž‘์—…์„ ๋๋‚ด๋Š” ๊ฒƒ์„ ๋ณด์žฅ

(๋‹จ์ˆœํžˆ ๋นจ๋ฆฌ ๋๋‚ด๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ž‘์—…์˜ ์ฒ˜๋ฆฌ๋ฅผ ๋ณด์žฅ)

 - ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ์‹œ์Šคํ…œ(๊ตญ๋ฐฉ ์‹œ์Šคํ…œ, ์•ˆ์ „๋ณด์กฐ์žฅ์น˜ ๋“ฑ)์— ๋งŽ์ด ์‚ฌ์šฉ

 - RTOS๊ฐ€ ํ™œ์šฉ๋˜๋Š” ๊ธฐ๊ธฐ๋Š” ๊ฑฐ์˜ ๋Œ€๋ถ€๋ถ„ ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ

 - ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ์ฒ˜๋ฆฌ ์š”์ฒญ์„ ์ •ํ•ด์ง„ ์‹œ๊ฐ„๋‚ด์— ๋๋งˆ์น  ์ˆ˜ ์žˆ๋Š” ์„ฑ๋Šฅ์— ์ค‘์ 

 - ์„ ์ ํ˜• ๋ฉ€ํ‹ฐ ํƒœ์Šคํ‚น์„ ์ง€์›ํ•˜๊ณ  ๊ฐ ํ”„๋กœ์„ธ์Šค์˜ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ์ง€์ •ํ•ด ํšจ์œจ์ ์ธ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅ

 - 100% ์™„์ „ ๋ฌด๋ฃŒ์ด๊ณ , ๋ณด์ฆ ๋ฐ ๊ธฐ์ˆ ์ ์ธ ๋ฒ•์ ๋ณดํ˜ธ๋Š” ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค

 

๐ŸŒณ ํƒœ์Šคํฌ (Task)

FreeRTOS์—์„œ ํ•˜๋‚˜์˜ task๋Š” ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ(thread)๋ฅผ ์˜๋ฏธ

 

1๏ธโƒฃ ๊ฐ task์—๋Š” ์šฐ์„ ์ˆœ์œ„๋ฅผ ํ• ๋‹นํ•˜๋ฉฐ ์ˆซ์ž๊ฐ€ ๋†’์„์ˆ˜๋ก ํฐ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

์šฐ์„ ์ˆœ์œ„๋Š” 0๋ถ€ํ„ฐ configMAX_PRIORITIES๊นŒ์ง€ ํ• ๋‹น์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ task๋Š” ๋‚ฎ์€ task๋ฅผ ์„ ์ (preemption)ํ•  ์ˆ˜ ์žˆ๊ณ , ์ด๋•Œ context switching์ด ๋ฐœ์ƒ

๋™์ผํ•œ ์šฐ์„ ์ˆœ์œ„ ์‚ฌ์ด์—์„œ๋Š” round robin์„ ์‚ฌ์šฉ

 

2๏ธโƒฃ Task๋Š” return value๊ฐ€ ์—†์œผ๋ฉฐ (void*) ํƒ€์ž…์œผ๋กœ ์—ฌ๋Ÿฌ ์ž๋ฃŒํ˜•์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค

3๏ธโƒฃ Task๋Š” ์ผํšŒ์šฉ task์™€ ์ฃผ๊ธฐ์  task 2๊ฐ€์ง€ ์ข…๋ฅ˜

1) ์ผํšŒ์šฉ task๋Š” ๊ธฐ๋Šฅ์„ ํ•œ ๋ฒˆ ์ˆ˜ํ–‰ํ•œ ๋’ค ๋งˆ์ง€๋ง‰์— ์Šค์Šค๋กœ๋ฅผ ์‚ญ์ œํ•œ๋‹ค (๊ผญ)

void ํƒœ์Šคํฌ์ด๋ฆ„( void* pvParameters ) { /* ~~~ */ vTaskDelete(NULL); }

2) ์ฃผ๊ธฐ์  task๋Š” ๋ฌดํ•œ loop๊ฐ€ ๋“ค์–ด์žˆ๋‹ค

Delay ๋˜๋Š” suspend ํ•จ์ˆ˜ ๋“ฑ์œผ๋กœ task์˜ state๊ฐ€ blocked(waiting)๋กœ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ์ด์ƒ ๊ณ„์†ํ•ด์„œ ๊ธฐ๋Šฅ์„ ๋น ๋ฅด๊ฒŒ ๋ฐ˜๋ณต ์‹คํ–‰

void ํƒœ์Šคํฌ์ด๋ฆ„( void* pvParameters ) { while(true) { /* ~~~~~ */ } }

 

4๏ธโƒฃ ๊ฐ task๋งˆ๋‹ค local stack ๊ณต๊ฐ„์ด ํ• ๋‹น

์ด ๊ณต๊ฐ„์€ ๋ฉ”๋ชจ๋ฆฌ์˜ .bss์˜์—ญ ๋˜๋Š” .heap ์˜์—ญ์— ๋“ค์–ด๊ฐ„๋‹ค

Stack ๋ฉ”๋ชจ๋ฆฌ๋Š” ์ •์  ๋˜๋Š” ๋™์ ์œผ๋กœ ํ• ๋‹น์ด ๊ฐ€๋Šฅ

 

๐ŸŒณํƒœ์Šคํฌ (Task) ๊ด€๋ จ API

1๏ธโƒฃ xTaskCreate

    /* Create our tasks. */
    xTaskCreate(
        vTaskBlink,                 /* Pointer to the Task implementation. */
        "Blink",                    /* Internal name of the task. */
        configMINIMAL_STACK_SIZE,   /* Wanted task stack size. */
        NULL,                       /* Task parameter (optional). */
        1,                          /* Task priority. */
        NULL                        /* Task handle (optional). */
    );

freertos.ino - VxWorks

pvTaskCode : task์˜ ๊ธฐ๋Šฅ์ด ์„ ์–ธ๋œ ํ•จ์ˆ˜์˜ ํ•จ์ˆ˜ํฌ์ธํ„ฐ

pcName : ๋””๋ฒ„๊น… ์šฉ๋„๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฌธ์ž์—ด์ด๋ฉฐ task์˜ ์ด๋ฆ„

usStackDepth :  task๋งˆ๋‹ค ํ• ๋‹น๋˜๋Š” stack ๋ฉ”๋ชจ๋ฆฌ

(๋‹จ์œ„๋Š” WORD์ด๋ฉฐ ARM Cortex-M๋ณด๋“œ์—์„œ๋Š” 1WORD == 4Byte)

pvParameters : task ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•  ๋งค๊ฐœ๋ณ€์ˆ˜

์—†๋‹ค๋ฉด NULL

์ „๋‹ฌํ•  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ (void*) ํƒ€์ž…์œผ๋กœ ์บ์ŠคํŒ…ํ•œ ๋’ค ์—ฌ๊ธฐ๋‹ค๊ฐ€ ๋„ฃ์–ด์ฃผ๋ฉด task ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉ

pxCreatedTaskV : task๋ฅผ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•œ TaskHandle_t ํƒ€์ž… ํ•ธ๋“ค

Task์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋ฐ”๊พธ๊ฑฐ๋‚˜, task๋ฅผ ๋ฉˆ์ถ”๊ฑฐ๋‚˜ ๋“ฑ task์— ๋Œ€ํ•œ ์„ค์ •์€ ๋ชจ๋‘ ์ด ํ•ธ๋“ค์„ ํ†ตํ•ด์„œ ์ด๋ค„์ง„๋‹ค.

 

2๏ธโƒฃ vTaskDelay

/* Delay the task 1000ms to create a 1Hz blinking. */
vTaskDelay( 1000 / portTICK_PERIOD_MS );

Task์˜ ์ƒํƒœ๋ฅผ running์—์„œ blocked(waiting)์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜

์„ค์ •๋œ ์‹œ๊ฐ„ xTicksToDelay๋™์•ˆ ํ•ด๋‹น task๋Š” blocked task๊ฐ€ ๋˜๋ฉฐ, ๋‹ค์Œ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ task๊ฐ€ ์‹คํ–‰

 

ํ™•์žฅ์„ฑ ๋ฐ ์ด์‹์„ฑ ์ข‹์€ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ tick๋‹จ์œ„ ์‹œ๊ฐ„์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค pdMS_TO_TICKS() ๋งคํฌ๋กœ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์šฐ๋ฆฌ์—๊ฒŒ ํŽธํ•œ ms(๋ฐ€๋ฆฌ์ดˆ) ๋‹จ์œ„๋ฅผ tick์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค

=> ์™œ๋ƒํ•˜๋ฉด, ์‚ฌ์šฉํ•˜๋Š” ๋ณด๋“œ์™€ ์‚ฌ์šฉ์ž ํ™˜๊ฒฝ์„ค์ • ๊ฐ’์— ๋”ฐ๋ผ 1 Tick์ด ์˜๋ฏธํ•˜๋Š” ์‹œ๊ฐ„์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ

 

๐ŸŒณ CODE ( freertos.ino - VxWorks)

// ๋ฉ€ํ‹ฐํƒœ์Šคํ‚น ํ™˜๊ฒฝ์—์„œ Task ์ฒ˜๋ฆฌ์‹œ๊ฐ„์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„๋กœ ์‚ฌ์šฉ
// ์‹ค์‹œ๊ฐ„(Real Time) ์šด์˜์ฒด์ œ(Operating System)์˜ ์•ฝ์ž
#include <Arduino_FreeRTOS.h>

/*-----------------------------------------------------------*/

void vTaskBlink( void * pvParameters );
void vTaskAnalogRead( void * pvParameters );

/*-----------------------------------------------------------*/

void setup( void )
{
    /* Initialize the serial port. */
    Serial.begin( 9600 );

    /* Create our tasks. */
    xTaskCreate(
        vTaskBlink,                 /* Pointer to the Task implementation. */
        "Blink",                    /* Internal name of the task. */
        configMINIMAL_STACK_SIZE,   /* Wanted task stack size. */
        NULL,                       /* Task parameter (optional). */
        1,                          /* Task priority. */
        NULL                        /* Task handle (optional). */
    );

    xTaskCreate( vTaskAnalogRead, "Analog", configMINIMAL_STACK_SIZE, NULL, 1, NULL );

    /* Start the kernel sheduler. */
    vTaskStartScheduler();
}
/*-----------------------------------------------------------*/

void loop( void )
{
    /* The Arduino loop function is used as the idle hook. In FreeRTOSConfig.h
    configUSE_IDLE_HOOK must be set because there are (serial) events that were
    processed in the backround of the Arduino core implementation of loop(). */
}
/*-----------------------------------------------------------*/

void vTaskBlink( void * pvParameters )
{
    /* Initialize the built in LED. */
    pinMode( LED_BUILTIN, OUTPUT );

    /* Keep the compiler happy because pvParameters is not used here. */
    ( void ) pvParameters;

    for( ;; )
    {
        /* Toggle the built in LED. */
        digitalWrite( LED_BUILTIN, digitalRead( LED_BUILTIN ) ^ 1 );

        /* Delay the task 1000ms to create a 1Hz blinking. */
        vTaskDelay( 1000 / portTICK_PERIOD_MS );
    }
}
/*-----------------------------------------------------------*/

void vTaskAnalogRead( void * pvParameters )
{
    int16_t sAnalogValue;

    /* Keep the compiler happy because pvParameters is not used here. */
    ( void ) pvParameters;

    for( ;; )
    {
        /* Read the analog value from A0 print it out. */
        sAnalogValue = analogRead( A0 );
        Serial.println( sAnalogValue );

        /* Short delay for stability. */
        vTaskDelay( 1 );
    }
}

728x90
๋ฐ˜์‘ํ˜•
Comments