24
24
#include "critical.h"
25
25
26
26
// lp_ticker tick = us = timestamp
27
- // clock of timer peripheral = ms
28
- #define US_PER_TICK (1 )
27
+ #define US_PER_TICK (1)
28
+ #define US_PER_SEC (1000 * 1000 )
29
29
30
- #define MS_PER_TMR2_INT (1000 * 10)
31
- #define TMR2_FIRE_FREQ (1000 / MS_PER_TMR2_INT)
32
- #define MS_PER_TMR2_CLK 1
33
- #define TMR2_CLK_FREQ (1000 / MS_PER_TMR2_CLK)
34
-
35
- #define MS_PER_TMR3_CLK 1
36
- #define TMR3_CLK_FREQ (1000 / MS_PER_TMR3_CLK)
30
+ #define US_PER_TMR2_INT (US_PER_SEC * 10)
31
+ #define TMR2_CLK_PER_SEC (__LXT)
32
+ #define TMR2_CLK_PER_TMR2_INT ((uint32_t) ((uint64_t) US_PER_TMR2_INT * TMR2_CLK_PER_SEC / US_PER_SEC))
33
+ #define TMR3_CLK_PER_SEC (__LXT)
37
34
38
35
static void tmr2_vec (void );
39
36
static void tmr3_vec (void );
40
37
static void lp_ticker_arm_cd (void );
41
38
42
39
static int lp_ticker_inited = 0 ;
43
40
static volatile uint32_t counter_major = 0 ;
44
- static volatile int cd_major_minor_ms = 0 ;
45
- static volatile int cd_minor_ms = 0 ;
41
+ static volatile int cd_major_minor_clks = 0 ;
42
+ static volatile int cd_minor_clks = 0 ;
46
43
static volatile uint32_t wakeup_tick = (uint32_t ) -1 ;
47
44
48
45
// NOTE: To wake the system from power down mode, timer clock source must be ether LXT or LIRC.
@@ -61,8 +58,8 @@ void lp_ticker_init(void)
61
58
lp_ticker_inited = 1 ;
62
59
63
60
counter_major = 0 ;
64
- cd_major_minor_ms = 0 ;
65
- cd_minor_ms = 0 ;
61
+ cd_major_minor_clks = 0 ;
62
+ cd_minor_clks = 0 ;
66
63
wakeup_tick = (uint32_t ) -1 ;
67
64
68
65
// Reset module
@@ -78,9 +75,10 @@ void lp_ticker_init(void)
78
75
79
76
// Configure clock
80
77
uint32_t clk_timer2 = TIMER_GetModuleClock ((TIMER_T * ) NU_MODBASE (timer2_modinit .modname ));
81
- uint32_t prescale_timer2 = clk_timer2 / TMR2_CLK_FREQ - 1 ;
78
+ uint32_t prescale_timer2 = clk_timer2 / TMR2_CLK_PER_SEC - 1 ;
82
79
MBED_ASSERT ((prescale_timer2 != (uint32_t ) -1 ) && prescale_timer2 <= 127 );
83
- uint32_t cmp_timer2 = MS_PER_TMR2_INT / MS_PER_TMR2_CLK ;
80
+ MBED_ASSERT ((clk_timer2 % TMR2_CLK_PER_SEC ) == 0 );
81
+ uint32_t cmp_timer2 = TMR2_CLK_PER_TMR2_INT ;
84
82
MBED_ASSERT (cmp_timer2 >= TMR_CMP_MIN && cmp_timer2 <= TMR_CMP_MAX );
85
83
// Continuous mode
86
84
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
@@ -113,31 +111,31 @@ timestamp_t lp_ticker_read()
113
111
TIMER_T * timer2_base = (TIMER_T * ) NU_MODBASE (timer2_modinit .modname );
114
112
115
113
do {
116
- uint64_t major_minor_ms ;
117
- uint32_t minor_ms ;
114
+ uint64_t major_minor_clks ;
115
+ uint32_t minor_clks ;
118
116
119
117
// NOTE: As TIMER_CNT = TIMER_CMP and counter_major has increased by one, TIMER_CNT doesn't change to 0 for one tick time.
120
118
// NOTE: As TIMER_CNT = TIMER_CMP or TIMER_CNT = 0, counter_major (ISR) may not sync with TIMER_CNT. So skip and fetch stable one at the cost of 1 clock delay on this read.
121
119
do {
122
120
core_util_critical_section_enter ();
123
121
124
122
// NOTE: Order of reading minor_us/carry here is significant.
125
- minor_ms = TIMER_GetCounter (timer2_base ) * MS_PER_TMR2_CLK ;
123
+ minor_clks = TIMER_GetCounter (timer2_base );
126
124
uint32_t carry = (timer2_base -> INTSTS & TIMER_INTSTS_TIF_Msk ) ? 1 : 0 ;
127
125
// When TIMER_CNT approaches TIMER_CMP and will wrap soon, we may get carry but TIMER_CNT not wrapped. Hanlde carefully carry == 1 && TIMER_CNT is near TIMER_CMP.
128
- if (carry && minor_ms > (MS_PER_TMR2_INT / 2 )) {
129
- major_minor_ms = (counter_major + 1 ) * MS_PER_TMR2_INT ;
126
+ if (carry && minor_clks > (TMR2_CLK_PER_TMR2_INT / 2 )) {
127
+ major_minor_clks = (counter_major + 1 ) * TMR2_CLK_PER_TMR2_INT ;
130
128
}
131
129
else {
132
- major_minor_ms = (counter_major + carry ) * MS_PER_TMR2_INT + minor_ms ;
130
+ major_minor_clks = (counter_major + carry ) * TMR2_CLK_PER_TMR2_INT + minor_clks ;
133
131
}
134
132
135
133
core_util_critical_section_exit ();
136
134
}
137
- while (minor_ms == 0 || minor_ms == MS_PER_TMR2_INT );
135
+ while (minor_clks == 0 || minor_clks == TMR2_CLK_PER_TMR2_INT );
138
136
139
137
// Add power-down compensation
140
- return (major_minor_ms * 1000 / US_PER_TICK );
138
+ return (( uint64_t ) major_minor_clks * US_PER_SEC / TMR3_CLK_PER_SEC / US_PER_TICK );
141
139
}
142
140
while (0 );
143
141
}
@@ -151,8 +149,8 @@ void lp_ticker_set_interrupt(timestamp_t timestamp)
151
149
152
150
int delta = (timestamp > now ) ? (timestamp - now ) : (uint32_t ) ((uint64_t ) timestamp + 0xFFFFFFFFu - now );
153
151
// NOTE: If this event was in the past, arm an interrupt to be triggered immediately.
154
- cd_major_minor_ms = delta * US_PER_TICK / 1000 ;
155
-
152
+ cd_major_minor_clks = ( uint64_t ) delta * US_PER_TICK * TMR3_CLK_PER_SEC / US_PER_SEC ;
153
+
156
154
lp_ticker_arm_cd ();
157
155
}
158
156
@@ -177,8 +175,12 @@ static void tmr3_vec(void)
177
175
{
178
176
TIMER_ClearIntFlag ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
179
177
TIMER_ClearWakeupFlag ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
180
- cd_major_minor_ms -= cd_minor_ms ;
181
- if (cd_major_minor_ms > 0 ) {
178
+ cd_major_minor_clks -= cd_minor_clks ;
179
+ if (cd_major_minor_clks <= 0 ) {
180
+ // NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
181
+ lp_ticker_irq_handler ();
182
+ }
183
+ else {
182
184
lp_ticker_arm_cd ();
183
185
}
184
186
}
@@ -191,15 +193,16 @@ static void lp_ticker_arm_cd(void)
191
193
timer3_base -> CTL |= TIMER_CTL_RSTCNT_Msk ;
192
194
// One-shot mode, Clock = 1 KHz
193
195
uint32_t clk_timer3 = TIMER_GetModuleClock ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
194
- uint32_t prescale_timer3 = clk_timer3 / TMR3_CLK_FREQ - 1 ;
196
+ uint32_t prescale_timer3 = clk_timer3 / TMR3_CLK_PER_SEC - 1 ;
195
197
MBED_ASSERT ((prescale_timer3 != (uint32_t ) -1 ) && prescale_timer3 <= 127 );
198
+ MBED_ASSERT ((clk_timer3 % TMR3_CLK_PER_SEC ) == 0 );
196
199
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
197
200
timer3_base -> CTL &= ~(TIMER_CTL_OPMODE_Msk | TIMER_CTL_PSC_Msk /* | TIMER_CTL_CNTDATEN_Msk*/ );
198
201
timer3_base -> CTL |= TIMER_ONESHOT_MODE | prescale_timer3 /* | TIMER_CTL_CNTDATEN_Msk*/ ;
199
202
200
- cd_minor_ms = cd_major_minor_ms ;
201
- cd_minor_ms = NU_CLAMP (cd_minor_ms , TMR_CMP_MIN * MS_PER_TMR3_CLK , TMR_CMP_MAX * MS_PER_TMR3_CLK );
202
- timer3_base -> CMP = cd_minor_ms / MS_PER_TMR3_CLK ;
203
+ cd_minor_clks = cd_major_minor_clks ;
204
+ cd_minor_clks = NU_CLAMP (cd_minor_clks , TMR_CMP_MIN , TMR_CMP_MAX );
205
+ timer3_base -> CMP = cd_minor_clks ;
203
206
204
207
TIMER_EnableInt (timer3_base );
205
208
TIMER_EnableWakeup ((TIMER_T * ) NU_MODBASE (timer3_modinit .modname ));
0 commit comments