CS/Embedded System

FreeRTOS - Task Management

WakaraNai 2021. 12. 8. 01:06
728x90
반응형

Sharing Resources

한 화면에 각 task가 동시에 글을 쓰려고 하면 글이 깨짐

여기서 화면이 바로 공유되는 자원

 

FreeRTOS

이를 이용하면  AWS와도 되는 IoT를 만들 수 있음

 

특징

  • source code - 일관성 있고, 깔끔하고, 주석도 많아서 이해하기 좋음
  • portable : 이식성 (ARM, intel, texas instrument 등 가능) (Assembly로 보관)
  • scalable : 필요한 기능만 설정해서 쓸 수 있게 하여 크기를 작게 (FreeRTOSConfig.h) (최소 footprint=4KB)
  • fully preemptive scheduling : 더 높은 우선순위가 오면 지금 하는 걸 당장 stop
  • copperative scheduling : context switch 발생하는 경우는
    • when a task/co-routine blocks (ex - by pending semaphore)
    • when a task/co-routine yields the CPU (ex - by explicit yield API)
  • multitasking : task 개수 제한X . 우선순위가 동일한 task들은 시간을 잘게 쪼개서 최대한 동시에 돌아가는 것처럼 보이게 함 (==round robin)
  • service : 큐, semaphore(binary or counting), mutexes (recursion, priority inheritance)
  • interrupt management (RTOS Time Tick Interrupt) :
    • system interrupt가 들어올 때마다
    • 지금 시간을 공평하게 나눠가져야하는 task 가 있다면
    • CPU scheduler가 시간을 잘게 쪼개어 자원을 할당함 (Round Robin)
    • 그리고 매 5초마다 동작해야하는 일이 있다면
    • tick timer가 5초 간격으로 도착했을 때마다 task를 실행하도록 하기 (suspend a task execution)
    • EXP_MSP432P411 port에서 systick이 RTOS time tick으로 사용됨

 

FreeRTOS for EXP_MSP432P411



main() in FreeRTOS Overview

  1. initialize HW - led, btn 등등
  2. create task
  3. initialize resource sharing primitives - semaphore, queue…
  4. start os

header file

/* Driver configuration */
#include <ti/devices/msp432p4xx/inc/msp.h>
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
#include <ti/drivers/Board.h>

/* RTOS header files */
#include <FreeRTOS.h>
#include <task.h>
#include <semphr.h>

 


 

Task

각 task는 return 되지 않는 기능, 즉 무한루프를 가짐

각 task마다 필요한 함수를 stack space에 올리기 위해 필요한 space를 적고 priority를 매김

모든 task는 void return type이고 single void * argument를 가짐.

즉 argument를 가질 때 필요한 pointer를 넣을 수 있게 됨

 

예) LED P1.0을 무한히 깜박이는 task를 작성해달라고 하면 이걸 작성하면 됨

 

 

task 생성

xTaskCreate( Task1, /* The function that implements the task. */
  "Task 1", /* The text name assigned to the task – for debug only as it is not used by the kernel. */
  configMINIMAL_STACK_SIZE, // The size of the stack to allocate to the task. 
  ( void * ) 0, // The parameter passed to the task - just to check the functionality. 
  5, // The priority assigned to the task. 
  NULL ); // The task handle is not required, so NULL is passed.
  • pvTaskCode: Pointer to the task entry function
    • Tasks must be implemented to never return (i.e.continuous loop)
  • pcName: A descriptive name for the task
    • This is mainly used to facilitate debugging. 
    • Max length defined by tskMAX_TASK_NAME_LEN – default = 16
  • usStackDepth: The size of the task stack
    • specified as the number of variables the stack can hold - not the number of bytes. 
    • For example, if the stack is 16 bits wide and usStackDepth is defined as 100, 
    • 200 bytes (1600/8) will be allocated for stack storage
  • 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 ).
  • pvCreatedTask: Used to pass back a handle by which the created task can be referenced
  • pdPASS: If the task was successfully created and added to a ready listotherwise an error code
    defined in the file errors.h

 

Task Priorities

The priority of a task is a number between 0 and configMAX_PRIORITIES – 1

  • A higher number indicates a higher priority
  • configMAX_PRIORITIES can be adjusted in FreeRTOSConfig.h.
    • The default is: #define configMAX_PRIORITIES 10 - maximum
  •  0과 10은 idle task가 쓰기에 user defined task는 그 외의 숫자를 사용해야 함
    • 0은 삭제된 task에 할당된 memory를 free하는 것에 사용
    • #define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)

Task and Stack

 


Programming Exercise : 2 Tasks

필요한 header와 선언

/* Driver configuration */
#include <ti/devices/msp432p4xx/inc/msp.h>
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
#include <ti/drivers/Board.h>

/* RTOS header files */
#include <FreeRTOS.h>
#include <task.h>#include <semphr.h>



만든 2개의 task를 main()에서 실행시키자

-> Task1의 우선순위가 더 높아서 Task2가 실행 안 됨

-> RGB LED 동작X

/* function prototypes */
void Task1( void *pvParameters );
void Task2( void *pvParameters );

void main(void)
{
  /* Configuring S1&S2 buttons/Red LED&RGB LEDs in mainboard */
  P1->DIR = BIT0;
  P1->DIR &= ~(BIT1|BIT4);
  P2->DIR |= 1<<2 | 1<<1 | 1<<0;
  P1->REN |= (BIT1|BIT4);
  P1->OUT |= (BIT1|BIT4);
  P2->OUT = 0x00;
  

  xTaskCreate( Task1,
 		"Task 1", 
        	configMINIMAL_STACK_SIZE, 
            (void*)0, 
            5,
            NULL);
            

  xTaskCreate( Task2,
 		"Task 2", 
        	configMINIMAL_STACK_SIZE, 
            (void*)0, 
            4,
            NULL);
            
            
    /* Start the tasks and timer running. */
  vTaskStartScheduler();

  while (1)
  {
  }
  
}


/*
void wait (void) {
  int d;
  for (d = 0; d < 2000000; d++);
}
*/

void Task1(void *pvParameters)
{
  int a;
  while (1) {
    P1->OUT = BIT1 | BIT4 | BIT0;
    for (i=0;i<100000;i++) ; // wait();
    P1->OUT = BIT1|BIT4;
    for (i=0;i<100000;i++) ; // wait();
  }
}

void Task2( void *pvParameters )
{
  int i;
  while (1) {
    P2->OUT = BIT0;
    for (i=0;i<100000;i++) ;
    P2->OUT = 0x00;
    for (i=0;i<100000;i++) ;
  }
}

 

 


 

Prioritized Preemptive Scheduling with Time Slicing

It can be selected in FreeRTOSConfig.h

#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1

이 알고리즘은 고정된 priority로 변하지 않음

더 높은 우선순위의 task가 ready가 되면 running task는 선점된다(preemted)

 

Time slicing

동등한 우선순위를 갖는 ready tasks 사이에서 processing time을 공유하기 위해 사용 

"take it in turn" policy (round robin scheduling)

 

 

Task Status in FreeRTOS

  • Running : Task is actually executing
  • Ready
    • Task is ready to execute
    • but a task of equal or higher priority is Running
  • Blocked : Task is waiting for some event
    • Time: if a task calls vTaskDelay() it will block until the delay period has expired
    • Resource: Tasks can also block waiting for queue and semaphore events
  • Suspended
    • Much like blocked, but not waiting for anything
    • Tasks will only enter or exit the suspended state 
    • suspended state is on only when explicitly commanded to do so
    • through the vTaskSuspend() and xTaskResume() API calls respectively

 

 

Task Management API in FreeRTOS

<우선순위 변경>

pxTask: 우선순위 값 설정. NULL을 주면 task 생성 시 우선순위로 결정

uxNewPriority: The priority to which the task will be set.

(즉, xTaskCreate()의 pvCreatedTask 값)

void vTaskPrioritySet(
    xTaskHandle pxTask,
    unsigned uxNewPriority );


Programming Exercise : 2 Tasks with Task Handler

vTaskPrioritySet() 추가 

-> 이제는 Red LED와 RED LED가 교대로 깜박임

-> 근데 동시에는 아님

/////// 추가
/* global variables */
TaskHandle_t task1Handle, task2Handle;
///////////

/* function prototypes */
void Task1( void *pvParameters );
void Task2( void *pvParameters );

void main(void)
{
  /* Configuring S1&S2 buttons/Red LED&RGB LEDs in mainboard */
  P1->DIR = BIT0;
  P1->DIR &= ~(BIT1|BIT4);
  P2->DIR |= 1<<2 | 1<<1 | 1<<0;
  P1->REN |= (BIT1|BIT4);
  P1->OUT |= (BIT1|BIT4);
  P2->OUT = 0x00;
  

  xTaskCreate( Task1,
 		"Task 1", 
        	configMINIMAL_STACK_SIZE, 
            (void*)0, 
            5,
            &task1Handle); // 변경
            

  xTaskCreate( Task2,
 		"Task 2", 
        	configMINIMAL_STACK_SIZE, 
            (void*)0, 
            4,
            &task2Handle); // 변경
            
            
    /* Start the tasks and timer running. */
  vTaskStartScheduler();

  while (1)
  {
  }
  
}


/*
void wait (void) {
  int d;
  for (d = 0; d < 2000000; d++);
}
*/


// task1은 자신의 일을 끝내고 task2보다 우선순위를 낮춤
// task2가 실행된 후 task1을 자신보다 높임
void Task1(void *pvParameters)
{
  int a;
  while (1) {
    P1->OUT = BIT1 | BIT4 | BIT0;
    for (i=0;i<100000;i++) ; // wait();
    P1->OUT = BIT1|BIT4 ;
    for (i=0;i<100000;i++) ; // wait();
    vTaskPrioritySet(task1Handle, 3); // 추가
  }
}

void Task2( void *pvParameters )
{
  int i;
  while (1) {
    P2->OUT = BIT0;
    for (i=0;i<100000;i++) ;
    P2->OUT = 0x00;
    for (i=0;i<100000;i++) ;
    vTaskPrioritySet(task1Handle, 5); // 추가
  }
}
// 동시에 실행 - 서로의  handler에 같은 우선순위 부여
void Task1( void *pvParameters )
{
    int i;
    while (1)
    {

       P1->OUT = BIT1|BIT4 | BIT0;
       for (i=0;i<100000;i++);
       P1->OUT = BIT1|BIT4;
       for (i=0;i<100000;i++);
       vTaskPrioritySet(task2Handle,5);
    }
}

void Task2( void *pvParameters )
{
    int i=0;
    while (1)
    {
        P2->OUT = BIT0;
        for (i=0;i<100000;i++);
        P2->OUT = 0x00;
        for (i=0;i<100000;i++);
        vTaskPrioritySet(task1Handle,5);
    }
}

Programming Exercise : 2 Tasks with vTaskDelay()

동시에 깜박이게 하기 위해

FreeRTOS는 time ticks에서 vTaskDelay(x)를 제공

 

for (i=0;i<10000;i++); 대신에

vTaskDelay(100);

/* function prototypes */
void Task1( void *pvParameters );
void Task2( void *pvParameters );

void main(void)
{
  /* Configuring S1&S2 buttons/Red LED&RGB LEDs in mainboard */
  P1->DIR = BIT0;
  P1->DIR &= ~(BIT1|BIT4);
  P2->DIR |= 1<<2 | 1<<1 | 1<<0;
  P1->REN |= (BIT1|BIT4);
  P1->OUT |= (BIT1|BIT4);
  P2->OUT = 0x00;
  

  xTaskCreate( Task1,
 		"Task 1", 
        	configMINIMAL_STACK_SIZE, 
            (void*)0, 
            5,
            NULL);
            

  xTaskCreate( Task2,
 		"Task 2", 
        	configMINIMAL_STACK_SIZE, 
            (void*)0, 
            4,
            NULL);
            
            
    /* Start the tasks and timer running. */
  vTaskStartScheduler();

  while (1)
  {
  }
  
}

void Task1(void *pvParameters)
{
  while (1) {
    P1->OUT = BIT1 | BIT4 | BIT0;
    vTaskDelay(100);
    P1->OUT = BIT1|BIT4;
    vTaskDelay(100);
  }
}

void Task2( void *pvParameters )
{
  while (1) {
    P2->OUT = BIT0;
    vTaskDelay(100);
    P2->OUT = 0x00;
    vTaskDelay(100);
  }
}

 

1. Task 1과 2를 실행할 준비가 되었습니다. (ready to run)
2. Task 1이 예약됨(scheduled) (Task 2보다 우선 순위가 높기 때문에)
3. Task 1 속 vTaskDelay() → Task 1은 다음 100회까지 blocked됨
4. Task 2가 예약됨(scheduled) (우선 순위가 높은 Task 1이 blocked되어 있기 때문).
5. Task 2 속 vTaskDelay()Task 2는 다음 100번까지 blocked됨
6. Task 1은 100회 체크 후 blocked state에서 ready state를 가져옴
7. Task 1이 예약됨 
8. Task 2는 100회 체크 후  blocked state에서 ready state를 가져옴
그러나 Task 1이 running 중이므로 scheduled할 수 없습니다.
9. ...

 


Time Tick Hook

매 SysTick interrupt마다 

main_freertos.c(main파일) 속 vApplicationTickHook()이 호출됨

그니까 고리에 걸린 것도 같이 호출하게 하는 식

// main_freertos.c:
void vApplicationTickHook()
{
	/* Handle Time Tick */
}

이 기능을 쓰고 싶다면

FreeRTOSConfig.h에서 1로 설정해줘야함

#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 1
#define configUSE_MALLOC_FAILED_HOOK 0

아무 것도 안 하는 Task1을 작성하고

time tick hook을 써서 Red LED 깜박여보세요

/* function prototypes */
void Task1( void *pvParameters );
void Task2( void *pvParameters );

void main(void)
{
  /* Configuring S1&S2 buttons/Red LED&RGB LEDs in mainboard */
  P1->DIR = BIT0;
  P1->DIR &= ~(BIT1|BIT4);
  P2->DIR |= 1<<2 | 1<<1 | 1<<0;
  P1->REN |= (BIT1|BIT4);
  P1->OUT |= (BIT1|BIT4);
  P2->OUT = 0x00;
  

  xTaskCreate( Task1,
 		"Task 1", 
        	configMINIMAL_STACK_SIZE, 
            (void*)0, 
            5,
            NULL);
            

  xTaskCreate( Task2,
 		"Task 2", 
        	configMINIMAL_STACK_SIZE, 
            (void*)0, 
            4,
            NULL);
            
            
    /* Start the tasks and timer running. */
  vTaskStartScheduler();

  while (1)
  {
  }
  
}

void Task1(void *pvParameters)
{
  while (1) {}
}

void Task2( void *pvParameters )
{
  while (1) {}
}

void vApplicationTickHook (void)
{
	static int flag = 1; // 이 파일 밖에서 접근할 수 있도록 static 선언
    if (flag % 100 == 0) {
    	P1->OUT ^= BIT0;
        flag = 0;
    }
    flag++;
}
728x90
반응형