drivers: systick: implement option for sys_clock_cycle_get_64()
This driver, due to its limited 24-bits counter, is already tracking a cycle count in software. Allow that count to be a 64-bits value so this won't wrap in a matter of only a few seconds when the hardware clock is fast. This is very cheap to do as expensive math operations (i.e. divisions) are performed only on counter intervals whose values fit in 32 bits like before. Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
parent
b3d78de656
commit
49580bd374
2 changed files with 48 additions and 5 deletions
|
@ -24,3 +24,19 @@ config CORTEX_M_SYSTICK_INSTALL_ISR
|
|||
help
|
||||
This option should be selected by SysTick-based drivers so that the
|
||||
sys_clock_isr() function is installed.
|
||||
|
||||
config CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER
|
||||
bool "Cortex-M SYSTICK timer with sys_clock_cycle_get_64() support"
|
||||
depends on CORTEX_M_SYSTICK
|
||||
default y if (SYS_CLOCK_HW_CYCLES_PER_SEC > 60000000)
|
||||
select TIMER_HAS_64BIT_CYCLE_COUNTER
|
||||
help
|
||||
This driver, due to its limited 24-bits hardware counter, is already
|
||||
tracking a separate cycle count in software. This option make that
|
||||
count a 64-bits value to support sys_clock_cycle_get_64().
|
||||
This is cheap to do as expensive math operations (i.e. divisions)
|
||||
are performed only on counter interval values that always fit in
|
||||
32 bits.
|
||||
|
||||
This is set to y by default when the hardware clock is fast enough
|
||||
to wrap sys_clock_cycle_get_32() in about a minute or less.
|
||||
|
|
|
@ -36,6 +36,12 @@ static struct k_spinlock lock;
|
|||
|
||||
static uint32_t last_load;
|
||||
|
||||
#ifdef CONFIG_CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER
|
||||
#define cycle_t uint64_t
|
||||
#else
|
||||
#define cycle_t uint32_t
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This local variable holds the amount of SysTick HW cycles elapsed
|
||||
* and it is updated in sys_clock_isr() and sys_clock_set_timeout().
|
||||
|
@ -46,13 +52,19 @@ static uint32_t last_load;
|
|||
*
|
||||
* t = cycle_counter + elapsed();
|
||||
*/
|
||||
static uint32_t cycle_count;
|
||||
static cycle_t cycle_count;
|
||||
|
||||
/*
|
||||
* This local variable holds the amount of elapsed SysTick HW cycles
|
||||
* that have been announced to the kernel.
|
||||
*
|
||||
* Note:
|
||||
* Additions/subtractions/comparisons of 64-bits values on 32-bits systems
|
||||
* are very cheap. Divisions are not. Make sure the difference between
|
||||
* cycle_count and announced_cycles is stored in a 32-bit variable before
|
||||
* dividing it by CYC_PER_TICK.
|
||||
*/
|
||||
static uint32_t announced_cycles;
|
||||
static cycle_t announced_cycles;
|
||||
|
||||
/*
|
||||
* This local variable holds the amount of elapsed HW cycles due to
|
||||
|
@ -119,6 +131,7 @@ static uint32_t elapsed(void)
|
|||
void sys_clock_isr(void *arg)
|
||||
{
|
||||
ARG_UNUSED(arg);
|
||||
uint32_t dcycles;
|
||||
uint32_t dticks;
|
||||
|
||||
/* Update overflow_cyc and clear COUNTFLAG by invoking elapsed() */
|
||||
|
@ -143,7 +156,8 @@ void sys_clock_isr(void *arg)
|
|||
* We can assess if this is the case by inspecting COUNTFLAG.
|
||||
*/
|
||||
|
||||
dticks = (cycle_count - announced_cycles) / CYC_PER_TICK;
|
||||
dcycles = cycle_count - announced_cycles;
|
||||
dticks = dcycles / CYC_PER_TICK;
|
||||
announced_cycles += dticks * CYC_PER_TICK;
|
||||
sys_clock_announce(dticks);
|
||||
} else {
|
||||
|
@ -240,7 +254,8 @@ uint32_t sys_clock_elapsed(void)
|
|||
}
|
||||
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
uint32_t cyc = elapsed() + cycle_count - announced_cycles;
|
||||
uint32_t unannounced = cycle_count - announced_cycles;
|
||||
uint32_t cyc = elapsed() + unannounced;
|
||||
|
||||
k_spin_unlock(&lock, key);
|
||||
return cyc / CYC_PER_TICK;
|
||||
|
@ -249,11 +264,23 @@ uint32_t sys_clock_elapsed(void)
|
|||
uint32_t sys_clock_cycle_get_32(void)
|
||||
{
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
uint32_t ret = elapsed() + cycle_count;
|
||||
uint32_t ret = cycle_count;
|
||||
|
||||
ret += elapsed();
|
||||
k_spin_unlock(&lock, key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER
|
||||
uint64_t sys_clock_cycle_get_64(void)
|
||||
{
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
uint64_t ret = cycle_count + elapsed();
|
||||
|
||||
k_spin_unlock(&lock, key);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void sys_clock_idle_exit(void)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue