Skip to content

Commit fdb4a8e

Browse files
committed
Re-implement us_ticker and lp_ticker for Silicon Labs targets
Re-implemented both us_ticker and lp_ticker to match the new API and specifications. Details: * On EFM32GG, EFM32WG, EFM32LG, EFM32HG, EFM32ZG: Use the RTC peripheral to back lp_ticker, and a TIMER to back us_ticker. * On EFM32PG, EFR32MG, EFM32PG12, EFR32MG12: Use the RTCC peripheral to back lp_ticker (dual-purpose, also used to back RTC), and a TIMER to back us_ticker.
1 parent abb9f6d commit fdb4a8e

File tree

5 files changed

+108
-307
lines changed

5 files changed

+108
-307
lines changed

targets/TARGET_Silicon_Labs/TARGET_EFM32/common/clocking.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,12 @@
106106
#endif
107107

108108
/* Adjust this to change speed of RTC and LP ticker ticks */
109-
#define RTC_CLOCKDIV cmuClkDiv_8
109+
#define RTC_CLOCKDIV cmuClkDiv_1
110110
/* Adjust this to match RTC_CLOCKDIV as integer value */
111-
#define RTC_CLOCKDIV_INT 8U
111+
#define RTC_CLOCKDIV_INT 1U
112112
/* Adjust this to match RTC_CLOCKDIV as shift for 1 second worth of ticks.
113113
* E.g. with 32768 Hz crystal and CLOCKDIV of 8, 1 second is 4096 ticks.
114114
* 4096 equals 1 << 12, so RTC_FREQ_SHIFT needs to be 12. */
115-
#define RTC_FREQ_SHIFT 12U
115+
#define RTC_FREQ_SHIFT 15U
116116

117117
#endif

targets/TARGET_Silicon_Labs/TARGET_EFM32/lp_ticker.c

Lines changed: 32 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -65,45 +65,24 @@
6565
#define RTC_MAX_VALUE (0xFFFFFFUL)
6666

6767
static bool rtc_inited = false;
68-
static time_t time_base = 0;
69-
static uint32_t time_extend = 0;
70-
static uint32_t extended_comp0 = 0;
68+
69+
const ticker_info_t* lp_ticker_get_info(void)
70+
{
71+
static const ticker_info_t rtc_info = {
72+
LOW_ENERGY_CLOCK_FREQUENCY,
73+
RTC_BITS
74+
};
75+
return &rtc_info;
76+
}
7177

7278
void RTC_IRQHandler(void)
7379
{
7480
uint32_t flags;
7581
flags = RTC_IntGet();
76-
if (flags & RTC_IF_OF) {
77-
RTC_IntClear(RTC_IF_OF);
78-
/* RTC has overflowed (24 bits). Use time_extend as software counter for 32 more bits. */
79-
time_extend += 1;
80-
}
81-
if (flags & RTC_IF_COMP0) {
82+
if ((flags & RTC_IF_COMP0) && rtc_inited) {
8283
RTC_IntClear(RTC_IF_COMP0);
83-
if (lp_ticker_irq_handler != NULL && time_extend == extended_comp0) {
84-
lp_ticker_irq_handler();
85-
}
86-
}
87-
}
88-
89-
uint64_t rtc_get_full(void)
90-
{
91-
uint64_t ticks = 0;
92-
93-
do
94-
{
95-
/* In case someone's trying to read time in a critical section */
96-
if (RTC_IntGet() & RTC_IF_OF) {
97-
RTC_IntClear(RTC_IF_OF);
98-
time_extend += 1;
99-
}
100-
101-
ticks = (uint64_t)time_extend << RTC_BITS;
102-
ticks += RTC_CounterGet();
84+
lp_ticker_irq_handler();
10385
}
104-
while ( (ticks & RTC_MAX_VALUE) != RTC_CounterGet() );
105-
106-
return ticks;
10786
}
10887

10988
void lp_ticker_init()
@@ -112,24 +91,27 @@ void lp_ticker_init()
11291
if (!rtc_inited) {
11392
CMU_ClockEnable(cmuClock_RTC, true);
11493

115-
/* Scale clock to save power */
116-
CMU_ClockDivSet(cmuClock_RTC, RTC_CLOCKDIV);
117-
11894
/* Initialize RTC */
11995
RTC_Init_TypeDef init = RTC_INIT_DEFAULT;
12096
init.enable = 1;
12197
/* Don't use compare register 0 as top value */
12298
init.comp0Top = 0;
12399

100+
/* Initialize */
101+
RTC_Init(&init);
102+
RTC_CounterSet(20);
103+
124104
/* Enable Interrupt from RTC */
125-
RTC_IntEnable(RTC_IEN_OF);
105+
RTC_IntDisable(RTC_IF_COMP0);
106+
RTC_IntClear(RTC_IF_COMP0);
126107
NVIC_SetVector(RTC_IRQn, (uint32_t)RTC_IRQHandler);
127108
NVIC_EnableIRQ(RTC_IRQn);
128109

129-
/* Initialize */
130-
RTC_Init(&init);
131-
132110
rtc_inited = true;
111+
} else {
112+
/* Cancel current interrupt by virtue of calling init again */
113+
RTC_IntDisable(RTC_IF_COMP0);
114+
RTC_IntClear(RTC_IF_COMP0);
133115
}
134116
core_util_critical_section_exit();
135117
}
@@ -145,90 +127,38 @@ void lp_ticker_free()
145127
}
146128
}
147129

148-
void rtc_enable_comp0(bool enable)
149-
{
150-
RTC_FreezeEnable(true);
151-
if (!enable) {
152-
RTC_IntDisable(RTC_IF_COMP0);
153-
} else {
154-
RTC_IntEnable(RTC_IF_COMP0);
155-
}
156-
RTC_FreezeEnable(false);
157-
}
158-
159-
void rtc_set_comp0_value(uint64_t value, bool enable)
130+
void lp_ticker_set_interrupt(timestamp_t timestamp)
160131
{
161-
rtc_enable_comp0(false);
162-
163-
/* Set callback */
132+
RTC_IntDisable(RTC_IF_COMP0);
133+
RTC_IntClear(RTC_IF_COMP0);
164134
RTC_FreezeEnable(true);
165-
extended_comp0 = (uint32_t) (value >> RTC_BITS);
166-
RTC_CompareSet(0, (uint32_t) (value & RTC_MAX_VALUE));
135+
RTC_CompareSet(0, (uint32_t) (timestamp & RTC_MAX_VALUE));
167136
RTC_FreezeEnable(false);
168-
169-
rtc_enable_comp0(enable);
170-
}
171-
172-
void lp_ticker_set_interrupt(timestamp_t timestamp)
173-
{
174-
uint64_t rtc_compare_value;
175-
uint64_t current_ticks = rtc_get_full();
176-
timestamp_t current_time = lp_ticker_read();
177-
178-
/* calculate offset value */
179-
timestamp_t offset = timestamp - current_time;
180-
181-
/* If the requested timestamp is too far in the future, we might not be able
182-
* to set the interrupt accurately due to potentially having ticked between
183-
* calculating the timestamp to set and us calculating the offset. */
184-
if(offset > 0xFFFF0000) offset = 100;
185-
186-
/* map offset to RTC value */
187-
// ticks = offset * RTC frequency div 1000000
188-
rtc_compare_value = ((uint64_t)offset * (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT)) / 1000000;
189-
190-
/* If RTC offset is less then 2 RTC ticks, the interrupt won't fire */
191-
if(rtc_compare_value < 2) {
192-
rtc_compare_value = 2;
193-
}
194-
195-
rtc_compare_value += current_ticks;
196-
197-
rtc_set_comp0_value(rtc_compare_value, true);
137+
RTC_IntEnable(RTC_IF_COMP0);
198138
}
199139

200140
void lp_ticker_fire_interrupt(void)
201141
{
202-
RTC_IntSet(RTC_IFS_COMP0);
142+
RTC_IntEnable(RTC_IF_COMP0);
143+
RTC_IntSet(RTC_IF_COMP0);
203144
}
204145

205146
void lp_ticker_disable_interrupt()
206147
{
207-
rtc_enable_comp0(false);
148+
RTC_IntDisable(RTC_IF_COMP0);
208149
}
209150

210151
void lp_ticker_clear_interrupt()
211152
{
212-
/* No need to clear interrupt flag, since that already happens at RTC level */
153+
RTC_IntClear(RTC_IF_COMP0);
213154
}
214155

215156
timestamp_t lp_ticker_read()
216157
{
217-
lp_ticker_init();
218-
219-
uint64_t ticks_temp;
220-
uint64_t ticks = rtc_get_full();
221-
222-
/* ticks = counter tick value
223-
* timestamp = value in microseconds
224-
* timestamp = ticks * 1.000.000 / RTC frequency
225-
*/
226-
227-
ticks_temp = (ticks * 1000000) / (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT);
228-
return (timestamp_t) (ticks_temp & 0xFFFFFFFF);
158+
return (timestamp_t) RTC_CounterGet();
229159
}
230160

231161
#elif defined(RTCC_PRESENT)
232162
/* lp_ticker api is implemented in rtc_rtcc.c */
233163
#endif /* RTC_PRESENT */
234-
#endif /* DEVICE_LOWPOWERTIMER */
164+
#endif /* DEVICE_LPTICKER */

targets/TARGET_Silicon_Labs/TARGET_EFM32/rtcc.c

Lines changed: 27 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636

3737
static bool lptick_inited = false;
3838
static uint32_t lptick_offset = 0;
39-
static uint32_t extended_comp0 = 0;
4039

4140
void rtc_init(void)
4241
{
@@ -79,30 +78,32 @@ void rtc_write(time_t t)
7978
{
8079
core_util_critical_section_enter();
8180
uint32_t diff = t - RTCC_CounterGet();
82-
if (extended_comp0 != 0xFFFFFFFFUL) {
83-
extended_comp0 += diff;
84-
}
8581
lptick_offset += diff;
8682

83+
if(RTCC_IntGetEnabled() & RTCC_IF_CC0) {
84+
RTCC->CC[0].CCV += diff << 15;
85+
}
86+
8787
RTCC_CounterSet(t);
8888
core_util_critical_section_exit();
8989
}
9090

9191
/************************* LP_TICKER **************************/
92+
const ticker_info_t* lp_ticker_get_info(void)
93+
{
94+
static const ticker_info_t rtc_info = {
95+
LOW_ENERGY_CLOCK_FREQUENCY,
96+
32
97+
};
98+
return &rtc_info;
99+
}
100+
92101
void RTCC_IRQHandler(void)
93102
{
94103
uint32_t flags;
95104
flags = RTCC_IntGet();
96105
if (flags & RTCC_IF_CC0) {
97-
RTCC_IntClear(RTCC_IF_CC0);
98-
if ((RTCC_CounterGet() - lptick_offset) == extended_comp0) {
99-
RTCC_IntDisable(RTCC_IF_CC0);
100-
lp_ticker_irq_handler();
101-
}
102-
if (0xFFFFFFFFUL == extended_comp0) {
103-
RTCC_IntDisable(RTCC_IF_CC0);
104-
lp_ticker_irq_handler();
105-
}
106+
lp_ticker_irq_handler();
106107
}
107108
}
108109

@@ -113,12 +114,17 @@ void lp_ticker_init()
113114
lptick_offset = RTCC_CounterGet();
114115
RTCC_CCChConf_TypeDef lp_chan_init = RTCC_CH_INIT_COMPARE_DEFAULT;
115116
lp_chan_init.compBase = rtccCompBasePreCnt;
116-
lp_chan_init.compMask = 17;
117+
lp_chan_init.compMask = 0;
117118
RTCC_ChannelInit(0, &lp_chan_init);
118119
lptick_inited = true;
119120

120-
/* Enable Interrupt from RTCC */
121+
/* Enable Interrupt from RTCC in NVIC, but don't start generating them */
122+
RTCC_IntDisable(RTCC_IF_CC0);
123+
RTCC_IntClear(RTCC_IF_CC0);
121124
NVIC_EnableIRQ(RTCC_IRQn);
125+
} else {
126+
RTCC_IntDisable(RTCC_IF_CC0);
127+
RTCC_IntClear(RTCC_IF_CC0);
122128
}
123129
}
124130

@@ -133,45 +139,13 @@ void lp_ticker_free()
133139

134140
void lp_ticker_set_interrupt(timestamp_t timestamp)
135141
{
136-
uint64_t rtc_compare_value;
137-
uint64_t current_ticks = 0;
138-
do
139-
{
140-
current_ticks = (uint64_t)((uint64_t)RTCC_CounterGet() - lptick_offset) << 15;
141-
current_ticks += RTCC_PreCounterGet();
142-
}
143-
while ( (current_ticks & 0x7FFF) != RTCC_PreCounterGet() );
144-
145-
uint64_t ticks_temp = (current_ticks * 1000000) / LOW_ENERGY_CLOCK_FREQUENCY;
146-
timestamp_t current_time = ticks_temp & 0xFFFFFFFF;
147-
148-
/* calculate offset value */
149-
timestamp_t offset = timestamp - current_time;
150-
151-
/* If the requested timestamp is too far in the future, we might not be able
152-
* to set the interrupt accurately due to potentially having ticked between
153-
* calculating the timestamp to set and us calculating the offset. */
154-
if(offset > 0xFFFF0000) offset = 100;
155-
156-
/* map offset to RTC value */
157-
// ticks = offset * RTC frequency div 1000000
158-
rtc_compare_value = ((uint64_t)offset * LOW_ENERGY_CLOCK_FREQUENCY) / 1000000;
159-
160-
/* If RTC offset is less then 2 RTC ticks, the interrupt won't fire */
161-
if(rtc_compare_value < 2) {
162-
rtc_compare_value = 2;
163-
}
164-
165-
rtc_compare_value += current_ticks;
166-
167-
extended_comp0 = rtc_compare_value >> 15;
168-
RTCC_ChannelCCVSet(0, rtc_compare_value & 0xFFFFFFFFUL);
142+
RTCC_ChannelCCVSet(0, timestamp + (lptick_offset << 15));
169143
RTCC_IntEnable(RTCC_IF_CC0);
170144
}
171145

172146
void lp_ticker_fire_interrupt(void)
173147
{
174-
extended_comp0 = 0xFFFFFFFFUL;
148+
RTCC_IntEnable(RTCC_IF_CC0);
175149
RTCC_IntSet(RTCC_IF_CC0);
176150
}
177151

@@ -187,25 +161,11 @@ void lp_ticker_clear_interrupt()
187161

188162
timestamp_t lp_ticker_read()
189163
{
190-
lp_ticker_init();
191-
192-
uint64_t ticks_temp;
193-
uint64_t ticks = 0;
194-
195-
do
196-
{
197-
ticks = (uint64_t)((uint64_t)RTCC_CounterGet() - lptick_offset) << 15;
198-
ticks += RTCC_PreCounterGet();
199-
}
200-
while ( (ticks & 0x7FFF) != RTCC_PreCounterGet() );
201-
202-
/* ticks = counter tick value
203-
* timestamp = value in microseconds
204-
* timestamp = ticks * 1.000.000 / RTC frequency
205-
*/
164+
core_util_critical_section_enter();
165+
uint32_t ticks = RTCC_CombinedCounterGet() - (lptick_offset << 15);
166+
core_util_critical_section_exit();
206167

207-
ticks_temp = (ticks * 1000000) / LOW_ENERGY_CLOCK_FREQUENCY;
208-
return (timestamp_t) (ticks_temp & 0xFFFFFFFF);
168+
return (timestamp_t) (ticks);
209169
}
210170
#endif /* RTCC_PRESENT */
211171
#endif /* DEVICE_RTC */

0 commit comments

Comments
 (0)