diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/burtc.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/burtc.c new file mode 100644 index 0000000000..5c86ad9f14 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/burtc.c @@ -0,0 +1,106 @@ +/***************************************************************************//** + * @file rtc_burtc.c + ******************************************************************************* + * @section License + * (C) Copyright 2018 Silicon Labs, http://www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "device.h" +#if DEVICE_RTC + +/* Use BURTC on devices that have it, and don't use the RTCC abstraction */ +#if defined(BURTC_PRESENT) && !defined(RTCC_PRESENT) + +#include "clocking.h" +#include "em_cmu.h" +#include "em_emu.h" +#include "em_burtc.h" +#include "rtc_api.h" + +void rtc_init(void) +{ + /* Only reset & configure the RTC if it has never run before */ + if(BUS_RegBitRead(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT)) { + EMU_EM4Init_TypeDef em4_init = EMU_EM4INIT_DEFAULT; +#if (LOW_ENERGY_CLOCK_SOURCE == LFXO) + em4_init.osc = emuEM4Osc_LFXO; +#elif (LOW_ENERGY_CLOCK_SOURCE == LFRCO) + em4_init.osc = emuEM4Osc_LFRCO; +#else +#error "Can't use BURTC on mbed with ULFRCO" +#endif + EMU_EM4Init(&em4_init); + + BURTC_Init_TypeDef burtc_init = BURTC_INIT_DEFAULT; + burtc_init.mode = burtcModeEM4; +#if (LOW_ENERGY_CLOCK_SOURCE == LFXO) + burtc_init.clkSel = burtcClkSelLFXO; +#elif (LOW_ENERGY_CLOCK_SOURCE == LFRCO) + burtc_init.clkSel = burtcClkSelLFRCO; +#else +#error "Can't use BURTC on mbed with ULFRCO" +#endif + burtc_init.clkDiv = burtcClkDiv_128; + burtc_init.lowPowerMode = burtcLPEnable; + + BURTC_Reset(); + BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, 0); + BURTC_Init(&burtc_init); + BURTC_RetRegSet(0, 0); + BURTC_RetRegSet(1, 0); + } +} + +void rtc_free(void) +{ + /* Nothing to release here */ +} + +int rtc_isenabled(void) +{ + return (BUS_RegBitRead(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT) == 0); +} + +time_t rtc_read(void) +{ + uint32_t ts = 0; + uint32_t ts2 = 1; + do { + if (BURTC->IF & BURTC_IF_OF) { + BURTC_RetRegSet(1, BURTC_RetRegGet(1)+1); + BURTC->IFC = BURTC_IFC_OF; + } + + ts = ts2; + ts2 = (BURTC_CounterGet() >> 8) + BURTC_RetRegGet(0) + (BURTC_RetRegGet(1) << 16); + } while (ts != ts2); + return ts2; +} + +void rtc_write(time_t t) +{ + BURTC_RetRegSet(0, t - (BURTC_CounterGet() >> 8)); + BURTC_RetRegSet(1, 0); + if (BURTC->IF & BURTC_IF_OF) { + BURTC->IFC = BURTC_IFC_OF; + } +} + +#endif /* BURTC_PRESENT && !RTCC_PRESENT */ +#endif /* DEVICE_RTC */ \ No newline at end of file diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/common/mbed_overrides.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/common/mbed_overrides.c index bc8f479a6c..c39707e7f0 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/common/mbed_overrides.c +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/common/mbed_overrides.c @@ -117,6 +117,11 @@ void mbed_sdk_init() # error "Low energy clock selection not valid" #endif +#if defined(RTCC_PRESENT) + /* Turn RTCC clock gate back on to keep RTC time correct */ + CMU_ClockEnable(cmuClock_RTCC, true); +#endif + #if defined(EFM_BC_EN) /* Enable BC line driver to avoid garbage on CDC port */ gpio_init_out_ex(&bc_enable, EFM_BC_EN, 1); diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c index 0e4d7e7984..42f589b5af 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c @@ -32,6 +32,17 @@ * for the low power timer, which should be good enough for a low power use * case. * + * Mapping of mbed APIs to Silicon Labs peripherals: + * ---: Does not meet mbed API requirements + * X : Implemented to provide mbed API functionality + * + * -------------------------------------------- + * | ------------- | RTCC | BURTC | RTC | TIMER | + * | rtc_api | X | X | --- | ----- | + * | lp_ticker_api | X | | X | ----- | + * | us_ticker_api | --- | ----- | --- | X | + * -------------------------------------------- + * * On Silicon Labs devices, the lowest width RTC implementation has a 24-bit * counter, which gets extended with a further 32-bit software counter. This * gives 56 bits of actual width, which with the default speed maps to @@ -40,34 +51,124 @@ * (At max speed the wraparound is at 69730 years, which is unlikely as well) ******************************************************************************/ -#include "rtc_api.h" -#include "rtc_api_HAL.h" +#if defined(RTC_PRESENT) +#include "em_rtc.h" +#include "em_cmu.h" #include "lp_ticker_api.h" #include "mbed_critical.h" -static int rtc_reserved = 0; +#if RTC_CLOCKDIV_INT > 16 +#error invalid prescaler value RTC_CLOCKDIV_INT, since LP ticker resolution will exceed 1ms. +#endif + +#define RTC_BITS (24U) +#define RTC_MAX_VALUE (0xFFFFFFUL) + +static bool rtc_inited = false; +static time_t time_base = 0; +static uint32_t time_extend = 0; +static uint32_t extended_comp0 = 0; + +void RTC_IRQHandler(void) +{ + uint32_t flags; + flags = RTC_IntGet(); + if (flags & RTC_IF_OF) { + RTC_IntClear(RTC_IF_OF); + /* RTC has overflowed (24 bits). Use time_extend as software counter for 32 more bits. */ + time_extend += 1; + } + if (flags & RTC_IF_COMP0) { + RTC_IntClear(RTC_IF_COMP0); + if (lp_ticker_irq_handler != NULL && time_extend == extended_comp0) { + lp_ticker_irq_handler(); + } + } +} + +uint64_t rtc_get_full(void) +{ + uint64_t ticks = 0; + + do + { + /* In case someone's trying to read time in a critical section */ + if (RTC_IntGet() & RTC_IF_OF) { + RTC_IntClear(RTC_IF_OF); + time_extend += 1; + } + + ticks = (uint64_t)time_extend << RTC_BITS; + ticks += RTC_CounterGet(); + } + while ( (ticks & RTC_MAX_VALUE) != RTC_CounterGet() ); + + return ticks; +} void lp_ticker_init() { - if(!rtc_reserved) { - core_util_critical_section_enter(); - rtc_init_real(RTC_INIT_LPTIMER); - rtc_set_comp0_handler((uint32_t)lp_ticker_irq_handler); - rtc_reserved = 1; - core_util_critical_section_exit(); + core_util_critical_section_enter(); + if (!rtc_inited) { + CMU_ClockEnable(cmuClock_RTC, true); + + /* Scale clock to save power */ + CMU_ClockDivSet(cmuClock_RTC, RTC_CLOCKDIV); + + /* Initialize RTC */ + RTC_Init_TypeDef init = RTC_INIT_DEFAULT; + init.enable = 1; + /* Don't use compare register 0 as top value */ + init.comp0Top = 0; + + /* Enable Interrupt from RTC */ + RTC_IntEnable(RTC_IEN_OF); + NVIC_SetVector(RTC_IRQn, (uint32_t)RTC_IRQHandler); + NVIC_EnableIRQ(RTC_IRQn); + + /* Initialize */ + RTC_Init(&init); + + rtc_inited = true; } + core_util_critical_section_exit(); } void lp_ticker_free() { - if(rtc_reserved) { - core_util_critical_section_enter(); - rtc_free_real(RTC_INIT_LPTIMER); - rtc_reserved = 0; - core_util_critical_section_exit(); + /* Disable the RTC if it was inited and is no longer in use by anyone. */ + if (rtc_inited) { + NVIC_DisableIRQ(RTC_IRQn); + RTC_Reset(); + CMU_ClockEnable(cmuClock_RTC, false); + rtc_inited = false; } } +void rtc_enable_comp0(bool enable) +{ + RTC_FreezeEnable(true); + if (!enable) { + RTC_IntDisable(RTC_IF_COMP0); + } else { + RTC_IntEnable(RTC_IF_COMP0); + } + RTC_FreezeEnable(false); +} + +void rtc_set_comp0_value(uint64_t value, bool enable) +{ + rtc_enable_comp0(false); + + /* Set callback */ + RTC_FreezeEnable(true); + extended_comp0 = (uint32_t) (value >> RTC_BITS); + RTC_CompareSet(0, (uint32_t) (value & RTC_MAX_VALUE)); + RTC_FreezeEnable(false); + + rtc_enable_comp0(enable); +} + void lp_ticker_set_interrupt(timestamp_t timestamp) { uint64_t rtc_compare_value; @@ -96,17 +197,17 @@ void lp_ticker_set_interrupt(timestamp_t timestamp) rtc_set_comp0_value(rtc_compare_value, true); } -inline void lp_ticker_fire_interrupt(void) +void lp_ticker_fire_interrupt(void) { - rtc_force_comp0(); + RTC_IntSet(RTC_IFS_COMP0); } -inline void lp_ticker_disable_interrupt() +void lp_ticker_disable_interrupt() { rtc_enable_comp0(false); } -inline void lp_ticker_clear_interrupt() +void lp_ticker_clear_interrupt() { /* No need to clear interrupt flag, since that already happens at RTC level */ } @@ -127,4 +228,7 @@ timestamp_t lp_ticker_read() return (timestamp_t) (ticks_temp & 0xFFFFFFFF); } -#endif +#elif defined(RTCC_PRESENT) +/* lp_ticker api is implemented in rtc_rtcc.c */ +#endif /* RTC_PRESENT */ +#endif /* DEVICE_LOWPOWERTIMER */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api.c deleted file mode 100644 index 81e64cbc00..0000000000 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api.c +++ /dev/null @@ -1,345 +0,0 @@ -/***************************************************************************//** - * @file rtc_api.c - ******************************************************************************* - * @section License - * (C) Copyright 2015 Silicon Labs, http://www.silabs.com - ******************************************************************************* - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "device.h" -#if DEVICE_RTC - -#include "rtc_api.h" -#include "rtc_api_HAL.h" -#include "em_cmu.h" -#include "sleep_api.h" - -#if (defined RTC_COUNT) && (RTC_COUNT > 0) -#include "em_rtc.h" -#endif - -#if (defined RTCC_COUNT) && (RTCC_COUNT > 0) -#include "em_rtcc.h" -#endif - -static bool rtc_inited = false; -static bool rtc_cancelled = false; -static time_t time_base = 0; -static uint32_t useflags = 0; -static uint32_t time_extend = 0; -static uint32_t extended_comp0 = 0; - -static void (*comp0_handler)(void) = NULL; - -#ifndef RTCC_PRESENT -/* Using RTC API */ - -#if RTC_CLOCKDIV_INT > 16 -#error invalid prescaler value RTC_CLOCKDIV_INT, since LP ticker resolution will exceed 1ms. -#endif - -void RTC_IRQHandler(void) -{ - uint32_t flags; - flags = RTC_IntGet(); - if (flags & RTC_IF_OF) { - RTC_IntClear(RTC_IF_OF); - /* RTC has overflowed (24 bits). Use time_extend as software counter for 32 more bits. */ - time_extend += 1; - } - if (flags & RTC_IF_COMP0) { - RTC_IntClear(RTC_IF_COMP0); - if (comp0_handler != NULL && ((time_extend == extended_comp0) || (rtc_cancelled))) { - rtc_cancelled = false; - comp0_handler(); - } - } -} - -uint64_t rtc_get_full(void) -{ - uint64_t ticks = 0; - - do - { - ticks = RTC_CounterGet(); - - if (RTC_IntGet() & RTC_IF_OF) { - RTC_IntClear(RTC_IF_OF); - /* RTC has overflowed in a critical section, so handle the overflow here */ - time_extend += 1; - } - - ticks += (uint64_t)time_extend << RTC_BITS; - } - while ( (ticks & RTC_MAX_VALUE) != RTC_CounterGet() ); - - return ticks; -} - -void rtc_init_real(uint32_t flags) -{ - useflags |= flags; - - if (!rtc_inited) { - CMU_ClockEnable(cmuClock_RTC, true); - - /* Enable clock to the interface of the low energy modules */ - CMU_ClockEnable(cmuClock_CORELE, true); - - /* Scale clock to save power */ - CMU_ClockDivSet(cmuClock_RTC, RTC_CLOCKDIV); - - /* Initialize RTC */ - RTC_Init_TypeDef init = RTC_INIT_DEFAULT; - init.enable = 1; - /* Don't use compare register 0 as top value */ - init.comp0Top = 0; - - /* Enable Interrupt from RTC */ - RTC_IntEnable(RTC_IEN_OF); - NVIC_SetVector(RTC_IRQn, (uint32_t)RTC_IRQHandler); - NVIC_EnableIRQ(RTC_IRQn); - - /* Initialize */ - RTC_Init(&init); - - rtc_inited = true; - } -} - -void rtc_free(void) -{ - rtc_free_real(RTC_INIT_RTC); -} - -void rtc_free_real(uint32_t flags) -{ - /* Clear use flag */ - useflags &= ~flags; - - /* Disable the RTC if it was inited and is no longer in use by anyone. */ - if (rtc_inited && (useflags == 0)) { - NVIC_DisableIRQ(RTC_IRQn); - RTC_Reset(); - CMU_ClockEnable(cmuClock_RTC, false); - rtc_inited = false; - } -} - -void rtc_enable_comp0(bool enable) -{ - RTC_FreezeEnable(true); - if (!enable) { - RTC_IntDisable(RTC_IF_COMP0); - } else { - RTC_IntEnable(RTC_IF_COMP0); - } - RTC_FreezeEnable(false); -} - -void rtc_set_comp0_value(uint64_t value, bool enable) -{ - rtc_enable_comp0(false); - - /* Set callback */ - RTC_FreezeEnable(true); - extended_comp0 = (uint32_t) (value >> RTC_BITS); - RTC_CompareSet(0, (uint32_t) (value & RTC_MAX_VALUE)); - RTC_FreezeEnable(false); - - rtc_enable_comp0(enable); -} - -void rtc_force_comp0(void) -{ - rtc_cancelled = true; - RTC_IntSet(RTC_IFS_COMP0); -} - -#else -/* Using RTCC API */ - -void RTCC_IRQHandler(void) -{ - uint32_t flags; - flags = RTCC_IntGet(); - - if (flags & RTCC_IF_OF) { - RTCC_IntClear(RTCC_IF_OF); - /* RTC has overflowed (32 bits). Use time_extend as software counter for 32 more bits. */ - time_extend += 1; - } - - if (flags & RTCC_IF_CC0) { - RTCC_IntClear(RTCC_IF_CC0); - if (comp0_handler != NULL && ((time_extend == extended_comp0) || (rtc_cancelled))) { - comp0_handler(); - } - } -} - -uint64_t rtc_get_full(void) -{ - uint64_t ticks = 0; - - do - { - ticks = RTCC_CounterGet(); - - if (RTCC_IntGet() & RTCC_IF_OF) { - RTCC_IntClear(RTCC_IF_OF); - /* RTCC has overflowed in critical section, so handle the rollover here */ - time_extend += 1; - } - - ticks += (uint64_t)time_extend << RTC_BITS; - } - while ( (ticks & RTC_MAX_VALUE) != RTCC_CounterGet() ); - - return ticks; -} - -void rtc_init_real(uint32_t flags) -{ - useflags |= flags; - - if (!rtc_inited) { - CMU_ClockEnable(cmuClock_RTCC, true); - - /* Enable clock to the interface of the low energy modules */ - CMU_ClockEnable(cmuClock_CORELE, true); - - /* Initialize RTC */ - RTCC_Init_TypeDef init = RTCC_INIT_DEFAULT; - init.enable = 1; - init.precntWrapOnCCV0 = false; - init.cntWrapOnCCV1 = false; -#if RTC_CLOCKDIV_INT == 1 - init.presc = rtccCntPresc_1; -#elif RTC_CLOCKDIV_INT == 2 - init.presc = rtccCntPresc_2; -#elif RTC_CLOCKDIV_INT == 4 - init.presc = rtccCntPresc_4; -#elif RTC_CLOCKDIV_INT == 8 - init.presc = rtccCntPresc_8; -#elif RTC_CLOCKDIV_INT == 16 - init.presc = rtccCntPresc_16; -#else -#error invalid prescaler value RTC_CLOCKDIV_INT, since LP ticker resolution will exceed 1ms. -#endif - - /* Enable Interrupt from RTC */ - RTCC_IntEnable(RTCC_IEN_OF); - NVIC_SetVector(RTCC_IRQn, (uint32_t)RTCC_IRQHandler); - NVIC_EnableIRQ(RTCC_IRQn); - - /* Initialize */ - RTCC_Init(&init); - rtc_inited = true; - } -} - -void rtc_free(void) -{ - rtc_free_real(RTC_INIT_RTC); -} - -void rtc_free_real(uint32_t flags) -{ - /* Clear use flag */ - useflags &= ~flags; - - /* Disable the RTC if it was inited and is no longer in use by anyone. */ - if (rtc_inited && (useflags == 0)) { - NVIC_DisableIRQ(RTCC_IRQn); - RTCC_Reset(); - CMU_ClockEnable(cmuClock_RTCC, false); - rtc_inited = false; - } -} - -void rtc_enable_comp0(bool enable) -{ - if(!enable) { - RTCC_IntDisable(RTCC_IF_CC0); - } else { - RTCC_IntEnable(RTCC_IF_CC0); - } -} - -void rtc_set_comp0_value(uint64_t value, bool enable) -{ - rtc_enable_comp0(false); - - /* init channel */ - RTCC_CCChConf_TypeDef ccchConf = RTCC_CH_INIT_COMPARE_DEFAULT; - RTCC_ChannelInit(0,&ccchConf); - /* Set callback */ - extended_comp0 = (uint32_t) (value >> RTC_BITS); - RTCC_ChannelCCVSet(0, (uint32_t) (value & RTC_MAX_VALUE)); - - rtc_enable_comp0(enable); -} - -void rtc_force_comp0(void) -{ - rtc_cancelled = true; - RTCC_IntSet(RTCC_IFS_CC0); -} - -#endif /* RTCC_COUNT */ - -void rtc_set_comp0_handler(uint32_t handler) -{ - comp0_handler = (void (*)(void)) handler; -} - -void rtc_init(void) -{ - /* Register that the RTC is used for timekeeping. */ - rtc_init_real(RTC_INIT_RTC); -} - -int rtc_isenabled(void) -{ - return rtc_inited; -} - -time_t rtc_read(void) -{ - return (time_t) (rtc_get_full() >> RTC_FREQ_SHIFT) + time_base; -} - -time_t rtc_read_uncompensated(void) -{ - return (time_t) (rtc_get_full() >> RTC_FREQ_SHIFT); -} - -void rtc_write(time_t t) -{ - /* We have to check that the RTC did not tick while doing this. */ - /* If the RTC ticks we just redo this. */ - uint32_t time; - do { - time = rtc_read_uncompensated(); - time_base = t - time; - } while (time != (uint32_t)rtc_read_uncompensated()); -} - -#endif diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api_HAL.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api_HAL.h deleted file mode 100644 index 702c42ccd7..0000000000 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api_HAL.h +++ /dev/null @@ -1,61 +0,0 @@ -/***************************************************************************//** - * @file rtc_api_HAL.h - ******************************************************************************* - * @section License - * (C) Copyright 2015 Silicon Labs, http://www.silabs.com - ******************************************************************************* - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#ifndef MBED_RTC_API_HAL_H -#define MBED_RTC_API_HAL_H - -#include -#include "rtc_api.h" -#include "clocking.h" - -#define RTC_INIT_LPTIMER (1U << 1) -#define RTC_INIT_RTC (1U << 0) - -#if defined(RTCC_PRESENT) -#define RTC_BITS (32U) -#define RTC_MAX_VALUE (0xFFFFFFFFUL) -#elif defined(RTC_PRESENT) -#define RTC_BITS (24U) -#define RTC_MAX_VALUE (0xFFFFFFUL) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Purpose of this file: extend rtc_api.h to include EFM-specific stuff*/ -void rtc_set_comp0_handler(uint32_t handler); -void rtc_enable_comp0(bool enable); -void rtc_set_comp0_value(uint64_t value, bool enable); -void rtc_force_comp0(void); - -uint64_t rtc_get_full(void); - -void rtc_init_real(uint32_t flags); -void rtc_free_real(uint32_t flags); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/rtcc.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/rtcc.c new file mode 100644 index 0000000000..5efe497aa1 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/rtcc.c @@ -0,0 +1,211 @@ +/***************************************************************************//** + * @file rtc_rtcc.c + ******************************************************************************* + * @section License + * (C) Copyright 2018 Silicon Labs, http://www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "device.h" +#if DEVICE_RTC || DEVICE_LPTIMER + +/* Use RTCC on devices that have it */ +#if defined(RTCC_PRESENT) + +#include "em_cmu.h" +#include "em_rmu.h" +#include "em_rtcc.h" +#include "rtc_api.h" +#include "lp_ticker_api.h" +#include "clocking.h" + +static bool lptick_inited = false; +static uint32_t lptick_offset = 0; +static uint32_t extended_comp0 = 0; + +void rtc_init(void) +{ + if (BUS_RegBitRead((&RTCC->CTRL), _RTCC_CTRL_ENABLE_SHIFT) != 0) { + /* RTCC already up & running */ + return; + } + + /* Make sure RTCC doesn't get reset (mbed specification) */ + RMU_ResetControl(rmuResetWdog, rmuResetModeLimited); + RMU_ResetControl(rmuResetCoreLockup, rmuResetModeLimited); + RMU_ResetControl(rmuResetSys, rmuResetModeLimited); + RMU_ResetControl(rmuResetPin, rmuResetModeFull); + + /* Set up the RTCC and let it run, Forrest, run */ + RTCC_Reset(); + RTCC_Init_TypeDef rtcc_init = RTCC_INIT_DEFAULT; + rtcc_init.presc = rtccCntPresc_32768; + RTCC_Init(&rtcc_init); + RTCC_Enable(true); +} + +void rtc_free(void) +{ + /* Can't turn off any clock gates here since other parts of the + * system might be using the CORELE clock. */ +} + +int rtc_isenabled(void) +{ + return BUS_RegBitRead((&RTCC->CTRL), _RTCC_CTRL_ENABLE_SHIFT); +} + +time_t rtc_read(void) +{ + return RTCC_CounterGet(); +} + +void rtc_write(time_t t) +{ + core_util_critical_section_enter(); + uint32_t diff = t - RTCC_CounterGet(); + if (extended_comp0 != 0xFFFFFFFFUL) { + extended_comp0 += diff; + } + lptick_offset += diff; + + RTCC_CounterSet(t); + core_util_critical_section_exit(); +} + +/************************* LP_TICKER **************************/ +void RTCC_IRQHandler(void) +{ + uint32_t flags; + flags = RTCC_IntGet(); + if (flags & RTCC_IF_CC0) { + RTCC_IntClear(RTCC_IF_CC0); + if ((RTCC_CounterGet() - lptick_offset) == extended_comp0) { + RTCC_IntDisable(RTCC_IF_CC0); + lp_ticker_irq_handler(); + } + if (0xFFFFFFFFUL == extended_comp0) { + RTCC_IntDisable(RTCC_IF_CC0); + lp_ticker_irq_handler(); + } + } +} + +void lp_ticker_init() +{ + if (!lptick_inited) { + rtc_init(); + lptick_offset = RTCC_CounterGet(); + RTCC_CCChConf_TypeDef lp_chan_init = RTCC_CH_INIT_COMPARE_DEFAULT; + lp_chan_init.compBase = rtccCompBasePreCnt; + lp_chan_init.compMask = 17; + RTCC_ChannelInit(0, &lp_chan_init); + lptick_inited = true; + + /* Enable Interrupt from RTCC */ + NVIC_EnableIRQ(RTCC_IRQn); + } +} + +void lp_ticker_free() +{ + if (lptick_inited) { + lp_ticker_disable_interrupt(); + lp_ticker_clear_interrupt(); + lptick_inited = false; + } +} + +void lp_ticker_set_interrupt(timestamp_t timestamp) +{ + uint64_t rtc_compare_value; + uint64_t current_ticks = 0; + do + { + current_ticks = (uint64_t)((uint64_t)RTCC_CounterGet() - lptick_offset) << 15; + current_ticks += RTCC_PreCounterGet(); + } + while ( (current_ticks & 0x7FFF) != RTCC_PreCounterGet() ); + + uint64_t ticks_temp = (current_ticks * 1000000) / LOW_ENERGY_CLOCK_FREQUENCY; + timestamp_t current_time = ticks_temp & 0xFFFFFFFF; + + /* calculate offset value */ + timestamp_t offset = timestamp - current_time; + + /* If the requested timestamp is too far in the future, we might not be able + * to set the interrupt accurately due to potentially having ticked between + * calculating the timestamp to set and us calculating the offset. */ + if(offset > 0xFFFF0000) offset = 100; + + /* map offset to RTC value */ + // ticks = offset * RTC frequency div 1000000 + rtc_compare_value = ((uint64_t)offset * LOW_ENERGY_CLOCK_FREQUENCY) / 1000000; + + /* If RTC offset is less then 2 RTC ticks, the interrupt won't fire */ + if(rtc_compare_value < 2) { + rtc_compare_value = 2; + } + + rtc_compare_value += current_ticks; + + extended_comp0 = rtc_compare_value >> 15; + RTCC_ChannelCCVSet(0, rtc_compare_value & 0xFFFFFFFFUL); + RTCC_IntEnable(RTCC_IF_CC0); +} + +void lp_ticker_fire_interrupt(void) +{ + extended_comp0 = 0xFFFFFFFFUL; + RTCC_IntSet(RTCC_IF_CC0); +} + +void lp_ticker_disable_interrupt() +{ + RTCC_IntDisable(RTCC_IF_CC0); +} + +void lp_ticker_clear_interrupt() +{ + RTCC_IntClear(RTCC_IF_CC0); +} + +timestamp_t lp_ticker_read() +{ + lp_ticker_init(); + + uint64_t ticks_temp; + uint64_t ticks = 0; + + do + { + ticks = (uint64_t)((uint64_t)RTCC_CounterGet() - lptick_offset) << 15; + ticks += RTCC_PreCounterGet(); + } + while ( (ticks & 0x7FFF) != RTCC_PreCounterGet() ); + + /* ticks = counter tick value + * timestamp = value in microseconds + * timestamp = ticks * 1.000.000 / RTC frequency + */ + + ticks_temp = (ticks * 1000000) / LOW_ENERGY_CLOCK_FREQUENCY; + return (timestamp_t) (ticks_temp & 0xFFFFFFFF); +} +#endif /* RTCC_PRESENT */ +#endif /* DEVICE_RTC */ \ No newline at end of file diff --git a/targets/targets.json b/targets/targets.json index ca6dee453d..f2103ccffa 100755 --- a/targets/targets.json +++ b/targets/targets.json @@ -3069,7 +3069,7 @@ }, "EFM32ZG_STK3200": { "inherits": ["EFM32ZG222F32"], - "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], "forced_reset_timeout": 2, "config": { "hf_clock_src": { @@ -3123,7 +3123,7 @@ }, "EFM32HG_STK3400": { "inherits": ["EFM32HG322F64"], - "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], "forced_reset_timeout": 2, "config": { "hf_clock_src": { @@ -3239,7 +3239,7 @@ }, "EFR32MG1_BRD4150": { "inherits": ["EFR32MG1P132F256GM48"], - "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "FLASH"], + "device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "FLASH"], "forced_reset_timeout": 2, "config": { "hf_clock_src": {