mimxrt: clean up unused systick code, and fix `mp_hal_delay_ms(0)` by dpgeorge · Pull Request #19115 · micropython/micropython · GitHub
Skip to content

mimxrt: clean up unused systick code, and fix mp_hal_delay_ms(0)#19115

Open
dpgeorge wants to merge 4 commits intomicropython:masterfrom
dpgeorge:mimxrt-clean-up-systick
Open

mimxrt: clean up unused systick code, and fix mp_hal_delay_ms(0)#19115
dpgeorge wants to merge 4 commits intomicropython:masterfrom
dpgeorge:mimxrt-clean-up-systick

Conversation

@dpgeorge
Copy link
Copy Markdown
Member

@dpgeorge dpgeorge commented Apr 16, 2026

Summary

This PR cleans up and improves mimxrt's systick component:

  1. remove unused functions and macro (which were copied from stm32 and never used)
  2. use the SysTick 1ms counter to implement mp_hal_ticks_ms(); this counter already exists and is much more efficient than ticks_ms32() which needs to convert a 64-bit microsecond counter to milliseconds
  3. fix mp_hal_delay_ms(0) so it runs the scheduler

Point 2 addresses #19076, providing a fast mp_hal_ticks_ms().

Edit: as discussed further in #19076, there's no need to change how ticks-ms works, so that's been reverted.

Testing

Tested on TEENSY40, running the test suite in standard mode, and with --via-mpy --emit native. With the native emitter tests/micropython/schedule_sleep.py would lock up prior to the fix in this PR. Now it passes, as do all other tests (except socket_badconstructor.py which is fixed by a different PR).

Trade-offs and Alternatives

Note that systick_ms will stop counting if IRQs are disabled. That's also partly true of the existing ticks based on a GPT, due to the handling of the overflow in an IRQ, although there the overflow happens every 71 minutes, rather than every millisecond.

This also makes ticks_ms32() unused, so it could be removed. But probably best to keep it in case it's needed again.

Alternatively, could provide a config option to select the mp_hal_ticks_ms() implementation: systick vs microsecond GPT. Another alternative would be to provide a mp_hal_ticks_ms_fast() which uses systick, and keep mp_hal_ticks_ms() using the GPT.

Generative AI

I did not use generative AI tools when creating this PR.

@dpgeorge
Copy link
Copy Markdown
Member Author

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 16, 2026

Code size report:

Reference:  extmod/moductypes: Be more defensive with uctypes_struct_agg_size args. [8a56be6]
Comparison: mimxrt/mphalport: Run events at least once in mp_hal_delay_ms. [merge of ab6c2a5]
  mpy-cross:    +0 +0.000% 
   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
      esp32:    +0 +0.000% ESP32_GENERIC
     mimxrt:   +24 +0.006% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

@robert-hh
Copy link
Copy Markdown
Contributor

robert-hh commented Apr 16, 2026

Cleaning out unused stuff is always good. I'm a little bit skeptic about disable IRQ stopping the ms tick. IRQ is disabled often during flash write/erase, e.g. when files are written. I cannot estimate how serious the problem is for using ticks_ms(). It seems better to keep the timer based ticks and provide a separate function.

Edit: No all GPT devices are used. So maybe one could set up a GPT counting at 1kHz or a power of 2. Using the low frequency reference clock, 1kHz is possible. When the 24MHz crystal is used, a 8kHz timer can be set up, The GPT prescaler has a range of 1-4096.

@kwagyeman
Copy link
Copy Markdown
Contributor

For our use cases, it's expected that the value wouldn't increment when there are no IRQs. STM32 systick behavior sets the standard, which does not increment when interrupts are disabled.

@robert-hh
Copy link
Copy Markdown
Contributor

Still mp_hal_ticks_ms() as the source for time.ticks_ms() should have no dropouts. So your use case would more be covered by a separate function, e.g. mp_hal_ticks_ms_fast().

@dpgeorge
Copy link
Copy Markdown
Member Author

So your use case would more be covered by a separate function, e.g. mp_hal_ticks_ms_fast().

Yes, I agree, I think it would be best to leave the existing implementation of mp_hal_ticks_ms() as-is (using GPT), and hence retain the current behaviour of time.sleep() and time.sleep_ms() (which are based on mp_hal_ticks_ms().

Then we could provide mp_hal_ticks_ms_fast() as a uniform API across ports. (I still think my original proposal #19076 (comment) of having the timebase unspecified is better, eg on mimxrt it allows using the raw GPT count value as the timebase, which is fast, accurate, and keeps going even with IRQs disabled).

@dpgeorge
Copy link
Copy Markdown
Member Author

I've updated this PR to go back to using GPT for mp_hal_ticks_ms(), and added a new function mp_hal_ticks_ms_fast() which gives access to the low-level SysTick counter.

These legacy functions were copied verbatim from the stm32 port and never
used.  And the use of WFI in `systick_wait_at_least()` is probably wrong.

And correct the comment in SysTick_Handler, which was also copied from
stm32.

Signed-off-by: Damien George <damien@micropython.org>
The config option `MICROPY_SOFT_TIMER_TICKS_MS` is used instead.

Signed-off-by: Damien George <damien@micropython.org>
`systick.h` and `pendsv.h` both use MICROPY-level configuration macros, so
must include `py/mpconfig.h`.

Signed-off-by: Damien George <damien@micropython.org>
Per the docs for `time.sleep()` and `time.sleep_ms()`.  This gets the
`tests/micropython/schedule_sleep.py` test working when using the native
emitter.

Signed-off-by: Damien George <damien@micropython.org>
@dpgeorge dpgeorge force-pushed the mimxrt-clean-up-systick branch from b3d053e to ab6c2a5 Compare April 21, 2026 03:54
@dpgeorge dpgeorge changed the title mimxrt: use systick 1ms counter for mp_hal_ticks_ms(), and fix mp_hal_delay_ms(0) mimxrt: clean up unused systick code, and fix mp_hal_delay_ms(0) Apr 21, 2026
@dpgeorge
Copy link
Copy Markdown
Member Author

Based on discussion I've now removed the new mp_hal_ticks_ms_fast() function. So this PR is mostly a clean up PR and should be good to merge.

@robert-hh
Copy link
Copy Markdown
Contributor

robert-hh commented Apr 21, 2026

Looks fine. Tested with three representative candidates: MIMXRT1010 (Makerdiary), MIMXRT1015 (MIMXRT1015-EVK), MIMXRT1062 (Teensy 4.1) and MIXRT1176 (MIMXRT1070-EVK) and the test suite packages micropython and extmod. MIMXRFT1010 fails some test running out of heap space.

On a side note: Looking why the MIMX1010 failed a socket test I wondered, why it was not skipped. Reason: socket and network modules are enabled on MIMXRT1010 and MIMXRT1015, even if they have no network support. I cannot recall if that was for a reason or just an oversight. Disabling it saves ~3k flash. I can make a separate PR for that, or revive the habit of maintenance PRs collecting small uncritical changes.

Edit: Another aspect of test: I noticed that with MIMXRT all vfs_lfs tests are skipped, just because the MIMXRT port does not support VFS_LFS1. Maybe the tests could be adapted to support either one.

@dpgeorge
Copy link
Copy Markdown
Member Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants