This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 5fd518a27c0adcf156a1d2de963cd3ac486e07a7
Author: Marco Casaroli <[email protected]>
AuthorDate: Sat Jul 25 02:50:26 2026 +0200

    rp23xx: Add tickless OS support using the RP2350 hardware TIMER.
    
    The port could only run with a periodic ARM SysTick tick.  Add an alarm/
    oneshot lower-half backed by an RP2350 system timer block so the scheduler
    can run tickless, waking the CPU only when a timer actually expires.
    
    rp23xx_oneshot.c implements the ONESHOT_COUNT lower-half (mirroring the
    RISC-V mtimer driver).  A timer block is a free-running 64-bit microsecond
    counter (clocked by the TICKS block, independent of the SysTick), which 
serves
    directly as the monotonic time base returned by current(), so timekeeping is
    exact to 1 us.  The one adaptation versus a full 64-bit compare timer is 
that
    the RP2350 ALARM registers match only the low 32 bits of the counter:
    max_delay() is therefore capped below 2^32 counts (~71.5 minutes) so the
    scheduler never asks for a longer interval, and any deadline that is already
    due -- or that the counter reaches while the alarm is being armed -- is
    raised immediately through the INTF force register instead of waiting a full
    32-bit wrap for the compare to match again.
    
    Enabled with CONFIG_RP23XX_SYSTIMER_TICKLESS (mutually exclusive with
    RP23XX_SYSTIMER_SYSTICK), which selects ONESHOT, ONESHOT_COUNT and
    ALARM_ARCH; up_timer_initialize() then hands the oneshot to
    up_alarm_set_lowerhalf().  ARCH_CHIP_RP23XX now selects ARCH_HAVE_TICKLESS.
    The block is selectable with CONFIG_RP23XX_SYSTIMER_TICKLESS_TIMER0 
(default)
    or _TIMER1; the chosen block is claimed exclusively by the scheduler and is
    excluded from the /dev/timer driver (CONFIG_RP23XX_TIMER) in Kconfig, so the
    tickless clock and a /dev/timer device can coexist on different blocks.
    
    Tested on Pimoroni Pico Plus 2 (RP2350B) hardware with CONFIG_SCHED_TICKLESS
    and CONFIG_SCHED_TICKLESS_ALARM: the image boots to nsh and keeps accurate
    time -- "uptime" advances at real-time rate (17 s over a measured 17.4 s) 
and
    "sleep 4" blocks for 4.25 s of wall time -- confirming the oneshot both 
drives
    the scheduler and provides a correct 1 MHz monotonic clock.
    
    Assisted-by: Claude Opus 4.8 (1M context) <[email protected]>
    Signed-off-by: Marco Casaroli <[email protected]>
---
 Documentation/platforms/arm/rp23xx/index.rst |  23 ++
 arch/arm/Kconfig                             |   1 +
 arch/arm/src/rp23xx/CMakeLists.txt           |   4 +
 arch/arm/src/rp23xx/Kconfig                  |  34 +++
 arch/arm/src/rp23xx/Make.defs                |   4 +
 arch/arm/src/rp23xx/rp23xx_oneshot.c         | 331 +++++++++++++++++++++++++++
 arch/arm/src/rp23xx/rp23xx_oneshot.h         |  71 ++++++
 arch/arm/src/rp23xx/rp23xx_timerisr.c        |  14 +-
 8 files changed, 480 insertions(+), 2 deletions(-)

diff --git a/Documentation/platforms/arm/rp23xx/index.rst 
b/Documentation/platforms/arm/rp23xx/index.rst
index b8422a9e688..e34b82af760 100644
--- a/Documentation/platforms/arm/rp23xx/index.rst
+++ b/Documentation/platforms/arm/rp23xx/index.rst
@@ -44,6 +44,7 @@ PSRAM            Working       Three modes of heap allocation 
described below
 TRNG             Working       Hardware RNG at /dev/random and /dev/urandom
 Flash MTD        Working       Unused flash tail as an MTD device, answers 
BIOC_XIPBASE
 Timer            Working       /dev/timerN on TIMER0/TIMER1, 1 us resolution
+Tickless         Working       Optional, RP2350 TIMER via the alarm/oneshot
 ==============   ============  =====
 
 Installation
@@ -195,6 +196,28 @@ TIMER1).  With tickless disabled, both `/dev/timer0` and
 `/dev/timer1` are available.  The `examples/timer` application can exercise a
 device; point `CONFIG_EXAMPLES_TIMER_DEVNAME` at the block you enabled.
 
+Tickless OS
+===========
+
+By default the OS tick is a periodic ARM SysTick interrupt.  The RP2350 can
+instead run tickless, driving the scheduler from a hardware alarm so the CPU
+is only interrupted when a timer actually expires.
+
+Enable `RP23XX_SYSTIMER_TICKLESS` together with `SCHED_TICKLESS` and
+`SCHED_TICKLESS_ALARM`.  Choose the timer block with the "Tickless timer
+block" option (`RP23XX_SYSTIMER_TICKLESS_TIMER0`, the default, or
+`RP23XX_SYSTIMER_TICKLESS_TIMER1`).  The system time is then taken from that
+block -- a free-running 64-bit microsecond counter -- and its ALARM0 provides
+the next-event interrupt through the alarm/oneshot lower-half
+(`rp23xx_oneshot.c`).  Because the 64-bit counter is the monotonic time base,
+timekeeping is exact to 1 us, and a single alarm can schedule up to ~71
+minutes ahead, so long idle periods need no wake-ups.  This is mutually
+exclusive with `RP23XX_SYSTIMER_SYSTICK`.
+
+The block chosen here is claimed exclusively by the scheduler and is removed
+from the `/dev/timer` driver's choices (see the Timer section), so the tickless
+clock and a `/dev/timer` device can run at the same time on different blocks.
+
 Programming
 ============
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b107f0ab91d..6b2ea0d0886 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -394,6 +394,7 @@ config ARCH_CHIP_RP23XX
        select ARM_HAVE_DSP
        select ARCH_HAVE_FPU
        select ARCH_HAVE_CUSTOM_TESTSET
+       select ARCH_HAVE_TICKLESS
        select ARCH_BOARD_COMMON
        ---help---
                Raspberry Pi RP23XX architectures (ARM dual Cortex-M33 or 
RISC-V).
diff --git a/arch/arm/src/rp23xx/CMakeLists.txt 
b/arch/arm/src/rp23xx/CMakeLists.txt
index 5c52dca2aa0..6036cb04ebf 100644
--- a/arch/arm/src/rp23xx/CMakeLists.txt
+++ b/arch/arm/src/rp23xx/CMakeLists.txt
@@ -60,6 +60,10 @@ if(CONFIG_RP23XX_TIMER)
   list(APPEND SRCS rp23xx_timer.c)
 endif()
 
+if(CONFIG_RP23XX_SYSTIMER_TICKLESS)
+  list(APPEND SRCS rp23xx_oneshot.c)
+endif()
+
 if(CONFIG_RP23XX_I2C)
   list(APPEND SRCS rp23xx_i2c.c)
 endif()
diff --git a/arch/arm/src/rp23xx/Kconfig b/arch/arm/src/rp23xx/Kconfig
index e3f2f499a05..cb71ef9f529 100644
--- a/arch/arm/src/rp23xx/Kconfig
+++ b/arch/arm/src/rp23xx/Kconfig
@@ -23,6 +23,40 @@ config RP23XX_SYSTIMER_SYSTICK
        ---help---
                Use ARM SysTick.
 
+config RP23XX_SYSTIMER_TICKLESS
+       bool "Tickless OS using the RP2350 hardware TIMER"
+       default n
+       depends on !RP23XX_SYSTIMER_SYSTICK
+       select ONESHOT
+       select ONESHOT_COUNT
+       select ALARM_ARCH
+       ---help---
+               Use an RP2350 system timer block (TIMER0 or TIMER1, chosen 
below)
+               as the OS time source and drive the scheduler through the
+               alarm/oneshot interface.  Each block is a free-running 64-bit
+               microsecond counter, independent of the ARM SysTick.  This is 
the
+               arch-side support required by CONFIG_SCHED_TICKLESS (with
+               CONFIG_SCHED_TICKLESS_ALARM) and gives long tickless idle 
intervals
+               -- up to ~71 minutes per alarm -- with 1 us resolution.
+
+choice
+       prompt "Tickless timer block"
+       default RP23XX_SYSTIMER_TICKLESS_TIMER0
+       depends on RP23XX_SYSTIMER_TICKLESS
+       ---help---
+               Which RP2350 system timer block drives the tickless OS clock.  
The
+               block used here is claimed exclusively by the scheduler; the 
other
+               block stays available for the /dev/timer driver 
(CONFIG_RP23XX_TIMER),
+               so both features can be enabled at once.
+
+config RP23XX_SYSTIMER_TICKLESS_TIMER0
+       bool "TIMER0"
+
+config RP23XX_SYSTIMER_TICKLESS_TIMER1
+       bool "TIMER1"
+
+endchoice
+
 #####################################################################
 #  UART Configuration
 #####################################################################
diff --git a/arch/arm/src/rp23xx/Make.defs b/arch/arm/src/rp23xx/Make.defs
index fb41bb5c6a8..8f59e6aac6d 100644
--- a/arch/arm/src/rp23xx/Make.defs
+++ b/arch/arm/src/rp23xx/Make.defs
@@ -64,6 +64,10 @@ ifeq ($(CONFIG_RP23XX_TIMER),y)
 CHIP_CSRCS += rp23xx_timer.c
 endif
 
+ifeq ($(CONFIG_RP23XX_SYSTIMER_TICKLESS),y)
+CHIP_CSRCS += rp23xx_oneshot.c
+endif
+
 ifeq ($(CONFIG_RP23XX_I2C),y)
 CHIP_CSRCS += rp23xx_i2c.c
 endif
diff --git a/arch/arm/src/rp23xx/rp23xx_oneshot.c 
b/arch/arm/src/rp23xx/rp23xx_oneshot.c
new file mode 100644
index 00000000000..f052cc0dc48
--- /dev/null
+++ b/arch/arm/src/rp23xx/rp23xx_oneshot.c
@@ -0,0 +1,331 @@
+/****************************************************************************
+ * arch/arm/src/rp23xx/rp23xx_oneshot.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ *
+ * A oneshot lower-half backed by an RP2350 system timer block (TIMER0 or
+ * TIMER1, selected by CONFIG_RP23XX_SYSTIMER_TICKLESS_TIMERn), used to drive
+ * the tickless scheduler via up_alarm_set_lowerhalf().  The block is a
+ * free-running 64-bit counter incremented once per microsecond (the 1 MHz
+ * tick is set up by the TICKS block in rp23xx_clock.c), and serves directly
+ * as the monotonic time base returned by current().  The other block is left
+ * free for the /dev/timer driver.
+ *
+ * The one wrinkle versus a full 64-bit compare timer (e.g. the RISC-V mtimer
+ * this mirrors) is that the RP2350 ALARM registers match only the low 32
+ * bits of the counter.  max_delay() is therefore capped below 2^32 counts so
+ * the scheduler never asks for a longer interval, and any deadline that is
+ * already due (or that the counter reaches while the alarm is being armed)
+ * is raised at once through the INTF force register rather than waiting a
+ * full 32-bit wrap (~71.5 minutes) for the compare to match again.
+ *
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/timers/oneshot.h>
+
+#include "chip.h"
+#include "arm_internal.h"
+#include "rp23xx_oneshot.h"
+#include "hardware/rp23xx_timer.h"
+#include "hardware/rp23xx_memorymap.h"
+
+#ifdef CONFIG_RP23XX_SYSTIMER_TICKLESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* This driver uses ALARM0 of TIMER0; alarm 0 is bit 0 in the ARMED, INTE,
+ * INTF, INTR and INTS registers.
+ */
+
+#define ONESHOT_ALARM0_BIT  (1 << 0)
+
+/* The counter is clocked at 1 MHz (1 us per count). */
+
+#define ONESHOT_FREQ_HZ     1000000
+
+/* The ALARM compare is only 32 bits wide, so never schedule further ahead
+ * than this many counts.
+ */
+
+#define ONESHOT_MAX_COUNTS  ((clkcnt_t)UINT32_MAX)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Cast-compatible with struct oneshot_lowerhalf_s (embedded first). */
+
+struct rp23xx_oneshot_lowerhalf_s
+{
+  struct oneshot_lowerhalf_s lower;   /* Lower-half instance (must be first) */
+  uint32_t                   base;    /* TIMER block base address */
+  int                        irq;     /* ALARM0 interrupt number */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static clkcnt_t rp23xx_oneshot_max_delay(FAR struct oneshot_lowerhalf_s *l);
+static clkcnt_t rp23xx_oneshot_current(FAR struct oneshot_lowerhalf_s *l);
+static void rp23xx_oneshot_start_absolute(FAR struct oneshot_lowerhalf_s *l,
+                                          clkcnt_t expected);
+static void rp23xx_oneshot_start(FAR struct oneshot_lowerhalf_s *l,
+                                 clkcnt_t delta);
+static void rp23xx_oneshot_cancel(FAR struct oneshot_lowerhalf_s *l);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct oneshot_operations_s g_rp23xx_oneshot_ops =
+{
+  .current        = rp23xx_oneshot_current,
+  .start          = rp23xx_oneshot_start,
+  .start_absolute = rp23xx_oneshot_start_absolute,
+  .cancel         = rp23xx_oneshot_cancel,
+  .max_delay      = rp23xx_oneshot_max_delay,
+};
+
+static struct rp23xx_oneshot_lowerhalf_s g_rp23xx_oneshot =
+{
+  .lower.ops = &g_rp23xx_oneshot_ops,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_count
+ *
+ * Description:
+ *   Read the free-running 64-bit microsecond counter, guarding against a
+ *   carry from the low word into the high word between the two reads.
+ *
+ ****************************************************************************/
+
+static uint64_t
+rp23xx_oneshot_count(FAR struct rp23xx_oneshot_lowerhalf_s *p)
+{
+  uint32_t hi = getreg32(p->base + RP23XX_TIMER_TIMERAWH_OFFSET);
+  uint32_t lo;
+  uint32_t next;
+
+  for (; ; )
+    {
+      lo   = getreg32(p->base + RP23XX_TIMER_TIMERAWL_OFFSET);
+      next = getreg32(p->base + RP23XX_TIMER_TIMERAWH_OFFSET);
+      if (hi == next)
+        {
+          break;
+        }
+
+      hi = next;
+    }
+
+  return ((uint64_t)hi << 32) | lo;
+}
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_setcompare
+ *
+ * Description:
+ *   Arm ALARM0 for the absolute counter value "target".  Must be called with
+ *   interrupts disabled.  If the target is already due -- or the counter
+ *   reaches it while the alarm is being armed -- the interrupt is forced
+ *   immediately through INTF instead of waiting a full 32-bit wrap for the
+ *   compare to match.
+ *
+ ****************************************************************************/
+
+static void
+rp23xx_oneshot_setcompare(FAR struct rp23xx_oneshot_lowerhalf_s *priv,
+                          uint64_t target)
+{
+  /* Clear any stale force left from a previous expiry. */
+
+  modifyreg32(priv->base + RP23XX_TIMER_INTF_OFFSET, ONESHOT_ALARM0_BIT, 0);
+
+  if ((int64_t)(target - rp23xx_oneshot_count(priv)) <= 0)
+    {
+      /* Already due: raise the interrupt now. */
+
+      modifyreg32(priv->base + RP23XX_TIMER_INTF_OFFSET, 0,
+                  ONESHOT_ALARM0_BIT);
+    }
+  else
+    {
+      /* Writing ALARM0 arms it against the low 32 bits of the counter. */
+
+      putreg32((uint32_t)target, priv->base + RP23XX_TIMER_ALARM0_OFFSET);
+
+      /* Close the race: if the counter reached the target while we were
+       * arming, force so we do not wait a full wrap for the match.
+       */
+
+      if ((int64_t)(rp23xx_oneshot_count(priv) - target) >= 0)
+        {
+          modifyreg32(priv->base + RP23XX_TIMER_INTF_OFFSET, 0,
+                      ONESHOT_ALARM0_BIT);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_interrupt
+ ****************************************************************************/
+
+static int rp23xx_oneshot_interrupt(int irq, FAR void *context,
+                                    FAR void *arg)
+{
+  FAR struct rp23xx_oneshot_lowerhalf_s *priv = arg;
+
+  /* Disarm the alarm, drop any force and clear the latched match. */
+
+  putreg32(ONESHOT_ALARM0_BIT, priv->base + RP23XX_TIMER_ARMED_OFFSET);
+  modifyreg32(priv->base + RP23XX_TIMER_INTF_OFFSET, ONESHOT_ALARM0_BIT, 0);
+  putreg32(ONESHOT_ALARM0_BIT, priv->base + RP23XX_TIMER_INTR_OFFSET);
+
+  oneshot_process_callback(&priv->lower);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_max_delay
+ ****************************************************************************/
+
+static clkcnt_t rp23xx_oneshot_max_delay(FAR struct oneshot_lowerhalf_s *l)
+{
+  UNUSED(l);
+  return ONESHOT_MAX_COUNTS;
+}
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_current
+ ****************************************************************************/
+
+static clkcnt_t rp23xx_oneshot_current(FAR struct oneshot_lowerhalf_s *l)
+{
+  return rp23xx_oneshot_count((FAR struct rp23xx_oneshot_lowerhalf_s *)l);
+}
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_start_absolute
+ ****************************************************************************/
+
+static void rp23xx_oneshot_start_absolute(FAR struct oneshot_lowerhalf_s *l,
+                                          clkcnt_t expected)
+{
+  FAR struct rp23xx_oneshot_lowerhalf_s *priv =
+    (FAR struct rp23xx_oneshot_lowerhalf_s *)l;
+  irqstate_t flags = up_irq_save();
+
+  rp23xx_oneshot_setcompare(priv, expected);
+  up_irq_restore(flags);
+}
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_start
+ ****************************************************************************/
+
+static void rp23xx_oneshot_start(FAR struct oneshot_lowerhalf_s *l,
+                                 clkcnt_t delta)
+{
+  FAR struct rp23xx_oneshot_lowerhalf_s *priv =
+    (FAR struct rp23xx_oneshot_lowerhalf_s *)l;
+  irqstate_t flags = up_irq_save();
+
+  rp23xx_oneshot_setcompare(priv, rp23xx_oneshot_count(priv) + delta);
+  up_irq_restore(flags);
+}
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_cancel
+ ****************************************************************************/
+
+static void rp23xx_oneshot_cancel(FAR struct oneshot_lowerhalf_s *l)
+{
+  FAR struct rp23xx_oneshot_lowerhalf_s *priv =
+    (FAR struct rp23xx_oneshot_lowerhalf_s *)l;
+  irqstate_t flags = up_irq_save();
+
+  putreg32(ONESHOT_ALARM0_BIT, priv->base + RP23XX_TIMER_ARMED_OFFSET);
+  modifyreg32(priv->base + RP23XX_TIMER_INTF_OFFSET, ONESHOT_ALARM0_BIT, 0);
+  putreg32(ONESHOT_ALARM0_BIT, priv->base + RP23XX_TIMER_INTR_OFFSET);
+  up_irq_restore(flags);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_initialize
+ *
+ * Description:
+ *   Initialise the selected system timer block (TIMER0 or TIMER1) as a
+ *   oneshot lower-half.  See rp23xx_oneshot.h.
+ *
+ ****************************************************************************/
+
+FAR struct oneshot_lowerhalf_s *rp23xx_oneshot_initialize(void)
+{
+  FAR struct rp23xx_oneshot_lowerhalf_s *priv = &g_rp23xx_oneshot;
+
+#ifdef CONFIG_RP23XX_SYSTIMER_TICKLESS_TIMER1
+  priv->base = RP23XX_TIMER1_BASE;
+  priv->irq  = RP23XX_TIMER1_IRQ_0;
+#else
+  priv->base = RP23XX_TIMER0_BASE;
+  priv->irq  = RP23XX_TIMER0_IRQ_0;
+#endif
+
+  oneshot_count_init(&priv->lower, ONESHOT_FREQ_HZ);
+
+  /* Start from a known-idle state: alarm disarmed, no force, status clear,
+   * then enable the ALARM0 interrupt at the peripheral and the NVIC.
+   */
+
+  putreg32(ONESHOT_ALARM0_BIT, priv->base + RP23XX_TIMER_ARMED_OFFSET);
+  modifyreg32(priv->base + RP23XX_TIMER_INTF_OFFSET, ONESHOT_ALARM0_BIT, 0);
+  putreg32(ONESHOT_ALARM0_BIT, priv->base + RP23XX_TIMER_INTR_OFFSET);
+  modifyreg32(priv->base + RP23XX_TIMER_INTE_OFFSET, 0, ONESHOT_ALARM0_BIT);
+
+  irq_attach(priv->irq, rp23xx_oneshot_interrupt, priv);
+  up_enable_irq(priv->irq);
+
+  return &priv->lower;
+}
+
+#endif /* CONFIG_RP23XX_SYSTIMER_TICKLESS */
diff --git a/arch/arm/src/rp23xx/rp23xx_oneshot.h 
b/arch/arm/src/rp23xx/rp23xx_oneshot.h
new file mode 100644
index 00000000000..eec8184a79c
--- /dev/null
+++ b/arch/arm/src/rp23xx/rp23xx_oneshot.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+ * arch/arm/src/rp23xx/rp23xx_oneshot.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_RP23XX_RP23XX_ONESHOT_H
+#define __ARCH_ARM_SRC_RP23XX_RP23XX_ONESHOT_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/timers/oneshot.h>
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_oneshot_initialize
+ *
+ * Description:
+ *   Initialise the RP2350 system timer TIMER0 as a oneshot lower-half and
+ *   return it, ready to be handed to up_alarm_set_lowerhalf() to drive the
+ *   tickless scheduler.  TIMER0 is a free-running 64-bit microsecond counter
+ *   whose ALARM0 provides the compare event.
+ *
+ * Returned Value:
+ *   The oneshot lower-half instance on success; NULL never happens (the
+ *   instance is statically allocated).
+ *
+ ****************************************************************************/
+
+FAR struct oneshot_lowerhalf_s *rp23xx_oneshot_initialize(void);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_ARM_SRC_RP23XX_RP23XX_ONESHOT_H */
diff --git a/arch/arm/src/rp23xx/rp23xx_timerisr.c 
b/arch/arm/src/rp23xx/rp23xx_timerisr.c
index f0ef2171cae..f49778e5252 100644
--- a/arch/arm/src/rp23xx/rp23xx_timerisr.c
+++ b/arch/arm/src/rp23xx/rp23xx_timerisr.c
@@ -40,6 +40,11 @@
 #include "chip.h"
 #include "systick.h"
 
+#ifdef CONFIG_RP23XX_SYSTIMER_TICKLESS
+#  include <nuttx/timers/arch_alarm.h>
+#  include "rp23xx_oneshot.h"
+#endif
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -76,7 +81,8 @@
  *   of the systems.
  *
  ****************************************************************************/
-#ifndef CONFIG_RP23XX_SYSTIMER_SYSTICK
+#if !defined(CONFIG_RP23XX_SYSTIMER_SYSTICK) && \
+    !defined(CONFIG_RP23XX_SYSTIMER_TICKLESS)
 static int rp23xx_timerisr(int irq, uint32_t *regs, void *arg)
 {
   /* Process timer interrupt */
@@ -110,7 +116,11 @@ void up_timer_initialize(void)
   regval |= (NVIC_SYSH_PRIORITY_DEFAULT << NVIC_SYSH_PRIORITY_PR15_SHIFT);
   putreg32(regval, NVIC_SYSH12_15_PRIORITY);
 
-#ifdef CONFIG_RP23XX_SYSTIMER_SYSTICK
+#if defined(CONFIG_RP23XX_SYSTIMER_TICKLESS)
+  /* Drive the tickless scheduler from the selected RP2350 hardware TIMER. */
+
+  up_alarm_set_lowerhalf(rp23xx_oneshot_initialize());
+#elif defined(CONFIG_RP23XX_SYSTIMER_SYSTICK)
   up_timer_set_lowerhalf(systick_initialize(true, SYSTICK_CLOCK, -1));
 #else
 

Reply via email to