Skip to content

Commit 8978859

Browse files
Merge pull request #6394 from OpenNuvoton/nuvoton_fix_ticker
Nuvoton: Fix us_ticker/lp_ticker
2 parents 0615111 + ccec9d7 commit 8978859

File tree

8 files changed

+172
-82
lines changed

8 files changed

+172
-82
lines changed

targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ static int ticker_inited = 0;
4747
#define TMR_CMP_MIN 2
4848
#define TMR_CMP_MAX 0xFFFFFFu
4949

50+
/* NOTE: When system clock is higher than timer clock, we need to add 3 engine clock
51+
* (recommended by designer) delay to wait for above timer control to take effect. */
52+
5053
void lp_ticker_init(void)
5154
{
5255
if (ticker_inited) {
@@ -63,28 +66,39 @@ void lp_ticker_init(void)
6366
// Enable IP clock
6467
CLK_EnableModuleClock(TIMER_MODINIT.clkidx);
6568

69+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
70+
6671
// Configure clock
67-
uint32_t clk_timer = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
72+
uint32_t clk_timer = TIMER_GetModuleClock(timer_base);
6873
uint32_t prescale_timer = clk_timer / NU_TMRCLK_PER_SEC - 1;
6974
MBED_ASSERT((prescale_timer != (uint32_t) -1) && prescale_timer <= 127);
7075
MBED_ASSERT((clk_timer % NU_TMRCLK_PER_SEC) == 0);
7176
uint32_t cmp_timer = TMR_CMP_MAX;
7277
MBED_ASSERT(cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX);
7378
// Continuous mode
7479
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
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;
80+
timer_base->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
81+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
82+
83+
timer_base->CMP = cmp_timer;
84+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
7785

7886
// Set vector
7987
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);
8088

8189
NVIC_EnableIRQ(TIMER_MODINIT.irq_n);
8290

83-
TIMER_EnableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
84-
TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
85-
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
91+
TIMER_EnableInt(timer_base);
92+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
93+
94+
TIMER_EnableWakeup(timer_base);
95+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
96+
97+
TIMER_Start(timer_base);
8698
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
87-
TIMER_Start((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
99+
100+
/* Wait for timer to start counting and raise active flag */
101+
while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk));
88102
}
89103

90104
timestamp_t lp_ticker_read()
@@ -93,7 +107,7 @@ timestamp_t lp_ticker_read()
93107
lp_ticker_init();
94108
}
95109

96-
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
110+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
97111

98112
return (TIMER_GetCounter(timer_base) / NU_TMRCLK_PER_TICK);
99113
}
@@ -108,27 +122,27 @@ void lp_ticker_set_interrupt(timestamp_t timestamp)
108122
* This behavior is not what we want. To fix it, we could configure new CMP value
109123
* without stopping counting first.
110124
*/
111-
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
125+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
112126

113127
/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
114128
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
115129
uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK;
116130
cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX);
117-
timer_base->CMP = cmp_timer;
118131

119-
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
132+
timer_base->CMP = cmp_timer;
120133
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
121-
TIMER_Start(timer_base);
122134
}
123135

124136
void lp_ticker_disable_interrupt(void)
125137
{
126138
TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
139+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
127140
}
128141

129142
void lp_ticker_clear_interrupt(void)
130143
{
131144
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
145+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
132146
}
133147

134148
void lp_ticker_fire_interrupt(void)
@@ -150,8 +164,11 @@ const ticker_info_t* lp_ticker_get_info()
150164
static void tmr1_vec(void)
151165
{
152166
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
167+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
168+
153169
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
154-
170+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
171+
155172
// NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
156173
lp_ticker_irq_handler();
157174
}

targets/TARGET_NUVOTON/TARGET_M451/us_ticker.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,28 @@ void us_ticker_init(void)
5858
// Enable IP clock
5959
CLK_EnableModuleClock(TIMER_MODINIT.clkidx);
6060

61+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
62+
6163
// Timer for normal counter
62-
uint32_t clk_timer = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
64+
uint32_t clk_timer = TIMER_GetModuleClock(timer_base);
6365
uint32_t prescale_timer = clk_timer / NU_TMRCLK_PER_SEC - 1;
6466
MBED_ASSERT((prescale_timer != (uint32_t) -1) && prescale_timer <= 127);
6567
MBED_ASSERT((clk_timer % NU_TMRCLK_PER_SEC) == 0);
6668
uint32_t cmp_timer = TMR_CMP_MAX;
6769
MBED_ASSERT(cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX);
6870
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451. In M451, TIMER_CNT is updated continuously by default.
69-
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
70-
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CMP = cmp_timer;
71+
timer_base->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
72+
timer_base->CMP = cmp_timer;
7173

7274
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);
7375

7476
NVIC_EnableIRQ(TIMER_MODINIT.irq_n);
7577

76-
TIMER_EnableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
77-
TIMER_Start((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
78+
TIMER_EnableInt(timer_base);
79+
80+
TIMER_Start(timer_base);
81+
/* Wait for timer to start counting and raise active flag */
82+
while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk));
7883
}
7984

8085
uint32_t us_ticker_read()
@@ -83,7 +88,7 @@ uint32_t us_ticker_read()
8388
us_ticker_init();
8489
}
8590

86-
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
91+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
8792

8893
return (TIMER_GetCounter(timer_base) / NU_TMRCLK_PER_TICK);
8994
}
@@ -98,7 +103,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
98103
* This behavior is not what we want. To fix it, we could configure new CMP value
99104
* without stopping counting first.
100105
*/
101-
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
106+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
102107

103108
/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
104109
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */

targets/TARGET_NUVOTON/TARGET_M480/lp_ticker.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ static int ticker_inited = 0;
4747
#define TMR_CMP_MIN 2
4848
#define TMR_CMP_MAX 0xFFFFFFu
4949

50+
/* NOTE: When system clock is higher than timer clock, we need to add 3 engine clock
51+
* (recommended by designer) delay to wait for above timer control to take effect. */
52+
5053
void lp_ticker_init(void)
5154
{
5255
if (ticker_inited) {
@@ -63,28 +66,39 @@ void lp_ticker_init(void)
6366
// Enable IP clock
6467
CLK_EnableModuleClock(TIMER_MODINIT.clkidx);
6568

69+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
70+
6671
// Configure clock
67-
uint32_t clk_timer = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
72+
uint32_t clk_timer = TIMER_GetModuleClock(timer_base);
6873
uint32_t prescale_timer = clk_timer / NU_TMRCLK_PER_SEC - 1;
6974
MBED_ASSERT((prescale_timer != (uint32_t) -1) && prescale_timer <= 127);
7075
MBED_ASSERT((clk_timer % NU_TMRCLK_PER_SEC) == 0);
7176
uint32_t cmp_timer = TMR_CMP_MAX;
7277
MBED_ASSERT(cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX);
7378
// Continuous mode
7479
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451/M480. In M451/M480, TIMER_CNT is updated continuously by default.
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;
80+
timer_base->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
81+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
82+
83+
timer_base->CMP = cmp_timer;
84+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
7785

7886
// Set vector
7987
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);
8088

8189
NVIC_EnableIRQ(TIMER_MODINIT.irq_n);
8290

83-
TIMER_EnableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
84-
TIMER_EnableWakeup((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
85-
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
91+
TIMER_EnableInt(timer_base);
92+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
93+
94+
TIMER_EnableWakeup(timer_base);
95+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
96+
97+
TIMER_Start(timer_base);
8698
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
87-
TIMER_Start((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
99+
100+
/* Wait for timer to start counting and raise active flag */
101+
while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk));
88102
}
89103

90104
timestamp_t lp_ticker_read()
@@ -93,7 +107,7 @@ timestamp_t lp_ticker_read()
93107
lp_ticker_init();
94108
}
95109

96-
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
110+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
97111

98112
return (TIMER_GetCounter(timer_base) / NU_TMRCLK_PER_TICK);
99113
}
@@ -108,27 +122,27 @@ void lp_ticker_set_interrupt(timestamp_t timestamp)
108122
* This behavior is not what we want. To fix it, we could configure new CMP value
109123
* without stopping counting first.
110124
*/
111-
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
125+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
112126

113127
/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
114128
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */
115129
uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK;
116130
cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX);
117-
timer_base->CMP = cmp_timer;
118131

119-
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
132+
timer_base->CMP = cmp_timer;
120133
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
121-
TIMER_Start(timer_base);
122134
}
123135

124136
void lp_ticker_disable_interrupt(void)
125137
{
126138
TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
139+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
127140
}
128141

129142
void lp_ticker_clear_interrupt(void)
130143
{
131144
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
145+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
132146
}
133147

134148
void lp_ticker_fire_interrupt(void)
@@ -150,8 +164,11 @@ const ticker_info_t* lp_ticker_get_info()
150164
static void tmr1_vec(void)
151165
{
152166
TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
167+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
168+
153169
TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
154-
170+
wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3);
171+
155172
// NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler();
156173
lp_ticker_irq_handler();
157174
}

targets/TARGET_NUVOTON/TARGET_M480/us_ticker.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,28 @@ void us_ticker_init(void)
5858
// Enable IP clock
5959
CLK_EnableModuleClock(TIMER_MODINIT.clkidx);
6060

61+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
62+
6163
// Timer for normal counter
62-
uint32_t clk_timer = TIMER_GetModuleClock((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
64+
uint32_t clk_timer = TIMER_GetModuleClock(timer_base);
6365
uint32_t prescale_timer = clk_timer / NU_TMRCLK_PER_SEC - 1;
6466
MBED_ASSERT((prescale_timer != (uint32_t) -1) && prescale_timer <= 127);
6567
MBED_ASSERT((clk_timer % NU_TMRCLK_PER_SEC) == 0);
6668
uint32_t cmp_timer = TMR_CMP_MAX;
6769
MBED_ASSERT(cmp_timer >= TMR_CMP_MIN && cmp_timer <= TMR_CMP_MAX);
6870
// NOTE: TIMER_CTL_CNTDATEN_Msk exists in NUC472, but not in M451/M480. In M451/M480, TIMER_CNT is updated continuously by default.
69-
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
70-
((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname))->CMP = cmp_timer;
71+
timer_base->CTL = TIMER_CONTINUOUS_MODE | prescale_timer/* | TIMER_CTL_CNTDATEN_Msk*/;
72+
timer_base->CMP = cmp_timer;
7173

7274
NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var);
7375

7476
NVIC_EnableIRQ(TIMER_MODINIT.irq_n);
7577

76-
TIMER_EnableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
77-
TIMER_Start((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname));
78+
TIMER_EnableInt(timer_base);
79+
80+
TIMER_Start(timer_base);
81+
/* Wait for timer to start counting and raise active flag */
82+
while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk));
7883
}
7984

8085
uint32_t us_ticker_read()
@@ -83,7 +88,7 @@ uint32_t us_ticker_read()
8388
us_ticker_init();
8489
}
8590

86-
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
91+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
8792

8893
return (TIMER_GetCounter(timer_base) / NU_TMRCLK_PER_TICK);
8994
}
@@ -98,7 +103,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
98103
* This behavior is not what we want. To fix it, we could configure new CMP value
99104
* without stopping counting first.
100105
*/
101-
TIMER_T * timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
106+
TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname);
102107

103108
/* NOTE: Because H/W timer requests min compare value, our implementation would have alarm delay of
104109
* (TMR_CMP_MIN - interval_clk) clocks when interval_clk is between [1, TMR_CMP_MIN). */

0 commit comments

Comments
 (0)