Skip to content

Commit 2c4e466

Browse files
committed
drivers: timer: Improve the accuracy of the MCUX OS Timer
1. The sys_clock_idle_exit function could be invoked multiple times. Hence add code so that is counter is stopped and the OS Timer is initialized once. 2. Reset the OS Timer when exiting low power modes where the OS Timer loses its state 3. Improve the cycles conversion algorithm. Round to the nearest microsecond when converting from ticks to microsecond rather than always rounding up to the next highest value. Signed-off-by: Mahesh Mahadevan <mahesh.mahadevan@nxp.com>
1 parent 6e0b49e commit 2c4e466

File tree

1 file changed

+38
-28
lines changed

1 file changed

+38
-28
lines changed

drivers/timer/mcux_os_timer.c

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
#define CYC_PER_TICK ((uint32_t)((uint64_t)sys_clock_hw_cycles_per_sec() \
2424
/ (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC))
25+
#define CYC_PER_US ((uint32_t)((uint64_t)sys_clock_hw_cycles_per_sec() \
26+
/ (uint64_t)USEC_PER_SEC))
2527
#define MAX_CYC INT_MAX
2628
#define MAX_TICKS ((MAX_CYC - CYC_PER_TICK) / CYC_PER_TICK)
2729
#define MIN_DELAY 1000
@@ -37,7 +39,12 @@ static OSTIMER_Type *base;
3739
*/
3840
static uint64_t cyc_sys_compensated;
3941
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(standby)) && CONFIG_PM
42+
/* This is the counter device used when OS timer is not available in
43+
* standby mode.
44+
*/
4045
static const struct device *counter_dev;
46+
/* Indicates if the counter is running. */
47+
bool counter_running;
4148
#endif
4249

4350
static uint64_t mcux_lpc_ostick_get_compensated_timer_value(void)
@@ -86,8 +93,7 @@ static uint32_t mcux_lpc_ostick_set_counter_timeout(int32_t curr_timeout)
8693
uint32_t timeout;
8794
int32_t ticks;
8895
struct counter_top_cfg top_cfg = { 0 };
89-
90-
timeout = k_ticks_to_us_ceil32(curr_timeout);
96+
timeout = k_ticks_to_us_near32(curr_timeout);
9197

9298
ticks = counter_us_to_ticks(counter_dev, timeout);
9399
ticks = CLAMP(ticks, 1, counter_get_max_top_value(counter_dev));
@@ -111,17 +117,18 @@ static uint32_t mcux_lpc_ostick_set_counter_timeout(int32_t curr_timeout)
111117
}
112118
}
113119

120+
/* Counter is set to wakeup the system after the requested time */
121+
if (counter_start(counter_dev) != 0) {
122+
ret = 1;
123+
goto done;
124+
}
125+
counter_running = true;
114126
#if CONFIG_MCUX_OS_TIMER_PM_POWERED_OFF
115127
/* Capture the current timer value for cases where it loses its state
116128
* in low power modes.
117129
*/
118130
cyc_sys_compensated += OSTIMER_GetCurrentTimerValue(base);
119131
#endif
120-
121-
/* Counter is set to wakeup the system after the requested time */
122-
if (counter_start(counter_dev) != 0) {
123-
ret = 1;
124-
}
125132
} else {
126133
ret = 1;
127134
}
@@ -137,34 +144,37 @@ static uint32_t mcux_lpc_ostick_set_counter_timeout(int32_t curr_timeout)
137144
*/
138145
static uint32_t mcux_lpc_ostick_compensate_system_timer(void)
139146
{
140-
uint32_t ret = 0;
141-
142-
if (counter_dev) {
143-
uint32_t slept_time_ticks;
144-
uint32_t slept_time_us;
147+
uint32_t slept_time_ticks;
148+
uint32_t slept_time_us;
145149

146-
counter_stop(counter_dev);
150+
if (!counter_dev) {
151+
return 1;
152+
}
147153

148-
counter_get_value(counter_dev, &slept_time_ticks);
154+
if (!counter_running) {
155+
return 0;
156+
}
149157

150-
if (!(counter_is_counting_up(counter_dev))) {
151-
slept_time_ticks = counter_get_top_value(counter_dev) - slept_time_ticks;
152-
}
153-
slept_time_us = counter_ticks_to_us(counter_dev, slept_time_ticks);
154-
cyc_sys_compensated += (k_us_to_ticks_floor32(slept_time_us) * CYC_PER_TICK);
158+
counter_stop(counter_dev);
159+
counter_running = false;
160+
counter_get_value(counter_dev, &slept_time_ticks);
155161

162+
if (!(counter_is_counting_up(counter_dev))) {
163+
slept_time_ticks = counter_get_top_value(counter_dev) -
164+
slept_time_ticks;
165+
}
166+
slept_time_us = counter_ticks_to_us(counter_dev, slept_time_ticks);
167+
cyc_sys_compensated += CYC_PER_US * slept_time_us;
156168
#if CONFIG_MCUX_OS_TIMER_PM_POWERED_OFF
157-
/* Reactivate os_timer for cases where it loses its state */
158-
OSTIMER_Init(base);
169+
/* Reset the OS Timer to a known state */
170+
RESET_PeripheralReset(kOSEVENT_TIMER_RST_SHIFT_RSTn);
171+
/* Reactivate os_timer for cases where it loses its state */
172+
OSTIMER_Init(base);
159173
#endif
174+
/* Announce the time slept to the kernel*/
175+
mcux_lpc_ostick_isr(NULL);
160176

161-
/* Announce the time slept to the kernel*/
162-
mcux_lpc_ostick_isr(NULL);
163-
} else {
164-
ret = 1;
165-
}
166-
167-
return ret;
177+
return 0;
168178
}
169179

170180
#endif

0 commit comments

Comments
 (0)