summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2024-01-10 14:37:52 +1100
committerDamien George <damien@micropython.org>2025-04-09 00:22:32 +1000
commit40ff0c2f276883ea325ce8977453bd16a2f2029a (patch)
treea13aafcb71a33dd85f61a6291accdd043ed83785
parentccc5935234bbef026db776ebeb83a94f353e7d6b (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/Makefile2
-rw-r--r--ports/alif/main.c3
-rw-r--r--ports/alif/mphalport.c36
-rw-r--r--ports/alif/system_tick.c128
-rw-r--r--ports/alif/system_tick.h38
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