Skip to content

arch/arm/stm32 and sched/clock: fix tickless timer compare-match race, zero-period hang, and timekeeping updates - #20173

Merged
xiaoxiang781216 merged 2 commits into
apache:masterfrom
daniel-p-carvalho:feat/stm32-tickless-fixes
Sep 18, 2026
Merged

xiaoxiang781216 merged 2 commits into
apache:masterfrom
daniel-p-carvalho:feat/stm32-tickless-fixes

Conversation

@daniel-p-carvalho

@daniel-p-carvalho daniel-p-carvalho commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR addresses two critical timing bugs in the single-timer capture/compare tickless OS drivers across STM32 families (stm32_tickless_m3m4_v1.c for F1/F2/F3/F4/G4, stm32f7, stm32h7, and stm32wb), along with wall time progression fixes for tickless timekeeping:

  1. Zero-period handling:
    When up_timer_start() is invoked with a zero/negative duration (or when converted delay equals 0 ticks), the driver now enables the compare match interrupt and immediately forces a hardware event via the Event Generation Register (EGR_CCxG). Previously, zero period could lead to missed events, improper compare programming, or undefined timeout behavior.

  2. Compare-match race condition (elimination of ~71-minute hang):
    In the single-timer continuous free-running architecture (32-bit counter, 0 to 0xFFFFFFFF), interval timing relies on setting the capture/compare register (CCR = count + period) and waiting for the counter to match. If the counter reaches or advances past count + period during register programming or critical section entry, the compare match event is missed, causing the CPU to hang until the 32-bit counter wraps all the way around (4,294,967,295 ticks, which corresponds to ~71.5 minutes at 1 MHz).
    A post-configuration check is introduced to verify whether (counter - count) >= period. If the target timestamp already elapsed, the compare interrupt is triggered immediately via EGR, preventing any hang.

  3. up_timer_cancel() remaining time calculation:
    Fixes signed/unsigned casting and remaining time calculation when the timer has already expired.

  4. Sched / Clock Timekeeping:

    • In nxsched_process_timer(), clock_update_wall_time() is now called under CONFIG_CLOCK_TIMEKEEPING, ensuring monotonic progression of wall time across tickless timer wakeups.
    • In clock_timekeeping_get_wall_time(), clock_update_wall_time() is called prior to sampling.
    • Allows overriding NTP_MAX_ADJUST with CONFIG_CLOCK_ADJTIME_SLEWLIMIT_PPM.

Note on STM32L4/L5/U5: STM32L4/L5/U5 utilizes a fundamentally different two-timer tickless architecture (stm32l4_tickless.c with 1 oneshot timer in pulse mode + 1 freerun timer). It does not use compare match and is intentionally excluded from this PR.

Impact

  • Bug fix: Eliminates intermittent multi-minute / 71-minute deadlocks in tickless OS mode on STM32 platforms when short sleeps or zero-delay timeouts are scheduled.
  • Affected targets: STM32F1, STM32F2, STM32F3, STM32F4, STM32F7, STM32G4, STM32H7, STM32WB.
  • Compatibility: Fully backward-compatible. No API breaks.

Testing

Host machine: Linux x86_64, arm-none-eabi-gcc 13.3.1.
All patches verified with ./tools/checkpatch.sh (zero errors, zero warnings).

Hardware tested (validated in bench):

  1. STM32H7 (STM32H743BI / Custom board):

    • Driver: arch/arm/src/stm32h7/stm32_tickless.c
    • Config: CONFIG_SCHED_TICKLESS=y, 32-bit TIM2 at 1 MHz, Ethernet RMII active.
    • Results:
      • Continuous ICMP ping during tickless idle sleeps: 0% packet loss, RTT ~0.6 ms.
      • Accurate sleep 1s, sleep 2s, sleep 5s executions.
      • Rapid usleep calls wake up immediately without deadlocks or missed interrupts.
  2. STM32G4 (Nucleo-G431KB):

    • Driver: arch/arm/src/common/stm32/stm32_tickless_m3m4_v1.c (shared core driver with F1/F2/F3/F4)
    • Config: nucleo-g431kb:nsh with CONFIG_SCHED_TICKLESS=y, TIM2 at 1 MHz (CONFIG_USEC_PER_TICK=1).
    • Results:
      • sleep 1 wall-clock: 0.9989s
      • sleep 2 wall-clock: 1.9966s
      • sleep 3 wall-clock: 2.9931s
      • usleep 1000 wakes up immediately without hang.

What was NOT tested on real hardware:

  • STM32F7 / STM32WB: Drivers received the identical logic and build cleanly, but physical F7/WB boards were not connected to bench during this test session.
  • STM32F4 / F1 / F2 / F3: Code executed is the exact same stm32_tickless_m3m4_v1.c validated on STM32G4, but physical F4/F1/F2/F3 boards were not flashed.
  • STM32L4: Tested on Nucleo-L432KC, confirmed that it uses a different two-timer strategy (stm32l4_tickless.c) and is not part of this PR.

This patch addresses two issues in the single-timer capture/compare
tickless OS drivers for STM32 families (common m3m4 v1 for F1/F2/F3/F4/G4,
F7, H7, and WB):

1. Zero-period handling: when up_timer_start() is called with a zero or
   negative duration (or period converts to 0 ticks), the driver now
   enables the compare match interrupt and immediately fires an event
   via EGR (CCxG), avoiding missed events or unexpected counter behavior.

2. Compare-match race condition: after programming CCR and enabling the
   compare interrupt, a post-check validates whether the free-running
   counter already reached or passed count + period during register
   configuration. If elapsed, the interrupt is forced immediately via EGR,
   preventing the counter from missing the match and hanging until a full
   32-bit rollover (approx. 71 minutes at 1 MHz).

Verified on real hardware:
- STM32H743ZI (IED R550): validated with ping, sleep, and usleep.
- STM32G431KB (Nucleo-G431KB): validated with uptime, sleep, and usleep.

Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
… PPM

1. nxsched_process_timer: call clock_update_wall_time() under
   CONFIG_CLOCK_TIMEKEEPING so that wall time is updated on timer
   events during tickless operation.

2. clock_timekeeping_get_wall_time: call clock_update_wall_time()
   before sampling the base and counter.

3. clock_timekeeping: allow overriding NTP_MAX_ADJUST with
   CONFIG_CLOCK_ADJTIME_SLEWLIMIT_PPM if configured.

4. Use clock_t consistently for counter values in clock_timekeeping.c.

Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
@github-actions github-actions Bot added Arch: arm Issues related to ARM (32-bit) architecture Area: OS Components OS Components issues Size: M The size of the change in this PR is medium labels Sep 17, 2026
@github-actions

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@xiaoxiang781216
xiaoxiang781216 merged commit 9b9423a into apache:master Sep 18, 2026
53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm Issues related to ARM (32-bit) architecture Area: OS Components OS Components issues Size: M The size of the change in this PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants