Skip to content

Commit aea7108

Browse files
Jerzy Kasenbergkartben
authored andcommitted
smartbond_timer: Fix tick-base behavior
When system was configured to use smartbond_timer with tick-based kernel, timer interrupt could fire only once and then time would not advance. Now when tick-based kernel is chosen timer2_isr() schedules that it should be fired at next tick. Timer comparator calculation code was extracted from existing sys_clock_set_timeout() function without change so it can be used for tick-less and tick-based kernel. Signed-off-by: Jerzy Kasenberg <jerzy.kasenberg.xr@bp.renesas.com>
1 parent 12a9392 commit aea7108

File tree

1 file changed

+31
-21
lines changed

1 file changed

+31
-21
lines changed

drivers/timer/smartbond_timer.c

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,34 @@ static uint32_t timer_val_32_noupdate(void)
8181
return val;
8282
}
8383

84-
void sys_clock_set_timeout(int32_t ticks, bool idle)
84+
static void schedule_next_interrupt(uint32_t ticks)
8585
{
86-
uint32_t target_val;
8786
uint32_t timer_val;
87+
uint32_t target_val;
88+
89+
timer_val = timer_val_32_noupdate();
90+
91+
/* Calculate target timer value and align to full tick */
92+
target_val = timer_val + TICK_TO_CYC(ticks);
93+
target_val = ((target_val + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK;
94+
95+
set_reload(target_val);
96+
97+
/*
98+
* If time was so small that it already fired or should fire
99+
* just now, mark interrupt as pending to avoid losing timer event.
100+
* Condition is true when target_val (point in time that should be
101+
* used for wakeup) is behind timer value or is equal to it.
102+
* In that case we don't know if reload value was set in time or
103+
* not but time expired anyway so make sure that interrupt is pending.
104+
*/
105+
if ((int32_t)(target_val - timer_val_32_noupdate() - 1) < 0) {
106+
NVIC_SetPendingIRQ(TIMER2_IRQn);
107+
}
108+
}
88109

110+
void sys_clock_set_timeout(int32_t ticks, bool idle)
111+
{
89112
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
90113
return;
91114
}
@@ -130,25 +153,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
130153
ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
131154
ticks = CLAMP(ticks - 1, 0, (int32_t)MAX_TICKS);
132155

133-
timer_val = timer_val_32_noupdate();
134-
135-
/* Calculate target timer value and align to full tick */
136-
target_val = timer_val + TICK_TO_CYC(ticks);
137-
target_val = ((target_val + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK;
138-
139-
set_reload(target_val);
140-
141-
/*
142-
* If time was so small that it already fired or should fire
143-
* just now, mark interrupt as pending to avoid losing timer event.
144-
* Condition is true when target_val (point in time that should be
145-
* used for wakeup) is behind timer value or is equal to it.
146-
* In that case we don't know if reload value was set in time or
147-
* not but time expired anyway so make sure that interrupt is pending.
148-
*/
149-
if ((int32_t)(target_val - timer_val_32_noupdate() - 1) < 0) {
150-
NVIC_SetPendingIRQ(TIMER2_IRQn);
151-
}
156+
schedule_next_interrupt(ticks);
152157
}
153158

154159
uint32_t sys_clock_elapsed(void)
@@ -192,6 +197,11 @@ static void timer2_isr(const void *arg)
192197
last_isr_val_rounded += TICK_TO_CYC(dticks);
193198
announced_ticks += dticks;
194199
sys_clock_announce(dticks);
200+
201+
/* For tick-based kernel, schedule interrupt after 1 tick */
202+
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
203+
schedule_next_interrupt(1);
204+
}
195205
}
196206

197207
static int sys_clock_driver_init(void)

0 commit comments

Comments
 (0)