alif/system_tick: Integrate soft timer.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George 2024-01-10 23:41:00 +11:00
parent 975f84f2ad
commit ada0939c5f
4 changed files with 63 additions and 2 deletions

View file

@ -33,6 +33,7 @@
#include "shared/readline/readline.h"
#include "shared/runtime/gchelper.h"
#include "shared/runtime/pyexec.h"
#include "shared/runtime/softtimer.h"
#include "shared/tinyusb/mp_usbd.h"
#include "tusb.h"
#include "mpuart.h"
@ -119,6 +120,7 @@ void _start(void) {
soft_reset_exit:
mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
soft_timer_deinit();
gc_sweep_all();
mp_deinit();
}

View file

@ -31,11 +31,13 @@
#include "py/stream.h"
#include "extmod/misc.h"
#include "shared/runtime/interrupt_char.h"
#include "shared/runtime/softtimer.h"
#include "shared/timeutils/timeutils.h"
#include "shared/tinyusb/mp_usbd.h"
#include "shared/tinyusb/mp_usbd_cdc.h"
#include "tusb.h"
#include "mpuart.h"
#include "pendsv.h"
#include "system_tick.h"
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
@ -146,3 +148,18 @@ void mp_hal_delay_ms(mp_uint_t ms) {
uint64_t mp_hal_time_ns(void) {
return 0;
}
void system_tick_schedule_callback(void) {
pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler);
}
uint32_t soft_timer_get_ms(void) {
return mp_hal_ticks_ms();
}
void soft_timer_schedule_at_ms(uint32_t ticks_ms) {
int32_t ms = soft_timer_ticks_diff(ticks_ms, mp_hal_ticks_ms());
ms = MAX(0, ms);
ms = MIN(ms, 4000000); // ensure ms * 1000 doesn't overflow
system_tick_schedule_after_us(ms * 1000);
}

View file

@ -59,9 +59,13 @@ void system_tick_init(void) {
utimer_control_enable(UTIMER, UTIMER_CHANNEL);
utimer_counter_start(UTIMER, UTIMER_CHANNEL);
// Set up the UTIMER compare interrupt, to be used later.
// Set up the UTIMER compare A interrupt, to be used by system_tick_wfe_with_timeout_us.
system_tick_nvic_config(2);
UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_COMPARE_CTRL_A |= COMPARE_CTRL_DRV_COMPARE_EN;
// Set up the UTIMER compare B interrupt, to be used by soft-timer.
system_tick_nvic_config(4);
UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_COMPARE_CTRL_B |= COMPARE_CTRL_DRV_COMPARE_EN;
}
// COMPARE_A_BUF1
@ -73,6 +77,17 @@ void UTIMER_IRQ90Handler(void) {
}
}
// COMPARE_B_BUF1
void UTIMER_IRQ92Handler(void) {
uint32_t chan_interrupt = UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_CHAN_INTERRUPT;
if (chan_interrupt & CHAN_INTERRUPT_COMPARE_B_BUF1_MASK) {
utimer_clear_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_B_BUF1_MASK);
utimer_mask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_B_BUF1_MASK);
system_tick_schedule_callback();
__SEV();
}
}
// OVER_FLOW
void UTIMER_IRQ95Handler(void) {
uint32_t chan_interrupt = UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_CHAN_INTERRUPT;
@ -106,7 +121,7 @@ uint64_t system_tick_get_u64(void) {
}
void system_tick_wfe_with_timeout_us(uint32_t timeout_us) {
// Maximum 10 second timeout, to not overflow signed 32-bit ticks when
// Maximum 10 second timeout, to not overflow 32-bit ticks when
// system_core_clock_mhz==400.
uint32_t timeout_ticks = MIN(timeout_us, 10000000) * system_core_clock_mhz;
@ -126,3 +141,28 @@ void system_tick_wfe_with_timeout_us(uint32_t timeout_us) {
// Disable the UTIMER compare interrupt.
utimer_mask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_A_BUF1_MASK);
}
void system_tick_schedule_after_us(uint32_t ticks_us) {
// Disable the interrupt in case it's still active.
utimer_mask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_B_BUF1_MASK);
// Maximum 10 second timeout, to not overflow 32-bit ticks when
// system_core_clock_mhz==400.
uint32_t timeout_ticks = MIN(ticks_us, 10000000) * system_core_clock_mhz;
// Set up the UTIMER compare interrupt to fire after the given timeout.
uint32_t cntr = utimer_get_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR);
utimer_set_count(UTIMER, UTIMER_CHANNEL, UTIMER_COMPARE_B_BUF1, cntr + timeout_ticks);
utimer_clear_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_B_BUF1_MASK);
utimer_unmask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_B_BUF1_MASK);
// Handle the case of short timeouts.
uint32_t cntr2 = utimer_get_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR);
if ((uint32_t)(cntr2 - cntr) >= timeout_ticks) {
if (!(UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_CHAN_INTERRUPT_MASK & CHAN_INTERRUPT_COMPARE_B_BUF1_MASK)) {
// Interrupt is still enabled, so disable it and manually call the callback.
utimer_mask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_B_BUF1_MASK);
system_tick_schedule_callback();
}
}
}

View file

@ -34,5 +34,7 @@ void system_tick_init(void);
uint32_t system_tick_get_u32(void);
uint64_t system_tick_get_u64(void);
void system_tick_wfe_with_timeout_us(uint32_t timeout_us);
void system_tick_schedule_after_us(uint32_t ticks_us);
void system_tick_schedule_callback(void);
#endif // MICROPY_INCLUDED_ALIF_SYSTEM_TICK_H