summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2024-08-28 12:59:47 +1000
committerDamien George <damien@micropython.org>2025-04-09 00:22:32 +1000
commitc6ebecc4c3dbeeecbb0eecabd4ecb6162b8f14bb (patch)
tree0003d275fa4f0b2087f5b716f315e3ebe12fc89e
parentbbb8fd77fde3400cc1b9902e94f05889a7c1f49a (diff)
alif/system_tick: Implement optional ARM SysTick support for systick.
Signed-off-by: Damien George <damien@micropython.org>
-rw-r--r--ports/alif/mpconfigport.h6
-rw-r--r--ports/alif/mphalport.c16
-rw-r--r--ports/alif/system_tick.c64
-rw-r--r--ports/alif/system_tick.h2
4 files changed, 82 insertions, 6 deletions
diff --git a/ports/alif/mpconfigport.h b/ports/alif/mpconfigport.h
index b1a019106..0fee2c379 100644
--- a/ports/alif/mpconfigport.h
+++ b/ports/alif/mpconfigport.h
@@ -37,10 +37,14 @@
#endif
// Select the low-level system tick implementation.
-#if !defined(MICROPY_HW_SYSTEM_TICK_USE_LPTIMER) \
+#if !defined(MICROPY_HW_SYSTEM_TICK_USE_SYSTICK) \
+ && !defined(MICROPY_HW_SYSTEM_TICK_USE_LPTIMER) \
&& !defined(MICROPY_HW_SYSTEM_TICK_USE_UTIMER)
#define MICROPY_HW_SYSTEM_TICK_USE_UTIMER (1)
#endif
+#if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
+#define MICROPY_SOFT_TIMER_TICKS_MS system_tick_ms_counter
+#endif
#ifndef MICROPY_HW_ENABLE_OSPI
#define MICROPY_HW_ENABLE_OSPI (CORE_M55_HP)
diff --git a/ports/alif/mphalport.c b/ports/alif/mphalport.c
index becac8f3b..5e3dad141 100644
--- a/ports/alif/mphalport.c
+++ b/ports/alif/mphalport.c
@@ -120,7 +120,9 @@ mp_uint_t mp_hal_ticks_cpu(void) {
mp_uint_t mp_hal_ticks_us(void) {
// Convert system tick to microsecond counter.
- #if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
+ #if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
+ return system_tick_get_u64();
+ #elif MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
return system_tick_get_u64() * 1000000 / system_tick_source_hz;
#else
return system_tick_get_u64() / system_core_clock_mhz;
@@ -129,7 +131,9 @@ mp_uint_t mp_hal_ticks_us(void) {
mp_uint_t mp_hal_ticks_ms(void) {
// Convert system tick to millisecond counter.
- #if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
+ #if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
+ return system_tick_get_u64() / 1000ULL;
+ #elif MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
return system_tick_get_u64() * 1000ULL / system_tick_source_hz;
#else
return system_tick_get_u64() / (SystemCoreClock / 1000);
@@ -137,7 +141,9 @@ mp_uint_t mp_hal_ticks_ms(void) {
}
void mp_hal_delay_us(mp_uint_t us) {
- #if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
+ #if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
+ uint64_t ticks_delay = (uint64_t)us;
+ #elif MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
uint64_t ticks_delay = (uint64_t)us * system_tick_source_hz / 1000000;
#else
uint64_t ticks_delay = (uint64_t)us * system_core_clock_mhz;
@@ -167,6 +173,8 @@ void system_tick_schedule_callback(void) {
pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler);
}
+#if !defined(MICROPY_SOFT_TIMER_TICKS_MS)
+
uint32_t soft_timer_get_ms(void) {
return mp_hal_ticks_ms();
}
@@ -177,3 +185,5 @@ void soft_timer_schedule_at_ms(uint32_t ticks_ms) {
ms = MIN(ms, 4000000); // ensure ms * 1000 doesn't overflow
system_tick_schedule_after_us(ms * 1000);
}
+
+#endif
diff --git a/ports/alif/system_tick.c b/ports/alif/system_tick.c
index 72b8d021c..4f161e670 100644
--- a/ports/alif/system_tick.c
+++ b/ports/alif/system_tick.c
@@ -29,7 +29,69 @@
#define MIN(x, y) ((x) < (y) ? (x) : (y))
-#if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
+#if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
+
+#include "shared/runtime/softtimer.h"
+#include "pendsv.h"
+
+volatile uint32_t system_tick_ms_counter;
+
+void system_tick_init(void) {
+ // Configure SysTick to run at 1kHz (1ms interval)
+ SysTick_Config(SystemCoreClock / 1000);
+ NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTEM_TICK);
+ NVIC_EnableIRQ(SysTick_IRQn);
+}
+
+void SysTick_Handler(void) {
+ uint32_t uw_tick = system_tick_ms_counter + 1;
+ system_tick_ms_counter = uw_tick;
+
+ // Read the systick control register to clear the COUNTFLAG bit.
+ SysTick->CTRL;
+
+ if (soft_timer_next == uw_tick) {
+ pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler);
+ }
+}
+
+uint32_t system_tick_get_u32(void) {
+ return system_tick_get_u64();
+}
+
+uint64_t system_tick_get_u64(void) {
+ mp_uint_t irq_state = disable_irq();
+ uint32_t counter = SysTick->VAL;
+ uint32_t milliseconds = system_tick_ms_counter;
+ uint32_t status = SysTick->CTRL;
+ enable_irq(irq_state);
+
+ // It's still possible for the COUNTFLAG bit to get set if the counter was
+ // reloaded between reading VAL and reading CTRL. With interrupts disabled
+ // it definitely takes less than 50 cycles between reading VAL and
+ // reading CTRL, so the test (counter > 50) is to cover the case where VAL
+ // is +ve and very close to zero, and the COUNTFLAG bit is also set.
+ if ((status & SysTick_CTRL_COUNTFLAG_Msk) && counter > 50) {
+ // This means that the HW reloaded VAL between the time we read VAL and the
+ // time we read CTRL, which implies that there is an interrupt pending
+ // to increment the tick counter.
+ milliseconds++;
+ }
+ uint32_t load = SysTick->LOAD;
+ counter = load - counter; // Convert from decrementing to incrementing
+
+ // Calculate 64-bit microsecond counter.
+ return (uint64_t)milliseconds * 1000ULL + (uint64_t)((counter * 1000) / (load + 1));
+}
+
+void system_tick_wfe_with_timeout_us(uint32_t timeout_us) {
+ if (timeout_us > 1000) {
+ // SysTick will wake us in at most 1ms.
+ __WFI();
+ }
+}
+
+#elif MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
#include "lptimer.h"
#include "sys_ctrl_lptimer.h"
diff --git a/ports/alif/system_tick.h b/ports/alif/system_tick.h
index d808b7632..a380808b2 100644
--- a/ports/alif/system_tick.h
+++ b/ports/alif/system_tick.h
@@ -30,7 +30,7 @@
#if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
extern uint64_t system_tick_source_hz;
-#else
+#elif MICROPY_HW_SYSTEM_TICK_USE_UTIMER
extern uint64_t system_core_clock_mhz;
#endif