시작하기
이번에는 타이머 예제로 rtc에 대해서 알아보도록 하자.
\examples\peripheral\rtc\pca10040\blank\ses 폴더에서 프로젝트를 실행해보자.
The Real Time Counter Example enables the real-time clock (RTC) with a TICK frequency of 8 Hz. It also configures and enables the TICK- and the COMPARE0-interrupts. The compare interrupt handler is triggered three seconds after the RTC starts. The TICK interrupt handler clears the interrupt request and toggles PIN8 (LED 1). The COMPARE0 handler clears the interrupt request and sets PIN9 (LED 2) to 1.
The application starts with configuring the GPIO and starting the internal low frequency clock oscillator (LFCLK XTAL oscillator). The RTC is configured with TICK for 8 Hz and COMPARE0 to 3 seconds.
1. Compile and program the application.
2. Observe that LED 1 toggles at the rate of 8 Hz.
3. After 3 seconds, LED 2 turns on.
rtc 예제는 8Hz 주기로 LED1이 반짝이다가 3초가 지나면 LED2가 켜지는 간단한 동작으로 되어 있다.
이제 main.c 소스코드를 살펴보자.
#define COMPARE_COUNTERTIME (3UL) /**< Get Compare event COMPARE_TIME seconds after the counter starts from 0. */
#ifdef BSP_LED_0
#define TICK_EVENT_OUTPUT BSP_LED_0 /**< Pin number for indicating tick event. */
#endif
#ifndef TICK_EVENT_OUTPUT
#error "Please indicate output pin"
#endif
#ifdef BSP_LED_1
#define COMPARE_EVENT_OUTPUT BSP_LED_1 /**< Pin number for indicating compare event. */
#endif
#ifndef COMPARE_EVENT_OUTPUT
#error "Please indicate output pin"
#endif
const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(0); /**< Declaring an instance of nrf_drv_rtc for RTC0. */
/** @brief: Function for handling the RTC0 interrupts.
* Triggered on TICK and COMPARE0 match.
*/
static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
if (int_type == NRF_DRV_RTC_INT_COMPARE0)
{
nrf_gpio_pin_toggle(COMPARE_EVENT_OUTPUT);
}
else if (int_type == NRF_DRV_RTC_INT_TICK)
{
nrf_gpio_pin_toggle(TICK_EVENT_OUTPUT);
}
}
/** @brief Function configuring gpio for pin toggling.
*/
static void leds_config(void)
{
bsp_board_init(BSP_INIT_LEDS);
}
/** @brief Function starting the internal LFCLK XTAL oscillator.
*/
static void lfclk_config(void)
{
ret_code_t err_code = nrf_drv_clock_init();
APP_ERROR_CHECK(err_code);
nrf_drv_clock_lfclk_request(NULL);
}
/** @brief Function initialization and configuration of RTC driver instance.
*/
static void rtc_config(void)
{
uint32_t err_code;
//Initialize RTC instance
nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
config.prescaler = 4095;
err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler);
APP_ERROR_CHECK(err_code);
//Enable tick event & interrupt
nrf_drv_rtc_tick_enable(&rtc,true);
//Set compare channel to trigger interrupt after COMPARE_COUNTERTIME seconds
err_code = nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME * 8,true);
APP_ERROR_CHECK(err_code);
//Power on RTC instance
nrf_drv_rtc_enable(&rtc);
}
/**
* @brief Function for application main entry.
*/
int main(void)
{
leds_config();
lfclk_config();
rtc_config();
while (true)
{
__SEV();
__WFE();
__WFE();
}
}
main 함수를 보면 leds_config, lfclk_config, rtc_config의 3개의 함수로 구성되어 있다.
lfclk_config 함수부터 살펴보면 nrf_drv_clock_init 함수와 nrf_drv_clock_lfclk_request 함수를 호출하여 LFCLK XTAL 발진기를 시작한다.
nRF52 DK 회로에는 외부 32.768kHz의 XTAL 발진기가 있다.
이를 사용하기 위해서는 LFCLKSRC 레지스터의 SRC 필드를 1로 설정해줘야 한다.
sdk_config.h 파일을 보면 CLOCK_CONFIG_LF_SRC 값이 1로 정의되어 있는 것을 확인할 수 있다.
nrf_drv_clock_init 함수 내 nrfx_clock_enable 함수를 보면 nrf_clock_lf_src_set 함수의 전달 인자로 NRFX_CLOCK_CONFIG_LF_SRC을 넘겨줌으로써 LFCLK을 XTAL로 설정하는 것을 알 수 있다.
// <o> CLOCK_CONFIG_LF_SRC - LF Clock Source
// <0=> RC
// <1=> XTAL
// <2=> Synth
// <131073=> External Low Swing
// <196609=> External Full Swing
#ifndef CLOCK_CONFIG_LF_SRC
#define CLOCK_CONFIG_LF_SRC 1
#endif
void nrfx_clock_enable(void)
{
NRFX_ASSERT(m_clock_cb.module_initialized);
nrfx_power_clock_irq_init();
nrf_clock_lf_src_set((nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC);
#if NRFX_CHECK(NRFX_POWER_ENABLED)
nrfx_clock_irq_enabled = true;
#endif
NRFX_LOG_INFO("Module enabled.");
}
nrf_drv_clock_lfclk_request 함수 내 nrfx_clock_lfclk_start 함수를 호출해서 LFCLK XTAL 발진을 시작하고 LFCLKSTARTE 인터럽트를 활성화한다.
void nrfx_clock_lfclk_start(void)
{
NRFX_ASSERT(m_clock_cb.module_initialized);
nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
nrf_clock_int_enable(NRF_CLOCK_INT_LF_STARTED_MASK);
#if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
nrfx_clock_anomaly_132();
#endif
nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
}
이렇게 해서 clock 세팅이 끝나며 마지막으로 rtc_config 함수를 살펴보자.
nrf_drv_rtc_init 함수의 전달 인자로 RTC 0, NRF_DRV_RTC_DEFAULT_CONFIG 값, rtc_handler를 넘겨주면서 rtc 설정을 해준다.
prescaler 값을 4095로 설정하면 다음과 같은 주기를 가지게 된다.
32.768 / (4095 + 1) = 0.00809... kHz이며 예제 설명에 나오듯이 8Hz의 주기이다.
nrfx_err_t nrfx_rtc_init(nrfx_rtc_t const * const p_instance,
nrfx_rtc_config_t const * p_config,
nrfx_rtc_handler_t handler)
{
NRFX_ASSERT(p_config);
NRFX_ASSERT(handler);
nrfx_err_t err_code;
m_handlers[p_instance->instance_id] = handler;
if (m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED)
{
err_code = NRFX_ERROR_INVALID_STATE;
NRFX_LOG_WARNING("Function: %s, error code: %s.",
__func__,
NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
NRFX_IRQ_PRIORITY_SET(p_instance->irq, p_config->interrupt_priority);
NRFX_IRQ_ENABLE(p_instance->irq);
nrf_rtc_prescaler_set(p_instance->p_reg, p_config->prescaler);
m_cb[p_instance->instance_id].reliable = p_config->reliable;
m_cb[p_instance->instance_id].tick_latency = p_config->tick_latency;
m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;
err_code = NRFX_SUCCESS;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
nrf_drv_rtc_tick_enable 함수를 호출해서 TICK 이벤트와 인터럽트를 활성화한다.
nrf_drv_rtc_cc_set 함수의 전달 인자로 RTC 0, Compare channel 0, Compare 값으로 24를 넘겨준다.
이렇게 하면 8Hz 주기의 24번째가 되는 시점에 COMPARE 0에 이벤트가 발생한다.
예제 설명에 나온 3초 뒤에 LED2가 켜지는 시점이 되는 것이다.
마지막으로 nrf_drv_rtc_enable(&rtc) 함수를 호출하면서 RTC 0을 활성화한다.
이렇게 8Hz TICK으로 rtc_handler 함수가 호출되면서 LED1을 토글 하고 24번째 주기에서 COMPARE 0 이벤트가 발생하면서 LED2를 켜게 된다.
예제에서는 COMPARE 0 이벤트가 한 번 발생하면 다시 해당 이벤트가 발생하지 않게 되는데 이를 3초마다 LED2를 토글 하기 위해선 다음과 같이 rtc_handler 함수를 수정하면 된다.
/** @brief: Function for handling the RTC0 interrupts.
* Triggered on TICK and COMPARE0 match.
*/
static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
if (int_type == NRF_DRV_RTC_INT_COMPARE0)
{
nrf_drv_rtc_counter_clear(&rtc);
nrf_drv_rtc_int_enable(&rtc, RTC_CHANNEL_INT_MASK(0));
nrf_gpio_pin_toggle(COMPARE_EVENT_OUTPUT);
}
else if (int_type == NRF_DRV_RTC_INT_TICK)
{
nrf_gpio_pin_toggle(TICK_EVENT_OUTPUT);
}
}
앞으로
지금까지 nRF52에서 사용 가능한 타이머들을 알아보았다.
마지막으로 WDT(Watch Dog Timer)를 알아보고 다른 예제로 넘어가도록 하자.
'Embedded > nRF52 BLE 개발 안내서' 카테고리의 다른 글
nRF52 BLE 개발하기 - NRF_LOG_INFO (0) | 2021.01.19 |
---|---|
nRF52 BLE 개발하기 - wdt (0) | 2021.01.18 |
nRF52 BLE 개발하기 - simple_timer (0) | 2021.01.14 |
nRF52 BLE 개발하기 - timer (0) | 2021.01.12 |
nRF52 BLE 개발하기 - pin_change_int (5) | 2021.01.11 |
댓글