1
1
/*******************************************************************************
2
- * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
2
+ * Copyright (C) 2016,2018 Maxim Integrated Products, Inc., All Rights Reserved.
3
3
*
4
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
5
* copy of this software and associated documentation files (the "Software"),
36
36
#include "rtc.h"
37
37
#include "lp.h"
38
38
39
- #define PRESCALE_VAL RTC_PRESCALE_DIV_2_0 // Set the divider for the 4kHz clock
40
- #define SHIFT_AMT (RTC_PRESCALE_DIV_2_12 - PRESCALE_VAL)
39
+ // LOG2 for 32-bit powers of 2
40
+ #define LOG2_1 (n ) (((n) >= (1 << 1)) ? 1 : 0)
41
+ #define LOG2_2 (n ) (((n) >= (1 << 2)) ? ( 2 + (LOG2_1((n) >> 2))) : LOG2_1(n))
42
+ #define LOG2_4 (n ) (((n) >= (1 << 4)) ? ( 4 + (LOG2_2((n) >> 4))) : LOG2_2(n))
43
+ #define LOG2_8 (n ) (((n) >= (1 << 8)) ? ( 8 + (LOG2_4((n) >> 8))) : LOG2_4(n))
44
+ #define LOG2 (n ) (((n) >= (1 << 16)) ? (16 + (LOG2_8((n) >> 16))) : LOG2_8(n))
41
45
42
- #define WINDOW 1000
46
+ #define LP_TIMER_FREQ_HZ 4096
47
+ #define LP_TIMER_PRESCALE RTC_PRESCALE_DIV_2_0
48
+ #define LP_TIMER_RATE_HZ (LP_TIMER_FREQ_HZ >> LP_TIMER_PRESCALE)
49
+ #define LP_TIMER_WIDTH 32
43
50
44
- static int rtc_inited = 0 ;
45
- static volatile uint32_t overflow_cnt = 0 ;
46
-
47
- static uint64_t rtc_read64 (void );
48
-
49
- //******************************************************************************
50
- static void overflow_handler (void )
51
- {
52
- overflow_cnt ++ ;
53
- RTC_ClearFlags (MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS );
54
- }
51
+ static volatile int rtc_inited = 0 ;
52
+ static volatile int lp_ticker_inited = 0 ;
55
53
56
54
//******************************************************************************
57
- void rtc_init (void )
55
+ static void init_rtc (void )
58
56
{
59
- if (rtc_inited ) {
60
- return ;
61
- }
62
- rtc_inited = 1 ;
63
-
64
- overflow_cnt = 0 ;
65
-
66
57
/* Enable power for RTC for all LPx states */
67
58
MXC_PWRSEQ -> reg0 |= (MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN |
68
59
MXC_F_PWRSEQ_REG0_PWR_RTCEN_SLP );
69
60
70
61
/* Enable clock to synchronizers */
71
62
CLKMAN_SetClkScale (CLKMAN_CLK_SYNC , CLKMAN_SCALE_DIV_1 );
72
63
73
- // Prepare interrupt handlers
74
- NVIC_SetVector (RTC0_IRQn , (uint32_t )lp_ticker_irq_handler );
75
- NVIC_EnableIRQ (RTC0_IRQn );
76
- NVIC_SetVector (RTC3_IRQn , (uint32_t )overflow_handler );
77
- NVIC_EnableIRQ (RTC3_IRQn );
78
-
79
- // Enable wakeup on RTC rollover
80
- LP_ConfigRTCWakeUp (0 , 0 , 0 , 1 );
81
-
82
64
/* RTC registers are only reset on a power cycle. Do not reconfigure the RTC
83
65
* if it is already running.
84
66
*/
85
67
if (!RTC_IsActive ()) {
86
- rtc_cfg_t cfg = {0 };
87
- cfg .prescaler = PRESCALE_VAL ;
68
+ rtc_cfg_t cfg = { 0 };
69
+ cfg .prescaler = LP_TIMER_PRESCALE ;
88
70
cfg .snoozeMode = RTC_SNOOZE_DISABLE ;
89
71
90
72
int retval = RTC_Init (& cfg );
@@ -96,163 +78,128 @@ void rtc_init(void)
96
78
}
97
79
98
80
//******************************************************************************
99
- void lp_ticker_init (void )
81
+ static void overflow_handler (void )
82
+ {
83
+ MXC_RTCTMR -> comp [1 ] += ((UINT32_MAX >> LOG2 (LP_TIMER_RATE_HZ )) + 1 );
84
+ RTC_ClearFlags (MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS );
85
+ }
86
+
87
+ //******************************************************************************
88
+ void rtc_init (void )
100
89
{
101
- rtc_init ();
90
+ if (rtc_inited ) {
91
+ return ;
92
+ }
93
+
94
+ NVIC_SetVector (RTC3_IRQn , (uint32_t )overflow_handler );
95
+ NVIC_EnableIRQ (RTC3_IRQn );
96
+ // Enable wakeup on RTC overflow
97
+ LP_ConfigRTCWakeUp (lp_ticker_inited , 0 , 0 , 1 );
98
+ init_rtc ();
99
+ rtc_inited = 1 ;
102
100
}
103
101
104
102
//******************************************************************************
105
103
void rtc_free (void )
106
104
{
107
- if (RTC_IsActive ()) {
108
- // Clear and disable RTC
109
- MXC_RTCTMR -> ctrl |= MXC_F_RTC_CTRL_CLEAR ;
110
- RTC_Stop ();
105
+ if (rtc_inited ) {
106
+ rtc_inited = 0 ;
107
+ if (lp_ticker_inited ) {
108
+ RTC_DisableINT (MXC_F_RTC_FLAGS_OVERFLOW );
109
+ } else {
110
+ MXC_RTCTMR -> ctrl |= MXC_F_RTC_CTRL_CLEAR ;
111
+ RTC_Stop ();
112
+ }
111
113
}
112
114
}
113
115
114
116
//******************************************************************************
115
117
int rtc_isenabled (void )
116
118
{
117
- return RTC_IsActive () ;
119
+ return rtc_inited ;
118
120
}
119
121
120
122
//******************************************************************************
121
- time_t rtc_read ( void )
123
+ void rtc_write ( time_t t )
122
124
{
123
- uint32_t ovf_cnt_1 , ovf_cnt_2 , timer_cnt ;
124
- uint32_t ovf1 , ovf2 ;
125
-
126
- // Make sure RTC is setup before trying to read
127
125
if (!rtc_inited ) {
128
126
rtc_init ();
129
127
}
130
128
131
- // Ensure coherency between overflow_cnt and timer
132
- do {
133
- ovf_cnt_1 = overflow_cnt ;
134
- ovf1 = RTC_GetFlags () & MXC_F_RTC_FLAGS_OVERFLOW ;
135
- timer_cnt = RTC_GetCount ();
136
- ovf2 = RTC_GetFlags () & MXC_F_RTC_FLAGS_OVERFLOW ;
137
- ovf_cnt_2 = overflow_cnt ;
138
- } while ((ovf_cnt_1 != ovf_cnt_2 ) || (ovf1 != ovf2 ));
129
+ MXC_RTCTMR -> comp [1 ] = t - (MXC_RTCTMR -> timer >> LOG2 (LP_TIMER_RATE_HZ ));
139
130
140
- // Account for an unserviced interrupt
141
- if (ovf1 ) {
142
- ovf_cnt_1 ++ ;
143
- }
144
-
145
- return (timer_cnt >> SHIFT_AMT ) + (ovf_cnt_1 << (32 - SHIFT_AMT ));
131
+ // Wait for pending transactions
132
+ while (MXC_RTCTMR -> ctrl & MXC_F_RTC_CTRL_PENDING );
146
133
}
147
134
148
135
//******************************************************************************
149
- static uint64_t rtc_read64 (void )
136
+ time_t rtc_read (void )
150
137
{
151
- uint32_t ovf_cnt_1 , ovf_cnt_2 , timer_cnt ;
152
- uint32_t ovf1 , ovf2 ;
153
- uint64_t current_us ;
154
-
155
- // Make sure RTC is setup before trying to read
156
138
if (!rtc_inited ) {
157
139
rtc_init ();
158
140
}
159
141
160
- // Ensure coherency between overflow_cnt and timer
161
- do {
162
- ovf_cnt_1 = overflow_cnt ;
163
- ovf1 = RTC_GetFlags () & MXC_F_RTC_FLAGS_OVERFLOW ;
164
- timer_cnt = RTC_GetCount ();
165
- ovf2 = RTC_GetFlags () & MXC_F_RTC_FLAGS_OVERFLOW ;
166
- ovf_cnt_2 = overflow_cnt ;
167
- } while ((ovf_cnt_1 != ovf_cnt_2 ) || (ovf1 != ovf2 ));
142
+ return (MXC_RTCTMR -> timer >> LOG2 (LP_TIMER_RATE_HZ )) + MXC_RTCTMR -> comp [1 ];
143
+ }
168
144
169
- // Account for an unserviced interrupt
170
- if (ovf1 ) {
171
- ovf_cnt_1 ++ ;
145
+ //******************************************************************************
146
+ void lp_ticker_init (void )
147
+ {
148
+ if (lp_ticker_inited ) {
149
+ return ;
172
150
}
173
151
174
- current_us = (((uint64_t )timer_cnt * 1000000 ) >> SHIFT_AMT ) + (((uint64_t )ovf_cnt_1 * 1000000 ) << (32 - SHIFT_AMT ));
175
-
176
- return current_us ;
152
+ NVIC_SetVector (RTC0_IRQn , (uint32_t )lp_ticker_irq_handler );
153
+ NVIC_EnableIRQ (RTC0_IRQn );
154
+ init_rtc ();
155
+ lp_ticker_inited = 1 ;
177
156
}
178
157
179
158
//******************************************************************************
180
- void rtc_write ( time_t t )
159
+ uint32_t lp_ticker_read ( void )
181
160
{
182
- // Make sure RTC is setup before accessing
183
- if (!rtc_inited ) {
184
- rtc_init ();
185
- }
186
-
187
- RTC_Stop ();
188
- RTC_SetCount (t << SHIFT_AMT );
189
- overflow_cnt = t >> (32 - SHIFT_AMT );
190
- RTC_Start ();
161
+ return MXC_RTCTMR -> timer ;
191
162
}
192
163
193
164
//******************************************************************************
194
165
void lp_ticker_set_interrupt (timestamp_t timestamp )
195
166
{
196
- uint32_t comp_value ;
197
- uint64_t curr_ts64 ;
198
- uint64_t ts64 ;
199
-
200
- // Note: interrupts are disabled before this function is called.
201
-
202
- // Disable the alarm while it is prepared
203
- RTC_DisableINT (MXC_F_RTC_INTEN_COMP0 );
204
-
205
- curr_ts64 = rtc_read64 ();
206
- ts64 = (uint64_t )timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL );
207
-
208
- // If this event is older than a recent window, it must be in the future
209
- if ((ts64 < (curr_ts64 - WINDOW )) && ((curr_ts64 - WINDOW ) < curr_ts64 )) {
210
- ts64 += 0x100000000ULL ;
211
- }
212
-
213
- uint32_t timer = RTC_GetCount ();
214
- if (ts64 <= curr_ts64 ) {
215
- // This event has already occurred. Set the alarm to expire immediately.
216
- comp_value = timer + 1 ;
217
- } else {
218
- comp_value = (ts64 << SHIFT_AMT ) / 1000000 ;
219
- }
220
-
221
- // Ensure that the compare value is far enough in the future to guarantee the interrupt occurs.
222
- if ((comp_value < (timer + 2 )) && (comp_value > (timer - 10 ))) {
223
- comp_value = timer + 2 ;
224
- }
225
-
226
- MXC_RTCTMR -> comp [0 ] = comp_value ;
167
+ MXC_RTCTMR -> comp [0 ] = timestamp ;
227
168
MXC_RTCTMR -> flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS ;
228
- RTC_EnableINT ( MXC_F_RTC_INTEN_COMP0 ) ;
169
+ MXC_RTCTMR -> inten |= MXC_F_RTC_INTEN_COMP0 ;
229
170
230
- // Enable wakeup from RTC
231
- LP_ConfigRTCWakeUp (1 , 0 , 0 , 1 );
171
+ // Enable wakeup from RTC compare 0
172
+ LP_ConfigRTCWakeUp (1 , 0 , 0 , rtc_inited );
232
173
233
174
// Wait for pending transactions
234
175
while (MXC_RTCTMR -> ctrl & MXC_F_RTC_CTRL_PENDING );
235
176
}
236
177
237
- void lp_ticker_fire_interrupt (void )
178
+ //******************************************************************************
179
+ void lp_ticker_disable_interrupt (void )
238
180
{
239
- NVIC_SetPendingIRQ ( RTC0_IRQn );
181
+ RTC_DisableINT ( MXC_F_RTC_INTEN_COMP0 );
240
182
}
241
183
242
184
//******************************************************************************
243
- inline void lp_ticker_disable_interrupt (void )
185
+ void lp_ticker_clear_interrupt (void )
244
186
{
245
- RTC_DisableINT ( MXC_F_RTC_INTEN_COMP0 );
187
+ RTC_ClearFlags ( MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS );
246
188
}
247
189
248
190
//******************************************************************************
249
- inline void lp_ticker_clear_interrupt (void )
191
+ void lp_ticker_fire_interrupt (void )
250
192
{
251
- RTC_ClearFlags ( MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS );
193
+ NVIC_SetPendingIRQ ( RTC0_IRQn );
252
194
}
253
195
254
196
//******************************************************************************
255
- inline uint32_t lp_ticker_read (void )
197
+ const ticker_info_t * lp_ticker_get_info (void )
256
198
{
257
- return rtc_read64 ();
199
+ static const ticker_info_t info = {
200
+ LP_TIMER_RATE_HZ ,
201
+ LP_TIMER_WIDTH
202
+ };
203
+
204
+ return & info ;
258
205
}
0 commit comments