Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions drivers/timer/cortex_m_systick.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ static cycle_t cycle_pre_idle;
/* Idle timer value before entering the idle state. */
static uint32_t idle_timer_pre_idle;

/* How many ticks the system was expected to sleep when
* idle timer was configured. Used to determine if the
* counter overflowed or not.
*/
static uint32_t idle_timer_scheduled_sleep_ticks;

/* Idle timer used for timer while entering the idle state */
static const struct device *idle_timer = DEVICE_DT_GET(DT_CHOSEN(zephyr_cortex_m_idle_timer));

Expand Down Expand Up @@ -154,25 +160,43 @@ void z_cms_lptim_hook_on_lpm_entry(uint64_t max_lpm_time_us)
* difference in measurements after exiting the idle state.
*/
counter_get_value(idle_timer, &idle_timer_pre_idle);

idle_timer_scheduled_sleep_ticks = cfg.ticks;
}

uint64_t z_cms_lptim_hook_on_lpm_exit(void)
{
/**
* Calculate how much time elapsed according to counter.
*/
uint32_t idle_timer_post, idle_timer_diff;
uint32_t idle_timer_post, idle_timer_diff, idle_timer_top;
bool idle_timer_int_pending, idle_timer_wrap;

counter_get_value(idle_timer, &idle_timer_post);
idle_timer_int_pending = counter_get_pending_int(idle_timer) ? true : false;
idle_timer_top = counter_get_top_value(idle_timer);

/**
* Check for counter timer overflow
* (TODO: this doesn't work for downcounting timers!)
*/
if (idle_timer_pre_idle > idle_timer_post) {
idle_timer_diff =
(counter_get_top_value(idle_timer) - idle_timer_pre_idle) +
idle_timer_post + 1;
/* Pre > Post: counter wrapped (overflow occurred) */
idle_timer_wrap = true;
} else if (idle_timer_pre_idle == idle_timer_post) {
/* Pre == Post: consider wrap only if interrupt is pending */
idle_timer_wrap = idle_timer_int_pending;
} else {
/* Pre < Post: normally no wrap; if interrupt pending and the
* expected sleep spans the counter top, treat as wrap.
*/
idle_timer_wrap = idle_timer_int_pending &&
((uint64_t)idle_timer_pre_idle + idle_timer_scheduled_sleep_ticks
>= idle_timer_top);
}

if (idle_timer_wrap) {
idle_timer_diff = idle_timer_top - idle_timer_pre_idle + idle_timer_post + 1;
} else {
idle_timer_diff = idle_timer_post - idle_timer_pre_idle;
}
Expand Down