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": {