Skip to content

Commit 7408ca1

Browse files
committed
mimxrt: Improve ticks and sleep functions using GPT.
SysTick cannot wake the CPU from WFI/WFE so a hardware timer is needed to keep track of ticks/delay (similar to the nrf port). Fixes issue micropython#7234. Signed-off-by: Damien George <[email protected]>
1 parent 452fa3f commit 7408ca1

File tree

7 files changed

+189
-27
lines changed

7 files changed

+189
-27
lines changed

ports/mimxrt/Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ SRC_TINYUSB_IMX_C += \
8282
$(MCU_DIR)/project_template/clock_config.c \
8383
$(MCU_DIR)/drivers/fsl_clock.c \
8484
$(MCU_DIR)/drivers/fsl_gpio.c \
85+
$(MCU_DIR)/drivers/fsl_gpt.c \
8586
$(MCU_DIR)/drivers/fsl_common.c \
8687
$(MCU_DIR)/drivers/fsl_lpuart.c \
8788
$(MCU_DIR)/drivers/fsl_flexram.c \
@@ -90,6 +91,7 @@ SRC_C = \
9091
main.c \
9192
led.c \
9293
pin.c \
94+
ticks.c \
9395
tusb_port.c \
9496
board_init.c \
9597
$(BOARD_DIR)/flash_config.c \

ports/mimxrt/board_init.c

-7
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,6 @@ void board_init(void) {
5353
// Enable IOCON clock
5454
CLOCK_EnableClock(kCLOCK_Iomuxc);
5555

56-
// 1ms tick timer
57-
SysTick_Config(SystemCoreClock / 1000);
58-
5956
// ------------- USB0 ------------- //
6057

6158
// Clock
@@ -85,10 +82,6 @@ void board_init(void) {
8582
// CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
8683
}
8784

88-
void SysTick_Handler(void) {
89-
systick_ms++;
90-
}
91-
9285
void USB_OTG1_IRQHandler(void) {
9386
tud_int_handler(0);
9487
tud_task();

ports/mimxrt/main.c

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "py/stackctrl.h"
3333
#include "lib/utils/gchelper.h"
3434
#include "lib/utils/pyexec.h"
35+
#include "ticks.h"
3536
#include "tusb.h"
3637
#include "led.h"
3738

@@ -41,6 +42,7 @@ void board_init(void);
4142

4243
int main(void) {
4344
board_init();
45+
ticks_init();
4446
tusb_init();
4547
led_init();
4648

ports/mimxrt/mphalport.c

+1-16
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "py/runtime.h"
2929
#include "py/mphal.h"
30+
#include "ticks.h"
3031
#include "tusb.h"
3132

3233
#include CPU_HEADER_H
@@ -46,22 +47,6 @@ void mp_hal_set_interrupt_char(int c) {
4647

4748
#endif
4849

49-
void mp_hal_delay_ms(mp_uint_t ms) {
50-
ms += 1;
51-
uint32_t t0 = systick_ms;
52-
while (systick_ms - t0 < ms) {
53-
MICROPY_EVENT_POLL_HOOK
54-
}
55-
}
56-
57-
void mp_hal_delay_us(mp_uint_t us) {
58-
uint32_t ms = us / 1000 + 1;
59-
uint32_t t0 = systick_ms;
60-
while (systick_ms - t0 < ms) {
61-
__WFI();
62-
}
63-
}
64-
6550
int mp_hal_stdin_rx_chr(void) {
6651
for (;;) {
6752
// TODO

ports/mimxrt/mphalport.h

+12-4
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,29 @@
2828
#define MICROPY_INCLUDED_MIMXRT_MPHALPORT_H
2929

3030
#include <stdint.h>
31+
#include "ticks.h"
3132

3233
#define mp_hal_pin_high(p) (GPIO_PinWrite(p->gpio, p->pin, 1U))
3334
#define mp_hal_pin_low(p) (GPIO_PinWrite(p->gpio, p->pin, 0U))
3435
#define mp_hal_pin_toggle(p) (GPIO_PortToggle(p->gpio, (1 << p->pin)))
3536

36-
extern volatile uint32_t systick_ms;
37-
3837
void mp_hal_set_interrupt_char(int c);
3938

4039
static inline mp_uint_t mp_hal_ticks_ms(void) {
41-
return systick_ms;
40+
return ticks_ms32();
4241
}
4342

4443
static inline mp_uint_t mp_hal_ticks_us(void) {
45-
return systick_ms * 1000;
44+
return ticks_us32();
45+
}
46+
47+
static inline void mp_hal_delay_ms(mp_uint_t ms) {
48+
uint64_t us = (uint64_t)ms * 1000;
49+
ticks_delay_us64(us);
50+
}
51+
52+
static inline void mp_hal_delay_us(mp_uint_t us) {
53+
ticks_delay_us64(us);
4654
}
4755

4856
static inline mp_uint_t mp_hal_ticks_cpu(void) {

ports/mimxrt/ticks.c

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2021 Damien P. George
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 "py/mphal.h"
28+
#include "ticks.h"
29+
#include "fsl_gpt.h"
30+
31+
// General purpose timer for keeping microsecond and millisecond tick values.
32+
#define GPTx GPT2
33+
#define GPTx_IRQn GPT2_IRQn
34+
#define GPTx_IRQHandler GPT2_IRQHandler
35+
36+
static uint32_t ticks_us64_upper;
37+
static uint32_t ticks_ms_upper;
38+
39+
void ticks_init(void) {
40+
ticks_us64_upper = 0;
41+
ticks_ms_upper = 0;
42+
43+
gpt_config_t config;
44+
config.clockSource = kGPT_ClockSource_Osc;
45+
config.divider = 24; // XTAL is 24MHz
46+
config.enableFreeRun = true;
47+
config.enableRunInWait = true;
48+
config.enableRunInStop = true;
49+
config.enableRunInDoze = true;
50+
config.enableRunInDbg = false;
51+
config.enableMode = true;
52+
GPT_Init(GPTx, &config);
53+
54+
GPT_EnableInterrupts(GPTx, kGPT_RollOverFlagInterruptEnable);
55+
NVIC_SetPriority(GPTx_IRQn, 0); // highest priority
56+
NVIC_EnableIRQ(GPTx_IRQn);
57+
58+
GPT_StartTimer(GPTx);
59+
}
60+
61+
void GPTx_IRQHandler(void) {
62+
if (GPT_GetStatusFlags(GPTx, kGPT_OutputCompare1Flag)) {
63+
GPT_ClearStatusFlags(GPTx, kGPT_OutputCompare1Flag);
64+
GPT_DisableInterrupts(GPTx, kGPT_OutputCompare1InterruptEnable);
65+
__SEV();
66+
}
67+
if (GPT_GetStatusFlags(GPTx, kGPT_RollOverFlag)) {
68+
GPT_ClearStatusFlags(GPTx, kGPT_RollOverFlag);
69+
++ticks_us64_upper;
70+
if (++ticks_ms_upper >= 1000) {
71+
// Wrap upper counter at a multiple of 1000 so that when mp_hal_ticks_ms()
72+
// wraps due to overflow it wraps smoothly.
73+
ticks_ms_upper = 0;
74+
}
75+
}
76+
}
77+
78+
static void ticks_wake_after_us32(uint32_t us) {
79+
if (us < 2) {
80+
// Delay too short to guarantee that we won't miss it when setting the OCR below.
81+
__SEV();
82+
} else {
83+
// Disable IRQs so setting the OCR is done without any interruption.
84+
uint32_t irq_state = DisableGlobalIRQ();
85+
GPT_EnableInterrupts(GPTx, kGPT_OutputCompare1InterruptEnable);
86+
uint32_t oc = GPT_GetCurrentTimerCount(GPTx) + us;
87+
GPT_SetOutputCompareValue(GPTx, kGPT_OutputCompare_Channel1, oc);
88+
EnableGlobalIRQ(irq_state);
89+
}
90+
}
91+
92+
static uint64_t ticks_us64_with(uint32_t *upper_ptr) {
93+
uint32_t irq_state = DisableGlobalIRQ();
94+
uint32_t lower = GPT_GetCurrentTimerCount(GPTx);
95+
uint32_t upper = *upper_ptr;
96+
uint32_t overflow = GPT_GetStatusFlags(GPTx, kGPT_RollOverFlag);
97+
EnableGlobalIRQ(irq_state);
98+
if (overflow && lower < 0x80000000) {
99+
// The timer counter overflowed before reading it but the IRQ handler
100+
// has not yet been called, so perform the IRQ arithmetic now.
101+
++upper;
102+
}
103+
return (uint64_t)upper << 32 | (uint64_t)lower;
104+
}
105+
106+
uint32_t ticks_us32(void) {
107+
return GPT_GetCurrentTimerCount(GPTx);
108+
}
109+
110+
uint64_t ticks_us64(void) {
111+
return ticks_us64_with(&ticks_us64_upper);
112+
}
113+
114+
uint32_t ticks_ms32(void) {
115+
// This will return a value that only has the lower 32-bits valid.
116+
return ticks_us64_with(&ticks_ms_upper) / 1000;
117+
}
118+
119+
void ticks_delay_us64(uint64_t us) {
120+
uint64_t t0 = ticks_us64();
121+
for (;;) {
122+
uint64_t dt = ticks_us64() - t0;
123+
if (dt >= us) {
124+
return;
125+
}
126+
dt = us - dt;
127+
if (dt > 0xffffffff) {
128+
dt = 0xffffffff;
129+
}
130+
ticks_wake_after_us32((uint32_t)dt);
131+
if (dt < 50) {
132+
__WFE();
133+
} else {
134+
MICROPY_EVENT_POLL_HOOK
135+
}
136+
}
137+
}

ports/mimxrt/ticks.h

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2021 Damien P. George
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_MIMXRT_TICKS_H
27+
#define MICROPY_INCLUDED_MIMXRT_TICKS_H
28+
29+
void ticks_init(void);
30+
uint32_t ticks_us32(void);
31+
uint64_t ticks_us64(void);
32+
uint32_t ticks_ms32(void);
33+
void ticks_delay_us64(uint64_t us);
34+
35+
#endif // MICROPY_INCLUDED_MIMXRT_TICKS_H

0 commit comments

Comments
 (0)