Skip to content
Snippets Groups Projects
Commit 676fa2bc authored by rahix's avatar rahix
Browse files

fix(pycardium): Implement proper delays


The old delay implementation is based on `mxc_delay`, provided by the
SDK.  This implementation has issues, as details in #177.  To fix these
issues, `mxc_delay` is replaced with a re-implementation which polls the
MicroPython scheduler and calls `wfi` when we can safely sleep.

The SysTick timer is configured globally (on core 1) to tick every 80ms.
This seems to be a reasonable value to allow at least some `wfi`-sleep
in the bounds used by most apps.

Signed-off-by: default avatarRahix <rahix@rahix.de>
parent b4641dde
No related branches found
No related tags found
No related merge requests found
...@@ -31,6 +31,17 @@ void pycardium_hal_init(void) ...@@ -31,6 +31,17 @@ void pycardium_hal_init(void)
* a character becomes available. * a character becomes available.
*/ */
epic_interrupt_enable(EPIC_INT_UART_RX); 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) ...@@ -124,16 +135,80 @@ void mp_hal_set_interrupt_char(char c)
* Time & Delay * 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) 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) 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) mp_uint_t mp_hal_ticks_ms(void)
{ {
return 0; return 0;
...@@ -163,3 +238,12 @@ int mp_hal_trng_read_int(void) ...@@ -163,3 +238,12 @@ int mp_hal_trng_read_int(void)
epic_trng_read((uint8_t *)&result, sizeof(result)); epic_trng_read((uint8_t *)&result, sizeof(result));
return result; return result;
} }
/******************************************************************************
* SysTick Handler
*/
void SysTick_Handler(void)
{
/* Needed for delay implementation */
systick_delay_handler();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment