35
35
/* Timer max counter */
36
36
#define NU_TMR_MAXCNT ((1 << NU_TMR_MAXCNT_BITSIZE) - 1)
37
37
38
- static void tmr2_vec (void );
39
- static void tmr3_vec (void );
40
- /* Configure scheduled alarm */
41
- static void arm_alarm (uint32_t cd_clk );
42
-
43
- static int ticker_inited = 0 ;
44
- static uint32_t ticker_last_read_clk = 0 ;
38
+ static void tmr1_vec (void );
45
39
46
40
/* NOTE: To wake the system from power down mode, timer clock source must be ether LXT or LIRC. */
47
- /* NOTE: TIMER_2 for normal counting and TIMER_3 for scheduled alarm */
48
- static const struct nu_modinit_s timer2_modinit = {TIMER_2 , TMR2_MODULE , CLK_CLKSEL1_TMR2SEL_LXT , 0 , TMR2_RST , TMR2_IRQn , (void * ) tmr2_vec };
49
- static const struct nu_modinit_s timer3_modinit = {TIMER_3 , TMR3_MODULE , CLK_CLKSEL1_TMR3SEL_LXT , 0 , TMR3_RST , TMR3_IRQn , (void * ) tmr3_vec };
41
+ static const struct nu_modinit_s timer1_modinit = {TIMER_1 , TMR1_MODULE , CLK_CLKSEL1_TMR1SEL_LXT , 0 , TMR1_RST , TMR1_IRQn , (void * ) tmr1_vec };
42
+
43
+ #define TIMER_MODINIT timer1_modinit
44
+
45
+ static int ticker_inited = 0 ;
50
46
51
47
#define TMR_CMP_MIN 2
52
48
#define TMR_CMP_MAX 0xFFFFFFu
@@ -58,43 +54,37 @@ void lp_ticker_init(void)
58
54
}
59
55
ticker_inited = 1 ;
60
56
61
- ticker_last_read_clk = 0 ;
62
-
63
57
// Reset module
64
- SYS_ResetModule (timer2_modinit .rsetidx );
65
- SYS_ResetModule (timer3_modinit .rsetidx );
58
+ SYS_ResetModule (TIMER_MODINIT .rsetidx );
66
59
67
60
// Select IP clock source
68
- CLK_SetModuleClock (timer2_modinit .clkidx , timer2_modinit .clksrc , timer2_modinit .clkdiv );
69
- CLK_SetModuleClock ( timer3_modinit . clkidx , timer3_modinit . clksrc , timer3_modinit . clkdiv );
61
+ CLK_SetModuleClock (TIMER_MODINIT .clkidx , TIMER_MODINIT .clksrc , TIMER_MODINIT .clkdiv );
62
+
70
63
// Enable IP clock
71
- CLK_EnableModuleClock (timer2_modinit .clkidx );
72
- CLK_EnableModuleClock (timer3_modinit .clkidx );
64
+ CLK_EnableModuleClock (TIMER_MODINIT .clkidx );
73
65
74
66
// Configure clock
75
- uint32_t clk_timer2 = TIMER_GetModuleClock ((TIMER_T * ) NU_MODBASE (timer2_modinit .modname ));
76
- uint32_t prescale_timer2 = clk_timer2 / NU_TMRCLK_PER_SEC - 1 ;
77
- MBED_ASSERT ((prescale_timer2 != (uint32_t ) -1 ) && prescale_timer2 <= 127 );
78
- MBED_ASSERT ((clk_timer2 % NU_TMRCLK_PER_SEC ) == 0 );
79
- uint32_t cmp_timer2 = TMR_CMP_MAX ;
80
- MBED_ASSERT (cmp_timer2 >= TMR_CMP_MIN && cmp_timer2 <= TMR_CMP_MAX );
67
+ uint32_t clk_timer = TIMER_GetModuleClock ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ));
68
+ uint32_t prescale_timer = clk_timer / NU_TMRCLK_PER_SEC - 1 ;
69
+ MBED_ASSERT ((prescale_timer != (uint32_t ) -1 ) && prescale_timer <= 127 );
70
+ MBED_ASSERT ((clk_timer % NU_TMRCLK_PER_SEC ) == 0 );
71
+ uint32_t cmp_timer = TMR_CMP_MAX ;
72
+ MBED_ASSERT (cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX );
81
73
// Continuous mode
82
74
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
83
- ((TIMER_T * ) NU_MODBASE (timer2_modinit .modname ))-> CTL = TIMER_PERIODIC_MODE | prescale_timer2 /* | TIMER_CTL_CNTDATEN_Msk*/ ;
84
- ((TIMER_T * ) NU_MODBASE (timer2_modinit .modname ))-> CMP = cmp_timer2 ;
75
+ ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ))-> CTL = TIMER_CONTINUOUS_MODE | prescale_timer /* | TIMER_CTL_CNTDATEN_Msk*/ ;
76
+ ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ))-> CMP = cmp_timer ;
85
77
86
78
// Set vector
87
- NVIC_SetVector (timer2_modinit .irq_n , (uint32_t ) timer2_modinit .var );
88
- NVIC_SetVector (timer3_modinit .irq_n , (uint32_t ) timer3_modinit .var );
79
+ NVIC_SetVector (TIMER_MODINIT .irq_n , (uint32_t ) TIMER_MODINIT .var );
89
80
90
- NVIC_EnableIRQ (timer2_modinit .irq_n );
91
- NVIC_EnableIRQ (timer3_modinit .irq_n );
81
+ NVIC_EnableIRQ (TIMER_MODINIT .irq_n );
92
82
93
- TIMER_EnableInt ((TIMER_T * ) NU_MODBASE (timer2_modinit .modname ));
94
- TIMER_EnableWakeup ((TIMER_T * ) NU_MODBASE (timer2_modinit .modname ));
83
+ TIMER_EnableInt ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ));
84
+ TIMER_EnableWakeup ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ));
95
85
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
96
86
wait_us ((NU_US_PER_SEC / NU_TMRCLK_PER_SEC ) * 3 );
97
- TIMER_Start ((TIMER_T * ) NU_MODBASE (timer2_modinit .modname ));
87
+ TIMER_Start ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ));
98
88
}
99
89
100
90
timestamp_t lp_ticker_read ()
@@ -103,145 +93,49 @@ timestamp_t lp_ticker_read()
103
93
lp_ticker_init ();
104
94
}
105
95
106
- TIMER_T * timer2_base = (TIMER_T * ) NU_MODBASE (timer2_modinit .modname );
96
+ TIMER_T * timer_base = (TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname );
107
97
108
- ticker_last_read_clk = TIMER_GetCounter (timer2_base );
109
- return (ticker_last_read_clk / NU_TMRCLK_PER_TICK );
98
+ return (TIMER_GetCounter (timer_base ) / NU_TMRCLK_PER_TICK );
110
99
}
111
100
112
101
void lp_ticker_set_interrupt (timestamp_t timestamp )
113
102
{
114
- TIMER_Stop ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
115
-
116
- /* We need to get alarm interval from alarm timestamp `timestamp` to configure H/W timer.
117
- *
118
- * Because both `timestamp` and xx_ticker_read() would wrap around, we have difficulties in distinguishing
119
- * long future event and past event. To distinguish them, we need `tick_last_read` against which
120
- * `timestamp` is calculated out. In timeline, we would always have below after fixing wrap-around:
121
- * (1) tick_last_read <= present_clk
122
- * (2) tick_last_read <= alarm_ts_clk
123
- *
124
- *
125
- * 1. Future event case:
126
- *
127
- * tick_last_read present_clk alarm_ts_clk
128
- * | | |
129
- * --------------------------------------------------------
130
- * |-alarm_intvl1_clk-|
131
- * |-------------------alarm_intvl2_clk-------------------|
132
- *
133
- * 2. Past event case:
134
- *
135
- * tick_last_read alarm_ts_clk present_clk
136
- * | | |
137
- * --------------------------------------------------------
138
- * |-------------------alarm_intvl1_clk-------------------|
139
- * |-alarm_intvl2_clk-|
103
+ /* In continuous mode, counter will be reset to zero with the following sequence:
104
+ * 1. Stop counting
105
+ * 2. Configure new CMP value
106
+ * 3. Restart counting
140
107
*
141
- * Unfortunately, `tick_last_read` is not passed along the xx_ticker_set_interrupt() call. To solve it, we
142
- * assume that `tick_last_read` tick is exactly the one returned by the last xx_ticker_read() call before
143
- * xx_ticker_set_interrupt() is invoked. With this assumption, we can hold it via `xx_ticker_last_read_clk`
144
- * in xx_ticker_read().
108
+ * This behavior is not what we want. To fix it, we could configure new CMP value
109
+ * without stopping counting first.
145
110
*/
146
-
147
- /* ticker_last_read_clk will update in lp_ticker_read(). Keep it beforehand. */
148
- uint32_t last_read_clk = ticker_last_read_clk ;
149
- uint32_t present_clk = lp_ticker_read () * NU_TMRCLK_PER_TICK ;
150
- uint32_t alarm_ts_clk = timestamp * NU_TMRCLK_PER_TICK ;
151
- uint32_t alarm_intvl1_clk , alarm_intvl2_clk ;
152
-
153
- /* alarm_intvl1_clk = present_clk - last_read_clk
154
- *
155
- * NOTE: Don't miss the `=` sign here. Otherwise, we would get the wrong result.
156
- */
157
- if (present_clk >= last_read_clk ) {
158
- alarm_intvl1_clk = present_clk - last_read_clk ;
159
- } else {
160
- alarm_intvl1_clk = (uint32_t ) (((uint64_t ) NU_TMR_MAXCNT ) + 1 + present_clk - last_read_clk );
161
- }
111
+ TIMER_T * timer_base = (TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname );
162
112
163
- /* alarm_intvl2_clk = alarm_ts_clk - last_read_clk
164
- *
165
- * NOTE: Don't miss the `=` sign here. Otherwise, we would get the wrong result.
166
- */
167
- if (alarm_ts_clk >= last_read_clk ) {
168
- alarm_intvl2_clk = alarm_ts_clk - last_read_clk ;
169
- } else {
170
- alarm_intvl2_clk = (uint32_t ) (((uint64_t ) NU_TMR_MAXCNT ) + 1 + alarm_ts_clk - last_read_clk );
171
- }
113
+ /* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
114
+ * (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
115
+ uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK ;
116
+ cmp_timer = NU_CLAMP (cmp_timer , TMR_CMP_MIN , TMR_CMP_MAX );
117
+ timer_base -> CMP = cmp_timer ;
172
118
173
- /* Distinguish (long) future event and past event
174
- *
175
- * NOTE: No '=' sign here. Alarm should go off immediately in equal case.
176
- */
177
- if (alarm_intvl2_clk > alarm_intvl1_clk ) {
178
- /* Schedule for future event */
179
- arm_alarm (alarm_intvl2_clk - alarm_intvl1_clk );
180
- } else {
181
- /* Go off immediately for past event, including equal case */
182
- lp_ticker_fire_interrupt ();
183
- }
119
+ /* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
120
+ wait_us ((NU_US_PER_SEC / NU_TMRCLK_PER_SEC ) * 3 );
121
+ TIMER_Start (timer_base );
184
122
}
185
123
186
124
void lp_ticker_disable_interrupt (void )
187
125
{
188
- TIMER_DisableInt ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
126
+ TIMER_DisableInt ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ));
189
127
}
190
128
191
129
void lp_ticker_clear_interrupt (void )
192
130
{
193
- TIMER_ClearIntFlag ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
131
+ TIMER_ClearIntFlag ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ));
194
132
}
195
133
196
134
void lp_ticker_fire_interrupt (void )
197
135
{
198
136
// NOTE: This event was in the past. Set the interrupt as pending, but don't process it here.
199
137
// This prevents a recursive loop under heavy load which can lead to a stack overflow.
200
- NVIC_SetPendingIRQ (timer3_modinit .irq_n );
201
- }
202
-
203
- static void tmr2_vec (void )
204
- {
205
- TIMER_ClearIntFlag ((TIMER_T * ) NU_MODBASE (timer2_modinit .modname ));
206
- TIMER_ClearWakeupFlag ((TIMER_T * ) NU_MODBASE (timer2_modinit .modname ));
207
- }
208
-
209
- static void tmr3_vec (void )
210
- {
211
- TIMER_ClearIntFlag ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
212
- TIMER_ClearWakeupFlag ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
213
-
214
- // NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
215
- lp_ticker_irq_handler ();
216
-
217
- }
218
-
219
- static void arm_alarm (uint32_t cd_clk )
220
- {
221
- TIMER_T * timer3_base = (TIMER_T * ) NU_MODBASE (timer3_modinit .modname );
222
-
223
- // Reset 8-bit PSC counter, 24-bit up counter value and CNTEN bit
224
- timer3_base -> CTL |= TIMER_CTL_RSTCNT_Msk ;
225
- // One-shot mode, Clock = 1 KHz
226
- uint32_t clk_timer3 = TIMER_GetModuleClock ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
227
- uint32_t prescale_timer3 = clk_timer3 / NU_TMRCLK_PER_SEC - 1 ;
228
- MBED_ASSERT ((prescale_timer3 != (uint32_t ) -1 ) && prescale_timer3 <= 127 );
229
- MBED_ASSERT ((clk_timer3 % NU_TMRCLK_PER_SEC ) == 0 );
230
- // NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
231
- timer3_base -> CTL &= ~(TIMER_CTL_OPMODE_Msk | TIMER_CTL_PSC_Msk /* | TIMER_CTL_CNTDATEN_Msk*/ );
232
- timer3_base -> CTL |= TIMER_ONESHOT_MODE | prescale_timer3 /* | TIMER_CTL_CNTDATEN_Msk*/ ;
233
-
234
- /* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
235
- * (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
236
- uint32_t cmp_timer3 = cd_clk ;
237
- cmp_timer3 = NU_CLAMP (cmp_timer3 , TMR_CMP_MIN , TMR_CMP_MAX );
238
- timer3_base -> CMP = cmp_timer3 ;
239
-
240
- TIMER_EnableInt (timer3_base );
241
- TIMER_EnableWakeup ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
242
- /* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
243
- wait_us ((NU_US_PER_SEC / NU_TMRCLK_PER_SEC ) * 3 );
244
- TIMER_Start (timer3_base );
138
+ NVIC_SetPendingIRQ (TIMER_MODINIT .irq_n );
245
139
}
246
140
247
141
const ticker_info_t * lp_ticker_get_info ()
@@ -253,4 +147,13 @@ const ticker_info_t* lp_ticker_get_info()
253
147
return & info ;
254
148
}
255
149
150
+ static void tmr1_vec (void )
151
+ {
152
+ TIMER_ClearIntFlag ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ));
153
+ TIMER_ClearWakeupFlag ((TIMER_T * ) NU_MODBASE (TIMER_MODINIT .modname ));
154
+
155
+ // NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
156
+ lp_ticker_irq_handler ();
157
+ }
158
+
256
159
#endif
0 commit comments