[FreeRTOS 정리] 4. IPC (Inter Process Communication)

Embedded June·2021년 8월 15일
0

FreeRTOS

목록 보기
4/5

인프런 강의 링크
홍영기(가일스쿨) 교수님 블로그 링크

졸업프로젝트로 FreeRTOS 기반 상용 RTOS인 'ESP-IDF'를 활용한 프로젝트를 진행한 뒤, 인프런의 FreeRTOS 강의 수강을 통해 내용을 확실히 정리했습니다. 이해한 내용을 최종적으로 정리하며 기록을 남기고자 글을 올립니다.

저작권을 최대한 존중하기 위해 홍영기 교수님의 강의자료와 실습자료는 일부라도 절대 공유하지 않으며, FreeRTOS 공식 레퍼런스 문서를 기반으로 작성합니다.


6. IPC (Inter Process Communication)

Task와 task 간의 communication을 위해서 FreeRTOS에서 마련한 세 가지 방법은 다음과 같다.

  1. Semaphore
  2. Event flag
  3. Message box(queue)

이 중 semaphore에 대해서는 앞서 다뤘으니, 이번에는 나머지 IPC 방법들에 대해 다뤄보자.

6.1. Event Flag Group

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)

6.2. 실습 06 - Event Group Flag

  • Task1이 xEventGroupSetBits()group_id에게 ENGINE_OIL_PRES_OK event를 10번 전송한다.
  • Task2는 ENGINE_OIL_PRES_OKxEventGroupWaitBits()로 기다리다가 받자마자 ***Event Arrived!*** 문장을 송출한다.

6.3. Message Queue

지금까지 배운 IPC인 semaphore와 event flag는 bit값을 바꾸면서 서로 약속된 의미로 해석한 뒤 특정 기능을 수행하는 방식으로 돼있다면, message queue는 정수, 실수, 구조체, 심지어는 사진, 음악도 전송할 수 있는 아주 강력한 IPC 기능이다.

  1. Task A가 Queue에 자신의 지역변수 x를 write한다.
  2. Task A가 후속과정을 처리하다가 x값을 변경하고, x를 다시 queue에 write한다.
  3. Task B가 생성된 뒤 queue를 read해 자신의 지역변수 Y를 초기화한다. 이때 read와 동시에 delete한다.

FreeRTOS의 queue는 ‘copy’ 방식을 채택한다. 물론 queue에 무엇이 저장될지 알 수 없기 때문에 포인터를 사용한 reference 방식이 좋겠지만, 당연히 task에서 선언한 변수는 local stack에 저장되기 때문에 포인터를 사용했다가는 엄청난 fault가 발생할 것이 예상되기 때문이다.

Message Queue를 활용한 통신의 종류는 다음과 같다.

  1. 1:1 (단방향 / 양방향) 통신
  2. 1:多 통신
  3. 多:1 통신
    • 1:1과 1:多는 너무 기본적인 내용이라 직관적으로 이해가 갈 것이다. Queue가 비어있다면, receive를 요청한 task는 blocked 될 것이기 때문이다.
    • 반면 多:1은, 해당 정보를 ‘누가 보냈는가?’를 해소해줘야 한다. 따라서, FreeRTOS에서 권장하는 방법은 구조체를 사용하고, 약속된 임의의 task_id 라는 uint16_t 형의 양수를 선언해서 queue의 해당 정보가 어느 task로부터 전송됐는지를 표현하는 방법이다.
  4. 多:多 통신

6.4. 실습 07 - Message Queue 활용

  • Task1은 qid라는 message queue에서 xMessage를 기다리는 동안 blocked 될 것이다.
  • Task2는 1초에 한 번씩 qid에 10의 배수를 xQueueSend() 함수로 전송한다.
  • 메시지를 받은 task1은 blocked에서 풀려나며 받은 메시지를 출력한다.


profile
임베디드 시스템 공학자를 지망하는 컴퓨터공학+전자공학 복수전공 학부생입니다. 타인의 피드백을 수용하고 숙고하고 대응하며 자극과 반응 사이의 간격을 늘리며 스스로 반응을 컨트롤 할 수 있는 주도적인 사람이 되는 것이 저의 20대의 목표입니다.

0개의 댓글