Skip to content

Commit 40ff0c2

Browse files
committed
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>
1 parent ccc5935 commit 40ff0c2

5 files changed

Lines changed: 184 additions & 23 deletions

File tree

ports/alif/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ SRC_C = \
119119
msc_disk.c \
120120
ospi_flash.c \
121121
pendsv.c \
122+
system_tick.c \
122123
usbd.c \
123124
$(wildcard $(BOARD_DIR)/*.c)
124125

@@ -175,6 +176,7 @@ ALIF_SRC_C += $(addprefix $(ALIF_DFP_REL_TOP)/,\
175176
Device/core/$(MCU_CORE)/source/startup_$(MCU_CORE).c \
176177
drivers/source/pinconf.c \
177178
drivers/source/uart.c \
179+
drivers/source/utimer.c \
178180
ospi_xip/source/ospi/ospi_drv.c \
179181
)
180182

ports/alif/main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "mpuart.h"
3939
#include "ospi_flash.h"
4040
#include "pendsv.h"
41+
#include "system_tick.h"
4142

4243
extern uint8_t __StackTop, __StackLimit;
4344
extern uint8_t __GcHeapStart, __GcHeapEnd;
@@ -53,7 +54,7 @@ NORETURN void panic(const char *msg) {
5354
}
5455

5556
void _start(void) {
56-
SysTick_Config(SystemCoreClock / 1000);
57+
system_tick_init();
5758

5859
MICROPY_BOARD_STARTUP();
5960

ports/alif/mphalport.c

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "shared/tinyusb/mp_usbd_cdc.h"
3737
#include "tusb.h"
3838
#include "mpuart.h"
39+
#include "system_tick.h"
3940

4041
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
4142
#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) {
109110
return did_write ? ret : 0;
110111
}
111112

112-
static uint32_t volatile ticks_ms;
113-
114-
void SysTick_Handler(void) {
115-
++ticks_ms;
116-
}
117-
118113
mp_uint_t mp_hal_ticks_cpu(void) {
119-
if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) {
120-
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
121-
#if defined(__CORTEX_M) && __CORTEX_M == 7
122-
// on Cortex-M7 we must unlock the DWT before writing to its registers
123-
DWT->LAR = 0xc5acce55;
124-
#endif
125-
DWT->CYCCNT = 0;
126-
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
127-
}
128-
return DWT->CYCCNT;
114+
return system_tick_get_u32();
129115
}
130116

131117
mp_uint_t mp_hal_ticks_us(void) {
132-
return ticks_ms / 1000;
118+
// Convert system tick to microsecond counter.
119+
return system_tick_get_u64() / system_core_clock_mhz;
133120
}
134121

135122
mp_uint_t mp_hal_ticks_ms(void) {
136-
return ticks_ms;
123+
// Convert system tick to millisecond counter.
124+
return system_tick_get_u64() / (SystemCoreClock / 1000);
137125
}
138126

139127
void mp_hal_delay_us(mp_uint_t us) {
140-
mp_hal_delay_ms(us / 1000);
128+
uint64_t ticks_delay = (uint64_t)us * system_core_clock_mhz;
129+
uint64_t start = system_tick_get_u64();
130+
while (system_tick_get_u64() - start < ticks_delay) {
131+
}
141132
}
142133

143134
void mp_hal_delay_ms(mp_uint_t ms) {
144135
uint32_t t0 = mp_hal_ticks_ms();
145-
while ((mp_hal_ticks_ms() - t0) < ms) {
146-
__WFI();
147-
}
136+
do {
137+
// TODO: power saving wait
138+
mp_event_handle_nowait();
139+
} while (mp_hal_ticks_ms() - t0 < ms);
148140
}
149141

150142
uint64_t mp_hal_time_ns(void) {

ports/alif/system_tick.c

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2024 OpenMV LLC.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "irq.h"
28+
#include "system_tick.h"
29+
30+
#include "utimer.h"
31+
32+
#define MIN(x, y) ((x) < (y) ? (x) : (y))
33+
34+
#define UTIMER ((UTIMER_Type *)UTIMER_BASE)
35+
#define UTIMER_CHANNEL (11)
36+
37+
uint64_t system_core_clock_mhz;
38+
static volatile uint32_t system_tick_hi;
39+
40+
static void system_tick_nvic_config(unsigned int index) {
41+
NVIC_ClearPendingIRQ(UTIMER_IRQ0_IRQn + UTIMER_CHANNEL * 8 + index);
42+
NVIC_SetPriority(UTIMER_IRQ0_IRQn + UTIMER_CHANNEL * 8 + index, IRQ_PRI_SYSTEM_TICK);
43+
NVIC_EnableIRQ(UTIMER_IRQ0_IRQn + UTIMER_CHANNEL * 8 + index);
44+
}
45+
46+
void system_tick_init(void) {
47+
system_tick_hi = 0;
48+
system_core_clock_mhz = SystemCoreClock / 1000000;
49+
50+
// Configure NVIC OVER_FLOW interrupt.
51+
system_tick_nvic_config(7);
52+
53+
utimer_clock_enable(UTIMER, UTIMER_CHANNEL);
54+
utimer_channel_config cfg = { 0 };
55+
cfg.fixed_buffer = false;
56+
utimer_config_direction(UTIMER, UTIMER_CHANNEL, UTIMER_COUNTER_UP, &cfg);
57+
utimer_set_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR_PTR, 0xffffffff);
58+
utimer_unmask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_OVER_FLOW_MASK);
59+
utimer_control_enable(UTIMER, UTIMER_CHANNEL);
60+
utimer_counter_start(UTIMER, UTIMER_CHANNEL);
61+
62+
// Set up the UTIMER compare interrupt, to be used later.
63+
system_tick_nvic_config(2);
64+
UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_COMPARE_CTRL_A |= COMPARE_CTRL_DRV_COMPARE_EN;
65+
}
66+
67+
// COMPARE_A_BUF1
68+
void UTIMER_IRQ90Handler(void) {
69+
uint32_t chan_interrupt = UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_CHAN_INTERRUPT;
70+
if (chan_interrupt & CHAN_INTERRUPT_COMPARE_A_BUF1_MASK) {
71+
utimer_clear_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_A_BUF1_MASK);
72+
__SEV();
73+
}
74+
}
75+
76+
// OVER_FLOW
77+
void UTIMER_IRQ95Handler(void) {
78+
uint32_t chan_interrupt = UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_CHAN_INTERRUPT;
79+
if (chan_interrupt & CHAN_INTERRUPT_OVER_FLOW_MASK) {
80+
utimer_clear_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_OVER_FLOW_MASK);
81+
++system_tick_hi;
82+
}
83+
}
84+
85+
uint32_t system_tick_get_u32(void) {
86+
return utimer_get_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR);
87+
}
88+
89+
uint64_t system_tick_get_u64(void) {
90+
uint32_t irq_state = disable_irq();
91+
uint32_t ticks_lo = utimer_get_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR);
92+
uint32_t ticks_hi = system_tick_hi;
93+
uint32_t chan_interrupt = UTIMER->UTIMER_CHANNEL_CFG[UTIMER_CHANNEL].UTIMER_CHAN_INTERRUPT;
94+
enable_irq(irq_state);
95+
96+
if (chan_interrupt & CHAN_INTERRUPT_OVER_FLOW_MASK) {
97+
// The timer had an overflow while interrupts were disabled.
98+
if (ticks_lo < 0x80000000) {
99+
// The timer had an overflow just before we sampled it.
100+
++ticks_hi;
101+
}
102+
}
103+
104+
// This ticks runs at SystemCoreClock.
105+
return (uint64_t)ticks_hi << 32 | ticks_lo;
106+
}
107+
108+
void system_tick_wfe_with_timeout_us(uint32_t timeout_us) {
109+
// Maximum 10 second timeout, to not overflow signed 32-bit ticks when
110+
// system_core_clock_mhz==400.
111+
uint32_t timeout_ticks = MIN(timeout_us, 10000000) * system_core_clock_mhz;
112+
113+
// Set up the UTIMER compare interrupt to fire after the given timeout.
114+
uint32_t cntr = utimer_get_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR);
115+
utimer_set_count(UTIMER, UTIMER_CHANNEL, UTIMER_COMPARE_A_BUF1, cntr + timeout_ticks);
116+
utimer_clear_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_A_BUF1_MASK);
117+
utimer_unmask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_A_BUF1_MASK);
118+
119+
// Wait for an event (or compare timeout event) if the timeout hasn't expired yet
120+
// (this check handles the case of short timeouts).
121+
uint32_t cntr2 = utimer_get_count(UTIMER, UTIMER_CHANNEL, UTIMER_CNTR);
122+
if ((uint32_t)(cntr2 - cntr) < timeout_ticks) {
123+
__WFE();
124+
}
125+
126+
// Disable the UTIMER compare interrupt.
127+
utimer_mask_interrupt(UTIMER, UTIMER_CHANNEL, CHAN_INTERRUPT_COMPARE_A_BUF1_MASK);
128+
}

ports/alif/system_tick.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2024 OpenMV LLC.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
#ifndef MICROPY_INCLUDED_ALIF_SYSTEM_TICK_H
27+
#define MICROPY_INCLUDED_ALIF_SYSTEM_TICK_H
28+
29+
#include <stdint.h>
30+
31+
extern uint64_t system_core_clock_mhz;
32+
33+
void system_tick_init(void);
34+
uint32_t system_tick_get_u32(void);
35+
uint64_t system_tick_get_u64(void);
36+
void system_tick_wfe_with_timeout_us(uint32_t timeout_us);
37+
38+
#endif // MICROPY_INCLUDED_ALIF_SYSTEM_TICK_H

0 commit comments

Comments
 (0)