diff options
| author | Damien George <damien@micropython.org> | 2024-01-10 14:37:52 +1100 |
|---|---|---|
| committer | Damien George <damien@micropython.org> | 2025-04-09 00:22:32 +1000 |
| commit | 40ff0c2f276883ea325ce8977453bd16a2f2029a (patch) | |
| tree | a13aafcb71a33dd85f61a6291accdd043ed83785 | |
| parent | ccc5935234bbef026db776ebeb83a94f353e7d6b (diff) | |
alif/system_tick: Use a UTIMER for system ticks and timing.
Includes an implementation of `system_tick_wfe_with_timeout_us()`.
Signed-off-by: Damien George <damien@micropython.org>
| -rw-r--r-- | ports/alif/Makefile | 2 | ||||
| -rw-r--r-- | ports/alif/main.c | 3 | ||||
| -rw-r--r-- | ports/alif/mphalport.c | 36 | ||||
| -rw-r--r-- | ports/alif/system_tick.c | 128 | ||||
| -rw-r--r-- | ports/alif/system_tick.h | 38 |
5 files changed, 184 insertions, 23 deletions
diff --git a/ports/alif/Makefile b/ports/alif/Makefile index 2863ebe2c..cd02f4ac2 100644 --- a/ports/alif/Makefile +++ b/ports/alif/Makefile @@ -119,6 +119,7 @@ SRC_C = \ msc_disk.c \ ospi_flash.c \ pendsv.c \ + system_tick.c \ usbd.c \ $(wildcard $(BOARD_DIR)/*.c) @@ -175,6 +176,7 @@ ALIF_SRC_C += $(addprefix $(ALIF_DFP_REL_TOP)/,\ Device/core/$(MCU_CORE)/source/startup_$(MCU_CORE).c \ drivers/source/pinconf.c \ drivers/source/uart.c \ + drivers/source/utimer.c \ ospi_xip/source/ospi/ospi_drv.c \ ) diff --git a/ports/alif/main.c b/ports/alif/main.c index 0eb43a382..9293d74c0 100644 --- a/ports/alif/main.c +++ b/ports/alif/main.c @@ -38,6 +38,7 @@ #include "mpuart.h" #include "ospi_flash.h" #include "pendsv.h" +#include "system_tick.h" extern uint8_t __StackTop, __StackLimit; extern uint8_t __GcHeapStart, __GcHeapEnd; @@ -53,7 +54,7 @@ NORETURN void panic(const char *msg) { } void _start(void) { - SysTick_Config(SystemCoreClock / 1000); + system_tick_init(); MICROPY_BOARD_STARTUP(); diff --git a/ports/alif/mphalport.c b/ports/alif/mphalport.c index b433aa5e1..abb71aae6 100644 --- a/ports/alif/mphalport.c +++ b/ports/alif/mphalport.c @@ -36,6 +36,7 @@ #include "shared/tinyusb/mp_usbd_cdc.h" #include "tusb.h" #include "mpuart.h" +#include "system_tick.h" #ifndef MICROPY_HW_STDIN_BUFFER_LEN #define MICROPY_HW_STDIN_BUFFER_LEN 512 @@ -109,42 +110,33 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) { return did_write ? ret : 0; } -static uint32_t volatile ticks_ms; - -void SysTick_Handler(void) { - ++ticks_ms; -} - mp_uint_t mp_hal_ticks_cpu(void) { - if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - #if defined(__CORTEX_M) && __CORTEX_M == 7 - // on Cortex-M7 we must unlock the DWT before writing to its registers - DWT->LAR = 0xc5acce55; - #endif - DWT->CYCCNT = 0; - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - } - return DWT->CYCCNT; + return system_tick_get_u32(); } mp_uint_t mp_hal_ticks_us(void) { - return ticks_ms / 1000; + // Convert system tick to microsecond counter. + return system_tick_get_u64() / system_core_clock_mhz; } mp_uint_t mp_hal_ticks_ms(void) { - return ticks_ms; + // Convert system tick to millisecond counter. + return system_tick_get_u64() / (SystemCoreClock / 1000); } void mp_hal_delay_us(mp_uint_t us) { - mp_hal_delay_ms(us / 1000); + uint64_t ticks_delay = (uint64_t)us * system_core_clock_mhz; + uint64_t start = system_tick_get_u64(); + while (system_tick_get_u64() - start < ticks_delay) { + } } void mp_hal_delay_ms(mp_uint_t ms) { uint32_t t0 = mp_hal_ticks_ms(); - while ((mp_hal_ticks_ms() - t0) < ms) { - __WFI(); - } + do { + // TODO: power saving wait + mp_event_handle_nowait(); + } while (mp_hal_ticks_ms() - t0 < ms); } uint64_t mp_hal_time_ns(void) { diff --git a/ports/alif/system_tick.c b/ports/alif/system_tick.c new file mode 100644 index 000000000..95d5391c0 --- /dev/null +++ b/ports/alif/system_tick.c @@ -0,0 +1,128 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 OpenMV LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "irq.h" +#include "system_tick.h" + +#include "utimer.h" + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define UTIMER ((UTIMER_Type *)UTIMER_BASE) +#define UTIMER_CHANNEL (11) + +uint64_t system_core_clock_mhz; +static volatile uint32_t system_tick_hi; + +static void system_tick_nvic_config(unsigned int index) { + NVIC_ClearPendingIRQ(UTIMER_IRQ0_IRQn + UTIMER_CHANNEL * 8 + index); + NVIC_SetPriority(UTIMER_IRQ0_IRQn + UTIMER_CHANNEL * 8 + index, IRQ_PRI_SYSTEM_TICK); + NVIC_EnableIRQ(UTIMER_IRQ0_IRQn + UTIMER_CHANNEL * 8 + index); +} + +void system_tick_init(void) { + system_tick_hi = 0; + system_core_clock_mhz = SystemCoreClock / 1000000; + + // Configure NVIC OVER_FLOW interrupt. + system_tick_nvic_config(7); + + utimer_clock_enable(UTIMER, UTIMER_CHANNEL); + utimer_channel_config cfg = { 0 }; + cfg.fixed_buffer = false; + utimer_config_direction(UTIMER, UTIMER_CHANNEL, UTIMER_COUNTER_UP, &cfg); + utimer_set_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR_PTR, 0xffffffff); + utimer_unmask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_OVER_FLOW_MASK); + utimer_control_enable(UTIMER, UTIMER_CHANNEL); + utimer_counter_start(UTIMER, UTIMER_CHANNEL); + + // Set up the UTIMER compare interrupt, to be used later. + system_tick_nvic_config(2); + UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_COMPARE_CTRL_A |= COMPARE_CTRL_DRV_COMPARE_EN; +} + +// COMPARE_A_BUF1 +void UTIMER_IRQ90Handler(void) { + uint32_t chan_interrupt = UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_CHAN_INTERRUPT; + if (chan_interrupt & CHAN_INTERRUPT_COMPARE_A_BUF1_MASK) { + utimer_clear_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_A_BUF1_MASK); + __SEV(); + } +} + +// OVER_FLOW +void UTIMER_IRQ95Handler(void) { + uint32_t chan_interrupt = UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_CHAN_INTERRUPT; + if (chan_interrupt & CHAN_INTERRUPT_OVER_FLOW_MASK) { + utimer_clear_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_OVER_FLOW_MASK); + ++system_tick_hi; + } +} + +uint32_t system_tick_get_u32(void) { + return utimer_get_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR); +} + +uint64_t system_tick_get_u64(void) { + uint32_t irq_state = disable_irq(); + uint32_t ticks_lo = utimer_get_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR); + uint32_t ticks_hi = system_tick_hi; + uint32_t chan_interrupt = UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_CHAN_INTERRUPT; + enable_irq(irq_state); + + if (chan_interrupt & CHAN_INTERRUPT_OVER_FLOW_MASK) { + // The timer had an overflow while interrupts were disabled. + if (ticks_lo < 0x80000000) { + // The timer had an overflow just before we sampled it. + ++ticks_hi; + } + } + + // This ticks runs at SystemCoreClock. + return (uint64_t)ticks_hi << 32 | ticks_lo; +} + +void system_tick_wfe_with_timeout_us(uint32_t timeout_us) { + // Maximum 10 second timeout, to not overflow signed 32-bit ticks when + // system_core_clock_mhz==400. + uint32_t timeout_ticks = MIN(timeout_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_A_BUF1, cntr + timeout_ticks); + utimer_clear_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_A_BUF1_MASK); + utimer_unmask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_A_BUF1_MASK); + + // Wait for an event (or compare timeout event) if the timeout hasn't expired yet + // (this check handles the case of short timeouts). + uint32_t cntr2 = utimer_get_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR); + if ((uint32_t)(cntr2 - cntr) < timeout_ticks) { + __WFE(); + } + + // Disable the UTIMER compare interrupt. + utimer_mask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_A_BUF1_MASK); +} diff --git a/ports/alif/system_tick.h b/ports/alif/system_tick.h new file mode 100644 index 000000000..307c87a34 --- /dev/null +++ b/ports/alif/system_tick.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 OpenMV LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ALIF_SYSTEM_TICK_H +#define MICROPY_INCLUDED_ALIF_SYSTEM_TICK_H + +#include <stdint.h> + +extern uint64_t system_core_clock_mhz; + +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); + +#endif // MICROPY_INCLUDED_ALIF_SYSTEM_TICK_H |
