nRF52

nRF52 RTC(Real-Time Clock)를 활용한 캘린더 구현

임베디드 친구 2024. 9. 16. 17:10
반응형

RTC(Real-Time Clock)는 시간이 중요한 애플리케이션에서 필수적인 모듈입니다. 시간을 추적하고 알람을 설정하며, 정밀한 타이밍을 제어하는 등의 작업에서 RTC는 핵심적인 역할을 합니다. 특히 저전력 시스템에서는 프로세서가 지속적으로 작동하지 않더라도 RTC를 이용해 시간 관련 작업을 처리할 수 있어 전력 소비를 크게 줄일 수 있습니다.
이번 포스트에서는 nRF52840 SoC(System on Chip)에서 RTC를 이용해 캘린더를 구현하는 방법을 살펴보겠습니다. 실제 날짜와 시간을 추적하는 캘린더 설정부터 알람 기능, 시간 조정, 그리고 장시간 사용 시 발생할 수 있는 오차 관리 방법까지 다루어 보겠습니다.

1. RTC 모듈 개요

RTC는 마이크로컨트롤러에 내장된 저전력 타이머로, 시간 및 날짜 추적을 비롯해 주기적인 이벤트를 트리거하는 데 사용됩니다. nRF52840 SoC는 여러 RTC 인스턴스를 지원하며, 주로 저전력 애플리케이션에서 사용됩니다. RTC는 시스템이 슬립 모드에 들어가더라도 계속 작동하며, 필요한 순간에만 프로세서를 깨워 시간 기반 작업을 수행할 수 있습니다.

RTC의 주요 특징

  • 저전력 모드에서 동작: RTC는 저전력 상태에서도 작동 가능하므로, 배터리 기반 제품에서 에너지 효율을 높입니다.
  • 정밀한 타이밍: RTC는 초 단위의 정밀도를 제공하여, 주기적 이벤트나 일정 관리에 적합합니다.
  • 유연한 이벤트 처리*: RTC의 알람 및 이벤트 기능을 통해 특정 시간에 작업을 트리거할 수 있습니다.

2. RTC 캘린더의 유용성

RTC 캘린더는 년, 월, 일, 시, 분, 초와 같은 시간 정보 추적에 사용됩니다. 이 기능을 통해 실제 날짜 및 시간에 기반한 애플리케이션을 손쉽게 구현할 수 있습니다. nRF52840에서 RTC 캘린더를 이용하면 다음과 같은 장점이 있습니다:

  • 알람 설정: 특정 시간에 알람을 발생시켜 정해진 시간에 작업을 실행할 수 있습니다.
  • 정확한 타이밍 제어: 타이머 기능을 사용해 일정한 간격으로 이벤트를 트리거할 수 있습니다.
  • 저전력 상태에서 동작: nRF52840은 저전력 모드에서도 RTC가 동작하므로, 배터리 효율성을 높일 수 있습니다.
  • 다양한 시간 형식: RTC 캘린더는 사용자 필요에 맞춰 다양한 시간 형식을 설정할 수 있습니다.

3. RTC 캘린더 초기화

RTC를 초기화하고 설정하는 과정은 매우 중요합니다. 아래 코드에서는 RTC2를 사용해 1분 간격으로 타이머를 설정하고 인터럽트를 처리하는 과정을 보여줍니다.

#define CAL_RTC                 NRF_RTC2
#define CAL_RTC_IRQn            RTC2_IRQn
#define CAL_RTC_IRQHandler      RTC2_IRQHandler
#define CAL_RTC_IRQ_Priority    3

void nrf_cal_init(void)
{
    // RTC2를 1분 간격으로 동작하도록 설정
    CAL_RTC->PRESCALER = 0xFFF;
    CAL_RTC->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
    CAL_RTC->INTENSET = RTC_INTENSET_COMPARE0_Msk;
    CAL_RTC->CC[0] = m_rtc_increment * 8;
    CAL_RTC->TASKS_START = 1;
    NVIC_SetPriority(CAL_RTC_IRQn, CAL_RTC_IRQ_Priority);
    NVIC_EnableIRQ(CAL_RTC_IRQn);  
}

이 코드는 RTC의 Pre-scaler이벤트 라우팅(EVTENSET), 인터럽트 설정(INTENSET), 그리고 비교 레지스터(CC0) 설정을 통해 60초마다 인터럽트가 발생하도록 합니다.

코드 설명

  • Pre-scaler: 32.768kHz의 클럭 소스를 사용하는 RTC는 이를 조절하기 위해 Pre-scaler를 사용합니다. 위 코드에서는 0xFFF로 설정해 타이머가 1분마다 작동하도록 구성됩니다.
  • CC0 비교 레지스터: 이 레지스터는 타이머가 지정된 값에 도달하면 인터럽트를 발생시키는 역할을 합니다.
  • TASKS_START: RTC를 시작하는 명령입니다.
  • NVIC 설정: 인터럽트가 발생할 때 적절히 처리할 수 있도록 NVIC에서 인터럽트 우선순위와 핸들러를 설정합니다.

4. 캘린더 시간 설정

RTC를 사용해 실제 날짜와 시간을 설정할 수 있습니다. 아래 코드는 년, 월, 일, 시, 분, 초를 설정하는 함수입니다.

void nrf_cal_set_time(uint32_t year, uint32_t month, uint32_t day, uint32_t hour, uint32_t minute, uint32_t second)
{
    static time_t uncal_difftime, difftime, newtime;
    time_struct.tm_year = year - 1900;
    time_struct.tm_mon = month - 1;
    time_struct.tm_mday = day;
    time_struct.tm_hour = hour;
    time_struct.tm_min = minute;
    time_struct.tm_sec = second;   
    newtime = mktime(&time_struct);
    CAL_RTC->TASKS_CLEAR = 1;  

    // 시간 보정 오프셋 계산
    if(m_last_calibrate_time != 0)
    {
        difftime = newtime - m_last_calibrate_time;
        uncal_difftime = m_time - m_last_calibrate_time;
        m_calibrate_factor = (float)difftime / (float)uncal_difftime;
    }

    // 새로운 시간을 로컬 변수에 저장
    m_time = m_last_calibrate_time = newtime;
}

코드 설명

  • mktime(): 사용자가 입력한 시간을 time_t 형식으로 변환합니다.
  • 보정 오프셋 계산: 이전에 설정된 시간과 새로 설정된 시간 간의 차이를 계산하여 RTC의 오차를 보정합니다.
  • 인터럽트 초기화: RTC의 카운터를 초기화하여 설정한 시간부터 다시 카운트하도록 만듭니다.

5. 현재 시간 가져오기

RTC가 동작 중일 때, 현재 시간을 추적하고 반환하는 함수는 다음과 같습니다.

struct tm *nrf_cal_get_time(void)
{
    time_t return_time;
    return_time = m_time + CAL_RTC->COUNTER / 8;
    m_tm_return_time = *localtime(&return_time);
    return &m_tm_return_time;
}

이 함수는 RTC의 현재 카운터 값을 읽고 이를 time_t 형식으로 변환한 후, 현재 시간 구조체(struct tm)로 반환합니다.

6. RTC 인터럽트 처리

60초마다 발생하는 인터럽트를 처리하는 코드입니다.

void CAL_RTC_IRQHandler(void)
{
    if(CAL_RTC->EVENTS_COMPARE[0])
    {
        CAL_RTC->EVENTS_COMPARE[0] = 0;
        CAL_RTC->TASKS_CLEAR = 1;

        m_time += m_rtc_increment; // m_rtc_increment는 60초
        if(cal_event_callback) cal_event_callback();
    }
}

코드 설명

  • 인터럽트 처리: RTC의 비교 이벤트가 발생하면, 해당 이벤트 플래그를 클리어하고, 저장된 시간에 60초를 더해 시간을 업데이트합니다.

7. 정확성 보정과 외부 RTC 활용

nRF52840의 내장 RTC는 LFCLK (32.768 kHz 저속 클럭)를 사용하기 때문에 오차가 발생할 수 있습니다. 실제로 1개월에 약 1~2초의 오차가 발생할 수 있으며, 외부 크리스탈을 사용하더라도 이러한 오차는 더 클 수 있습니다.
실제 상용 제품에서는 이러한 오차를 보정하기 위해 다음과 같은 방법을 사용할 수 있습니다:

  1. 외부 RTC IC 추가: 보다 정확한 타이밍을 제공하는 외부 RTC 칩을 사용해 시스템의 시간을 관리할 수 있습니다.
  2. Bluetooth 시간 동기화: 주기적으로 Bluetooth를 통해 정확한 시간을 서버로부터 받아 동기화하는 방법도 사용할 수 있습니다.

8. 결론

RTC는 저전력 환경에서 시간 추적 및 일정 관리를 효과적으로 할 수 있는 강력한 모듈입니다. nRF52840에서 RTC를 이용해 캘린더를 구현하는 과정에서는 시간 설정, 인터럽트 처리, 보정 등 다양한 요소를 고려해야 합니다. 특히, 장시간 사용 시 발생할 수 있는 시간 오차는 외부 RTC 칩이나 주기적인 동기화를 통해 보정해야 할 필요가 있습니다.
이 포스트에서 소개한 예제를 기반으로, 여러분의 프로젝트에 맞는 RTC 캘린더 기능을 효율적으로 구현해 보세요!

반응형