점점 고급으로 넘어가네요 ㅋㅋ

이번에 다룰 내용은 메일박스와 메세지 큐입니다.

헷갈리지 않게 메일박스와 메세지 큐를 간단하게 비교해보면요

"메시지 큐는 메일박스를 조기 묶는 밧줄로 줄줄줄 묶어 놓은 것이다"

정도로 정의할 수 있겠군요 ㅋㅋ

자 그렀다면 Let's Move~~~~

(1) 메일 박스

테스크간에 정보를 공유하기 위해서 가장 쉬운 방법은??? 전역변수를 사용하는 방법이지요~ ㅋㅋ
이럴 경우에 문제가 발생할 수 있다고 하였지요??

상호배제(Mutual Exclusion) 할때 많이 다뤘었자나요 ㅋㅋㅋ 이제는 알때도 됐어요 ㅋㅋㅋㅋ

공유자원에 접근하는 것이라면 모르겠지만, 한 테스크에서 다른 테스크로 데이터를 넘겨 주는 경우가 있을 수 있잖아요 ㅋ 그때 메세지를 전달하기 위해서 생긴 개념이에요 ㅋㅋ

메시지를 받아야 처리하는 테스크 입장에서는 메시지가 왔는지 안왔는지 주기적으로 살펴보는 Polling 작업을 하지 않아도 되겠지요??

 


즉, 커널이 굉장히 효율적으로 작동할수 있게 되는 것이지요 ~ ㅋㅋㅋ


요론 개념이랍니다 ~ ㅋㅋㅋ

보내고 싶은 정보가 있으면 메일 박스에다가 밀어 넣어주고~ (Post or Send) 메일 박스는 이 메시지를 기다리고 있는 테스크 (Wait or Pend) 에게 " 야 메시지 도착했어~~~ " 하고 알려주는 것이지요 ~ ㅋㅋ

우체부 같죠??
이 우체부 역할을 Kernel 이 해주는 것이랍니다.

메일박스는 일반적으로 포인터 사이즈 (Pointer-Size) 변수에요~ 테스크와 테스크 뿐만아니라 ISR 와 Task 사이의 메시지 통신에도 사용할수 있습니다. 또한 한개 이상의 Task 가 하나의 메세지를 수신 할수도 있지요~

메시지 수신을 원하는 테스카가 하나 이상인 경우에 대비해서 각 메일박스에는 Waiting List (대기목록) 이 있답니다. 빈 메일박스로부터 메시지를 기다리는 테스크는 메시지가 수신 될 때까지 대기상태가 되고, 메일 박스의 대기목록에 기록되지요.

메시지가 메일박스에 전달되면 스케쥴러는 메일박스를 기다리고 있는 테스크 중에 최상위 우선순위 테스크에게 전달되거나 커널에 따라서는 맨 첨에 메일박스를 요청한 테스크에게 서비스 해주기도 합니다. 이렇게 먼저 들어온놈에서 먼저 서비스 해주는것을 FIFO (First in Firtst Out) 이라고 합니다 ㅋㅋ 한국말로는 '선착순' 정도가 되겠네요 ㅋㅋ

일반적으로 커널은 다음과 같은 메일박스 서비스를 제공 합니다.

(1) Mailbox Init
(2) Mailbox Send (Post)
(3) Mailbox Wait (Pend)

이전에 배웠던 Binary Semaphore 를 이용하여 이 메일박스를 대신 할 수도 있지만 구지 그럴 필요는 없겠지요? ㅋ
제공해주는 좋은 기능을 사용하는 것이 좋으니까요 ㅋㅋ

메일박스와 메시지 큐에서 가장 기억해야 할 점은
보내는 정보가 내가 보내고 싶어하는 정보의 내용 자체 (Value) 가 아니라 정보가 저장되어 있는 메모리의 주소(Adress) 인 Pointer 라는 점을 확실하게 인지하시길 바랍니다 ~ ㅋㅋ


제가 만들어 놓은 Firmware 에서는 이렇게 메일박스를 이용합니다~

ECG, Body Impedance, Accelerometer, Temperature Sensor, Gyro-Sensor, Power Manager Chip 등의 여러값을 받아온답니다.

(1) 신호를 ADC 하고 End of Conversion 신호가 뜨면 DMA 를 Request 한 다음 DMA 가 Interrupt 를 요청한다.
(2) 이때 DMA Interrupt Service Routine 에서는 t_CopyData_task 에게 Event 를 던져 준다~

void DMA1_Channel1_IRQHandler(void){   
 ITStatus Status;
 Status = DMA_GetITStatus(DMA1_IT_TC1); 

 if(Status){  
  isr_evt_set(0x0001,t_CopyData_task);
  DMA_ClearITPendingBit(DMA1_IT_TC1);
 }
}

(3) t_CopyData_task 에서는 해당되는 메일박스를 생성하고 각각의 데이터를 해당되는 메일박스에 꽃아준다.

__task void tCopyData_task(void) {
 //pointer of Sand Message
 ACC_DATA *pSM_Acc_data;
 IMP_DATA *pSM_Imp_data;
 GYRO_DATA *pSM_Gyro_data;
 
 u32 cnt = 0;
    const u8 x=0, y=1, z=2; 
 u16 Gyro_x=0, Gyro_y=0, Gyro_z=0;

 os_mbx_init(ACC_MBX, sizeof(ACC_MBX));
 os_mbx_init (IMP_MBX, sizeof(IMP_MBX));
 os_mbx_init (GYRO_MBX, sizeof(GYRO_MBX));

 while (1) {
  os_evt_wait_or(0x0001, 0xffff);

  if(!(cnt%rACC_Sample_FREQ)){
  pSM_Acc_data = _alloc_box(AccDataPool);
  pSM_Acc_data->X = ADC1ConvertedValue[2];      
  pSM_Acc_data->Y = ADC1ConvertedValue[3];      
  pSM_Acc_data->Z = ADC1ConvertedValue[4]; 

  os_mbx_send (ACC_MBX, pSM_Acc_data, 0xFFFF);  

  Gyro_z = Gyro_Communication(x);
  Gyro_x = Gyro_Communication(y);
  Gyro_y = Gyro_Communication(z);

  pSM_Gyro_data = _alloc_box(GyroDataPool);
  pSM_Gyro_data->x_Gyro = Gyro_x;
  pSM_Gyro_data->y_Gyro = Gyro_y;
  pSM_Gyro_data->z_Gyro = Gyro_z;
  
  os_mbx_send (GYRO_MBX, pSM_Gyro_data,0xFFFF) ;
  
  }    

  pSM_Imp_data = _alloc_box(ImpDataPool);
  pSM_Imp_data->Impedance = ADC1ConvertedValue[0];
  pSM_Imp_data->Resp = ADC1ConvertedValue[1];     
  
  os_mbx_send (IMP_MBX, pSM_Imp_data, 0xFFFF);
               
  cnt++;
 }
}

(하나의 데이터가 여러개인 것도 있어서 memory pool 을 이용해서 메시지 큐 형태로 보내고 있습니다만 이해하시는게 크게 어려움은 없으실 것에요, 뭐 아래쪽에 설명한 메시지 큐를 이해하는데 도움도 되고 좋죠 머 ㅋ)

(4) 각각의 신호를 처리하는 테스크들은 이 메일박스를 wait 하고있다고 데이터를 넘겨받아 신호처리 하고 가공하여 2차 파라미터 값들을 얻어낸다~

요론 순서로 진행을 하고 있지요 ㅋㅋ

저기서도 데이터를 넘겨줄때 구조체의 메모리 주소를 넘겨주는 부분을 집중해서 보세요 ~ㅋㅋ

(2) 메시지 큐

길게 설명하지 않아도 될듯 합니다 ㅋ

한개 이상의 메시지를 한번에 묶어서 테스크로 보내기 위해서 사용되는 것이지요 ~ 메시지 큐는 기본적으로 메일박스의 배열 형태로 되어있답니다~

하는 짓도 메일박스와 거의 같아요~

여러개를 하나로 묶어서 보내야 되기 때문에 Memory Pool 이라는 것이 필요합니다~
초기에 선언을 해줘야하죠~

선언을 할때 들어갈 데이터 1개의 사이즈와 이런 데이터를 몇개나 담을 것인지 결정한답니다~

그럼 커널은 이 메시지 들이 밀려들어올때 Linked_List 형태로 묶어주지요~ ㅋㅋ

os_mbx_declare (ACC_MBX, 5);
_declare_box (AccDataPool,sizeof(ACC_DATA),5);/* Dynamic memory pool1 */

요론식으로 선언한답니다~

_init_box(AccDataPool, sizeof(AccDataPool), sizeof(ACC_DATA));

초기화는 요론식ㅋㅋㅋ

여기서 ACC_DATA 는

typedef struct {         /* Message object structure      */
 int X;                      /* AD result of measured X       */
 int Y;                      /* AD result of measured Y       */
 int Z;                      /* AD result of measured Z       */
} ACC_DATA;

요론식의 구조체 형태구요 ~ ㅋㅋㅋ

여기까지는 이해를 돕기위한 부분 코드이지만

나중에 Cortex M3 강의에서는 실질적으로 어떻게 구현을 하는지를 알려드릴테니까 지금은 개념만 이해하고 넘어가세용~ ㅋㅋㅋ

저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear