32
32
* for the low power timer, which should be good enough for a low power use
33
33
* case.
34
34
*
35
+ * Mapping of mbed APIs to Silicon Labs peripherals:
36
+ * ---: Does not meet mbed API requirements
37
+ * X : Implemented to provide mbed API functionality
38
+ *
39
+ * --------------------------------------------
40
+ * | ------------- | RTCC | BURTC | RTC | TIMER |
41
+ * | rtc_api | X | X | --- | ----- |
42
+ * | lp_ticker_api | X | | X | ----- |
43
+ * | us_ticker_api | --- | ----- | --- | X |
44
+ * --------------------------------------------
45
+ *
35
46
* On Silicon Labs devices, the lowest width RTC implementation has a 24-bit
36
47
* counter, which gets extended with a further 32-bit software counter. This
37
48
* gives 56 bits of actual width, which with the default speed maps to
40
51
* (At max speed the wraparound is at 69730 years, which is unlikely as well)
41
52
******************************************************************************/
42
53
43
- #include "rtc_api.h"
44
- #include "rtc_api_HAL.h"
54
+ #if defined(RTC_PRESENT )
55
+ #include "em_rtc.h"
56
+ #include "em_cmu.h"
45
57
#include "lp_ticker_api.h"
46
58
#include "mbed_critical.h"
47
59
48
- static int rtc_reserved = 0 ;
60
+ #if RTC_CLOCKDIV_INT > 16
61
+ #error invalid prescaler value RTC_CLOCKDIV_INT, since LP ticker resolution will exceed 1ms.
62
+ #endif
63
+
64
+ #define RTC_BITS (24U)
65
+ #define RTC_MAX_VALUE (0xFFFFFFUL)
66
+
67
+ 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 ;
71
+
72
+ void RTC_IRQHandler (void )
73
+ {
74
+ uint32_t flags ;
75
+ 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
+ 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 ();
103
+ }
104
+ while ( (ticks & RTC_MAX_VALUE ) != RTC_CounterGet () );
105
+
106
+ return ticks ;
107
+ }
49
108
50
109
void lp_ticker_init ()
51
110
{
52
- if (!rtc_reserved ) {
53
- core_util_critical_section_enter ();
54
- rtc_init_real (RTC_INIT_LPTIMER );
55
- rtc_set_comp0_handler ((uint32_t )lp_ticker_irq_handler );
56
- rtc_reserved = 1 ;
57
- core_util_critical_section_exit ();
111
+ core_util_critical_section_enter ();
112
+ if (!rtc_inited ) {
113
+ CMU_ClockEnable (cmuClock_RTC , true);
114
+
115
+ /* Scale clock to save power */
116
+ CMU_ClockDivSet (cmuClock_RTC , RTC_CLOCKDIV );
117
+
118
+ /* Initialize RTC */
119
+ RTC_Init_TypeDef init = RTC_INIT_DEFAULT ;
120
+ init .enable = 1 ;
121
+ /* Don't use compare register 0 as top value */
122
+ init .comp0Top = 0 ;
123
+
124
+ /* Enable Interrupt from RTC */
125
+ RTC_IntEnable (RTC_IEN_OF );
126
+ NVIC_SetVector (RTC_IRQn , (uint32_t )RTC_IRQHandler );
127
+ NVIC_EnableIRQ (RTC_IRQn );
128
+
129
+ /* Initialize */
130
+ RTC_Init (& init );
131
+
132
+ rtc_inited = true;
58
133
}
134
+ core_util_critical_section_exit ();
59
135
}
60
136
61
137
void lp_ticker_free ()
62
138
{
63
- if (rtc_reserved ) {
64
- core_util_critical_section_enter ();
65
- rtc_free_real (RTC_INIT_LPTIMER );
66
- rtc_reserved = 0 ;
67
- core_util_critical_section_exit ();
139
+ /* Disable the RTC if it was inited and is no longer in use by anyone. */
140
+ if (rtc_inited ) {
141
+ NVIC_DisableIRQ (RTC_IRQn );
142
+ RTC_Reset ();
143
+ CMU_ClockEnable (cmuClock_RTC , false);
144
+ rtc_inited = false;
145
+ }
146
+ }
147
+
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 );
68
155
}
156
+ RTC_FreezeEnable (false);
157
+ }
158
+
159
+ void rtc_set_comp0_value (uint64_t value , bool enable )
160
+ {
161
+ rtc_enable_comp0 (false);
162
+
163
+ /* Set callback */
164
+ RTC_FreezeEnable (true);
165
+ extended_comp0 = (uint32_t ) (value >> RTC_BITS );
166
+ RTC_CompareSet (0 , (uint32_t ) (value & RTC_MAX_VALUE ));
167
+ RTC_FreezeEnable (false);
168
+
169
+ rtc_enable_comp0 (enable );
69
170
}
70
171
71
172
void lp_ticker_set_interrupt (timestamp_t timestamp )
@@ -96,17 +197,17 @@ void lp_ticker_set_interrupt(timestamp_t timestamp)
96
197
rtc_set_comp0_value (rtc_compare_value , true);
97
198
}
98
199
99
- inline void lp_ticker_fire_interrupt (void )
200
+ void lp_ticker_fire_interrupt (void )
100
201
{
101
- rtc_force_comp0 ( );
202
+ RTC_IntSet ( RTC_IFS_COMP0 );
102
203
}
103
204
104
- inline void lp_ticker_disable_interrupt ()
205
+ void lp_ticker_disable_interrupt ()
105
206
{
106
207
rtc_enable_comp0 (false);
107
208
}
108
209
109
- inline void lp_ticker_clear_interrupt ()
210
+ void lp_ticker_clear_interrupt ()
110
211
{
111
212
/* No need to clear interrupt flag, since that already happens at RTC level */
112
213
}
@@ -127,4 +228,7 @@ timestamp_t lp_ticker_read()
127
228
return (timestamp_t ) (ticks_temp & 0xFFFFFFFF );
128
229
}
129
230
130
- #endif
231
+ #elif defined(RTCC_PRESENT )
232
+ /* lp_ticker api is implemented in rtc_rtcc.c */
233
+ #endif /* RTC_PRESENT */
234
+ #endif /* DEVICE_LOWPOWERTIMER */
0 commit comments