32
32
*/
33
33
34
34
#include "rtc_api.h"
35
+ #include "lp_ticker_api.h"
35
36
#include "cmsis.h"
36
37
#include "rtc_regs.h"
37
38
#include "pwrseq_regs.h"
38
39
#include "clkman_regs.h"
39
40
41
+ #define PRESCALE_VAL MXC_E_RTC_PRESCALE_DIV_2_0 // Set the divider for the 4kHz clock
42
+ #define SHIFT_AMT (MXC_E_RTC_PRESCALE_DIV_2_12 - PRESCALE_VAL)
43
+
40
44
static int rtc_inited = 0 ;
41
45
static volatile uint32_t overflow_cnt = 0 ;
42
- static uint32_t overflow_alarm = 0 ;
46
+
47
+ static uint64_t rtc_read64 (void );
43
48
44
49
//******************************************************************************
45
50
static void overflow_handler (void )
46
51
{
47
- MXC_RTCTMR -> flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS ;
52
+ MXC_RTCTMR -> flags = MXC_F_RTC_FLAGS_OVERFLOW ;
48
53
overflow_cnt ++ ;
49
-
50
- if (overflow_cnt == overflow_alarm ) {
51
- // Enable the comparator interrupt for the alarm
52
- MXC_RTCTMR -> inten |= MXC_F_RTC_INTEN_COMP0 ;
53
- }
54
- }
55
-
56
- //******************************************************************************
57
- static void alarm_handler (void )
58
- {
59
- MXC_RTCTMR -> inten &= ~MXC_F_RTC_INTEN_COMP0 ;
60
- MXC_RTCTMR -> flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS ;
61
54
}
62
55
63
56
//******************************************************************************
64
57
void rtc_init (void )
65
58
{
66
- if (rtc_inited ) {
59
+ if (rtc_inited ) {
67
60
return ;
68
61
}
69
62
rtc_inited = 1 ;
70
63
64
+ overflow_cnt = 0 ;
65
+
71
66
// Enable the clock to the synchronizer
72
67
MXC_CLKMAN -> clk_ctrl_13_rtc_int_sync = MXC_E_CLKMAN_CLK_SCALE_ENABLED ;
73
68
74
69
// Enable the clock to the RTC
75
70
MXC_PWRSEQ -> reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN ;
76
71
77
- // Set the divider from the 4kHz clock
78
- MXC_RTCTMR -> prescale = MXC_E_RTC_PRESCALE_DIV_2_0 ;
72
+ // Set the clock divider
73
+ MXC_RTCTMR -> prescale = PRESCALE_VAL ;
79
74
80
75
// Enable the overflow interrupt
81
76
MXC_RTCTMR -> inten |= MXC_F_RTC_FLAGS_OVERFLOW ;
82
77
83
78
// Prepare interrupt handlers
84
- NVIC_SetVector (RTC0_IRQn , (uint32_t )alarm_handler );
79
+ NVIC_SetVector (RTC0_IRQn , (uint32_t )lp_ticker_irq_handler );
85
80
NVIC_EnableIRQ (RTC0_IRQn );
86
81
NVIC_SetVector (RTC3_IRQn , (uint32_t )overflow_handler );
87
82
NVIC_EnableIRQ (RTC3_IRQn );
@@ -90,6 +85,12 @@ void rtc_init(void)
90
85
MXC_RTCTMR -> ctrl |= MXC_F_RTC_CTRL_ENABLE ;
91
86
}
92
87
88
+ //******************************************************************************
89
+ void lp_ticker_init (void )
90
+ {
91
+ rtc_init ();
92
+ }
93
+
93
94
//******************************************************************************
94
95
void rtc_free (void )
95
96
{
@@ -118,73 +119,104 @@ int rtc_isenabled(void)
118
119
//******************************************************************************
119
120
time_t rtc_read (void )
120
121
{
121
- unsigned int shift_amt ;
122
122
uint32_t ovf_cnt_1 , ovf_cnt_2 , timer_cnt ;
123
-
124
- // Account for a change in the default prescaler
125
- shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR -> prescale ;
123
+ uint32_t ovf1 , ovf2 ;
126
124
127
125
// Ensure coherency between overflow_cnt and timer
128
126
do {
129
127
ovf_cnt_1 = overflow_cnt ;
128
+ ovf1 = MXC_RTCTMR -> flags & MXC_F_RTC_FLAGS_OVERFLOW ;
130
129
timer_cnt = MXC_RTCTMR -> timer ;
130
+ ovf2 = MXC_RTCTMR -> flags & MXC_F_RTC_FLAGS_OVERFLOW ;
131
131
ovf_cnt_2 = overflow_cnt ;
132
- } while (ovf_cnt_1 != ovf_cnt_2 );
132
+ } while (( ovf_cnt_1 != ovf_cnt_2 ) || ( ovf1 != ovf2 ) );
133
133
134
- return (timer_cnt >> shift_amt ) + (ovf_cnt_1 << (32 - shift_amt ));
134
+ // Account for an unserviced interrupt
135
+ if (ovf1 ) {
136
+ ovf_cnt_1 ++ ;
137
+ }
138
+
139
+ return (timer_cnt >> SHIFT_AMT ) + (ovf_cnt_1 << (32 - SHIFT_AMT ));
135
140
}
136
141
137
142
//******************************************************************************
138
- uint64_t rtc_read_us (void )
143
+ static uint64_t rtc_read64 (void )
139
144
{
140
- unsigned int shift_amt ;
141
145
uint32_t ovf_cnt_1 , ovf_cnt_2 , timer_cnt ;
142
- uint64_t currentUs ;
143
-
144
- // Account for a change in the default prescaler
145
- shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR -> prescale ;
146
+ uint32_t ovf1 , ovf2 ;
147
+ uint64_t current_us ;
146
148
147
149
// Ensure coherency between overflow_cnt and timer
148
150
do {
149
151
ovf_cnt_1 = overflow_cnt ;
152
+ ovf1 = MXC_RTCTMR -> flags & MXC_F_RTC_FLAGS_OVERFLOW ;
150
153
timer_cnt = MXC_RTCTMR -> timer ;
154
+ ovf2 = MXC_RTCTMR -> flags & MXC_F_RTC_FLAGS_OVERFLOW ;
151
155
ovf_cnt_2 = overflow_cnt ;
152
- } while (ovf_cnt_1 != ovf_cnt_2 );
156
+ } while (( ovf_cnt_1 != ovf_cnt_2 ) || ( ovf1 != ovf2 ) );
153
157
154
- currentUs = (((uint64_t )timer_cnt * 1000000 ) >> shift_amt ) + (((uint64_t )ovf_cnt_1 * 1000000 ) << (32 - shift_amt ));
158
+ // Account for an unserviced interrupt
159
+ if (ovf1 ) {
160
+ ovf_cnt_1 ++ ;
161
+ }
162
+
163
+ current_us = (((uint64_t )timer_cnt * 1000000 ) >> SHIFT_AMT ) + (((uint64_t )ovf_cnt_1 * 1000000 ) << (32 - SHIFT_AMT ));
155
164
156
- return currentUs ;
165
+ return current_us ;
157
166
}
158
167
159
168
//******************************************************************************
160
169
void rtc_write (time_t t )
161
170
{
162
- // Account for a change in the default prescaler
163
- unsigned int shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR -> prescale ;
164
-
165
171
MXC_RTCTMR -> ctrl &= ~MXC_F_RTC_CTRL_ENABLE ; // disable the timer while updating
166
- MXC_RTCTMR -> timer = t << shift_amt ;
167
- overflow_cnt = t >> (32 - shift_amt );
172
+ MXC_RTCTMR -> timer = t << SHIFT_AMT ;
173
+ overflow_cnt = t >> (32 - SHIFT_AMT );
168
174
MXC_RTCTMR -> ctrl |= MXC_F_RTC_CTRL_ENABLE ; // enable the timer while updating
169
175
}
170
176
171
177
//******************************************************************************
172
- void rtc_set_wakeup ( uint64_t wakeupUs )
178
+ void lp_ticker_set_interrupt ( timestamp_t timestamp )
173
179
{
174
- // Account for a change in the default prescaler
175
- unsigned int shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR -> prescale ;
180
+ // Note: interrupts are disabled before this function is called.
176
181
177
182
// Disable the alarm while it is prepared
178
183
MXC_RTCTMR -> inten &= ~MXC_F_RTC_INTEN_COMP0 ;
179
184
MXC_RTCTMR -> flags = MXC_F_RTC_FLAGS_COMP0 ; // clear interrupt
180
185
181
- overflow_alarm = (wakeupUs >> (32 - shift_amt )) / 1000000 ;
182
-
183
- if (overflow_alarm == overflow_cnt ) {
184
- MXC_RTCTMR -> comp [0 ] = (wakeupUs << shift_amt ) / 1000000 ;
185
- MXC_RTCTMR -> inten |= MXC_F_RTC_INTEN_COMP0 ;
186
+ uint64_t curr_ts64 = rtc_read64 ();
187
+ uint64_t ts64 = (uint64_t )timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL );
188
+ if (ts64 < curr_ts64 ) {
189
+ if (ts64 < (curr_ts64 - 1000 )) {
190
+ ts64 += 0x100000000ULL ;
191
+ } else {
192
+ // This event has already occurred. Set the alarm to expire immediately.
193
+ MXC_RTCTMR -> comp [0 ] = MXC_RTCTMR -> timer + 2 ;
194
+ MXC_RTCTMR -> inten |= MXC_F_RTC_INTEN_COMP0 ;
195
+ return ;
196
+ }
186
197
}
187
198
199
+ MXC_RTCTMR -> comp [0 ] = (ts64 << SHIFT_AMT ) / 1000000 ;
200
+ MXC_RTCTMR -> inten |= MXC_F_RTC_INTEN_COMP0 ;
201
+
188
202
// Enable wakeup from RTC
189
203
MXC_PWRSEQ -> msk_flags &= ~(MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER | MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0 );
190
204
}
205
+
206
+ //******************************************************************************
207
+ inline void lp_ticker_disable_interrupt (void )
208
+ {
209
+ MXC_RTCTMR -> inten &= ~MXC_F_RTC_INTEN_COMP0 ;
210
+ }
211
+
212
+ //******************************************************************************
213
+ inline void lp_ticker_clear_interrupt (void )
214
+ {
215
+ MXC_RTCTMR -> flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS ;
216
+ }
217
+
218
+ //******************************************************************************
219
+ inline uint32_t lp_ticker_read (void )
220
+ {
221
+ return rtc_read64 ();
222
+ }
0 commit comments