Skip to content

Commit 3cb9728

Browse files
authored
Merge pull request #5854 from SiliconLabs/bugfix/rtc_overflow
Fix for Silicon Labs RTC
2 parents 25aa0e6 + 5d6c5dd commit 3cb9728

File tree

5 files changed

+177
-156
lines changed

5 files changed

+177
-156
lines changed

targets/TARGET_Silicon_Labs/TARGET_EFM32/common/clocking.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#ifndef MBED_CLOCKING_H
2525
#define MBED_CLOCKING_H
2626

27+
#include "em_cmu.h"
28+
2729
/* Clock definitions */
2830
#define LFXO 0
2931
#define HFXO 1
@@ -51,8 +53,8 @@
5153
#ifndef CORE_CLOCK_SOURCE
5254
#define CORE_CLOCK_SOURCE HFRCO
5355
#if defined(_CMU_HFRCOCTRL_BAND_MASK)
54-
#define HFRCO_FREQUENCY_ENUM _CMU_HFRCOCTRL_BAND_21MHZ
55-
#define HFRCO_FREQUENCY 21000000
56+
#define HFRCO_FREQUENCY_ENUM _CMU_HFRCOCTRL_BAND_21MHZ
57+
#define HFRCO_FREQUENCY 21000000
5658
#elif defined(_CMU_HFRCOCTRL_FREQRANGE_MASK)
5759
#define HFRCO_FREQUENCY_ENUM cmuHFRCOFreq_32M0Hz
5860
#define HFRCO_FREQUENCY 32000000
@@ -103,4 +105,13 @@
103105
# endif
104106
#endif
105107

108+
/* Adjust this to change speed of RTC and LP ticker ticks */
109+
#define RTC_CLOCKDIV cmuClkDiv_8
110+
/* Adjust this to match RTC_CLOCKDIV as integer value */
111+
#define RTC_CLOCKDIV_INT 8U
112+
/* Adjust this to match RTC_CLOCKDIV as shift for 1 second worth of ticks.
113+
* E.g. with 32768 Hz crystal and CLOCKDIV of 8, 1 second is 4096 ticks.
114+
* 4096 equals 1 << 12, so RTC_FREQ_SHIFT needs to be 12. */
115+
#define RTC_FREQ_SHIFT 12U
116+
106117
#endif

targets/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c

Lines changed: 35 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,25 @@
2525
#include "clocking.h"
2626
#if DEVICE_LOWPOWERTIMER
2727

28+
/*******************************************************************************
29+
* The Silicon Labs lp_ticker implementation is mapped on top of an extended RTC
30+
* API, since the RTC is available in the lowest energy modes. By default, the
31+
* RTC counter is configured to run at 4kHz, giving us a quarter-ms resolution
32+
* for the low power timer, which should be good enough for a low power use
33+
* case.
34+
*
35+
* On Silicon Labs devices, the lowest width RTC implementation has a 24-bit
36+
* counter, which gets extended with a further 32-bit software counter. This
37+
* gives 56 bits of actual width, which with the default speed maps to
38+
* 557462 years before the extended RTC counter wraps around. We are pretty
39+
* certain no device is going to have that amount of uptime.
40+
* (At max speed the wraparound is at 69730 years, which is unlikely as well)
41+
******************************************************************************/
42+
2843
#include "rtc_api.h"
2944
#include "rtc_api_HAL.h"
3045
#include "lp_ticker_api.h"
31-
3246
#include "mbed_critical.h"
33-
#if (defined RTCC_COUNT) && (RTCC_COUNT > 0)
34-
#include "em_rtcc.h"
35-
#endif
3647

3748
static int rtc_reserved = 0;
3849

@@ -57,135 +68,55 @@ void lp_ticker_free()
5768
}
5869
}
5970

60-
#ifndef RTCC_COUNT
61-
62-
/* RTC API */
63-
6471
void lp_ticker_set_interrupt(timestamp_t timestamp)
6572
{
66-
uint64_t timestamp_ticks;
67-
uint64_t current_ticks = RTC_CounterGet();
68-
timestamp_t current_time = ((uint64_t)(current_ticks * 1000000) / (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT));
69-
70-
/* Initialize RTC */
71-
lp_ticker_init();
73+
uint64_t rtc_compare_value;
74+
uint64_t current_ticks = rtc_get_full();
75+
timestamp_t current_time = lp_ticker_read();
7276

7377
/* calculate offset value */
7478
timestamp_t offset = timestamp - current_time;
75-
if(offset > 0xEFFFFFFF) offset = 100;
76-
77-
/* map offset to RTC value */
78-
// ticks = offset * RTC frequency div 1000000
79-
timestamp_ticks = ((uint64_t)offset * (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT)) / 1000000;
80-
timestamp_ticks += current_ticks;
81-
82-
/* RTC has 24 bit resolution */
83-
timestamp_ticks &= 0xFFFFFF;
84-
85-
/* check for RTC limitation */
86-
if((timestamp_ticks - RTC_CounterGet()) >= 0x800000) timestamp_ticks = RTC_CounterGet() + 2;
8779

88-
/* Set callback */
89-
RTC_FreezeEnable(true);
90-
RTC_CompareSet(0, (uint32_t)timestamp_ticks);
91-
RTC_IntEnable(RTC_IF_COMP0);
92-
RTC_FreezeEnable(false);
93-
}
94-
95-
void lp_ticker_fire_interrupt(void)
96-
{
97-
RTC_IntSet(RTC_IFS_COMP0);
98-
}
99-
100-
inline void lp_ticker_disable_interrupt()
101-
{
102-
RTC_IntDisable(RTC_IF_COMP0);
103-
}
104-
105-
inline void lp_ticker_clear_interrupt()
106-
{
107-
RTC_IntClear(RTC_IF_COMP0);
108-
}
109-
110-
timestamp_t lp_ticker_read()
111-
{
112-
lp_ticker_init();
113-
114-
uint64_t ticks_temp;
115-
uint64_t ticks = RTC_CounterGet();
116-
117-
/* ticks = counter tick value
118-
* timestamp = value in microseconds
119-
* timestamp = ticks * 1.000.000 / RTC frequency
120-
*/
121-
122-
ticks_temp = (ticks * 1000000) / (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT);
123-
return (timestamp_t) (ticks_temp & 0xFFFFFFFF);
124-
}
125-
126-
#else
127-
128-
/* RTCC API */
129-
130-
void lp_ticker_set_interrupt(timestamp_t timestamp)
131-
{
132-
uint64_t timestamp_ticks;
133-
uint64_t current_ticks = RTCC_CounterGet();
134-
timestamp_t current_time = ((uint64_t)(current_ticks * 1000000) / (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT));
135-
136-
/* Initialize RTC */
137-
lp_ticker_init();
138-
139-
/* calculate offset value */
140-
timestamp_t offset = timestamp - current_time;
141-
if(offset > 0xEFFFFFFF) offset = 100;
80+
/* If the requested timestamp is too far in the future, we might not be able
81+
* to set the interrupt accurately due to potentially having ticked between
82+
* calculating the timestamp to set and us calculating the offset. */
83+
if(offset > 0xFFFF0000) offset = 100;
14284

14385
/* map offset to RTC value */
14486
// ticks = offset * RTC frequency div 1000000
145-
timestamp_ticks = ((uint64_t)offset * (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT)) / 1000000;
146-
// checking the rounding. If timeout is wanted between RTCC ticks, irq should be configured to
147-
// trigger in the latter RTCC-tick. Otherwise ticker-api fails to send timer event to its client
148-
if(((timestamp_ticks * 1000000) / (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT)) < offset){
149-
timestamp_ticks++;
150-
}
151-
152-
timestamp_ticks += current_ticks;
87+
rtc_compare_value = ((uint64_t)offset * (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT)) / 1000000;
15388

154-
/* RTCC has 32 bit resolution */
155-
timestamp_ticks &= 0xFFFFFFFF;
89+
/* If RTC offset is less then 2 RTC ticks, the interrupt won't fire */
90+
if(rtc_compare_value < 2) {
91+
rtc_compare_value = 2;
92+
}
15693

157-
/* check for RTCC limitation */
158-
if((timestamp_ticks - RTCC_CounterGet()) >= 0x80000000) timestamp_ticks = RTCC_CounterGet() + 2;
94+
rtc_compare_value += current_ticks;
15995

160-
/* init channel */
161-
RTCC_CCChConf_TypeDef ccchConf = RTCC_CH_INIT_COMPARE_DEFAULT;
162-
RTCC_ChannelInit(0,&ccchConf);
163-
/* Set callback */
164-
RTCC_ChannelCCVSet(0, (uint32_t)timestamp_ticks);
165-
RTCC_IntEnable(RTCC_IF_CC0);
96+
rtc_set_comp0_value(rtc_compare_value, true);
16697
}
16798

168-
void lp_ticker_fire_interrupt(void)
99+
inline void lp_ticker_fire_interrupt(void)
169100
{
170-
RTCC_IntSet(RTCC_IFS_CC0);
101+
rtc_force_comp0();
171102
}
172103

173104
inline void lp_ticker_disable_interrupt()
174105
{
175-
RTCC_IntDisable(RTCC_IF_CC0);
106+
rtc_enable_comp0(false);
176107
}
177108

178109
inline void lp_ticker_clear_interrupt()
179110
{
180-
RTCC_IntClear(RTCC_IF_CC0);
111+
/* No need to clear interrupt flag, since that already happens at RTC level */
181112
}
182113

183114
timestamp_t lp_ticker_read()
184115
{
185116
lp_ticker_init();
186-
117+
187118
uint64_t ticks_temp;
188-
uint64_t ticks = RTCC_CounterGet();
119+
uint64_t ticks = rtc_get_full();
189120

190121
/* ticks = counter tick value
191122
* timestamp = value in microseconds
@@ -196,6 +127,4 @@ timestamp_t lp_ticker_read()
196127
return (timestamp_t) (ticks_temp & 0xFFFFFFFF);
197128
}
198129

199-
#endif /* RTCC */
200-
201130
#endif

0 commit comments

Comments
 (0)