There are issues using lowercase min and max macros when compiling a C++ application with a third-party toolchain such as GNU ARM Embedded when using some STL headers i.e. <chrono>. This is because there are actual C++ functions called min and max defined in some of the STL headers and these macros interfere with them. By changing the macros to UPPERCASE, which is consistent with almost all other pre-processor macros this naming conflict is avoided. All files that use these macros have been updated. Signed-off-by: Carlos Stuart <carlosstuart1970@gmail.com>
150 lines
3.5 KiB
C
150 lines
3.5 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include <drivers/system_timer.h>
|
|
#include <sys_clock.h>
|
|
#include <spinlock.h>
|
|
#include <arch/arm/cortex_m/cmsis.h>
|
|
|
|
void _ExcExit(void);
|
|
|
|
/* Minimum cycles in the future to try to program. */
|
|
#define MIN_DELAY 512
|
|
|
|
#define COUNTER_MAX 0x00ffffff
|
|
#define TIMER_STOPPED 0xff000000
|
|
|
|
#define CYC_PER_TICK (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC \
|
|
/ CONFIG_SYS_CLOCK_TICKS_PER_SEC)
|
|
#define MAX_TICKS ((COUNTER_MAX / CYC_PER_TICK) - 1)
|
|
#define MAX_CYCLES (MAX_TICKS * CYC_PER_TICK)
|
|
|
|
#define TICKLESS (IS_ENABLED(CONFIG_TICKLESS_KERNEL) && \
|
|
!IS_ENABLED(CONFIG_QEMU_TICKLESS_WORKAROUND))
|
|
|
|
static struct k_spinlock lock;
|
|
|
|
static u32_t last_load;
|
|
|
|
static u32_t cycle_count;
|
|
|
|
static u32_t announced_cycles;
|
|
|
|
static volatile u32_t ctrl_cache; /* overflow bit clears on read! */
|
|
|
|
static u32_t elapsed(void)
|
|
{
|
|
u32_t val, ov;
|
|
|
|
do {
|
|
val = SysTick->VAL & COUNTER_MAX;
|
|
ctrl_cache |= SysTick->CTRL;
|
|
} while (SysTick->VAL > val);
|
|
|
|
ov = (ctrl_cache & SysTick_CTRL_COUNTFLAG_Msk) ? last_load : 0;
|
|
return (last_load - val) + ov;
|
|
}
|
|
|
|
/* Callout out of platform assembly, not hooked via IRQ_CONNECT... */
|
|
void z_clock_isr(void *arg)
|
|
{
|
|
ARG_UNUSED(arg);
|
|
u32_t dticks;
|
|
|
|
cycle_count += last_load;
|
|
dticks = (cycle_count - announced_cycles) / CYC_PER_TICK;
|
|
announced_cycles += dticks * CYC_PER_TICK;
|
|
|
|
ctrl_cache = SysTick->CTRL; /* Reset overflow flag */
|
|
ctrl_cache = 0U;
|
|
|
|
z_clock_announce(TICKLESS ? dticks : 1);
|
|
_ExcExit();
|
|
}
|
|
|
|
int z_clock_driver_init(struct device *device)
|
|
{
|
|
NVIC_SetPriority(SysTick_IRQn, _IRQ_PRIO_OFFSET);
|
|
last_load = CYC_PER_TICK;
|
|
SysTick->LOAD = last_load;
|
|
SysTick->VAL = 0; /* resets timer to last_load */
|
|
SysTick->CTRL |= (SysTick_CTRL_ENABLE_Msk |
|
|
SysTick_CTRL_TICKINT_Msk |
|
|
SysTick_CTRL_CLKSOURCE_Msk);
|
|
return 0;
|
|
}
|
|
|
|
void z_clock_set_timeout(s32_t ticks, bool idle)
|
|
{
|
|
/* Fast CPUs and a 24 bit counter mean that even idle systems
|
|
* need to wake up multiple times per second. If the kernel
|
|
* allows us to miss tick announcements in idle, then shut off
|
|
* the counter. (Note: we can assume if idle==true that
|
|
* interrupts are already disabled)
|
|
*/
|
|
if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && idle && ticks == K_FOREVER) {
|
|
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
|
|
last_load = TIMER_STOPPED;
|
|
return;
|
|
}
|
|
|
|
#if defined(CONFIG_TICKLESS_KERNEL) && !defined(CONFIG_QEMU_TICKLESS_WORKAROUND)
|
|
u32_t delay;
|
|
|
|
ticks = MIN(MAX_TICKS, MAX(ticks - 1, 0));
|
|
|
|
/* Desired delay in the future */
|
|
delay = (ticks == 0) ? MIN_DELAY : ticks * CYC_PER_TICK;
|
|
|
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
|
|
|
cycle_count += elapsed();
|
|
|
|
/* Round delay up to next tick boundary */
|
|
delay = delay + (cycle_count - announced_cycles);
|
|
delay = ((delay + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK;
|
|
last_load = delay - (cycle_count - announced_cycles);
|
|
|
|
SysTick->LOAD = last_load;
|
|
SysTick->VAL = 0; /* resets timer to last_load */
|
|
|
|
k_spin_unlock(&lock, key);
|
|
#endif
|
|
}
|
|
|
|
u32_t z_clock_elapsed(void)
|
|
{
|
|
if (!TICKLESS) {
|
|
return 0;
|
|
}
|
|
|
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
|
u32_t cyc = elapsed() + cycle_count - announced_cycles;
|
|
|
|
k_spin_unlock(&lock, key);
|
|
return cyc / CYC_PER_TICK;
|
|
}
|
|
|
|
u32_t _timer_cycle_get_32(void)
|
|
{
|
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
|
u32_t ret = elapsed() + cycle_count;
|
|
|
|
k_spin_unlock(&lock, key);
|
|
return ret;
|
|
}
|
|
|
|
void z_clock_idle_exit(void)
|
|
{
|
|
if (last_load == TIMER_STOPPED) {
|
|
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
|
|
}
|
|
}
|
|
|
|
void sys_clock_disable(void)
|
|
{
|
|
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
|
|
}
|