Re-implement RTC for Silicon Labs targets

mbed RTC specifications now dictate that the RTC needs to retain and keep on counting through reset. On Silicon Labs parts, this means the RTC API can not be backed by the Silicon Labs RTC peripheral, since that doesn't provide retention functionality.
Therefore:
* On EFM32GG, EFM32WG, EFM32LG: mbed RTC API is now backed by BURTC.
* On EFM32PG, EFR32MG, EFM32PG12, EFR32MG12: mbed RTC API is now backed by RTCC.
* On EFM32ZG, EFM32HG: mbed RTC API is sadly no longer supported, since these chips don't have retained memory.

# Conflicts:
#	targets/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c
#	targets/TARGET_Silicon_Labs/TARGET_EFM32/rtc_api.c
#	targets/targets.json
pull/7009/head
Steven Cooreman 2018-03-26 22:52:11 +02:00 committed by Bartek Szatkowski
parent 85ce887cea
commit 5590f2b495
7 changed files with 448 additions and 428 deletions

View File

@ -0,0 +1,106 @@
/***************************************************************************//**
* @file rtc_burtc.c
*******************************************************************************
* @section License
* <b>(C) Copyright 2018 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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 */

View File

@ -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);

View File

@ -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 */

View File

@ -1,345 +0,0 @@
/***************************************************************************//**
* @file rtc_api.c
*******************************************************************************
* @section License
* <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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

View File

@ -1,61 +0,0 @@
/***************************************************************************//**
* @file rtc_api_HAL.h
*******************************************************************************
* @section License
* <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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 <stdint.h>
#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

View File

@ -0,0 +1,211 @@
/***************************************************************************//**
* @file rtc_rtcc.c
*******************************************************************************
* @section License
* <b>(C) Copyright 2018 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* 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 */

View File

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