Skip to content

Various ports: add support for Timer hard= option #17580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

arachsys
Copy link
Contributor

@arachsys arachsys commented Jun 29, 2025

Summary

7816b1f, 8f85eda and 8162468 (PR #17363) added a hard= option to the rp2 Timer constructor and initialiser to allow the callback to be switched between hard-IRQ and soft-IRQ mode.

The behaviour of other ports varies: either hard-IRQ only or soft-IRQ only. @dpgeorge suggested that it would be good to make this consistently configurable across all ports, preserving the current default but allowing both behaviours everywhere.

This patch series is an attempt to do that, adding support to every port that has a machine.Timer except nrf (see below), ensuring there is cross-port test coverage of both variants, and documenting as appropriate.

Notes and issues

nrf is the only port with a machine.Timer that isn't covered by this patch series. This port doesn't have mp_sched_schedule() enabled so I don't think I can support hard=False there? I've left it out altogether, assuming that extra code size isn't worth it just to add an ignored hard=True option for consistency. (I also note that nrf also doesn't support the freq= option to the Timer constructor/init, just period=, so it's definitely a cut-back timer implementation more generally.)

I've added hard IRQ support to shared/runtime/softtimer, but have gated it to avoid bloat on platforms which have their own timer infrastructure and don't need hard IRQ support from the software timer. alif, mimxrt and samd are the three ports which turn this on.

Testing

Although I have compile tested every patch and every port via the Micropython test infrastructure, I don't have hardware to test ports other than rp2. The generalised test I have written in tests/extmod/machine_timer.py would exercise old and new codepaths on every modified platform if run there.

I would greatly appreciate help in verifying that this series does indeed work correctly on every port it claims to cover! Obviously I will happily fix any issues that do show up.

For the purposes of writing tests:

  • every port with machine.Timer except nrf supports both hard=True and hard=False
  • every port with machine.Timer except nrf supports freq=N (N in Hz)
  • every port with machine.Timer except renesas-ra supports period=N (N in ms)
  • esp32 and esp8266 don't support software timers (id = -1)

To try to cover the various cases a bit more thoroughly, my new test covers all ports with a machine.Timer including esp32/esp8266 but excluding nrf, exercising hard and soft timers with varying freq= and explicitly checking that the heap is locked in hard callbacks and unlocked in soft callbacks.

Copy link

codecov bot commented Jun 29, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.57%. Comparing base (4bd9926) to head (17e619b).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #17580   +/-   ##
=======================================
  Coverage   98.57%   98.57%           
=======================================
  Files         169      169           
  Lines       21968    21968           
=======================================
  Hits        21654    21654           
  Misses        314      314           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

github-actions bot commented Jun 29, 2025

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:   +32 +0.008% PYBV10
     mimxrt:  +152 +0.041% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:  +152 +0.057% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

@arachsys arachsys changed the title Hardtimer Various ports: add support for hard-IRQ or soft-IRQ Timer Jun 29, 2025
@arachsys arachsys force-pushed the hardtimer branch 4 times, most recently from a2b8b69 to 5e3cf0b Compare June 29, 2025 19:07
arachsys added 12 commits June 29, 2025 21:30
machine.Timer() has inconsistent behaviour between ports: some run
callbacks in hard IRQ context whereas others schedule them like soft IRQs.

As on the rp2 port, add support to the stm32 port for a hard= argument
to explicitly choose between these, setting the default to True to match
the existing behaviour.

Signed-off-by: Chris Webb <[email protected]>
machine.Timer() has inconsistent behaviour between ports: some run
callbacks in hard IRQ context whereas others schedule them like soft IRQs.

As on the rp2 port, add support to the esp2 port for a hard= argument
to explicitly choose between these, setting the default to False to match
the existing behaviour.

Signed-off-by: Chris Webb <[email protected]>
machine.Timer() has inconsistent behaviour between ports: some run
callbacks in hard IRQ context whereas others schedule them like soft IRQs.

As on the rp2 port, add support to the esp8266 port for a hard= argument
to explicitly choose between these, setting the default to False to match
the existing behaviour.

Signed-off-by: Chris Webb <[email protected]>
machine.Timer() has inconsistent behaviour between ports: some run
callbacks in hard IRQ context whereas others schedule them like soft IRQs.

As on the rp2 port, add support to the zephyr port for a hard= argument
to explicitly choose between these, setting the default to False to match
the existing behaviour.

Signed-off-by: Chris Webb <[email protected]>
machine.Timer() has inconsistent behaviour between ports: some run
callbacks in hard IRQ context whereas others schedule them like soft IRQs.

As on the rp2 port, add support to the renesas-ra port for a hard= argument
to explicitly choose between these, setting the default to True to match
the existing behaviour.

Signed-off-by: Chris Webb <[email protected]>
The Timer initialiser in ports/renesas-ra/timer.c appears to be based on
another port, and options that aren't actually available are listed in
documentation comments and an error message. Correct these.

Signed-off-by: Chris Webb <[email protected]>
Add a flag SOFT_TIMER_HARD_CALLBACK to request that a soft timer's python
callback is run directly from the IRQ handler with the scheduler and heap
locked, instead of being scheduled via mp_sched_schedule().

Gate support for this flag on MICROPY_SOFT_TIMER_HARD_CALLBACKS so ports
that don't use the softtimer for their machine.Timer() implementation
don't suffer the small code-size increase.

Signed-off-by: Chris Webb <[email protected]>
machine.Timer() has inconsistent behaviour between ports: some run
callbacks in hard IRQ context whereas others schedule them like soft IRQs.

As on the rp2 port, add support to the generic software timer for a hard=
argument to explicitly choose between these, setting the default to False
to match the existing behaviour.

Signed-off-by: Chris Webb <[email protected]>
machine.Timer() has inconsistent behaviour between ports: some run
callbacks in hard IRQ context whereas others schedule them like soft IRQs.

As on the rp2 port, add support to the samd port for a hard= argument to
explicitly choose between these. The samd Timer is implemented using the
shared software timer, so define MICROPY_SOFT_TIMER_HARD_CALLBACKS to
enable hard-IRQ support in shared/runtime/softtimer. This automatically
enables the hard= option in extmod/machine_timer, defaulting to False to
match the existing behaviour.

Signed-off-by: Chris Webb <[email protected]>
machine.Timer() has inconsistent behaviour between ports: some run
callbacks in hard IRQ context whereas others schedule them like soft IRQs.

As on the rp2 port, add support to the mimxrt port for a hard= argument to
explicitly choose between these. The mimxrt Timer is implemented using the
shared software timer, so define MICROPY_SOFT_TIMER_HARD_CALLBACKS to
enable hard-IRQ support in shared/runtime/softtimer. This automatically
enables the hard= option in extmod/machine_timer, defaulting to False to
match the existing behaviour.

Signed-off-by: Chris Webb <[email protected]>
machine.Timer() has inconsistent behaviour between ports: some run
callbacks in hard IRQ context whereas others schedule them like soft IRQs.

As on the rp2 port, add support to the alif port for a hard= argument to
explicitly choose between these. The alif Timer is implemented using the
shared software timer, so define MICROPY_SOFT_TIMER_HARD_CALLBACKS to
enable hard-IRQ support in shared/runtime/softtimer. This automatically
enables the hard= option in extmod/machine_timer, defaulting to False to
match the existing behaviour.

Signed-off-by: Chris Webb <[email protected]>
Now all ports with machine.Timer except nrf support both hard and
soft callbacks, generalise tests/ports/rp2_machine_timer.py into
tests/extmod/machine_timer.py.

There is an existing machine_soft_timer.py which varies period= and
covers the nrf port but skips esp32/esp8266 because they don't support
software timers. In our new test, we try varying freq= instead of period=,
and cover esp32/esp8266 (with a fixed choice of hardware timer) but skip
nrf because it doesn't support hard= or freq=.

Add a check that the heap is locked (so allocation fails) in hard
callbacks and it is unlocked (so allocation succeeds) in soft callbacks,
to ensure we're getting the right kind of callback, not falling back to
the default.

Signed-off-by: Chris Webb <[email protected]>
Update the main machine.Timer specification, and any references to
hard/soft interrupts in port-specific documentation. There is a separate
copy of the machine.Timer documentation for the pyboard, so update that
too to keep everything consistent.

Signed-off-by: Chris Webb <[email protected]>
@arachsys arachsys marked this pull request as ready for review June 30, 2025 12:52
@arachsys arachsys changed the title Various ports: add support for hard-IRQ or soft-IRQ Timer Various ports: add support for Timer hard= option Jun 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant