Skip to content

Commit 9b7642d

Browse files
committed
[NUC472/M453] Fix us_ticker/lp_ticker alarm error
Error occurs as newly scheduled alarm is behind now due to signed/unsigned comparison pitfall: -1 < 1u ==> 0 or 1
1 parent 516efa3 commit 9b7642d

File tree

4 files changed

+67
-33
lines changed

4 files changed

+67
-33
lines changed

targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ static void lp_ticker_arm_cd(void);
3838

3939
static int lp_ticker_inited = 0;
4040
static volatile uint32_t counter_major = 0;
41-
static volatile int cd_major_minor_clks = 0;
42-
static volatile int cd_minor_clks = 0;
41+
static volatile uint32_t cd_major_minor_clks = 0;
42+
static volatile uint32_t cd_minor_clks = 0;
4343
static volatile uint32_t wakeup_tick = (uint32_t) -1;
4444

4545
// NOTE: To wake the system from power down mode, timer clock source must be ether LXT or LIRC.
@@ -148,10 +148,18 @@ void lp_ticker_set_interrupt(timestamp_t timestamp)
148148
TIMER_Stop((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
149149

150150
int delta = (timestamp > now) ? (timestamp - now) : (uint32_t) ((uint64_t) timestamp + 0xFFFFFFFFu - now);
151-
// NOTE: If this event was in the past, arm an interrupt to be triggered immediately.
152-
cd_major_minor_clks = (uint64_t) delta * US_PER_TICK * TMR3_CLK_PER_SEC / US_PER_SEC;
153-
154-
lp_ticker_arm_cd();
151+
if (delta > 0) {
152+
cd_major_minor_clks = (uint64_t) delta * US_PER_TICK * TMR3_CLK_PER_SEC / US_PER_SEC;
153+
lp_ticker_arm_cd();
154+
}
155+
else {
156+
cd_major_minor_clks = cd_minor_clks = 0;
157+
/**
158+
* This event was in the past. Set the interrupt as pending, but don't process it here.
159+
* This prevents a recurive loop under heavy load which can lead to a stack overflow.
160+
*/
161+
NVIC_SetPendingIRQ(timer3_modinit.irq_n);
162+
}
155163
}
156164

157165
void lp_ticker_disable_interrupt(void)
@@ -175,8 +183,8 @@ static void tmr3_vec(void)
175183
{
176184
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
177185
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
178-
cd_major_minor_clks -= cd_minor_clks;
179-
if (cd_major_minor_clks <= 0) {
186+
cd_major_minor_clks = (cd_major_minor_clks > cd_minor_clks) ? (cd_major_minor_clks - cd_minor_clks) : 0;
187+
if (cd_major_minor_clks == 0) {
180188
// NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
181189
lp_ticker_irq_handler();
182190
}

targets/TARGET_NUVOTON/TARGET_M451/us_ticker.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ static void us_ticker_arm_cd(void);
4545
static int us_ticker_inited = 0;
4646
static volatile uint32_t counter_major = 0;
4747
static volatile uint32_t pd_comp_us = 0; // Power-down compenstaion for normal counter
48-
static volatile int cd_major_minor_us = 0;
49-
static volatile int cd_minor_us = 0;
48+
static volatile uint32_t cd_major_minor_us = 0;
49+
static volatile uint32_t cd_minor_us = 0;
5050
static volatile int cd_hires_tmr_armed = 0; // Flag of armed or not of hi-res timer for CD counter
5151

5252
// NOTE: PCLK is set up in mbed_sdk_init(), invocation of which must be before C++ global object constructor. See init_api.c for details.
@@ -116,7 +116,7 @@ uint32_t us_ticker_read()
116116

117117
do {
118118
uint32_t major_minor_us;
119-
uint32_t minor_us;
119+
uint32_t minor_us;
120120

121121
// NOTE: As TIMER_CNT = TIMER_CMP and counter_major has increased by one, TIMER_CNT doesn't change to 0 for one tick time.
122122
// 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.
@@ -157,12 +157,21 @@ void us_ticker_clear_interrupt(void)
157157
void us_ticker_set_interrupt(timestamp_t timestamp)
158158
{
159159
TIMER_Stop((TIMER_T *) NU_MODBASE(timer1lores_modinit.modname));
160+
cd_hires_tmr_armed = 0;
160161

161162
int delta = (int) (timestamp - us_ticker_read());
162-
// NOTE: If this event was in the past, arm an interrupt to be triggered immediately.
163-
cd_major_minor_us = delta * US_PER_TICK;
164-
165-
us_ticker_arm_cd();
163+
if (delta > 0) {
164+
cd_major_minor_us = delta * US_PER_TICK;
165+
us_ticker_arm_cd();
166+
}
167+
else {
168+
cd_major_minor_us = cd_minor_us = 0;
169+
/**
170+
* This event was in the past. Set the interrupt as pending, but don't process it here.
171+
* This prevents a recurive loop under heavy load which can lead to a stack overflow.
172+
*/
173+
NVIC_SetPendingIRQ(timer1lores_modinit.irq_n);
174+
}
166175
}
167176

168177
void us_ticker_prepare_sleep(struct sleep_s *obj)
@@ -206,9 +215,9 @@ static void tmr0_vec(void)
206215
static void tmr1_vec(void)
207216
{
208217
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer1lores_modinit.modname));
209-
cd_major_minor_us -= cd_minor_us;
218+
cd_major_minor_us = (cd_major_minor_us > cd_minor_us) ? (cd_major_minor_us - cd_minor_us) : 0;
210219
cd_hires_tmr_armed = 0;
211-
if (cd_major_minor_us <= 0) {
220+
if (cd_major_minor_us == 0) {
212221
// NOTE: us_ticker_set_interrupt() may get called in us_ticker_irq_handler();
213222
us_ticker_irq_handler();
214223
}

targets/TARGET_NUVOTON/TARGET_NUC472/lp_ticker.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ static void lp_ticker_arm_cd(void);
3838

3939
static int lp_ticker_inited = 0;
4040
static volatile uint32_t counter_major = 0;
41-
static volatile int cd_major_minor_clks = 0;
42-
static volatile int cd_minor_clks = 0;
41+
static volatile uint32_t cd_major_minor_clks = 0;
42+
static volatile uint32_t cd_minor_clks = 0;
4343
static volatile uint32_t wakeup_tick = (uint32_t) -1;
4444

4545
// NOTE: To wake the system from power down mode, timer clock source must be ether LXT or LIRC.
@@ -147,10 +147,18 @@ void lp_ticker_set_interrupt(timestamp_t timestamp)
147147
TIMER_Stop((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
148148

149149
int delta = (timestamp > now) ? (timestamp - now) : (uint32_t) ((uint64_t) timestamp + 0xFFFFFFFFu - now);
150-
// NOTE: If this event was in the past, arm an interrupt to be triggered immediately.
151-
cd_major_minor_clks = (uint64_t) delta * US_PER_TICK * TMR3_CLK_PER_SEC / US_PER_SEC;
152-
153-
lp_ticker_arm_cd();
150+
if (delta > 0) {
151+
cd_major_minor_clks = (uint64_t) delta * US_PER_TICK * TMR3_CLK_PER_SEC / US_PER_SEC;
152+
lp_ticker_arm_cd();
153+
}
154+
else {
155+
cd_major_minor_clks = cd_minor_clks = 0;
156+
/**
157+
* This event was in the past. Set the interrupt as pending, but don't process it here.
158+
* This prevents a recurive loop under heavy load which can lead to a stack overflow.
159+
*/
160+
NVIC_SetPendingIRQ(timer3_modinit.irq_n);
161+
}
154162
}
155163

156164
void lp_ticker_disable_interrupt(void)
@@ -174,8 +182,8 @@ static void tmr3_vec(void)
174182
{
175183
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
176184
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(timer3_modinit.modname));
177-
cd_major_minor_clks -= cd_minor_clks;
178-
if (cd_major_minor_clks <= 0) {
185+
cd_major_minor_clks = (cd_major_minor_clks > cd_minor_clks) ? (cd_major_minor_clks - cd_minor_clks) : 0;
186+
if (cd_major_minor_clks == 0) {
179187
// NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
180188
lp_ticker_irq_handler();
181189
}

targets/TARGET_NUVOTON/TARGET_NUC472/us_ticker.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ static void us_ticker_arm_cd(void);
4545
static int us_ticker_inited = 0;
4646
static volatile uint32_t counter_major = 0;
4747
static volatile uint32_t pd_comp_us = 0; // Power-down compenstaion for normal counter
48-
static volatile int cd_major_minor_us = 0;
49-
static volatile int cd_minor_us = 0;
48+
static volatile uint32_t cd_major_minor_us = 0;
49+
static volatile uint32_t cd_minor_us = 0;
5050
static volatile int cd_hires_tmr_armed = 0; // Flag of armed or not of hi-res timer for CD counter
5151

5252
// NOTE: PCLK is set up in mbed_sdk_init(), invocation of which must be before C++ global object constructor. See init_api.c for details.
@@ -156,12 +156,21 @@ void us_ticker_clear_interrupt(void)
156156
void us_ticker_set_interrupt(timestamp_t timestamp)
157157
{
158158
TIMER_Stop((TIMER_T *) NU_MODBASE(timer1lores_modinit.modname));
159+
cd_hires_tmr_armed = 0;
159160

160161
int delta = (int) (timestamp - us_ticker_read());
161-
// NOTE: If this event was in the past, arm an interrupt to be triggered immediately.
162-
cd_major_minor_us = delta * US_PER_TICK;
163-
164-
us_ticker_arm_cd();
162+
if (delta > 0) {
163+
cd_major_minor_us = delta * US_PER_TICK;
164+
us_ticker_arm_cd();
165+
}
166+
else {
167+
cd_major_minor_us = cd_minor_us = 0;
168+
/**
169+
* This event was in the past. Set the interrupt as pending, but don't process it here.
170+
* This prevents a recurive loop under heavy load which can lead to a stack overflow.
171+
*/
172+
NVIC_SetPendingIRQ(timer1lores_modinit.irq_n);
173+
}
165174
}
166175

167176
void us_ticker_prepare_sleep(struct sleep_s *obj)
@@ -205,9 +214,9 @@ static void tmr0_vec(void)
205214
static void tmr1_vec(void)
206215
{
207216
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(timer1lores_modinit.modname));
208-
cd_major_minor_us -= cd_minor_us;
217+
cd_major_minor_us = (cd_major_minor_us > cd_minor_us) ? (cd_major_minor_us - cd_minor_us) : 0;
209218
cd_hires_tmr_armed = 0;
210-
if (cd_major_minor_us <= 0) {
219+
if (cd_major_minor_us == 0) {
211220
// NOTE: us_ticker_set_interrupt() may get called in us_ticker_irq_handler();
212221
us_ticker_irq_handler();
213222
}

0 commit comments

Comments
 (0)