25
25
#include "clocking.h"
26
26
#if DEVICE_LOWPOWERTIMER
27
27
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
+
28
43
#include "rtc_api.h"
29
44
#include "rtc_api_HAL.h"
30
45
#include "lp_ticker_api.h"
31
-
32
46
#include "mbed_critical.h"
33
- #if (defined RTCC_COUNT ) && (RTCC_COUNT > 0 )
34
- #include "em_rtcc.h"
35
- #endif
36
47
37
48
static int rtc_reserved = 0 ;
38
49
@@ -57,135 +68,55 @@ void lp_ticker_free()
57
68
}
58
69
}
59
70
60
- #ifndef RTCC_COUNT
61
-
62
- /* RTC API */
63
-
64
71
void lp_ticker_set_interrupt (timestamp_t timestamp )
65
72
{
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 ();
72
76
73
77
/* calculate offset value */
74
78
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 ;
87
79
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 ;
142
84
143
85
/* map offset to RTC value */
144
86
// 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 ;
153
88
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
+ }
156
93
157
- /* check for RTCC limitation */
158
- if ((timestamp_ticks - RTCC_CounterGet ()) >= 0x80000000 ) timestamp_ticks = RTCC_CounterGet () + 2 ;
94
+ rtc_compare_value += current_ticks ;
159
95
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);
166
97
}
167
98
168
- void lp_ticker_fire_interrupt (void )
99
+ inline void lp_ticker_fire_interrupt (void )
169
100
{
170
- RTCC_IntSet ( RTCC_IFS_CC0 );
101
+ rtc_force_comp0 ( );
171
102
}
172
103
173
104
inline void lp_ticker_disable_interrupt ()
174
105
{
175
- RTCC_IntDisable ( RTCC_IF_CC0 );
106
+ rtc_enable_comp0 (false );
176
107
}
177
108
178
109
inline void lp_ticker_clear_interrupt ()
179
110
{
180
- RTCC_IntClear ( RTCC_IF_CC0 );
111
+ /* No need to clear interrupt flag, since that already happens at RTC level */
181
112
}
182
113
183
114
timestamp_t lp_ticker_read ()
184
115
{
185
116
lp_ticker_init ();
186
-
117
+
187
118
uint64_t ticks_temp ;
188
- uint64_t ticks = RTCC_CounterGet ();
119
+ uint64_t ticks = rtc_get_full ();
189
120
190
121
/* ticks = counter tick value
191
122
* timestamp = value in microseconds
@@ -196,6 +127,4 @@ timestamp_t lp_ticker_read()
196
127
return (timestamp_t ) (ticks_temp & 0xFFFFFFFF );
197
128
}
198
129
199
- #endif /* RTCC */
200
-
201
130
#endif
0 commit comments