rp23xx: Add /dev/timer driver on the TIMER0/TIMER1 blocks.

The RP2350 has two system timer blocks (TIMER0, TIMER1), each a free-running
64-bit counter incremented once per microsecond by the TICKS block (set up in
rp23xx_clock.c).  They are independent of the ARM SysTick that drives the OS
tick, so they are free for application use, but the port had no driver for
them.

Add rp23xx_timer.c, a NuttX timer lower-half that binds a block to a
/dev/timerN device.  It uses ALARM0 of the block, which matches the low 32
bits of the microsecond counter, to implement single-shot and periodic
timeouts with 1 us resolution and a maximum interval of 2^32 - 1 us (~71.5
minutes).  Periodic reloads are scheduled relative to the previous expiry to
avoid drift, but never behind the counter (an alarm set in the past would not
match until the 32-bit counter wraps).

Enable with CONFIG_RP23XX_TIMER (which selects CONFIG_TIMER), then turn on each
block independently: CONFIG_RP23XX_TIMER0 registers /dev/timer0 and
CONFIG_RP23XX_TIMER1 registers /dev/timer1.  A block claimed by the tickless
oneshot (CONFIG_RP23XX_SYSTIMER_TICKLESS) is excluded from these choices in
Kconfig, so the two features can be enabled together without colliding on the
same block or its alarm IRQ.

Tested on Pimoroni Pico Plus 2 (RP2350B) hardware with examples/timer and a
CMSIS-DAP probe.  The device registers as /dev/timer0; the ALARM0 interrupt
fires at the programmed period (verified over SWD at the configured 1 s
interval, not a busy loop), and the full path -- alarm match, the driver ISR,
the timer notification and delivery of the SIGNO to user space -- reaches the
example's signal handler and increments its counter.

Assisted-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
Marco Casaroli 2026-07-25 02:24:12 +02:00 committed by Alan C. Assis
parent 7eb6a3ca59
commit b00d7005b0
7 changed files with 566 additions and 0 deletions

View file

@ -45,6 +45,10 @@
#include "rp23xx_adc.h"
#endif
#ifdef CONFIG_RP23XX_TIMER
#include "rp23xx_timer.h"
#endif
#ifdef CONFIG_WATCHDOG
# include "rp23xx_wdt.h"
#endif
@ -492,6 +496,27 @@ int rp23xx_common_bringup(void)
#endif /* defined(CONFIG_ADC) && defined(CONFIG_RP23XX_ADC) */
/* Initialize the system timer blocks as /dev/timerN. Each enabled block
* is independent; a block claimed by the tickless oneshot is excluded in
* Kconfig, so the two features can be enabled together.
*/
#ifdef CONFIG_RP23XX_TIMER0
ret = rp23xx_timer_initialize("/dev/timer0", 0);
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize /dev/timer0: %d\n", ret);
}
#endif
#ifdef CONFIG_RP23XX_TIMER1
ret = rp23xx_timer_initialize("/dev/timer1", 1);
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize /dev/timer1: %d\n", ret);
}
#endif
/* Initialize board neo-pixel */
#if defined(CONFIG_RP23XX_BOARD_HAS_WS2812) && defined(CONFIG_WS2812)