CC2530 ZigBee 스택 아키텍처 및 동작 원리

ZigBee 프로토콜 스택의 이해

ZigBee 프로토콜 스택은 다양한 계층의 프로토콜들을 통합하여 함수 형태로 구현한 소프트웨어 묶음입니다. 이는 사용자에게 특정 기능을 직접 호출할 수 있는 인터페이스를 제공하며, 하나의 독립적인 소프트웨어 프로젝트로 간주될 수 있습니다.

주요 활용 방법

ZigBee 스택은 주로 세 가지 핵심 기능에 활용됩니다:

  1. 네트워크 구성: 노드들이 네트워크를 형성하고 다른 장치들이 합류하도록 하는 기능을 제공하는 스택의 네트워크 형성 함수를 호출합니다.
  2. 데이터 송신: 노드 간 무선 데이터 전송을 위해 스택의 메시지 송신 함수를 호출합니다.
  3. 데이터 수신: 무선으로 수신된 데이터를 처리하기 위한 스택의 메시지 수신 함수를 활용합니다.

이처럼 ZigBee 스택은 네트워크 설정, 데이터 송신, 데이터 수신을 위한 필수적인 함수들을 내장하고 있습니다.

ZigBee 프로토콜 스택 다운로드

TI(텍사스 인스트루먼트) 공식 웹사이트에서 CC2530용 ZigBee 프로토콜 스택(Z-Stack)을 다운로드할 수 있습니다.

예제 프로젝트 파일 구조

다운로드한 ZigBee 스택 예제 프로젝트를 열면 다음과 같은 주요 디렉토리들을 확인할 수 있습니다.

  • APP: 최상위 애플리케이션 코드가 위치하며, 개발자가 주로 작업하는 공간입니다.
  • BDB: ZigBee 3.0에서 추가된 기능으로, 기본 장치 동작(Base Device Behavior)을 구현합니다.
  • GP: ZigBee 그린 파워(Green Power) 기능을 구현하는 코드입니다.
  • HAL: 하드웨어 추상화 계층으로, 다양한 장치 드라이버가 포함되어 있습니다.
  • MAC: 미디어 액세스 제어를 담당하며, 물리 계층 통신 및 IEEE 802.15.4 프로토콜을 구현합니다.
  • MT: 모니터링 계층으로, 프로토콜 스택 각 계층의 실행 상태 모니터링을 지원합니다.
  • NWK: ZigBee 네트워크 계층 코드입니다.
  • OSAL: 운영 체제 추상화 계층입니다.
  • Profile: ZigBee 표준 정의 및 관련 기능 구현을 위한 소스 코드 파일이 있습니다.
  • Security: 보안 관련 서비스를 구현합니다.
  • Services: 공통적으로 사용되는 유틸리티 및 기능들을 제공합니다.
  • Tools: 프로젝트 구성 관련 파일들이 저장됩니다.
  • ZDO: ZigBee 장치 객체(ZigBee Device Object) 관련 소스 코드 파일이 있습니다.
  • ZMac: MAC 계층의 일부 기능을 포함합니다.
  • ZMain: 메인 함수를 포함하며 시스템 초기화 및 하드웨어 시작 관련 코드가 있는 곳입니다.
  • Output: 프로젝트 컴파일 및 링크 시 생성되는 출력 파일들이 저장됩니다.

ZigBee 네트워크 장치 유형은 코디네이터(Coordinator), 라우터(Router), 종단 장치(EndDevice)의 세 가지로 구분됩니다. 예제 프로젝트에서는 각 장치 유형별 빌드 옵션을 제공합니다:

  • CoordinatorEB: ZigBee 코디네이터 장치용 빌드.
  • RouterEB: ZigBee 라우터 장치용 빌드.
  • EndDeviceEB: ZigBee 종단 장치용 빌드.
  • EndDeviceEB-OTAClient: OTA(Over The Air) 무선 업데이트 기능을 지원하는 ZigBee 종단 장치용 빌드.
  • RouterEB-OTAClient: OTA 무선 업데이트 기능을 지원하는 ZigBee 라우터 장치용 빌드.

스택의 시작 과정

main() 함수

ZMain 폴더의 ZMain.c 파일에 있는 main() 함수는 프로그램의 시작점입니다. 여기서 시스템의 기본적인 초기화가 이루어지며, 특히 osal_init_system()osal_start_system() 두 함수가 핵심적인 역할을 합니다.

void main(void) {
    // ... 기타 초기화 코드 ...
    osal_init_system(); // OSAL 시스템 초기화
    osal_start_system(); // 태스크 스케줄링 시작
    // ...
}

osal_init_system() 함수

osal_init_system() 함수는 내부적으로 osalInitTasks()를 호출합니다. osalInitTasks() 함수는 ZigBee 스택의 각 계층을 초기화하고, 각 계층에 고유한 태스크 ID를 할당하는 역할을 수행합니다. 이 과정에서 각 계층의 초기화가 완료되고 태스크 ID가 부여됩니다.

osal_start_system() 함수

osal_start_system() 함수는 시스템의 태스크 스케줄러를 시작하는 역할을 합니다. 이 함수 내부에는 무한 루프가 존재하며, 주기적으로 osal_run_system() 함수를 호출하여 태스크 풀을 폴링합니다.

void osal_start_system( void )
{
  for(;;) // 무한 루프: 시스템 태스크를 지속적으로 실행
  {
    osal_run_system(); // 태스크 큐를 폴링하고 대기 중인 태스크를 실행
    // 실제 시스템에서는 전력 효율을 위해 다음 이벤트까지 대기하는 메커니즘이 있을 수 있습니다.
  }
}

osal_run_system() 함수(OSAL.c 파일에 정의)는 태스크 풀을 순회하며 실행할 태스크가 있는지 확인합니다. 다음은 osal_run_system() 내부의 핵심 로직을 간략화한 코드입니다:

// osal_run_system 함수 내부의 태스크 폴링 로직 (간략화)
// task_event_flags: 각 태스크의 이벤트 상태를 저장하는 배열
// task_handler_functions: 각 태스크의 이벤트 처리 함수 포인터 배열
// task_count: 전체 태스크의 개수
// idx: 현재 태스크 ID (태스크 인덱스)

do {
    if (task_event_flags[idx])  // 현재 태스크에 처리할 이벤트가 있는지 확인
    {
      break; // 이벤트가 있는 태스크를 찾았으므로 실행 단계로 이동
    }
} while (++idx < task_count); // 다음 태스크로 이동하여 반복

if (idx < task_count) // 이벤트를 가진 태스크가 발견된 경우
{
    uint16 current_events;
    // 임계 영역 진입 (간략화)
    // HAL_ENTER_CRITICAL_SECTION(intState);

    current_events = task_event_flags[idx]; // 해당 태스크의 현재 이벤트 가져오기
    task_event_flags[idx] = 0;              // 현재 태스크의 이벤트 플래그 초기화
    // 임계 영역 종료 (간략화)
    // HAL_EXIT_CRITICAL_SECTION(intState);

    // 해당 태스크의 이벤트 처리 함수 호출
    // task_handler_functions[idx]는 태스크 핸들러 함수의 포인터
    // 처리되지 않은 이벤트는 반환되어 다시 해당 태스크의 이벤트 플래그에 추가됨
    uint16 remaining_events = (task_handler_functions[idx])( idx, current_events );

    // 처리되지 않고 남아있는 이벤트를 다시 태스크 이벤트 플래그에 추가
    // HAL_ENTER_CRITICAL_SECTION(intState);
    task_event_flags[idx] |= remaining_events;
    // HAL_EXIT_CRITICAL_SECTION(intState);
}

이 코드에서 task_event_flags[idx]는 각 태스크에 발생한 이벤트를 나타내는 플래그 그룹이며, idx는 앞에서 언급된 태스크 ID입니다. 만약 특정 태스크에 이벤트가 발생하면 task_event_flags[idx]가 설정되고, 시스템은 해당 태스크의 task_handler_functions[idx] 함수를 호출하여 이벤트를 처리합니다. 처리된 후에도 남아있는 이벤트는 다시 플래그에 반영되어 다음 폴링 주기에서 처리될 수 있도록 합니다.

애플리케이션 계층

각 프로토콜 계층은 해당 계층의 작업을 처리하는 고유한 태스크를 가집니다. 예를 들어, MAC 계층, 네트워크 계층, HAL 계층, 그리고 애플리케이션 계층 각각에 대응하는 태스크가 존재하며, 이 모든 태스크들이 태스크 풀(즉, task_event_flags 배열)을 구성합니다.

예제 프로젝트의 APP 폴더 내에 있는 애플리케이션 파일(예: zcl_samplesw.c 또는 이와 유사한 이름)을 열어보면, 애플리케이션 태스크의 초기화 및 이벤트 처리 함수를 확인할 수 있습니다.

// 애플리케이션 태스크 초기화 함수 (예시)
void zclSampleSw_Init( uint8 task_id )
{
  zclSampleSw_TaskID = task_id; // 할당된 태스크 ID 저장
  // ... 기타 초기화 코드 (UART 초기화 및 태스크 ID 등록 등) ...
}
// 애플리케이션 태스크의 이벤트 루프 함수 (예시)
uint16 zclSampleSw_event_loop( uint8 task_id, uint16 events )
{
  // 수신된 메시지 처리
  if ( events & SYS_EVENT_MSG )
  {
    afIncomingMSGPacket_t *MSGpkt;
    while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( zclSampleSw_TaskID )) )
    {
      switch ( MSGpkt->hdr.event )
      {
        // ... 메시지 유형별 처리 로직 ...
        default:
          break;
      }
      osal_msg_deallocate( (uint8 *)MSGpkt ); // 메시지 메모리 해제
    }
    return (events ^ SYS_EVENT_MSG); // 처리되지 않은 이벤트 반환
  }

  // 네트워크 재연결 이벤트
  if ( events & SAMPLEAPP_REJOIN_EVT )
  {
   // 네트워크 재연결 및 바인딩 시도
   bdb_StartCommissioning(BDB_COMMISSIONING_MODE_NWK_STEERING | BDB_COMMISSIONING_MODE_FINDING_BINDING );
   return ( events ^ SAMPLEAPP_REJOIN_EVT );
  }

  // 알 수 없는 이벤트는 모두 버림
  return 0;
}

각 계층은 이와 유사하게 task_id를 인자로 받아 자신을 초기화하는 함수와, task_idevents를 인자로 받아 해당 계층의 이벤트를 처리하는 이벤트 루프 함수를 가지고 있습니다.

태그: ZigBee CC2530 ProtocolStack EmbeddedSystems OSAL

7월 13일 04:29에 게시됨