diff --git a/pycardium/mphalport.c b/pycardium/mphalport.c index 60cd9df0cdf1e08a01ffd3df84772d9c6276e7ac..61ea9def213de5f4a9f87f727a5b394272d11e60 100644 --- a/pycardium/mphalport.c +++ b/pycardium/mphalport.c @@ -31,6 +31,17 @@ void pycardium_hal_init(void) * a character becomes available. */ epic_interrupt_enable(EPIC_INT_UART_RX); + + /* + * Configure SysTick timer. + * + * Reload is configured for 80ms. This seems to be a reasonable value + * to allow at least some sleep for common sleep times in apps. + */ + SysTick->LOAD = 7679999 & SysTick_LOAD_RELOAD_Msk; + SysTick->VAL = 1; + SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk; } /****************************************************************************** @@ -124,16 +135,80 @@ void mp_hal_set_interrupt_char(char c) * Time & Delay */ +static volatile uint32_t delay_overflows = 0; + +/* + * A delay implementation based on the SysTick timer. + */ +static void systick_delay_us(uint32_t us) +{ + if (us == 0) { + return; + } + + uint32_t starttick = SysTick->VAL; + uint32_t ticks = (uint32_t)( + ((uint64_t)us * (uint64_t)SystemCoreClock) / 1000000 + ); + uint32_t reload = SysTick->LOAD + 1; + delay_overflows = ticks / reload; + uint32_t lasttick = ticks % reload; + + uint32_t endtick; + if (lasttick >= starttick) { + delay_overflows += 1; + endtick = reload - (lasttick - starttick); + } else { + endtick = starttick - lasttick; + } + + while (delay_overflows > 0) { + mp_handle_pending(); + /* + * Overflow triggers the SysTick interrupt so we can sleep here. + * + * Note that this does **not** apply to the while-loop following + * this one. + */ + __WFI(); + } + + while (SysTick->VAL > endtick) { + mp_handle_pending(); + } +} + +/* + * Interrupt handler needed for delay implementation. If we ever define a more + * sophisticated SysTick_Handler, make sure to include a call to this function! + */ +static void systick_delay_handler(void) +{ + if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + if (delay_overflows > 0) { + delay_overflows--; + } + } +} + +/* HAL function for MicroPython */ void mp_hal_delay_ms(mp_uint_t ms) { - mxc_delay(ms * 1000); + systick_delay_us(ms * 1000); } +/* HAL function for MicroPython */ void mp_hal_delay_us(mp_uint_t us) { - mxc_delay(us); + systick_delay_us(us); } +/* + * HAL function for MicroPython + * + * This function is not really used except in a debug code-path of + * `parse_compile_execute`. Thus we need to define it as a stub. + */ mp_uint_t mp_hal_ticks_ms(void) { return 0; @@ -163,3 +238,12 @@ int mp_hal_trng_read_int(void) epic_trng_read((uint8_t *)&result, sizeof(result)); return result; } + +/****************************************************************************** + * SysTick Handler + */ +void SysTick_Handler(void) +{ + /* Needed for delay implementation */ + systick_delay_handler(); +}