/* * Copyright (C) 2016-2017 Bas Stottelaar * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @ingroup cpu_efm32 * @ingroup drivers_periph_rtt * @{ * * @file * @brief RTT peripheral driver implementation * @author Bas Stottelaar * @} */ #include "cpu.h" #include "periph_conf.h" #include "periph/rtt.h" #include "em_cmu.h" #include "em_rtc.h" typedef struct { rtt_cb_t alarm_cb; /**< callback called from RTC alarm */ void *alarm_arg; /**< argument passed to the callback */ rtt_cb_t overflow_cb; /**< callback called when RTC overflows */ void *overflow_arg; /**< argument passed to the callback */ } rtt_state_t; static rtt_state_t rtt_state; /* prescaler of 32768 = 1 s of resolution and overflow each 194 days */ #if RTT_FREQUENCY == 1 #define RTT_CMU_CLK_DIV cmuClkDiv_32768 #elif RTT_FREQUENCY == 2 #define RTT_CMU_CLK_DIV cmuClkDiv_16384 #elif RTT_FREQUENCY == 4 #define RTT_CMU_CLK_DIV cmuClkDiv_8192 #elif RTT_FREQUENCY == 8 #define RTT_CMU_CLK_DIV cmuClkDiv_4096 #elif RTT_FREQUENCY == 16 #define RTT_CMU_CLK_DIV cmuClkDiv_2048 #elif RTT_FREQUENCY == 32 #define RTT_CMU_CLK_DIV cmuClkDiv_1024 #elif RTT_FREQUENCY == 64 #define RTT_CMU_CLK_DIV cmuClkDiv_512 #elif RTT_FREQUENCY == 128 #define RTT_CMU_CLK_DIV cmuClkDiv_256 #elif RTT_FREQUENCY == 256 #define RTT_CMU_CLK_DIV cmuClkDiv_128 #elif RTT_FREQUENCY == 512 #define RTT_CMU_CLK_DIV cmuClkDiv_64 #elif RTT_FREQUENCY == 1024 #define RTT_CMU_CLK_DIV cmuClkDiv_32 #elif RTT_FREQUENCY == 2048 #define RTT_CMU_CLK_DIV cmuClkDiv_16 #elif RTT_FREQUENCY == 4096 #define RTT_CMU_CLK_DIV cmuClkDiv_8 #elif RTT_FREQUENCY == 8192 #define RTT_CMU_CLK_DIV cmuClkDiv_4 #elif RTT_FREQUENCY == 16384 #define RTT_CMU_CLK_DIV cmuClkDiv_2 #elif RTT_FREQUENCY == 32768 #define RTT_CMU_CLK_DIV cmuClkDiv_1 #else #warning "no matching prescaler for RTT_FREQUENCY" #endif void rtt_init(void) { /* setup prescaler */ CMU_ClockDivSet(cmuClock_RTC, RTT_CMU_CLK_DIV); /* enable clocks */ CMU_ClockEnable(cmuClock_CORELE, true); CMU_ClockEnable(cmuClock_RTC, true); /* reset and initialize peripheral */ RTC_Init_TypeDef init = RTC_INIT_DEFAULT; init.enable = false; init.comp0Top = false; RTC_Reset(); RTC_Init(&init); /* enable interrupts */ RTC_IntEnable(RTC_IEN_OF); NVIC_ClearPendingIRQ(RTC_IRQn); NVIC_EnableIRQ(RTC_IRQn); /* enable peripheral */ RTC_Enable(true); } void rtt_set_overflow_cb(rtt_cb_t cb, void *arg) { rtt_state.overflow_cb = cb; rtt_state.overflow_arg = arg; RTC_IntClear(RTC_IFC_OF); RTC_IntEnable(RTC_IEN_OF); } void rtt_clear_overflow_cb(void) { rtt_state.overflow_cb = NULL; rtt_state.overflow_arg = NULL; RTC_IntDisable(RTC_IEN_OF); } uint32_t rtt_get_counter(void) { return RTC_CounterGet(); } void rtt_set_counter(uint32_t counter) { RTC->CNT = counter & RTT_MAX_VALUE; } void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) { rtt_state.alarm_cb = cb; rtt_state.alarm_arg = arg; /* disable interrupt so it doesn't accidentally trigger */ RTC_IntDisable(RTC_IEN_COMP0); /* set compare register */ RTC_CompareSet(0, alarm & RTT_MAX_VALUE); /* enable the interrupt */ RTC_IntClear(RTC_IFC_COMP0); RTC_IntEnable(RTC_IEN_COMP0); } uint32_t rtt_get_alarm(void) { return RTC_CompareGet(0); } void rtt_clear_alarm(void) { rtt_state.alarm_cb = NULL; rtt_state.alarm_arg = NULL; /* disable the interrupt */ RTC_IntDisable(RTC_IEN_COMP0); } void rtt_poweron(void) { CMU_ClockEnable(cmuClock_RTC, true); } void rtt_poweroff(void) { CMU_ClockEnable(cmuClock_RTC, false); } void isr_rtc(void) { if ((RTC_IntGet() & RTC_IF_COMP0)) { if (rtt_state.alarm_cb != NULL) { rtt_state.alarm_cb(rtt_state.alarm_arg); } /* clear interrupt */ RTC_IntClear(RTC_IFC_COMP0); } if (RTC_IntGet() & RTC_IF_OF) { if (rtt_state.overflow_cb != NULL) { rtt_state.overflow_cb(rtt_state.overflow_arg); } /* clear interrupt */ RTC_IntClear(RTC_IFC_OF); } cortexm_isr_end(); }