Skip to content

cpu/rp2350_common: add periph_timer driver for TIMER0#22270

Closed
cakirmert wants to merge 2 commits into
RIOT-OS:masterfrom
cakirmert:feat/rp2350-periph-timer
Closed

cpu/rp2350_common: add periph_timer driver for TIMER0#22270
cakirmert wants to merge 2 commits into
RIOT-OS:masterfrom
cakirmert:feat/rp2350-periph-timer

Conversation

@cakirmert
Copy link
Copy Markdown

@cakirmert cakirmert commented May 10, 2026

Contribution description

Adds the periph_timer driver for the RP2350 BSP using TIMER0,
plus the matching timer_conf_t typedef and timer_config[] array
in the shared rpi-pico-2 board header. With this PR,
BOARD=rpi-pico-2-arm now provides the periph_timer feature,
which unblocks ztimer_msec and any RIOT module / test that
depends on it (including tests/periph/timer,
tests/periph/uart, the shell read-timeout path, and so on).

Hardware notes:

  • The RP2350 has two independent 64-bit microsecond timers
    (TIMER0, TIMER1), each with four ALARM compare channels
    (ALARM0..3). Unlike the RP2040 (rpx0xx BSP), each ALARM has
    its own NVIC IRQ line (TIMERx_IRQ_0..3), so the ISR routing
    is one-to-one, with no shared-IRQ demux needed.
  • This PR exposes only TIMER0 (tim_t = 0) with all four
    channels. A second device for TIMER1 can be added later.
  • Alarms compare against the low 32 bits of the 64-bit counter,
    giving a ~71-minute wraparound at 1 MHz. timer_set() computes
    the target as TIMERAWL + timeout to keep the alarm in the
    correct 32-bit window, the same idiom as
    cpu/rpx0xx/periph/timer.c.
  • The 1 us tick is generated by the RP2350 TICKS block, set up by
    the boot ROM. No additional clock plumbing is required in
    timer_init().

What is intentionally not included:

  • TIMER1 (trivial follow-up if needed).
  • Sub-microsecond / non-1-MHz frequencies (timer_init() returns
    -1 for any freq != 1000000). Supporting other frequencies
    would require reconfiguring the TICKS block, which is out of
    scope here.
  • periph_timer_query_freqs (only one supported frequency).

Files touched:

  • cpu/rp2350_common/periph/timer.c: the driver (~210 lines)
  • boards/common/rpi-pico-2/include/periph_conf.h: timer_conf_t,
    timer_channel_conf_t, timer_config[], TIMER_0_ISRA..D
  • cpu/rp2350_common/Makefile.features: declares periph_timer

Testing procedure

Build and run RIOT's stock periph_timer test on a Pi Pico 2 H:

BOARD=rpi-pico-2-arm make -C tests/periph/timer flash term

On master this fails with
There are unsatisfied feature requirements: periph_timer. With
this PR applied, the test builds, flashes, and prints (the [A]
prefix below is added by an external multi-board UART aggregator,
not the firmware):

main(): This is RIOT! (Version: 2026.07-devel-161-g15a5b)
[A] Test for peripheral TIMERs
[A] Available timers: 1
[A] TIMER 0
[A] =======
[A]   - feature periph_timer_query_freqs unsupported
[A]   - Calling timer_init(0, 1000000)
[A]     initialization successful
[A]   - timer_stop(0): stopped
[A]   - timer_set(0, 0, 5000)    Successfully set timeout 5000 for channel 0
[A]   - timer_set(0, 1, 10000)   Successfully set timeout 10000 for channel 1
[A]   - timer_set(0, 2, 15000)   Successfully set timeout 15000 for channel 2
[A]   - timer_set(0, 3, 20000)   Successfully set timeout 20000 for channel 3
[A]   - timer_set(0, 4, 25000)   ERROR: Couldn't set timeout 25000 for channel 4
[A]   - timer_start(0)
[A]   - Results:
[A]     - channel 0 fired at SW count   122979   - init:   122979
[A]     - channel 1 fired at SW count   245799   - diff:   122820
[A]     - channel 2 fired at SW count   368814   - diff:   123015
[A]     - channel 3 fired at SW count   491837   - diff:   123023
[A]   - Validating no spurious IRQs are triggered:
[A]     [OK] (no spurious IRQs)
[A] TEST SUCCEEDED

All four ALARM channels fire at the expected offsets, the
out-of-range channel is correctly rejected, and no spurious IRQs
are triggered.

Before this PR is applied: on rpi-pico-2-arm, the
periph_timer feature is missing, so any RIOT application or test
that selects ztimer_msec (directly or via ztimer_sec, the
shell read-timeout path, network stack timers, etc.) fails at
feature-resolution. With the PR applied:

  • tests/periph/timer builds and passes (output above);
  • tests/periph/uart builds (its ztimer_msec dependency is
    satisfied; that is the original motivation for this PR);
  • the broader ztimer chain (ztimer_msec, ztimer_sec,
    ztimer_periodic) becomes selectable for any RP2350 application;
  • cpu/rp2350_common/Makefile.features declares
    periph_timer, so feature-gated USEMODULE rules across the
    tree resolve correctly on RP2350.

Issues/PRs references

Companion PRs from the same investigation, independent merge order:

Declaration of AI-Tools / LLMs usage:

AI-Tools / LLMs that were used are:

  • Claude Code (Anthropic, claude-opus-4-7): agent mode with user
    review for code drafting (the driver structure mirrors
    cpu/rpx0xx/periph/timer.c, adapted for RP2350's per-alarm IRQ
    routing and the local atomic_set/clear helpers in the BSP),
    PR description authoring, and hardware test orchestration. All
    commits are authored by me; every code change was reviewed
    before commit; the driver was hardware-verified on a Pi Pico 2 H
    using tests/periph/timer (full output above) before opening
    the PR.

@github-actions github-actions Bot added Area: boards Area: Board ports Area: cpu Area: CPU/MCU ports labels May 10, 2026
@Teufelchen1
Copy link
Copy Markdown
Contributor

In #22268 @AnnsAnns already asked you to use the PR template.

Please switch to the default PR template description and properly declare your AI usage.

Please follow up with that before opening more PRs. Otherwise I will close them as spam.

@cakirmert
Copy link
Copy Markdown
Author

cakirmert commented May 10, 2026

@Teufelchen1 Done, sorry about the friction. Both your comment and @AnnsAnns's landed while all three PRs were still in draft; I'd marked them ready for review at almost the same time without realising the comments had come in. The descriptions on all three PRs are now rewritten using PULL_REQUEST_TEMPLATE.md with the Contribution description / Testing procedure / Issues/PRs references / AI declaration sections.

Explicit AI declaration: this was done with Claude Code (Anthropic, claude-opus-4-7) in agent mode with my review on every commit. The driver was hardware-verified on a Pi Pico 2 H by running tests/periph/timer (full output in the PR description) before opening the PR.

Happy to take any further changes.

@AnnsAnns AnnsAnns added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label May 11, 2026
@riot-ci
Copy link
Copy Markdown

riot-ci commented May 11, 2026

Murdock results

✔️ PASSED

61c05f8 cpu/rp2350_common/periph/timer: drop invented index macros

Success Failures Total Runtime
11107 0 11108 11m:18s

Artifacts

Comment thread cpu/rp2350_common/periph/timer.c Outdated
Comment thread cpu/rp2350_common/periph/timer.c
Comment thread cpu/rp2350_common/periph/timer.c Outdated
}

/* RP2350 TIMER0 has four independent IRQ lines (one per alarm channel) */
void TIMER_0_ISRA(void) { _isr(0, 0); }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void TIMER_0_ISRA(void) { _isr(0, 0); }
void TIMER_0_ISRA(void)
{
_isr(0, 0);
}

We usually try to avoid single line ifs, functions, etc, see our Coding Convention: https://github.com/RIOT-OS/RIOT/blob/master/CODING_CONVENTIONS.md#indentation-and-braces

Same for the remaining three functions of course.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the _isr(0, 0) looks magic-numbery, as in: it is not clear what the 0 and 0,1,2,3 stand for.

Are there macros that could be used or what do the numbers stand for?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The four ISRs are now multi-line per the coding convention. On the magic numbers: I looked for an existing RIOT pattern and the closest precedent is the rpx0xx (RP2040) timer driver, which uses the same _isr(0, 0) literal indices with a /* timer 0 IRQ0 */ comment per ISR. I'm matching that pattern here for consistency, with an added block comment above the ISRs explaining what the two integers stand for: first arg is the tim_t device index (always 0 here since only TIMER0 is exposed, TIMER_NUMOF == 1); second arg is the alarm channel index 0..3, mapping 1:1 onto the hardware's ALARM0..ALARM3 registers. These are runtime function-call indices, not register bit positions; the picosdk TIMER_INTE_ALARM_0_BITS (= 1 << 0) macros are bit masks for register writes and a different concept. I had introduced TIMER_DEV_0 / ALARM_CH_0..3 defines in an earlier revision but reverted them since they had no precedent in any existing RIOT timer driver. If you'd prefer the defines anyway, happy to add them back.

Comment thread cpu/rp2350_common/periph/timer.c
@cakirmert cakirmert force-pushed the feat/rp2350-periph-timer branch from 774bc76 to 3dd586f Compare May 11, 2026 21:43
Implement the periph_timer driver for the RP2350 BSP using TIMER0
(64-bit microsecond counter, ALARM0..3 compare channels). Each
alarm has its own NVIC IRQ line, simplifying the ISR routing
relative to the RP2040 (where alarms share one IRQ).

Alarms compare against the low 32 bits of the counter, giving a
~71-minute wraparound at 1 MHz - the same trade-off as the rpx0xx
implementation. The driver supports periodic alarms with
TIM_FLAG_RESET_ON_MATCH / RESET_ON_SET / SET_STOPPED.

The 1 us tick is provided by the RP2350 TICKS block, set up at
boot by the ROM loader; no extra clock configuration needed.

Enables tests/periph/uart, tests/periph/timer, and the ztimer_msec
backend chain to build for BOARD=rpi-pico-2-arm.

Build-verified with tests/periph/timer for rpi-pico-2-arm.
@cakirmert cakirmert force-pushed the feat/rp2350-periph-timer branch from 3dd586f to 087d55b Compare May 12, 2026 07:09
Revert the TIMER_DEV_0 / ALARM_CH_0..3 defines and use literal
indices in the per-channel ISR thunks instead, matching the
existing rpx0xx (RP2040) timer driver pattern. The explanatory
comment block above the ISRs is kept so the meaning of the two
integer args is documented.
@crasbe crasbe added the Type: new feature The issue requests / The PR implemements a new feature for RIOT label May 12, 2026
@AnnsAnns
Copy link
Copy Markdown
Member

Hello, once again thank you for being wilful to contribute to RIOT, we do appreciate it.

Due to various reasons, such as the currently unresolved legal issues around AI code combined with the very high degree of AI assistance, among other things, we have decided that we can not accept this PR as of now.

This is not meant to stop you from contributing to RIOT. For example, if you want to PR code written by yourself, we are open to review and help you.

@AnnsAnns AnnsAnns closed this May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: boards Area: Board ports Area: cpu Area: CPU/MCU ports CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants