4. Free RTOS - Task 생성하기, Multi Task(with STM32L475VGT, B-L475E-IOT01A1)

728x90
반응형

https://vuzwa.tistory.com/entry/2-Free-RTOS-UART-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0with-STM32L475VGT-B-L475E-IOT01A1

 

2. Free RTOS - UART 사용하기(with STM32L475VGT, B-L475E-IOT01A1)

이전 포스팅에서는 RTOS 프로젝트 생성까지 확인해봤다. https://vuzwa.tistory.com/entry/1-Free-RTOSwith-STM32L475VGT-B-L475E-IOT01A1 1. Free RTOS(with STM32L475VGT, B-L475E-IOT01A1) RTOS를 포스팅해야지..

vuzwa.tistory.com

 

이전 포스팅에서는 C 표준 함수를 통해 UART 입출력을 구현했다. 여기까지 했으면 RTOS를 공부하기 위한 준비는 끝. 그럼 RTOS의 가장 기본이자 핵심?이라 말할 수 있는 Task에 대해 알아보자.

Task를 만들어주는 함수를 보면 Task.h에서 확인할 수 있고,

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
	BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,
	const char * const pcName,	/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
	const configSTACK_DEPTH_TYPE usStackDepth,
	void * const pvParameters,
	UBaseType_t uxPriority,
	TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;
#endif

 

이렇게 선언되어 있다. 전달 인자 별로 어떤 값을 넣어줘야 하는지 아래 정리한 표 참고,

 

이제부터 본격적으로 RTOS 프로그램을 할 건데 하기 전에 한 가지 알아둬야 할 게 있다. 

소스코드의 작성은 freertos.c에서 작성한다. 일반적으로 OS 없는 None OS 상태(Baremetal FW라고도 함.)에서 펌웨어를 작성하면 main.c에 while(1) 루프(슈퍼 루프, 빅루프라고 표현함.)에서 코드가 돌아가지만, RTOS를 올리는 순간부터는 Task에서 호출한 함수의 코드가 동작한다. 

 

 

Single Task


Task를 하나만 만들어서 확인해보자. 

  xTaskCreate(vTask1, /*Pointer to the function that implements the task*/
		"Task 1",		/*text name*/
		128,			/*stack depth*/
		NULL,			/*task parameter*/
		3,			/*task priority*/
		NULL);		/*task handle */

"Task 1"에서는 vTask1을 호출하고, Task의 사이즈는 128, 전달 인자는 없고, 우선순위는 3, 핸들러는 NULL로 Task를 만들었다. 

"Task 1"에서 호출될 함수를 작성해보자.

void vTask1(void *pvParameters)
{
	for(;;)	{
		HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
		vTaskDelay(500);
	}
}

이렇게 작성하고 동작시키면 LD2가 500 msec 간격으로 깜빡이는 걸 확인할 수 있다.

 

 

Multi Task


Multi Task, 두 개 이상의 Task가 동작할 때, Multi Task라고 표현한다. 구현 방법은 크게 두 가지가 있다.

 

첫 번째, 두 개 이상의 Task를 만들고, 하나의 함수를 호출하는 방법과

두 번째, 두 개 이상의 Task를 만들고, 각 Task마다 각각 다른 함수를 호출하는 방법

 

우선 두 번째 방법 먼저 확인해보자.

 

Task 생성 코드

  xTaskCreate(	vTask1, 	/* Pointer to the function that implements the task*/
            "Task1",	/* text name*/
            128, 		/* stack depth */
            NULL, 		/* task parameter. */
            3, 			/* task priority */
            NULL);		/* task handle */

  xTaskCreate( vTask2, "Task2", 128, NULL, 4, NULL);

 

2개의 Task를 만들고, 각각 다른 함수를 호출했다. vTask1, vTask2는 아래 코드와 같이 구현

void vTask1(void *pvParameters)
{
	while(1)	{
		printf("Task1\r\n");
		vTaskDelay(100);
	}
}

void vTask2(void *pvParameters)	
{
	while(1)	{
		printf("Task2\r\n");
		vTaskDelay(100);
	}
}

100 msec 간격으로 데이터를 전송한다. 결과는 

 

잘된다.

 

그럼 첫 번째 방법을 살펴보자.

 

 

우선 하나의 함수로 두 개의 Task를 생성

	xTaskCreate(vTaskFunction, "Task 1", 128, (void*)pcTextForTask1, 3, NULL);
	xTaskCreate(vTaskFunction, "Task 2", 128, (void*)pcTextForTask2, 3, NULL);

Task에서 동작시킬 함수를 Task 1, Task 2 모두 vTaskFunction으로 하고 Task의 파라미터에 각각 다른 변수를 전달했다.

 

변수는 다음과 같이 선언

const char *pcTextForTask1 = "Task 1\r\n";
const char *pcTextForTask2 = "Task 2\r\n";

 

Task 1에는 "Task 1\r\n", Task2에는 "Task 2\r\n" 문자열이 각각 전달,

 

vTaskFunction 함수는 아래와 같이 작성

void vTaskFunction(void *pvParameters)
{
	char *pcTaskName;
	pcTaskName = (char *)pvParameters;

	while(1)	{
		printf(pcTaskName);
		vTaskDelay(10);
	}
}

 

동작시켜보면 다음과 같다. 

하나의 함수를 서로 다른 Task에서 호출되는 것을 확인할 수 있다.

 

 

 

우선순위


FreeRTOS에서도 MCU의 interrupt와 마찬가지로 Task의 우선순위를 지정할 수 있다. 

 

xTaskCreate(	TaskFunction_t pxTaskCode,
                const char * const pcName,		/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                const configSTACK_DEPTH_TYPE usStackDepth,
                void * const pvParameters,
                UBaseType_t uxPriority,
                TaskHandle_t * const pxCreatedTask )

 

5번째 전달인자 uxPriority가 RTOS의 우선순위다. MCU interrupts는 숫자가 작을수록 우선순위가 높지만, RTOS는 숫자가 높을수록 우선순위가 높은 Task가 된다. 

 

우선순위에 관한 내용은 다음 포스팅에서 이어가도록 하겠다. 

 

- 끝 -

 

728x90
반응형