RTOS 동기화
RTOS에서 태스크 동기화(task synchronization)는 한마디로 특정 자원을 여려 태스크가 공유해 사용할 때 발생하는 교착상태(deadlock)를 해소하는 방법을 의미합니다.
교착상태는 하나의 자원을 여러 태스크가 서로 사용하겠다고 또는 어떤 이유에서 인지 태스크가 반환하지 못하는 경우에 발생해서 관련된 태스크들이 동작을 멈추는 현상으로 RTOS가 가지는 문제 중 하나입니다.
예를 들어 아두이노에서 Serial.pintln()을 두 개의 태스크가 서로 사용하려 하면 둘 중에 하나의 태스크만 사용할 수 있거나, 둘 다 사용하지 못하는 경우가 발생합니다.
이와 같은 문제를 해결하는 방법이 동기화이고 FreeRTOS는 세마포어(semaphore)와 뮤텍스(mutex)를 사용합니다.
세마포어
세마포어에는 이진 세마포어(binary semaphore)와 계수형 세마포어(counting semaphore)가 있습니다.
- 이진형 세마포어 : 두 가지 상태만 가지기 때문에 붙여진 이름입니다. 아래서 설명한 뮤 텍스도 두 가지 상태만 가지기 때문에 FreeRTOS는 이진 세마 모어를 뮤 텍스처 럼 사용합니다. 그러나 엄밀히 말하면 두 내용 조금 다릅니다.
- 계수형 세마포어 : 자원에 다수의 태스크가 접근이 가능하고, 대기하고 있다가 사용권한을 얻으면 태스크가 자원을 사용하는 방식입니다.
다른 글에서 세마포어를 사용한 시리얼통신에 대해 설명한 적이 있기 때문에 예제는 생략하겠습니다.
뮤텍스
- 뮤텍스는 두 개의 상태만 가집니다. 일반적으로 lock, unlock 상태라고 부르지만 FreeRTOS에서는 이진형 세마포어를 사용하기 때문에 다른 형태를 사용합니다.
- 뮤텍스는 태스크가 특정 자원을 사용할 때 lock을 설정하고 사용을 다했으면 unlock을 해서 다른 태스크가 사용하도록 유도합니다. 그래서 사용하고자 하는 자원에서 뮤텍스 상태를 제어합니다.
- 뮤텍스는 인터럽(interrupt)에서 사용할 수 없지만, FreeRTOS에서는 이진형 세마포어를 사용하기 때문에 인터럽 접근이 가능합니다.
- 단 뮤텍스는 우선순위가 높은 태스크가 계속 자원을 사용하면 낮은 태스크가 접근하지 못할 수 있는 단점이 있습니다.
다음은 뮤텍스와 Arduino Mega 등에서도 사용이 가능하도록 참조의 _printf()를 확장한 내용입니다. 즉 C언어의 printf 형식을 사용하면서 여러 uart 포트에 접근하면서 태스크 동기화까지 합니다.
RTOS를 사용하지 않는다면 _printf()에서 RTOS와 관련된 두 개의 함수만 삭제하면 됩니다.
// ref : https://studymake.tistory.com/696
// 설정방법을 참조해야합니다.
#include <FreeRTOS_AVR.h>
#include <stdio.h>
#include <stdarg.h>
#define UART0_USING (0)
#define UART1_USING (1)
SemaphoreHandle_t tx_mutex;
setup(){
Serial.begin(115200);
Serial1.begin(115200);
tx_mutex = xSemaphoreCreateMutex();
//- freertos 실행
vTaskStartScheduler();
//- freerto 오류임을 알림
Serial.println("FreeRTOS Error.");
while(1){;}
}
lop(){
}
// uart_nu = UART1 or UART2
void _printf(int uart_nu, const char *s, ...){
xSemaphoreTake(tx_mutex,portMAX_DELAY);
va_list args;
va_start(args, s);
int n = vsnprintf(NULL, 0, s, args);
char *str = new char[n+1];
vsprintf(str, s, args);
va_end(args);
//gpio.Control_LED4(LED4_SERIAL_PIN,HIGH);
switch(uart_nu){
case UART0_USING:
Serial.print(str);
break;
case UART1_USING:
Serial1.print(str);
break;
}
delete [] str;
xSemaphoreGive(tx_mutex);
}
- SemaphoreHandle_t tx_mutex로 UART 자원을 태스크 동기화할 뮤텍스를 선언
- tx_mutex = xSemaphoreMutex()로 이진형 세마포어를 뮤텍스 생성
- _printf()에서 Serial, Serial1에 접근하기 위한 키값으로 UART0_USING, UART1_USING을 사용
- _pritnf()를 어느 함수 또는 태스크에서 사용을 시작하면 xSemaphoreTake()로 뮤텍스를 얻어서 자원에 대한 점유를 lock으로 설정
- Serial로 통신이 완료되면 xSemaphoreGive()로 뮤텍스를 반환해서 unlock으로 자원 점유 해제해서 다른 태스크에서 서 uart 자원을 사용하도록 허용.
광고좀 꾹 눌러주시면 고맙겠습니다.
위의 내용을 참조용으로만 사용해주세요. 무단 도용이나 무단 복제는 불허합니다.
기타 문의 사항은 gigasound@naver.com에 남겨 주시면 고맙겠습니다.
'Embedded' 카테고리의 다른 글
FreeRTOS와 Semaphore, Queue를 이용한 시리얼 통신 (0) | 2021.10.24 |
---|---|
Arduino, FreeRTOS, LED Toggle (0) | 2021.10.23 |
라즈베리파이에서 UART 사용 (0) | 2021.10.10 |
시리얼 통신을 위한 Queue의 생성 (0) | 2021.08.17 |
RaspberryPi-온도에 따라 제어되는 FAN 구성 (0) | 2021.08.14 |