Skip to content

Commit c6ebecc

Browse files
committed
alif/system_tick: Implement optional ARM SysTick support for systick.
Signed-off-by: Damien George <damien@micropython.org>
1 parent bbb8fd7 commit c6ebecc

4 files changed

Lines changed: 82 additions & 6 deletions

File tree

ports/alif/mpconfigport.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,14 @@
3737
#endif
3838

3939
// Select the low-level system tick implementation.
40-
#if !defined(MICROPY_HW_SYSTEM_TICK_USE_LPTIMER) \
40+
#if !defined(MICROPY_HW_SYSTEM_TICK_USE_SYSTICK) \
41+
&& !defined(MICROPY_HW_SYSTEM_TICK_USE_LPTIMER) \
4142
&& !defined(MICROPY_HW_SYSTEM_TICK_USE_UTIMER)
4243
#define MICROPY_HW_SYSTEM_TICK_USE_UTIMER (1)
4344
#endif
45+
#if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
46+
#define MICROPY_SOFT_TIMER_TICKS_MS system_tick_ms_counter
47+
#endif
4448

4549
#ifndef MICROPY_HW_ENABLE_OSPI
4650
#define MICROPY_HW_ENABLE_OSPI (CORE_M55_HP)

ports/alif/mphalport.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ mp_uint_t mp_hal_ticks_cpu(void) {
120120

121121
mp_uint_t mp_hal_ticks_us(void) {
122122
// Convert system tick to microsecond counter.
123-
#if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
123+
#if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
124+
return system_tick_get_u64();
125+
#elif MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
124126
return system_tick_get_u64() * 1000000 / system_tick_source_hz;
125127
#else
126128
return system_tick_get_u64() / system_core_clock_mhz;
@@ -129,15 +131,19 @@ mp_uint_t mp_hal_ticks_us(void) {
129131

130132
mp_uint_t mp_hal_ticks_ms(void) {
131133
// Convert system tick to millisecond counter.
132-
#if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
134+
#if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
135+
return system_tick_get_u64() / 1000ULL;
136+
#elif MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
133137
return system_tick_get_u64() * 1000ULL / system_tick_source_hz;
134138
#else
135139
return system_tick_get_u64() / (SystemCoreClock / 1000);
136140
#endif
137141
}
138142

139143
void mp_hal_delay_us(mp_uint_t us) {
140-
#if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
144+
#if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
145+
uint64_t ticks_delay = (uint64_t)us;
146+
#elif MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
141147
uint64_t ticks_delay = (uint64_t)us * system_tick_source_hz / 1000000;
142148
#else
143149
uint64_t ticks_delay = (uint64_t)us * system_core_clock_mhz;
@@ -167,6 +173,8 @@ void system_tick_schedule_callback(void) {
167173
pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler);
168174
}
169175

176+
#if !defined(MICROPY_SOFT_TIMER_TICKS_MS)
177+
170178
uint32_t soft_timer_get_ms(void) {
171179
return mp_hal_ticks_ms();
172180
}
@@ -177,3 +185,5 @@ void soft_timer_schedule_at_ms(uint32_t ticks_ms) {
177185
ms = MIN(ms, 4000000); // ensure ms * 1000 doesn't overflow
178186
system_tick_schedule_after_us(ms * 1000);
179187
}
188+
189+
#endif

ports/alif/system_tick.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,69 @@
2929

3030
#define MIN(x, y) ((x) < (y) ? (x) : (y))
3131

32-
#if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
32+
#if MICROPY_HW_SYSTEM_TICK_USE_SYSTICK
33+
34+
#include "shared/runtime/softtimer.h"
35+
#include "pendsv.h"
36+
37+
volatile uint32_t system_tick_ms_counter;
38+
39+
void system_tick_init(void) {
40+
// Configure SysTick to run at 1kHz (1ms interval)
41+
SysTick_Config(SystemCoreClock / 1000);
42+
NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTEM_TICK);
43+
NVIC_EnableIRQ(SysTick_IRQn);
44+
}
45+
46+
void SysTick_Handler(void) {
47+
uint32_t uw_tick = system_tick_ms_counter + 1;
48+
system_tick_ms_counter = uw_tick;
49+
50+
// Read the systick control register to clear the COUNTFLAG bit.
51+
SysTick->CTRL;
52+
53+
if (soft_timer_next == uw_tick) {
54+
pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler);
55+
}
56+
}
57+
58+
uint32_t system_tick_get_u32(void) {
59+
return system_tick_get_u64();
60+
}
61+
62+
uint64_t system_tick_get_u64(void) {
63+
mp_uint_t irq_state = disable_irq();
64+
uint32_t counter = SysTick->VAL;
65+
uint32_t milliseconds = system_tick_ms_counter;
66+
uint32_t status = SysTick->CTRL;
67+
enable_irq(irq_state);
68+
69+
// It's still possible for the COUNTFLAG bit to get set if the counter was
70+
// reloaded between reading VAL and reading CTRL. With interrupts disabled
71+
// it definitely takes less than 50 cycles between reading VAL and
72+
// reading CTRL, so the test (counter > 50) is to cover the case where VAL
73+
// is +ve and very close to zero, and the COUNTFLAG bit is also set.
74+
if ((status & SysTick_CTRL_COUNTFLAG_Msk) && counter > 50) {
75+
// This means that the HW reloaded VAL between the time we read VAL and the
76+
// time we read CTRL, which implies that there is an interrupt pending
77+
// to increment the tick counter.
78+
milliseconds++;
79+
}
80+
uint32_t load = SysTick->LOAD;
81+
counter = load - counter; // Convert from decrementing to incrementing
82+
83+
// Calculate 64-bit microsecond counter.
84+
return (uint64_t)milliseconds * 1000ULL + (uint64_t)((counter * 1000) / (load + 1));
85+
}
86+
87+
void system_tick_wfe_with_timeout_us(uint32_t timeout_us) {
88+
if (timeout_us > 1000) {
89+
// SysTick will wake us in at most 1ms.
90+
__WFI();
91+
}
92+
}
93+
94+
#elif MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
3395

3496
#include "lptimer.h"
3597
#include "sys_ctrl_lptimer.h"

ports/alif/system_tick.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
#if MICROPY_HW_SYSTEM_TICK_USE_LPTIMER
3232
extern uint64_t system_tick_source_hz;
33-
#else
33+
#elif MICROPY_HW_SYSTEM_TICK_USE_UTIMER
3434
extern uint64_t system_core_clock_mhz;
3535
#endif
3636

0 commit comments

Comments
 (0)