From 7db61992f9d3464b70f988ecdd24cefb7b423f80 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 18 Jul 2020 10:00:41 +0200 Subject: [PATCH] arch/arm/src/nrf52: add a low-level TIMER interface --- arch/arm/src/nrf52/Kconfig | 9 + arch/arm/src/nrf52/Make.defs | 5 +- arch/arm/src/nrf52/hardware/nrf52_tim.h | 80 ++- arch/arm/src/nrf52/nrf52_tim.c | 857 ++++++++++++++++++++++++ arch/arm/src/nrf52/nrf52_tim.h | 176 +++++ 5 files changed, 1097 insertions(+), 30 deletions(-) create mode 100644 arch/arm/src/nrf52/nrf52_tim.c create mode 100644 arch/arm/src/nrf52/nrf52_tim.h diff --git a/arch/arm/src/nrf52/Kconfig b/arch/arm/src/nrf52/Kconfig index 394006cf80..acd40f25c2 100644 --- a/arch/arm/src/nrf52/Kconfig +++ b/arch/arm/src/nrf52/Kconfig @@ -90,6 +90,10 @@ config NRF52_UART bool default n +config NRF52_TIMER + bool + default n + config NRF52_SPI_MASTER_WORKAROUND_1BYTE_TRANSFER bool "SPI Master 1 Byte transfer anomaly workaround" depends on NRF52_SPI_MASTER && ARCH_FAMILY_NRF52832 @@ -181,22 +185,27 @@ config NRF52_SAADC config NRF52_TIMER0 bool "TIMER0" + select NRF52_TIMER default n config NRF52_TIMER1 bool "TIMER1" + select NRF52_TIMER default n config NRF52_TIMER2 bool "TIMER2" + select NRF52_TIMER default n config NRF52_TIMER3 bool "TIMER3" + select NRF52_TIMER default n config NRF52_TIMER4 bool "TIMER4" + select NRF52_TIMER default n config NRF52_RTC0 diff --git a/arch/arm/src/nrf52/Make.defs b/arch/arm/src/nrf52/Make.defs index b2c81c4b09..74f172a1fb 100644 --- a/arch/arm/src/nrf52/Make.defs +++ b/arch/arm/src/nrf52/Make.defs @@ -128,5 +128,8 @@ endif ifeq ($(CONFIG_NRF52_RADIO),y) CHIP_CSRCS += nrf52_radio.c - +endif + +ifeq ($(CONFIG_NRF52_TIMER),y) +CHIP_CSRCS += nrf52_tim.c endif diff --git a/arch/arm/src/nrf52/hardware/nrf52_tim.h b/arch/arm/src/nrf52/hardware/nrf52_tim.h index a61bcf5c0d..09f2ffeaf0 100644 --- a/arch/arm/src/nrf52/hardware/nrf52_tim.h +++ b/arch/arm/src/nrf52/hardware/nrf52_tim.h @@ -1,4 +1,4 @@ -/************************************************************************** +/************************************************************************************ * arch/arm/src/nrf52/hardware/nrf52_tim.h * * Copyright (C) 2020 Gregory Nutt. All rights reserved. @@ -31,60 +31,81 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ***************************************************************************/ + ************************************************************************************/ #ifndef __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_TIM_H #define __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_TIM_H -/*************************************************************************** +/************************************************************************************ * Included Files - ***************************************************************************/ + ************************************************************************************/ #include #include "hardware/nrf52_memorymap.h" -/*************************************************************************** +/************************************************************************************ * Pre-processor Definitions - ***************************************************************************/ + ************************************************************************************/ -/* Register offsets for TIM ************************************************/ +/* TIMER constants ******************************************************************/ -#define NRF52_TIM_TASKS_START_OFFSET 0x0000 /* Start Timer */ -#define NRF52_TIM_TASKS_STOP_OFFSET 0x0004 /* Stop Timer */ -#define NRF52_TIM_TASKS_COUNT_OFFSET 0x0008 /* Increment Timer*/ -#define NRF52_TIM_TASKS_CLEAR_OFFSET 0x000c /* Clear time */ -#define NRF52_TIM_TASKS_SHUTDOWN_OFFSET 0x0010 /* Shutdown Timer */ -#define NRF52_TIM_TASKS_CAPTURE_OFFSET(x) (0x0040 + ((x) * 0x04)) /* Capture Timer value to CC[x] */ -#define NRF52_TIM_EVENTS_COMPARE_OFFSET(x) (0x0140 + ((x) * 0x04)) /* Compare event on CC[x] */ -#define NRF52_TIM_SHORTS_OFFSET 0x0200 /* Shortcuts between local events and tasks */ -#define NRF52_TIM_INTENSET_OFFSET 0x0304 /* Enable interrupt */ -#define NRF52_TIM_MODE_OFFSET 0x0504 /* Timer mode selection */ -#define NRF52_TIM_BITMODE_OFFSET 0x0508 /* Configure the number of bits used by the Timer */ -#define NRF52_TIM_PRESCALER_OFFSET 0x0510 /* Timer prescaler register */ -#define NRF52_TIM_CC_OFFSET(x) (0x0540 + ((x) * 0x04)) /* Capture/Compare register x */ +#define TIMER_BASE_FERQUENCY (16000000) -/* Register offsets for TIM ************************************************/ +/* Register offsets for TIM *********************************************************/ + +#define NRF52_TIM_TASKS_START_OFFSET 0x0000 /* Start Timer */ +#define NRF52_TIM_TASKS_STOP_OFFSET 0x0004 /* Stop Timer */ +#define NRF52_TIM_TASKS_COUNT_OFFSET 0x0008 /* Increment Timer */ +#define NRF52_TIM_TASKS_CLEAR_OFFSET 0x000c /* Clear time */ +#define NRF52_TIM_TASKS_SHUTDOWN_OFFSET 0x0010 /* Shutdown Timer */ +#define NRF52_TIM_TASKS_CAPTURE_OFFSET(x) (0x0040 + ((x) * 4)) /* Capture Timer value to CC[x] */ +#define NRF52_TIM_EVENTS_COMPARE_OFFSET(x) (0x0140 + ((x) * 4)) /* Compare event on CC[x] */ +#define NRF52_TIM_SHORTS_OFFSET 0x0200 /* Shortcuts between local events and tasks */ +#define NRF52_TIM_INTENSET_OFFSET 0x0304 /* Enable interrupt */ +#define NRF52_TIM_INTCLR_OFFSET 0x0308 /* Disable interrupt */ +#define NRF52_TIM_MODE_OFFSET 0x0504 /* Timer mode selection */ +#define NRF52_TIM_BITMODE_OFFSET 0x0508 /* Configure the number of bits used by the Timer */ +#define NRF52_TIM_PRESCALER_OFFSET 0x0510 /* Timer prescaler register */ +#define NRF52_TIM_CC_OFFSET(x) (0x0540 + ((x) * 4)) /* Capture/Compare register x */ + +/* Register offsets for TIM *********************************************************/ + +/* TASKS_START Register */ + +#define TIM_TASKS_START (1 << 0) /* Bit 0: Start Timer */ + +/* TASKS_STOP Register */ + +#define TIM_TASKS_STOP (1 << 0) /* Bit 0: Stop Timer */ + +/* TASKS_COUNT Register */ + +#define TIM_TASKS_COUNT (1 << 0) /* Bit 0: Increment Timer */ + +/* TASKS_CLEAR Register */ + +#define TIM_TASKS_CLEAR (1 << 0) /* Bit 0: Clear Timer */ /* SHORTS Register */ -#define TIM_SHORTS_COMPARE_CLEAR(x) (1 << (x)) /* Bits 0-5: */ -#define TIM_SHORTS_COMPARE_STOP(x) (1 << (x + 0x8)) /* Bits 8-13 */ +#define TIM_SHORTS_COMPARE_CLEAR(x) (1 << (x)) /* Bits 0-5: */ +#define TIM_SHORTS_COMPARE_STOP(x) (1 << (x + 8)) /* Bits 8-13 */ /* INTENSET/INTENCLR Register */ -#define TIM_INT_COMPARE(x) (1 << (x + 0x16)) /* Bits 16-21 */ +#define TIM_INT_COMPARE(x) (1 << (x + 16)) /* Bits 16-21 */ /* MODE Register */ -#define TIM_MODE_SHIFT (0) /* Bits 0-1: Timer mode */ +#define TIM_MODE_SHIFT (0) /* Bits 0-1: Timer mode */ #define TIM_MODE_MASK (0x3 << TIM_MODE_SHIFT) # define TIM_MODE_TIMER (0x0 << TIM_MODE_SHIFT) /* 0: Timer mode */ # define TIM_MODE_COUNTER (0x1 << TIM_MODE_SHIFT) /* 1: Counter mode */ -# define TIM_MODE_LPCONUTER (0x2 << TIM_MODE_SHIFT) /* 2: Low Power Counter mode */ +# define TIM_MODE_LPCOUNTER (0x2 << TIM_MODE_SHIFT) /* 2: Low Power Counter mode */ /* BITMODE Register */ -#define TIM_BITMODE_SHIFT (0) /* Bits 0-1: Timer bit width */ +#define TIM_BITMODE_SHIFT (0) /* Bits 0-1: Timer bit width */ #define TIM_BITMODE_MASK (0x3 << TIM_BITMODE_SHIFT) # define TIM_BITMODE_16B (0x0 << TIM_BITMODE_SHIFT) /* 0: 16 bit */ # define TIM_BITMODE_8B (0x1 << TIM_BITMODE_SHIFT) /* 1: 8 bit */ @@ -93,7 +114,8 @@ /* PRESCALER Register */ -#define TIM_PRESCALER_SHIFT (0) /* Bits 0-3: Prescaler value */ -#define TIM_PRESCALER_MASK (0xf << TIM_PRESCALER_SHIFT) +#define TIM_PRESCALER_SHIFT (0) /* Bits 0-3: Prescaler value */ +#define TIM_PRESCALER_MAX (0xf) +#define TIM_PRESCALER_MASK (TIM_PRESCALER_MAX << TIM_PRESCALER_SHIFT) #endif /* __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_TIM_H */ diff --git a/arch/arm/src/nrf52/nrf52_tim.c b/arch/arm/src/nrf52/nrf52_tim.c new file mode 100644 index 0000000000..24b2c99524 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_tim.c @@ -0,0 +1,857 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_tim.c + * + * 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 + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "arm_arch.h" + +#include "hardware/nrf52_tim.h" + +#include "nrf52_tim.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nrf52_tim_priv_s +{ + FAR struct nrf52_tim_ops_s *ops; + uint32_t base; + uint32_t irq; + uint8_t chan; + bool inuse; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* TIM registers access *****************************************************/ + +static uint32_t nrf52_tim_getreg(FAR struct nrf52_tim_dev_s *dev, + uint32_t offset); +static void nrf52_tim_putreg(FAR struct nrf52_tim_dev_s *dev, + uint32_t offset, + uint32_t value); + +/* TIM helpers **************************************************************/ + +static uint32_t nrf52_tim_irq2reg(FAR struct nrf52_tim_dev_s *dev, + uint8_t s); + +/* TIM operations ***********************************************************/ + +static int nrf52_tim_start(FAR struct nrf52_tim_dev_s *dev); +static int nrf52_tim_stop(FAR struct nrf52_tim_dev_s *dev); +static int nrf52_tim_clear(FAR struct nrf52_tim_dev_s *dev); +static int nrf52_tim_configure(FAR struct nrf52_tim_dev_s *dev, uint8_t mode, + uint8_t width); +static int nrf52_tim_shorts(FAR struct nrf52_tim_dev_s *dev, uint8_t s, + uint8_t i, bool en); +static int nrf52_tim_count(FAR struct nrf52_tim_dev_s *dev); +static int nrf52_tim_setcc(FAR struct nrf52_tim_dev_s *dev, uint8_t i, + uint32_t cc); +static int nrf52_tim_getcc(FAR struct nrf52_tim_dev_s *dev, uint8_t i, + FAR uint32_t *cc); +static int nrf52_tim_setpre(FAR struct nrf52_tim_dev_s *dev, uint8_t pre); +static int nrf52_tim_setisr(FAR struct nrf52_tim_dev_s *dev, xcpt_t handler, + FAR void * arg); +static int nrf52_tim_enableint(FAR struct nrf52_tim_dev_s *dev, uint8_t s); +static int nrf52_tim_disableint(FAR struct nrf52_tim_dev_s *dev, uint8_t s); +static int nrf52_tim_checkint(FAR struct nrf52_tim_dev_s *dev, uint8_t s); +static int nrf52_tim_ackint(FAR struct nrf52_tim_dev_s *dev, uint8_t s); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* NRF52 TIM ops */ + +struct nrf52_tim_ops_s nrf52_tim_ops = +{ + .start = nrf52_tim_start, + .stop = nrf52_tim_stop, + .clear = nrf52_tim_clear, + .configure = nrf52_tim_configure, + .shorts = nrf52_tim_shorts, + .count = nrf52_tim_count, + .setcc = nrf52_tim_setcc, + .getcc = nrf52_tim_getcc, + .setpre = nrf52_tim_setpre, + .setisr = nrf52_tim_setisr, + .enableint = nrf52_tim_enableint, + .disableint = nrf52_tim_disableint, + .checkint = nrf52_tim_checkint, + .ackint = nrf52_tim_ackint +}; + +#ifdef CONFIG_NRF52_TIMER0 +/* TIMER0 */ + +struct nrf52_tim_priv_s g_nrf52_tim0_priv = +{ + .ops = &nrf52_tim_ops, + .base = NRF52_TIMER0_BASE, + .irq = NRF52_IRQ_TIMER0, + .chan = 4, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF52_TIMER1 +/* TIMER1 */ + +struct nrf52_tim_priv_s g_nrf52_tim1_priv = +{ + .ops = &nrf52_tim_ops, + .base = NRF52_TIMER1_BASE, + .irq = NRF52_IRQ_TIMER1, + .chan = 4, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF52_TIMER2 +/* TIMER2 */ + +struct nrf52_tim_priv_s g_nrf52_tim2_priv = +{ + .ops = &nrf52_tim_ops, + .base = NRF52_TIMER2_BASE, + .irq = NRF52_IRQ_TIMER2, + .chan = 4, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF52_TIMER3 +/* TIMER3 */ + +struct nrf52_tim_priv_s g_nrf52_tim3_priv = +{ + .ops = &nrf52_tim_ops, + .base = NRF52_TIMER3_BASE, + .irq = NRF52_IRQ_TIMER3, + .chan = 6, + .inuse = false, +}; +#endif + +#ifdef CONFIG_NRF52_TIMER4 +/* TIMER4 */ + +struct nrf52_tim_priv_s g_nrf52_tim4_priv = +{ + .ops = &nrf52_tim_ops, + .base = NRF52_TIMER4_BASE, + .irq = NRF52_IRQ_TIMER4, + .chan = 6, + .inuse = false, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_tim_getreg + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static uint32_t nrf52_tim_getreg(FAR struct nrf52_tim_dev_s *dev, + uint32_t offset) +{ + DEBUGASSERT(dev); + + return getreg32(((struct nrf52_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: nrf52_tim_putreg + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static void nrf52_tim_putreg(FAR struct nrf52_tim_dev_s *dev, + uint32_t offset, + uint32_t value) +{ + DEBUGASSERT(dev); + + putreg32(value, ((struct nrf52_tim_priv_s *)dev)->base + offset); +} + +/**************************************************************************** + * Name: nrf52_tim_irq2reg + * + * Description: + * Get the vaule of the interrupt register corresponding to the given + * interrupt source + * + ****************************************************************************/ + +static uint32_t nrf52_tim_irq2reg(FAR struct nrf52_tim_dev_s *dev, uint8_t s) +{ + uint32_t regval = 0; + + switch (s) + { + case NRF52_TIM_INT_COMPARE0: + { + regval = TIM_INT_COMPARE(0); + break; + } + + case NRF52_TIM_INT_COMPARE1: + { + regval = TIM_INT_COMPARE(1); + break; + } + + case NRF52_TIM_INT_COMPARE2: + { + regval = TIM_INT_COMPARE(2); + break; + } + + case NRF52_TIM_INT_COMPARE3: + { + regval = TIM_INT_COMPARE(3); + break; + } + + case NRF52_TIM_INT_COMPARE4: + { + regval = TIM_INT_COMPARE(4); + break; + } + + case NRF52_TIM_INT_COMPARE5: + { + regval = TIM_INT_COMPARE(5); + break; + } + + default: + { + tmrerr("ERROR: unsupported IRQ source %d\n", s); + regval = 0; + goto errout; + } + } + +errout: + return regval; +} + +/**************************************************************************** + * Name: nrf52_tim_start + ****************************************************************************/ + +static int nrf52_tim_start(FAR struct nrf52_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf52_tim_putreg(dev, NRF52_TIM_TASKS_START_OFFSET, TIM_TASKS_START); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_tim_stop + ****************************************************************************/ + +static int nrf52_tim_stop(FAR struct nrf52_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf52_tim_putreg(dev, NRF52_TIM_TASKS_STOP_OFFSET, TIM_TASKS_STOP); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_tim_clear + ****************************************************************************/ + +static int nrf52_tim_clear(FAR struct nrf52_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf52_tim_putreg(dev, NRF52_TIM_TASKS_CLEAR_OFFSET, TIM_TASKS_CLEAR); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_tim_configure + ****************************************************************************/ + +static int nrf52_tim_configure(FAR struct nrf52_tim_dev_s *dev, uint8_t mode, + uint8_t width) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Configure TIMER mode */ + + switch (mode) + { + case NRF52_TIM_MODE_UNUSED: + { + regval = 0; + break; + } + + case NRF52_TIM_MODE_TIMER: + { + regval = TIM_MODE_TIMER; + break; + } + + case NRF52_TIM_MODE_COUNTER: + { + regval = TIM_MODE_COUNTER; + break; + } + + case NRF52_TIM_MODE_LOWPOWER: + { + regval = TIM_MODE_LPCOUNTER; + break; + } + + default: + { + tmrerr("ERROR: unsupported TIMER mode %d\n", mode); + ret = -EINVAL; + goto errout; + } + } + + nrf52_tim_putreg(dev, NRF52_TIM_MODE_OFFSET, regval); + + /* Configure TIMER width */ + + switch (width) + { + case NRF52_TIM_WIDTH_16B: + { + regval = TIM_BITMODE_16B; + break; + } + + case NRF52_TIM_WIDTH_8B: + { + regval = TIM_BITMODE_8B; + break; + } + + case NRF52_TIM_WIDTH_24B: + { + regval = TIM_BITMODE_24B; + break; + } + + case NRF52_TIM_WIDTH_32B: + { + regval = TIM_BITMODE_32B; + break; + } + + default: + { + tmrerr("ERROR: unsupported TIMER width %d\n", width); + ret = -EINVAL; + goto errout; + } + } + + nrf52_tim_putreg(dev, NRF52_TIM_BITMODE_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_tim_shorts + ****************************************************************************/ + +static int nrf52_tim_shorts(FAR struct nrf52_tim_dev_s *dev, uint8_t s, + uint8_t i, bool en) +{ + uint32_t regval = 0; + uint32_t val = 0; + int ret = OK; + + regval = nrf52_tim_getreg(dev, NRF52_TIM_SHORTS_OFFSET); + + switch (s) + { + case NRF52_TIM_SHORT_COMPARE_CLEAR: + { + val = TIM_SHORTS_COMPARE_CLEAR(i); + break; + } + + case NRF52_TIM_SHORT_COMPARE_STOP: + { + val = TIM_SHORTS_COMPARE_STOP(i); + break; + } + + default: + { + tmrerr("ERROR: unsupported SHORT %d\n", s); + ret = -EINVAL; + goto errout; + } + } + + if (en == true) + { + regval |= val; + } + else + { + regval &= ~val; + } + + nrf52_tim_putreg(dev, NRF52_TIM_SHORTS_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_tim_count + ****************************************************************************/ + +static int nrf52_tim_count(FAR struct nrf52_tim_dev_s *dev) +{ + DEBUGASSERT(dev); + + nrf52_tim_putreg(dev, NRF52_TIM_TASKS_COUNT_OFFSET, TIM_TASKS_COUNT); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_tim_setcc + ****************************************************************************/ + +static int nrf52_tim_setcc(FAR struct nrf52_tim_dev_s *dev, uint8_t i, + uint32_t cc) +{ + FAR struct nrf52_tim_priv_s *tim = NULL; + int ret = OK; + + DEBUGASSERT(dev); + + tim = (FAR struct nrf52_tim_priv_s *)dev; + + /* Is the channel supported? */ + + if (i > tim->chan) + { + tmrerr("ERROR: unsupported TIMER channel %d\n", i); + ret = -EINVAL; + goto errout; + } + + nrf52_tim_putreg(dev, NRF52_TIM_CC_OFFSET(i), cc); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_tim_getcc + ****************************************************************************/ + +static int nrf52_tim_getcc(FAR struct nrf52_tim_dev_s *dev, uint8_t i, + FAR uint32_t *cc) +{ + FAR struct nrf52_tim_priv_s *tim = NULL; + int ret = OK; + + DEBUGASSERT(dev); + DEBUGASSERT(cc); + + tim = (FAR struct nrf52_tim_priv_s *)dev; + + /* Is the channel supported? */ + + if (i > tim->chan) + { + tmrerr("ERROR: unsupported TIMER channel %d\n", i); + ret = -EINVAL; + goto errout; + } + + *cc = nrf52_tim_getreg(dev, NRF52_TIM_CC_OFFSET(i)); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_tim_setpre + ****************************************************************************/ + +static int nrf52_tim_setpre(FAR struct nrf52_tim_dev_s *dev, uint8_t pre) +{ + int ret = OK; + + DEBUGASSERT(dev); + + if (pre < NRF52_TIM_PRE_16000000 || pre > NRF52_TIM_PRE_31250) + { + tmrerr("ERROR: unsupported TIMER prescaler %d\n", pre); + ret = -EINVAL; + goto errout; + } + + nrf52_tim_putreg(dev, NRF52_TIM_PRESCALER_OFFSET, pre); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_tim_setisr + ****************************************************************************/ + +static int nrf52_tim_setisr(FAR struct nrf52_tim_dev_s *dev, xcpt_t handler, + FAR void *arg) +{ + FAR struct nrf52_tim_priv_s *tim = NULL; + int ret = OK; + + DEBUGASSERT(dev); + + tim = (FAR struct nrf52_tim_priv_s *)dev; + + /* Disable interrupt when callback is removed */ + + if (!handler) + { + up_disable_irq(tim->irq); + irq_detach(tim->irq); + ret = OK; + goto errout; + } + + /* Otherwise set callback and enable interrupt */ + + irq_attach(tim->irq, handler, arg); + up_enable_irq(tim->irq); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_tim_enableint + ****************************************************************************/ + +static int nrf52_tim_enableint(FAR struct nrf52_tim_dev_s *dev, uint8_t s) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Get register value for given interrupt source */ + + regval = nrf52_tim_irq2reg(dev, s); + if (regval == 0) + { + ret = -EINVAL; + goto errout; + } + + nrf52_tim_putreg(dev, NRF52_TIM_INTENSET_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_tim_disableint + ****************************************************************************/ + +static int nrf52_tim_disableint(FAR struct nrf52_tim_dev_s *dev, uint8_t s) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Get register value for given interrupt source */ + + regval = nrf52_tim_irq2reg(dev, s); + if (regval == 0) + { + ret = -EINVAL; + goto errout; + } + + nrf52_tim_putreg(dev, NRF52_TIM_INTCLR_OFFSET, regval); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_tim_checkint + ****************************************************************************/ + +static int nrf52_tim_checkint(FAR struct nrf52_tim_dev_s *dev, uint8_t s) +{ + int ret = 0; + + DEBUGASSERT(dev); + + switch (s) + { + case NRF52_TIM_INT_COMPARE0: + { + ret = nrf52_tim_getreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(0)); + break; + } + + case NRF52_TIM_INT_COMPARE1: + { + ret = nrf52_tim_getreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(0)); + break; + } + + case NRF52_TIM_INT_COMPARE2: + { + ret = nrf52_tim_getreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(2)); + break; + } + + case NRF52_TIM_INT_COMPARE3: + { + ret = nrf52_tim_getreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(3)); + break; + } + + case NRF52_TIM_INT_COMPARE4: + { + ret = nrf52_tim_getreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(4)); + break; + } + + case NRF52_TIM_INT_COMPARE5: + { + ret = nrf52_tim_getreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(5)); + break; + } + + default: + { + tmrerr("ERROR: unsupported IRQ source %d\n", s); + ret = -EINVAL; + goto errout; + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_tim_ackint + ****************************************************************************/ + +static int nrf52_tim_ackint(FAR struct nrf52_tim_dev_s *dev, uint8_t s) +{ + int ret = 0; + + DEBUGASSERT(dev); + + switch (s) + { + case NRF52_TIM_INT_COMPARE0: + { + nrf52_tim_putreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(0), 0); + break; + } + + case NRF52_TIM_INT_COMPARE1: + { + nrf52_tim_putreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(1), 0); + break; + } + + case NRF52_TIM_INT_COMPARE2: + { + nrf52_tim_putreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(2), 0); + break; + } + + case NRF52_TIM_INT_COMPARE3: + { + nrf52_tim_putreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(3), 0); + break; + } + + case NRF52_TIM_INT_COMPARE4: + { + nrf52_tim_putreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(4), 0); + break; + } + + case NRF52_TIM_INT_COMPARE5: + { + nrf52_tim_putreg(dev, NRF52_TIM_EVENTS_COMPARE_OFFSET(5), 0); + break; + } + + default: + { + tmrerr("ERROR: unsupported IRQ source %d\n", s); + ret = -EINVAL; + goto errout; + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_tim_init + * + * Description: + * Initialize TIMER device + * + ****************************************************************************/ + +FAR struct nrf52_tim_dev_s *nrf52_tim_init(int timer) +{ + FAR struct nrf52_tim_priv_s *tim = NULL; + + /* Get timer instance */ + + switch (timer) + { +#ifdef CONFIG_NRF52_TIMER0 + case 0: + { + tim = &g_nrf52_tim0_priv; + break; + } +#endif + +#ifdef CONFIG_NRF52_TIMER1 + case 1: + { + tim = &g_nrf52_tim1_priv; + break; + } +#endif + +#ifdef CONFIG_NRF52_TIMER2 + case 2: + { + tim = &g_nrf52_tim2_priv; + break; + } +#endif + +#ifdef CONFIG_NRF52_TIMER3 + case 3: + { + tim = &g_nrf52_tim3_priv; + break; + } +#endif + +#ifdef CONFIG_NRF52_TIMER4 + case 4: + { + tim = &g_nrf52_tim4_priv; + break; + } +#endif + + default: + { + tmrerr("ERROR: unsupported TIMER %d\n", timer); + goto errout; + } + } + + if (tim->inuse != false) + { + /* Timer already in use */ + + tim = NULL; + } + +errout: + return (FAR struct nrf52_tim_dev_s *)tim; +} + +/**************************************************************************** + * Name: nrf52_tim_deinit + * + * Description: + * Deinit TIMER device + * + ****************************************************************************/ + +int nrf52_tim_deinit(FAR struct nrf52_tim_dev_s *dev) +{ + FAR struct nrf52_tim_priv_s *tim = NULL; + + DEBUGASSERT(dev); + + tim = (FAR struct nrf52_tim_priv_s *)dev; + + tim->inuse = false; + + return OK; +} diff --git a/arch/arm/src/nrf52/nrf52_tim.h b/arch/arm/src/nrf52/nrf52_tim.h new file mode 100644 index 0000000000..fe708879a9 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_tim.h @@ -0,0 +1,176 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_tim.h + * + * 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_NRF52_NRF52_TIM_H +#define __ARCH_ARM_SRC_NRF52_NRF52_TIM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Helpers ******************************************************************/ + +#define NRF52_TIM_START(d) ((d)->ops->start(d)) +#define NRF52_TIM_STOP(d) ((d)->ops->stop(d)) +#define NRF52_TIM_CLEAR(d) ((d)->ops->clear(d)) +#define NRF52_TIM_CONFIGURE(d, m, w) ((d)->ops->configure(d, m, w)) +#define NRF52_TIM_SHORTS(d, s, i, e) ((d)->ops->shorts(d, s, i, e)) +#define NRF52_TIM_COUNT(d) ((d)->ops->count(d)) +#define NRF52_TIM_SETCC(d, i, cc) ((d)->ops->setcc(d, i, cc)) +#define NRF52_TIM_GETCC(d, i, cc) ((d)->ops->setcc(d, i, cc)) +#define NRF52_TIM_SETPRE(d, pre) ((d)->ops->setpre(d, pre)) +#define NRF52_TIM_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg)) +#define NRF52_TIM_ENABLEINT(d, s) ((d)->ops->enableint(d, s)) +#define NRF52_TIM_DISABLEINT(d, s) ((d)->ops->disableint(d, s)) +#define NRF52_TIM_CHECKINT(d, s) ((d)->ops->checkint(d, s)) +#define NRF52_TIM_ACKINT(d, s) ((d)->ops->ackint(d, s)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Timer mode */ + +enum nrf52_tim_mode_e +{ + NRF52_TIM_MODE_UNUSED = 0, + NRF52_TIM_MODE_TIMER = 1, + NRF52_TIM_MODE_COUNTER = 2, + NRF52_TIM_MODE_LOWPOWER = 3, +}; + +/* Timer bit width */ + +enum nrf52_tim_width_e +{ + NRF52_TIM_WIDTH_16B = 0, + NRF52_TIM_WIDTH_8B = 1, + NRF52_TIM_WIDTH_24B = 2, + NRF52_TIM_WIDTH_32B = 3, +}; + +/* Timer CC index */ + +enum nrf52_tim_cc_e +{ + NRF52_TIM_CC0 = 0, + NRF52_TIM_CC1 = 1, + NRF52_TIM_CC2 = 2, + NRF52_TIM_CC3 = 3, + NRF52_TIM_CC4 = 4, + NRF52_TIM_CC5 = 5 +}; + +/* Timer IRQ source */ + +enum nrf52_tim_irq_e +{ + NRF52_TIM_INT_COMPARE0 = 0, + NRF52_TIM_INT_COMPARE1 = 1, + NRF52_TIM_INT_COMPARE2 = 2, + NRF52_TIM_INT_COMPARE3 = 3, + NRF52_TIM_INT_COMPARE4 = 4, + NRF52_TIM_INT_COMPARE5 = 5, +}; + +/* Timer shorts type */ + +enum nrf52_tim_shorts_e +{ + NRF52_TIM_SHORT_COMPARE_CLEAR = 1, + NRF52_TIM_SHORT_COMPARE_STOP = 2 +}; + +/* Timer frequency prescaler */ + +enum nrf52_tim_pre_e +{ + NRF52_TIM_PRE_16000000 = 0, + NRF52_TIM_PRE_8000000 = 1, + NRF52_TIM_PRE_4000000 = 2, + NRF52_TIM_PRE_2000000 = 3, + NRF52_TIM_PRE_1000000 = 4, + NRF52_TIM_PRE_500000 = 5, + NRF52_TIM_PRE_250000 = 6, + NRF52_TIM_PRE_125000 = 7, + NRF52_TIM_PRE_62500 = 8, + NRF52_TIM_PRE_31250 = 9 +}; + +/* NRF52 TIM device */ + +struct nrf52_tim_dev_s +{ + struct nrf52_tim_ops_s *ops; +}; + +/* NRF52 TIM ops */ + +struct nrf52_tim_ops_s +{ + /* Timer tasks */ + + CODE int (*start)(FAR struct nrf52_tim_dev_s *dev); + CODE int (*stop)(FAR struct nrf52_tim_dev_s *dev); + CODE int (*clear)(FAR struct nrf52_tim_dev_s *dev); + + /* Timer configuration */ + + CODE int (*configure)(FAR struct nrf52_tim_dev_s *dev, uint8_t mode, + uint8_t width); + CODE int (*shorts)(FAR struct nrf52_tim_dev_s *dev, uint8_t s, + uint8_t i, bool en); + + /* Timer operations */ + + CODE int (*count)(FAR struct nrf52_tim_dev_s *dev); + CODE int (*setcc)(FAR struct nrf52_tim_dev_s *dev, uint8_t i, uint32_t cc); + CODE int (*getcc)(FAR struct nrf52_tim_dev_s *dev, uint8_t i, + FAR uint32_t *cc); + CODE int (*setpre)(FAR struct nrf52_tim_dev_s *dev, uint8_t pre); + + /* Timer interrupts */ + + CODE int (*setisr)(FAR struct nrf52_tim_dev_s *dev, xcpt_t handler, + FAR void * arg); + CODE int (*enableint)(FAR struct nrf52_tim_dev_s *dev, uint8_t source); + CODE int (*disableint)(FAR struct nrf52_tim_dev_s *dev, uint8_t source); + CODE int (*checkint)(FAR struct nrf52_tim_dev_s *dev, uint8_t source); + CODE int (*ackint)(FAR struct nrf52_tim_dev_s *dev, uint8_t source); +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +FAR struct nrf52_tim_dev_s *nrf52_tim_init(int timer); +int nrf52_tim_deinit(FAR struct nrf52_tim_dev_s *dev); + +#endif /* __ARCH_ARM_SRC_NRF52_NRF52_TIM_H */