mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
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:
parent
5f0c1c8d10
commit
aeaf718fc9
7 changed files with 566 additions and 0 deletions
|
|
@ -43,6 +43,7 @@ SRAM Boot Working Requires external SWD debugger
|
|||
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
|
||||
============== ============ =====
|
||||
|
||||
Installation
|
||||
|
|
@ -171,6 +172,29 @@ external PSRAM is configured as a separate user heap called
|
|||
`psram` and can be used through the global variable
|
||||
`g_psramheap` after including `rp23xx_heaps.h`
|
||||
|
||||
Timer
|
||||
=====
|
||||
|
||||
The RP2350 has two system timer blocks, TIMER0 and TIMER1, each a
|
||||
free-running 64-bit counter incremented once per microsecond. They are
|
||||
independent of the ARM SysTick that drives the OS tick, so they are
|
||||
available for application timers.
|
||||
|
||||
Enable the driver with `RP23XX_TIMER` (which selects `TIMER`), then turn on
|
||||
each block you want: `RP23XX_TIMER0` registers `/dev/timer0` (TIMER0) and
|
||||
`RP23XX_TIMER1` registers `/dev/timer1` (TIMER1). Each device implements the
|
||||
standard NuttX timer lower-half: single-shot or periodic timeouts with 1 us
|
||||
resolution and a maximum interval of 2^32 - 1 us (about 71.5 minutes), driven
|
||||
by ALARM0 of the block.
|
||||
|
||||
A block claimed by the tickless-OS oneshot
|
||||
(`RP23XX_SYSTIMER_TICKLESS`) is removed from the choices above, so a
|
||||
`/dev/timer` device and the tickless OS time source never collide on the same
|
||||
block -- you can run both at once (e.g. tickless on TIMER0, `/dev/timer1` on
|
||||
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.
|
||||
|
||||
Programming
|
||||
============
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@ if(CONFIG_RP23XX_PWM)
|
|||
list(APPEND SRCS rp23xx_pwm.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_RP23XX_TIMER)
|
||||
list(APPEND SRCS rp23xx_timer.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_RP23XX_I2C)
|
||||
list(APPEND SRCS rp23xx_i2c.c)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -736,6 +736,46 @@ config RP23XX_SPISD_SPI_CH
|
|||
|
||||
endif # SPISD Configuration
|
||||
|
||||
#####################################################################
|
||||
# Timer Configuration
|
||||
#####################################################################
|
||||
|
||||
menuconfig RP23XX_TIMER
|
||||
bool "System timer (/dev/timer) support"
|
||||
default n
|
||||
select TIMER
|
||||
---help---
|
||||
Build the /dev/timerN driver on top of the RP2350 system timer
|
||||
blocks (TIMER0 and TIMER1). Each block is a free-running 64-bit
|
||||
microsecond counter, independent of the ARM SysTick that drives
|
||||
the OS tick, so it is available for application timers. The
|
||||
driver uses ALARM0 of a block for a single-shot or periodic
|
||||
timeout with 1 us resolution.
|
||||
|
||||
Enable one or both blocks below. A block claimed by the tickless
|
||||
oneshot (CONFIG_RP23XX_SYSTIMER_TICKLESS) is removed from the list
|
||||
so the two features never collide on the same block.
|
||||
|
||||
if RP23XX_TIMER
|
||||
|
||||
config RP23XX_TIMER0
|
||||
bool "Register TIMER0 as /dev/timer0"
|
||||
default y
|
||||
depends on !RP23XX_SYSTIMER_TICKLESS_TIMER0
|
||||
---help---
|
||||
Bind the TIMER0 block to /dev/timer0. Unavailable when the
|
||||
tickless oneshot is configured to use TIMER0.
|
||||
|
||||
config RP23XX_TIMER1
|
||||
bool "Register TIMER1 as /dev/timer1"
|
||||
default n
|
||||
depends on !RP23XX_SYSTIMER_TICKLESS_TIMER1
|
||||
---help---
|
||||
Bind the TIMER1 block to /dev/timer1. Unavailable when the
|
||||
tickless oneshot is configured to use TIMER1.
|
||||
|
||||
endif # RP23XX_TIMER
|
||||
|
||||
#####################################################################
|
||||
# ADC Configuration
|
||||
#####################################################################
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ ifeq ($(CONFIG_RP23XX_PWM),y)
|
|||
CHIP_CSRCS += rp23xx_pwm.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RP23XX_TIMER),y)
|
||||
CHIP_CSRCS += rp23xx_timer.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RP23XX_I2C),y)
|
||||
CHIP_CSRCS += rp23xx_i2c.c
|
||||
endif
|
||||
|
|
|
|||
395
arch/arm/src/rp23xx/rp23xx_timer.c
Normal file
395
arch/arm/src/rp23xx/rp23xx_timer.c
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/rp23xx/rp23xx_timer.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 /dev/timerN driver on top of an RP2350 system timer block (TIMER0 or
|
||||
* TIMER1). Each 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 independent of the ARM SysTick that drives the OS
|
||||
* tick, so it is free for application timers. This driver uses ALARM0 of
|
||||
* the selected block, which matches against the low 32 bits of the counter,
|
||||
* giving a single-shot or periodic timeout with 1 us resolution and a
|
||||
* maximum interval of 2^32 - 1 us (~71.5 minutes).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/timers/timer.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "arm_internal.h"
|
||||
#include "rp23xx_timer.h"
|
||||
#include "hardware/rp23xx_timer.h"
|
||||
#include "hardware/rp23xx_memorymap.h"
|
||||
|
||||
#ifdef CONFIG_RP23XX_TIMER
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* This driver uses ALARM0 of the block; alarm 0 is bit 0 in the ARMED,
|
||||
* INTE, INTF, INTR and INTS registers.
|
||||
*/
|
||||
|
||||
#define TIMER_ALARM0_BIT (1 << 0)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct rp23xx_timer_lowerhalf_s
|
||||
{
|
||||
const struct timer_ops_s *ops; /* Lower-half operations (must be 1st) */
|
||||
uint32_t base; /* TIMER block base address */
|
||||
int irq; /* ALARM0 interrupt number */
|
||||
tccb_t callback; /* Current user interrupt callback */
|
||||
void *arg; /* Argument passed to upper half cb */
|
||||
uint32_t timeout; /* The current timeout value (us) */
|
||||
bool started; /* True if the alarm is armed */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int rp23xx_timer_start(FAR struct timer_lowerhalf_s *lower);
|
||||
static int rp23xx_timer_stop(FAR struct timer_lowerhalf_s *lower);
|
||||
static int rp23xx_timer_getstatus(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR struct timer_status_s *status);
|
||||
static int rp23xx_timer_settimeout(FAR struct timer_lowerhalf_s *lower,
|
||||
uint32_t timeout);
|
||||
static void rp23xx_timer_setcallback(FAR struct timer_lowerhalf_s *lower,
|
||||
tccb_t callback, FAR void *arg);
|
||||
static int rp23xx_timer_maxtimeout(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR uint32_t *maxtimeout);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct timer_ops_s g_rp23xx_timer_ops =
|
||||
{
|
||||
.start = rp23xx_timer_start,
|
||||
.stop = rp23xx_timer_stop,
|
||||
.getstatus = rp23xx_timer_getstatus,
|
||||
.settimeout = rp23xx_timer_settimeout,
|
||||
.setcallback = rp23xx_timer_setcallback,
|
||||
.ioctl = NULL,
|
||||
.maxtimeout = rp23xx_timer_maxtimeout,
|
||||
};
|
||||
|
||||
static struct rp23xx_timer_lowerhalf_s g_rp23xx_timer_lowerhalf[2] =
|
||||
{
|
||||
{
|
||||
.ops = &g_rp23xx_timer_ops,
|
||||
},
|
||||
{
|
||||
.ops = &g_rp23xx_timer_ops,
|
||||
},
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_timer_interrupt
|
||||
*
|
||||
* Description:
|
||||
* The ALARM0 interrupt handler. Acknowledges the alarm, invokes the
|
||||
* upper-half callback and, for a periodic timer, re-arms the alarm for the
|
||||
* next expiry.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int rp23xx_timer_interrupt(int irq, FAR void *context, FAR void *arg)
|
||||
{
|
||||
FAR struct rp23xx_timer_lowerhalf_s *priv = arg;
|
||||
uint32_t next;
|
||||
uint32_t now;
|
||||
uint32_t target;
|
||||
|
||||
/* Acknowledge the alarm (write-1-clear of the latched interrupt). The
|
||||
* alarm auto-disarms in hardware when it fires.
|
||||
*/
|
||||
|
||||
putreg32(TIMER_ALARM0_BIT, priv->base + RP23XX_TIMER_INTR_OFFSET);
|
||||
|
||||
if (priv->callback != NULL)
|
||||
{
|
||||
next = priv->timeout;
|
||||
if (priv->callback(&next, priv->arg) && next > 0)
|
||||
{
|
||||
/* Periodic: schedule the next expiry relative to the previous
|
||||
* target so the period does not drift with interrupt latency, but
|
||||
* never behind the counter -- an alarm set in the past would not
|
||||
* match until the 32-bit microsecond counter wraps ~71 minutes
|
||||
* later.
|
||||
*/
|
||||
|
||||
priv->timeout = next;
|
||||
now = getreg32(priv->base + RP23XX_TIMER_TIMERAWL_OFFSET);
|
||||
target = getreg32(priv->base + RP23XX_TIMER_ALARM0_OFFSET) + next;
|
||||
|
||||
if ((int32_t)(target - now) <= 0)
|
||||
{
|
||||
target = now + next;
|
||||
}
|
||||
|
||||
putreg32(target, priv->base + RP23XX_TIMER_ALARM0_OFFSET);
|
||||
}
|
||||
else
|
||||
{
|
||||
rp23xx_timer_stop((FAR struct timer_lowerhalf_s *)priv);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rp23xx_timer_stop((FAR struct timer_lowerhalf_s *)priv);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_timer_start
|
||||
****************************************************************************/
|
||||
|
||||
static int rp23xx_timer_start(FAR struct timer_lowerhalf_s *lower)
|
||||
{
|
||||
FAR struct rp23xx_timer_lowerhalf_s *priv =
|
||||
(FAR struct rp23xx_timer_lowerhalf_s *)lower;
|
||||
irqstate_t flags;
|
||||
uint32_t now;
|
||||
|
||||
if (priv->timeout == 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
now = getreg32(priv->base + RP23XX_TIMER_TIMERAWL_OFFSET);
|
||||
putreg32(now + priv->timeout, priv->base + RP23XX_TIMER_ALARM0_OFFSET);
|
||||
modifyreg32(priv->base + RP23XX_TIMER_INTE_OFFSET, 0, TIMER_ALARM0_BIT);
|
||||
priv->started = true;
|
||||
|
||||
leave_critical_section(flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_timer_stop
|
||||
****************************************************************************/
|
||||
|
||||
static int rp23xx_timer_stop(FAR struct timer_lowerhalf_s *lower)
|
||||
{
|
||||
FAR struct rp23xx_timer_lowerhalf_s *priv =
|
||||
(FAR struct rp23xx_timer_lowerhalf_s *)lower;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Disable the interrupt, force-disarm the alarm (writing a 1 to the ARMED
|
||||
* bit disarms it) and clear any latched status.
|
||||
*/
|
||||
|
||||
modifyreg32(priv->base + RP23XX_TIMER_INTE_OFFSET, TIMER_ALARM0_BIT, 0);
|
||||
putreg32(TIMER_ALARM0_BIT, priv->base + RP23XX_TIMER_ARMED_OFFSET);
|
||||
putreg32(TIMER_ALARM0_BIT, priv->base + RP23XX_TIMER_INTR_OFFSET);
|
||||
priv->started = false;
|
||||
|
||||
leave_critical_section(flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_timer_getstatus
|
||||
****************************************************************************/
|
||||
|
||||
static int rp23xx_timer_getstatus(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR struct timer_status_s *status)
|
||||
{
|
||||
FAR struct rp23xx_timer_lowerhalf_s *priv =
|
||||
(FAR struct rp23xx_timer_lowerhalf_s *)lower;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
status->flags = 0;
|
||||
if (priv->started)
|
||||
{
|
||||
status->flags |= TCFLAGS_ACTIVE;
|
||||
}
|
||||
|
||||
if (priv->callback != NULL)
|
||||
{
|
||||
status->flags |= TCFLAGS_HANDLER;
|
||||
}
|
||||
|
||||
status->timeout = priv->timeout;
|
||||
|
||||
if (priv->started)
|
||||
{
|
||||
uint32_t now = getreg32(priv->base + RP23XX_TIMER_TIMERAWL_OFFSET);
|
||||
uint32_t target = getreg32(priv->base + RP23XX_TIMER_ALARM0_OFFSET);
|
||||
|
||||
/* Unsigned subtraction wraps mod 2^32, matching the counter. */
|
||||
|
||||
status->timeleft = target - now;
|
||||
}
|
||||
else
|
||||
{
|
||||
status->timeleft = 0;
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_timer_settimeout
|
||||
****************************************************************************/
|
||||
|
||||
static int rp23xx_timer_settimeout(FAR struct timer_lowerhalf_s *lower,
|
||||
uint32_t timeout)
|
||||
{
|
||||
FAR struct rp23xx_timer_lowerhalf_s *priv =
|
||||
(FAR struct rp23xx_timer_lowerhalf_s *)lower;
|
||||
irqstate_t flags;
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
priv->timeout = timeout;
|
||||
if (priv->started)
|
||||
{
|
||||
uint32_t now = getreg32(priv->base + RP23XX_TIMER_TIMERAWL_OFFSET);
|
||||
putreg32(now + timeout, priv->base + RP23XX_TIMER_ALARM0_OFFSET);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_timer_setcallback
|
||||
****************************************************************************/
|
||||
|
||||
static void rp23xx_timer_setcallback(FAR struct timer_lowerhalf_s *lower,
|
||||
tccb_t callback, FAR void *arg)
|
||||
{
|
||||
FAR struct rp23xx_timer_lowerhalf_s *priv =
|
||||
(FAR struct rp23xx_timer_lowerhalf_s *)lower;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
priv->callback = callback;
|
||||
priv->arg = arg;
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_timer_maxtimeout
|
||||
****************************************************************************/
|
||||
|
||||
static int rp23xx_timer_maxtimeout(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR uint32_t *maxtimeout)
|
||||
{
|
||||
UNUSED(lower);
|
||||
|
||||
/* ALARM0 matches the low 32 bits of the microsecond counter. */
|
||||
|
||||
*maxtimeout = UINT32_MAX;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_timer_initialize
|
||||
*
|
||||
* Description:
|
||||
* Bind TIMER0 or TIMER1 to a /dev/timerN device. See rp23xx_timer.h.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rp23xx_timer_initialize(FAR const char *devpath, int instance)
|
||||
{
|
||||
FAR struct rp23xx_timer_lowerhalf_s *priv;
|
||||
FAR void *handle;
|
||||
|
||||
if (instance != 0 && instance != 1)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = &g_rp23xx_timer_lowerhalf[instance];
|
||||
|
||||
priv->base = (instance == 0) ? RP23XX_TIMER0_BASE : RP23XX_TIMER1_BASE;
|
||||
priv->irq = (instance == 0) ?
|
||||
RP23XX_TIMER0_IRQ_0 : RP23XX_TIMER1_IRQ_0;
|
||||
priv->callback = NULL;
|
||||
priv->arg = NULL;
|
||||
priv->timeout = 0;
|
||||
priv->started = false;
|
||||
|
||||
/* Start from a known-idle state: interrupt disabled, alarm disarmed, any
|
||||
* latched status cleared.
|
||||
*/
|
||||
|
||||
modifyreg32(priv->base + RP23XX_TIMER_INTE_OFFSET, TIMER_ALARM0_BIT, 0);
|
||||
putreg32(TIMER_ALARM0_BIT, priv->base + RP23XX_TIMER_ARMED_OFFSET);
|
||||
putreg32(TIMER_ALARM0_BIT, priv->base + RP23XX_TIMER_INTR_OFFSET);
|
||||
|
||||
irq_attach(priv->irq, rp23xx_timer_interrupt, priv);
|
||||
up_enable_irq(priv->irq);
|
||||
|
||||
handle = timer_register(devpath, (FAR struct timer_lowerhalf_s *)priv);
|
||||
if (handle == NULL)
|
||||
{
|
||||
up_disable_irq(priv->irq);
|
||||
irq_detach(priv->irq);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RP23XX_TIMER */
|
||||
74
arch/arm/src/rp23xx/rp23xx_timer.h
Normal file
74
arch/arm/src/rp23xx/rp23xx_timer.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/rp23xx/rp23xx_timer.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_TIMER_H
|
||||
#define __ARCH_ARM_SRC_RP23XX_RP23XX_TIMER_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp23xx_timer_initialize
|
||||
*
|
||||
* Description:
|
||||
* Bind one of the two RP2350 system timer blocks (TIMER0 or TIMER1) to a
|
||||
* /dev/timerN device. Each block is a free-running 64-bit microsecond
|
||||
* counter; this driver uses its ALARM0 to implement the NuttX timer
|
||||
* lower-half (single-shot and periodic timeouts, 1 us resolution, up to
|
||||
* 2^32 - 1 us ~= 71.5 minutes per interval).
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - The full path to the timer device, e.g. "/dev/timer0".
|
||||
* instance - The timer block to use: 0 for TIMER0, 1 for TIMER1.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rp23xx_timer_initialize(FAR const char *devpath, int instance);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_ARM_SRC_RP23XX_RP23XX_TIMER_H */
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue