stm32h7: refactor systick code
rockbox-gerrit-noreply--- via rockbox-cvs <[email protected]>
| Newsgroups | gmane.comp.systems.archos.rockbox.cvs |
|---|---|
| Message-ID | <[email protected]> |
commit 62332841cf87f08728730e5dfa684a19b69ca5f9 Author: Aidan MacDonald <[email protected]> Date: Thu Jan 15 01:26:45 2026 +0000 stm32h7: refactor systick code Make systick setup less hardcoded, and create a public API for use by targets, in preparation for moving system_init() into target-specific code. Improve the implementation of udelay to make it more robust against timer wraparound. Change-Id: I21bb8821cfd1d7e4049fac6e6a4548d80a4276f7 diff --git a/firmware/target/arm/stm32/system-stm32h7.c b/firmware/target/arm/stm32/system-stm32h7.c index b58fd76322..35c1d2e60d 100644 --- a/firmware/target/arm/stm32/system-stm32h7.c +++ b/firmware/target/arm/stm32/system-stm32h7.c @@ -27,25 +27,31 @@ #include "regs/cortex-m/cm_systick.h" #include "regs/stm32h743/dbgmcu.h" -/* EXT timer is 1/8th of CPU clock */ -#define SYSTICK_FREQ (CPU_FREQ / 8) -#define SYSTICK_PER_MS (SYSTICK_FREQ / 1000) -#define SYSTICK_PER_US (SYSTICK_FREQ / 1000000) +/* Assumed initial CPU frequency for calculating systick */ +#ifndef CPUFREQ_INITIAL +# define CPUFREQ_INITIAL CPU_FREQ +#endif + +/* Tick interval in milliseconds */ +#ifndef SYSTICK_INTERVAL_INITIAL +# define SYSTICK_INTERVAL_INITIAL (1000 / HZ) +#endif -/* Max delay is limited by kernel tick interval + safety margin */ -#define SYSTICK_DELAY_MAX_US (1000000 / HZ / 2) -#define SYSTICK_DELAY_MAX_MS (SYSTICK_DELAY_MAX_US / 1000) +/* Use EXT source which is equal to CPU frequency divided by 8 */ +#define SYSTICK_SOURCE BV_CM_SYSTICK_CSR_CLKSOURCE_EXT +#define SYSTICK_PRESCALER 8 + +/* Convert CPU frequency to number of systick ticks in 1 ms */ +#define CPUFREQ_TO_SYSTICK_PER_MS(f) \ + ((f) / (SYSTICK_PRESCALER * 1000)) + +/* SysTick related state */ +static uint32_t systick_per_ms = CPUFREQ_TO_SYSTICK_PER_MS(CPUFREQ_INITIAL); +static uint32_t systick_interval_in_ms = SYSTICK_INTERVAL_INITIAL; /* Base address of vector table */ extern char __vectors_arm[]; -static void systick_init(unsigned int interval_in_ms) -{ - reg_writef(CM_SYSTICK_RVR, VALUE(SYSTICK_PER_MS * interval_in_ms - 1)); - reg_writef(CM_SYSTICK_CVR, VALUE(0)); - reg_writef(CM_SYSTICK_CSR, CLKSOURCE_V(EXT), ENABLE(1)); -} - static void stm_enable_caches(void) { __discard_idcache(); @@ -56,6 +62,45 @@ static void stm_enable_caches(void) arm_isb(); } +static void stm32_recalc_systick_rvr(void) +{ + uint32_t ticks = systick_per_ms * systick_interval_in_ms; + + reg_writef(CM_SYSTICK_RVR, VALUE(ticks - 1)); +} + +static void stm32_set_systick_interval(uint32_t interval_in_ms) +{ + if (interval_in_ms != systick_interval_in_ms) + { + systick_interval_in_ms = interval_in_ms; + stm32_recalc_systick_rvr(); + } +} + +void stm32_systick_set_cpu_freq(uint32_t freq) +{ + uint32_t ticks_per_ms = CPUFREQ_TO_SYSTICK_PER_MS(freq); + + if (ticks_per_ms != systick_per_ms) + { + systick_per_ms = ticks_per_ms; + stm32_recalc_systick_rvr(); + } +} + +void stm32_systick_enable(void) +{ + stm32_recalc_systick_rvr(); + reg_writef(CM_SYSTICK_CVR, VALUE(0)); + reg_writef(CM_SYSTICK_CSR, CLKSOURCE(SYSTICK_SOURCE), ENABLE(1)); +} + +void stm32_systick_disable(void) +{ + reg_writef(CM_SYSTICK_CSR, ENABLE(0), TICKINT(0)); +} + void system_init(void) { #if defined(DEBUG) @@ -72,8 +117,8 @@ void system_init(void) /* Initialize system clocks */ stm_clock_init(); - /* TODO: move this */ - systick_init(1000/HZ); + /* Initialize systick */ + stm32_systick_enable(); /* Call target-specific initialization */ gpio_init(); @@ -99,7 +144,8 @@ void system_debug_enable(bool enable) void tick_start(unsigned int interval_in_ms) { - (void)interval_in_ms; + stm32_set_systick_interval(interval_in_ms); + stm32_systick_enable(); reg_writef(CM_SYSTICK_CSR, TICKINT(1)); } @@ -110,47 +156,33 @@ void systick_handler(void) } /* - * NOTE: This assumes that the CPU cannot be reclocked during an interrupt. - * If that happens, the systick interval and reload value would be modified - * to maintain the kernel tick interval and the code here will break. + * This makes two assumptions: + * + * 1. the CPU frequency must not change while udelay() is running; + * otherwise the delay time will be wrong. + * 2. interrupt handlers should not block execution for more than + * one systick interval; if this happens the delay may be much + * longer than necessary. */ -static void __udelay(uint32_t us) +void udelay(uint32_t us) { + uint32_t delay_ticks = (us * systick_per_ms / 1000); uint32_t start = reg_readf(CM_SYSTICK_CVR, VALUE); uint32_t max = reg_readf(CM_SYSTICK_RVR, VALUE); - uint32_t delay = us * SYSTICK_PER_US; - for (;;) + while (delay_ticks > 0) { uint32_t value = reg_readf(CM_SYSTICK_CVR, VALUE); uint32_t diff = start - value; if (value > start) diff += max; - if (diff >= delay) - break; - } -} - -void udelay(uint32_t us) -{ - while (us > SYSTICK_DELAY_MAX_US) - { - __udelay(SYSTICK_DELAY_MAX_US); - us -= SYSTICK_DELAY_MAX_US; - } - __udelay(us); -} + if (diff >= delay_ticks) + break; -void mdelay(uint32_t ms) -{ - while (ms > SYSTICK_DELAY_MAX_MS) - { - __udelay(SYSTICK_DELAY_MAX_MS * 1000); - ms -= SYSTICK_DELAY_MAX_MS; + delay_ticks -= diff; + start = value; } - - __udelay(ms * 1000); } void system_exception_wait(void) diff --git a/firmware/target/arm/stm32/system-target.h b/firmware/target/arm/stm32/system-target.h index fa3e206baa..d828b40e16 100644 --- a/firmware/target/arm/stm32/system-target.h +++ b/firmware/target/arm/stm32/system-target.h @@ -25,6 +25,15 @@ #include "cpucache-armv7m.h" #include <stdbool.h> +/* Enables the SysTick timer -- SysTick interrupt won't be enabled */ +void stm32_systick_enable(void); + +/* Disables the SysTick timer -- also disables SysTick interrupt */ +void stm32_systick_disable(void); + +/* Update the CPU frequency to recalibrate SysTick timer */ +void stm32_systick_set_cpu_freq(uint32_t freq); + /* Enable/disable debug clock domain during sleep mode. */ void system_debug_enable(bool enable); @@ -32,7 +41,7 @@ void system_debug_enable(bool enable); void gpio_init(void) INIT_ATTR; void fmc_init(void) INIT_ATTR; +/* Busy loop delay based on systick */ void udelay(uint32_t us); -void mdelay(uint32_t ms); #endif /* __STM32_SYSTEM_TARGET_H__ */ -- rockbox-cvs mailing list [email protected] https://lists.haxx.se/mailman/listinfo/rockbox-cvs