인프런 강의 링크
홍영기(가일스쿨) 교수님 블로그 링크
졸업프로젝트로 FreeRTOS 기반 상용 RTOS인 'ESP-IDF'를 활용한 프로젝트를 진행한 뒤, 인프런의 FreeRTOS 강의 수강을 통해 내용을 확실히 정리했습니다. 이해한 내용을 최종적으로 정리하며 기록을 남기고자 글을 올립니다.
저작권을 최대한 존중하기 위해 홍영기 교수님의 강의자료와 실습자료는 일부라도 절대 공유하지 않으며, FreeRTOS 공식 레퍼런스 문서를 기반으로 작성합니다.
Task와 task 간의 communication을 위해서 FreeRTOS에서 마련한 세 가지 방법은 다음과 같다.
이 중 semaphore에 대해서는 앞서 다뤘으니, 이번에는 나머지 IPC 방법들에 대해 다뤄보자.
Event flag는 비트마스킹을 사용해 task로부터 event를 수신하는 방법이다. 임의의 task 또는 ISR에서 event flag를 set()
하면, 대응하는 다른 task 또는 ISR에서 get()
해서 특정 event를 수행하도록 만드는 것이 flag를 사용한 통신의 핵심이다.
예를 들어, 하나의 동작을 구성하는 n개의 작은 task가 있다고 가정하자. i번째 task는 i번째 인덱스의 bit에 대응하도록 event flag bit 배열을 만든다. 특정 task에서 문제가 발생해서 k번째 bit가 1
이 됐다. 모든 task를 수행한 뒤 event & 0 == event
라면 동작을 수행할 수 있지만, k번째 bit가 1
이므로 문제가 발생했고 그것이 k번 task에서 발생했음을 알 수 있다.
EventGroupHandle_t xEventGroupCreate()
EventBits_t xEventGroupSetBits(EventGroupHandle_t handle, EventBits_t uxBitsToSet)
xEventGroup
은 event group에 대한 handle을 의미한다. Create 함수의 반환 객체를 여기다가 넣어주면 된다.uxBitsToWaitFor
는 기다리고 있는 bit나 event를 ‘+’기호를 사용해서 표현한다.xClearOnExit
는 이름 그대로 event를 전달 받았을 때 해당 bit를 다시 초기화할 것인지 여부를 설정한다. 이를 pdTRUE
로 설정하지 않으면 마치 event가 미친듯이 빠른 속도로 연속해서 들어오는 것으로 인식한다. 특수한 경우 아니면 pdTRUE
로 고정할 것.xWaitForAllBits
는 기다리는 bits를 OR연산 처리할 것인지 AND연산 처리할 것인지 여부를 결정한다. pdFALSE
면 OR연산 처리되서 기다리는 bit 중 어느 하나라도 들어오면 성공 처리하고, pdTRUE
면 AND연산 처리되서 기다리는 bit 모두 들어와야 성공 처리한다.xTicksToWait
은 event를 기다리는 시간을 의미한다. 별 상관없으면 보통 portMAX_DELAY
를 사용해서 계속 기다리도록 설정한다.void xEventGroupDelete(EventGroupHandle_t handle)
xEventGroupSetBits()
로 group_id
에게 ENGINE_OIL_PRES_OK
event를 10번 전송한다.ENGINE_OIL_PRES_OK
를 xEventGroupWaitBits()
로 기다리다가 받자마자 ***Event Arrived!***
문장을 송출한다.지금까지 배운 IPC인 semaphore와 event flag는 bit값을 바꾸면서 서로 약속된 의미로 해석한 뒤 특정 기능을 수행하는 방식으로 돼있다면, message queue는 정수, 실수, 구조체, 심지어는 사진, 음악도 전송할 수 있는 아주 강력한 IPC 기능이다.
x
를 write한다.x
를 다시 queue에 write한다.Y
를 초기화한다. 이때 read와 동시에 delete한다.FreeRTOS의 queue는 ‘copy’ 방식을 채택한다. 물론 queue에 무엇이 저장될지 알 수 없기 때문에 포인터를 사용한 reference 방식이 좋겠지만, 당연히 task에서 선언한 변수는 local stack에 저장되기 때문에 포인터를 사용했다가는 엄청난 fault가 발생할 것이 예상되기 때문이다.
Message Queue를 활용한 통신의 종류는 다음과 같다.
task_id
라는 uint16_t
형의 양수를 선언해서 queue의 해당 정보가 어느 task로부터 전송됐는지를 표현하는 방법이다.qid
라는 message queue에서 xMessage
를 기다리는 동안 blocked 될 것이다.qid
에 10의 배수를 xQueueSend()
함수로 전송한다.