mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
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) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
parent
b00d7005b0
commit
5fd518a27c
8 changed files with 480 additions and 2 deletions
|
|
@ -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
|
||||
============
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#####################################################################
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
331
arch/arm/src/rp23xx/rp23xx_oneshot.c
Normal file
331
arch/arm/src/rp23xx/rp23xx_oneshot.c
Normal file
|
|
@ -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 */
|
||||
71
arch/arm/src/rp23xx/rp23xx_oneshot.h
Normal file
71
arch/arm/src/rp23xx/rp23xx_oneshot.h
Normal file
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue