RTOS Task

RTOS를 사용하는 이유는 여러가지 업무(Task)를 동시에 처리하기 위해서입니다. MP3 플레이어를 예를 들어 보겠습니다. MP3 플레이어의 기본적인 기능은 다음과 같습니다.

 

  • MP3 파일 입/출력 처리
  • MP3 파일 Decoding
  • Decoding 음원 출력
  • Button 입력 처리
  • GUI 화면 처리
  • 배터리 모니터링
  • 기타등등

 

간단한 MP3 플레이어라고 해도 꽤 많은 업무를 동시에 처리해야 합니다. 위의 업무중에서는 파일 입/출력, Decoding 과 같은 CPU의 로드가 상당히 많이 필요한 업무들이 있습니다.

 

이러한 업무들을 순차처리 할 경우에 CPU의 리소스를 하나의 업무에서 독점하므로 음원이 끊어지는 상황이나 Button이 간헐적으로 동작하지 않는 상황, GUI 업데이트 되지 않는 등의 문제가 발생할 수 있습니다.

 

이러한 문제점을 해결하기 위해서는 RTOS의 병렬처리가 필수입니다. 각각의 업무에 우선순위를 부여하고 우선순위가 높은 업무를 주로 처리하며 여유의 시간에 다른 우선순위가 낮은 업무들을 처리하게 하므로 마치 동시에 많은 업무들을 실시간으로 처리하는 듯한 느낌을 줄 수가 있습니다.

 

이러한 스케줄과 우선순위에 따라 동작하는 단위가 바로 Task입니다. Task는 사용자에 의해 생성이 가능하며 우선순위를 가질 수 있으며 RTOS 커널의 스케줄러에 의해 스위칭 될 수 있습니다.

 

싱글 CPU는 멀티 프로세싱을 할 수 없고 한번에 하나의 Task만 처리가 가능하기 때문에 우선순위와 스케줄링에 따라 다른 Task가 실행되도록 하여야 하며 이를 Context 스위칭이라고 합니다.

 

하나의 Task내에는 그 Task를 이루는 다양한 Context들이 존재합니다. 예를 들면 Task내에서 사용하는 변수나 CPU register 가 그것입니다. 이러한 Context들을 다음 스케줄에 올바르게 복원해줘야 RTOS의 병렬처리가 문제없이 구동됩니다.

 

이번장에서는 Task의 기본 구조체를 만들어 보도록 하겠습니다.

#define TASK_NAME_MAXLEN    (16)

/* Task의 현재 상태 */
enum
{
  TASK_WAITING,
  TASK_READY,
  TASK_RUNNING,
};

struct task_block
{
  char name[TASK_NAME_MAXLEN]; /* Task 이름 */
  int id;                      /* Task 고유 번호 */
  int state;                   /* Task 상태 */
  void (*start)(void *arg);    /* Task 함수 포인터 */
  void *arg;                   /* Task 함수 전달 파라메터 */
  uint8_t *sp;                 /* Task stack pointer */
  uint32_t wakeup_time;        /* Waiting 시간 */
  uint8_t priority;            /* 우선순위 */
  struct task_block *next;     /* 다음 실행 task */
};

typedef struct task_block task_block_t;
 

위의 task_block_t 구조체는 Task를 만들 때 사용하게 됩니다. 다음 장에서는 Task Creation 위한 스택에 대해 좀 더 자세히 이야기 해보도록 하겠습니다.

 

 

 

참조 : 임베디드 시스템 아키텍처(다니엘 라카메라)