From 3571ff3c54c8cd60b86cfbf100e821e838937715 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Mon, 13 Mar 2023 12:32:56 +0100 Subject: [PATCH] arch/nrf53: add SAADC support --- arch/arm/src/nrf53/Kconfig | 68 ++- arch/arm/src/nrf53/Make.defs | 4 + arch/arm/src/nrf53/nrf53_adc.c | 964 +++++++++++++++++++++++++++++++++ arch/arm/src/nrf53/nrf53_adc.h | 162 ++++++ 4 files changed, 1197 insertions(+), 1 deletion(-) create mode 100644 arch/arm/src/nrf53/nrf53_adc.c create mode 100644 arch/arm/src/nrf53/nrf53_adc.h diff --git a/arch/arm/src/nrf53/Kconfig b/arch/arm/src/nrf53/Kconfig index 7ed9deeb01..d9469c8d89 100644 --- a/arch/arm/src/nrf53/Kconfig +++ b/arch/arm/src/nrf53/Kconfig @@ -23,6 +23,7 @@ config NRF53_APPCORE select ARM_HAVE_DSP select ARCH_HAVE_FPU select NRF53_HAVE_PWM + select NRF53_HAVE_SAADC config NRF53_NETCORE bool @@ -36,7 +37,6 @@ choice config ARCH_CHIP_NRF5340_CPUAPP bool "NRF53 App core" select NRF53_APPCORE - select ARCH_HAVE_FPU config ARCH_CHIP_NRF5340_CPUNET bool "NRF53 Net core" @@ -74,6 +74,10 @@ config NRF53_HAVE_PWM bool default n +config NRF53_HAVE_SAADC + bool + default n + # Peripheral Selection config NRF53_IPC @@ -136,6 +140,10 @@ config NRF53_PWM2 select NRF53_PWM default n +config NRF53_SAADC + bool "SAADC" + default n + endmenu # NRF53 Peripheral Selection menu "Clock Configuration" @@ -332,6 +340,64 @@ endif # !NRF53_PWM_MULTICHAN endmenu # PWM configuration +menu "SAADC Configuration" + +if NRF53_SAADC + +choice + prompt "SAADC trigger selection" + default NRF53_SAADC_TASK + ---help--- + Choose mode for sample rate control + +config NRF53_SAADC_TASK + bool "SAADC Task trigger" + +config NRF53_SAADC_TIMER + bool "SAADC Timer trigger" + +endchoice # SAADC trigger selection + +if NRF53_SAADC_TIMER + +config NRF53_SAADC_TIMER_CC + int "SAADC Timer CC" + default 0 + range 80 2047 + +endif #NRF53_SAADC_TIMER + +config NRF53_SAADC_OVERSAMPLE + int "SAADC oversample" + default 0 + range 0 8 + ---help--- + SAADC oversample control + +config NRF53_SAADC_RESOLUTION + int "SAADC resolution" + default 0 + range 0 3 + ---help--- + SAADC resolution 0 - 8 bits, 1 - 10 bits, 2 - 12 bits, 3 - 14 bits + +config NRF53_SAADC_CHANNELS + int "SAADC channels" + default 8 + range 0 8 + ---help--- + SAADC channels + +config NRF53_SAADC_LIMITS + bool "SAADC limits enable" + default n + ---help--- + SAADC limist enable + +endif # NRF53_SAADC + +endmenu # SAADC Configuration + menuconfig NRF53_SOFTDEVICE_CONTROLLER bool "SoftDevice Controller" depends on ALLOW_BSDNORDIC_COMPONENTS diff --git a/arch/arm/src/nrf53/Make.defs b/arch/arm/src/nrf53/Make.defs index cef4be459b..ab2ee577a5 100644 --- a/arch/arm/src/nrf53/Make.defs +++ b/arch/arm/src/nrf53/Make.defs @@ -62,6 +62,10 @@ ifeq ($(CONFIG_NRF53_PWM),y) CHIP_CSRCS += nrf53_pwm.c endif +ifeq ($(CONFIG_NRF53_SAADC),y) +CHIP_CSRCS += nrf53_adc.c +endif + ifeq ($(CONFIG_PM),y) CHIP_CSRCS += nrf53_pminitialize.c endif diff --git a/arch/arm/src/nrf53/nrf53_adc.c b/arch/arm/src/nrf53/nrf53_adc.c new file mode 100644 index 0000000000..83d988229f --- /dev/null +++ b/arch/arm/src/nrf53/nrf53_adc.c @@ -0,0 +1,964 @@ +/**************************************************************************** + * arch/arm/src/nrf53/nrf53_adc.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 +#include + +#include +#include +#include +#include + +#include "arm_internal.h" +#include "nrf53_gpio.h" +#include "nrf53_adc.h" + +#include "hardware/nrf53_saadc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nrf53_adc_s +{ + /* Upper-half callback */ + + const struct adc_callback_s *cb; + + /* Channels configuration */ + + struct nrf53_adc_channel_s channels[CONFIG_NRF53_SAADC_CHANNELS]; + + /* Samples buffer */ + + int16_t buffer[CONFIG_NRF53_SAADC_CHANNELS]; + + uint8_t chan_len; /* Configured channels */ + uint32_t base; /* Base address of ADC register */ + uint32_t irq; /* ADC interrupt */ + uint8_t resolution; /* ADC resolution */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* ADC Register access */ + +static inline void nrf53_adc_putreg(struct nrf53_adc_s *priv, + uint32_t offset, + uint32_t value); +static inline uint32_t nrf53_adc_getreg(struct nrf53_adc_s *priv, + uint32_t offset); + +/* ADC helpers */ + +static int nrf53_adc_configure(struct nrf53_adc_s *priv); +static int nrf53_adc_calibrate(struct nrf53_adc_s *priv); +static uint32_t nrf53_adc_ch_config(struct nrf53_adc_channel_s *cfg); +static uint32_t nrf53_adc_chanpsel(int psel); +static int nrf53_adc_chancfg(struct nrf53_adc_s *priv, uint8_t chan, + struct nrf53_adc_channel_s *cfg); +static int nrf53_adc_isr(int irq, void *context, void *arg); + +/* ADC Driver Methods */ + +static int nrf53_adc_bind(struct adc_dev_s *dev, + const struct adc_callback_s *callback); +static void nrf53_adc_reset(struct adc_dev_s *dev); +static int nrf53_adc_setup(struct adc_dev_s *dev); +static void nrf53_adc_shutdown(struct adc_dev_s *dev); +static void nrf53_adc_rxint(struct adc_dev_s *dev, bool enable); +static int nrf53_adc_ioctl(struct adc_dev_s *dev, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* ADC interface operations */ + +static const struct adc_ops_s g_nrf53_adcops = +{ + .ao_bind = nrf53_adc_bind, + .ao_reset = nrf53_adc_reset, + .ao_setup = nrf53_adc_setup, + .ao_shutdown = nrf53_adc_shutdown, + .ao_rxint = nrf53_adc_rxint, + .ao_ioctl = nrf53_adc_ioctl, +}; + +/* SAADC device */ + +struct nrf53_adc_s g_nrf53_adcpriv = +{ + .cb = NULL, + .base = NRF53_SAADC_BASE, + .irq = NRF53_IRQ_SAADC, + .resolution = CONFIG_NRF53_SAADC_RESOLUTION +}; + +/* Upper-half ADC device */ + +static struct adc_dev_s g_nrf53_adc = +{ + .ad_ops = &g_nrf53_adcops, + .ad_priv = &g_nrf53_adcpriv, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_adc_putreg + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void nrf53_adc_putreg(struct nrf53_adc_s *priv, + uint32_t offset, + uint32_t value) +{ + DEBUGASSERT(priv); + + putreg32(value, priv->base + offset); +} + +/**************************************************************************** + * Name: nrf53_adc_getreg + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static inline uint32_t nrf53_adc_getreg(struct nrf53_adc_s *priv, + uint32_t offset) +{ + DEBUGASSERT(priv); + + return getreg32(priv->base + offset); +} + +/**************************************************************************** + * Name: nrf53_adc_isr + * + * Description: + * Common ADC interrupt service routine + * + ****************************************************************************/ + +static int nrf53_adc_isr(int irq, void *context, void *arg) +{ + struct adc_dev_s *dev = (struct adc_dev_s *) arg; + struct nrf53_adc_s *priv = NULL; + int ret = OK; + int i = 0; + + DEBUGASSERT(dev); + + priv = (struct nrf53_adc_s *) dev->ad_priv; + DEBUGASSERT(priv); + + ainfo("nrf53_adc_isr\n"); + + /* END event */ + + if (nrf53_adc_getreg(priv, NRF53_SAADC_EVENTS_END_OFFSET) == 1) + { + DEBUGASSERT(priv->cb != NULL); + DEBUGASSERT(priv->cb->au_receive != NULL); + + /* Give the ADC data to the ADC driver */ + + for (i = 0; i < priv->chan_len; i += 1) + { + priv->cb->au_receive(dev, i, priv->buffer[i]); + } + + /* Clear event */ + + nrf53_adc_putreg(priv, NRF53_SAADC_EVENTS_END_OFFSET, 0); + } + + return ret; +} + +/**************************************************************************** + * Name: nrf53_adc_configure + * + * Description: + * Configure ADC + * + ****************************************************************************/ + +static int nrf53_adc_configure(struct nrf53_adc_s *priv) +{ + int regval = 0; + + DEBUGASSERT(priv); + + /* Configure ADC resolution */ + + regval = CONFIG_NRF53_SAADC_RESOLUTION; + nrf53_adc_putreg(priv, NRF53_SAADC_RESOLUTION_OFFSET, regval); + + /* Configure oversampling */ + + regval = CONFIG_NRF53_SAADC_OVERSAMPLE; + nrf53_adc_putreg(priv, NRF53_SAADC_OVERSAMPLE_OFFSET, regval); + + /* Configure sample rate */ + +#if defined(CONFIG_NRF53_SAADC_TIMER) + /* Trigger from local timer */ + + regval = SAADC_SAMPLERATE_MODE_TIMERS; + regval |= ((CONFIG_NRF53_SAADC_TIMER_CC & SAADC_SAMPLERATE_CC_MASK) + << SAADC_SAMPLERATE_CC_SHIFT); +#elif defined(CONFIG_NRF53_SAADC_TASK) + /* Trigger on SAMPLE tas */ + + regval = SAADC_SAMPLERATE_MODE_TASK; +#else +# error SAADC trigger not selected +#endif + + nrf53_adc_putreg(priv, NRF53_SAADC_SAMPLERATE_OFFSET, regval); + + /* Configure ADC buffer */ + + regval = (uint32_t)&priv->buffer; + nrf53_adc_putreg(priv, NRF53_SAADC_PTR_OFFSET, regval); + + regval = priv->chan_len; + nrf53_adc_putreg(priv, NRF53_SAADC_MAXCNT_OFFSET, regval); + + return OK; +} + +/**************************************************************************** + * Name: nrf53_adc_calibrate + * + * Description: + * Calibrate ADC + * + ****************************************************************************/ + +static int nrf53_adc_calibrate(struct nrf53_adc_s *priv) +{ + /* Clear Event */ + + nrf53_adc_putreg(priv, NRF53_SAADC_EVENTS_CALDONE_OFFSET, 0); + + /* Start calibration */ + + nrf53_adc_putreg(priv, NRF53_SAADC_TASKS_CALOFFSET_OFFSET, 1); + + /* Wait for calibration done */ + + while (nrf53_adc_getreg(priv, NRF53_SAADC_EVENTS_CALDONE_OFFSET) != 1); + + return OK; +} + +/**************************************************************************** + * Name: nrf53_adc_ch_config + ****************************************************************************/ + +static uint32_t nrf53_adc_ch_config(struct nrf53_adc_channel_s *cfg) +{ + uint32_t regval = 0; + + /* Positive channel resistor control */ + + switch (cfg->resp) + { + case NRF53_ADC_RES_BYPASS: + { + regval |= SAADC_CONFIG_RESP_NONE; + break; + } + + case NRF53_ADC_RES_PULLDOWN: + { + regval |= SAADC_CONFIG_RESP_PD; + break; + } + + case NRF53_ADC_RES_PULLUP: + { + regval |= SAADC_CONFIG_RESP_PU; + break; + } + + case NRF53_ADC_RES_VDD_2: + { + regval |= SAADC_CONFIG_RESP_VDD1P2; + break; + } + + default: + { + aerr("ERROR: invalid cfg->resp: %d\n", cfg->resp); + } + } + + /* Negative channel resistor control */ + + switch (cfg->resn) + { + case NRF53_ADC_RES_BYPASS: + { + regval |= SAADC_CONFIG_RESN_NONE; + break; + } + + case NRF53_ADC_RES_PULLDOWN: + { + regval |= SAADC_CONFIG_RESN_PD; + break; + } + + case NRF53_ADC_RES_PULLUP: + { + regval |= SAADC_CONFIG_RESN_PU; + break; + } + + case NRF53_ADC_RES_VDD_2: + { + regval |= SAADC_CONFIG_RESN_VDD1P2; + break; + } + + default: + { + aerr("ERROR: invalid cfg->resn: %d\n", cfg->resn); + } + } + + /* Gain control */ + + switch (cfg->gain) + { + case NRF53_ADC_GAIN_1_6: + { + regval |= SAADC_CONFIG_GAIN_1P6; + break; + } + + case NRF53_ADC_GAIN_1_5: + { + regval |= SAADC_CONFIG_GAIN_1P5; + break; + } + + case NRF53_ADC_GAIN_1_4: + { + regval |= SAADC_CONFIG_GAIN_1P4; + break; + } + + case NRF53_ADC_GAIN_1_3: + { + regval |= SAADC_CONFIG_GAIN_1P3; + break; + } + + case NRF53_ADC_GAIN_1_2: + { + regval |= SAADC_CONFIG_GAIN_1P2; + break; + } + + case NRF53_ADC_GAIN_1: + { + regval |= SAADC_CONFIG_GAIN_1; + break; + } + + case NRF53_ADC_GAIN_2: + { + regval |= SAADC_CONFIG_GAIN_2; + break; + } + + case NRF53_ADC_GAIN_4: + { + regval |= SAADC_CONFIG_GAIN_4; + break; + } + + default: + { + aerr("ERROR: invalid cfg->gain: %d\n", cfg->gain); + } + } + + /* Reference control */ + + switch (cfg->refsel) + { + case NRF53_ADC_REFSEL_INTERNAL: + { + regval |= SAADC_CONFIG_REFSEL_INTERNAL; + break; + } + + case NRF53_ADC_REFSEL_VDD_4: + { + regval |= SAADC_CONFIG_REFSEL_VDD1P4; + break; + } + + default: + { + aerr("ERROR: invalid cfg->refsel: %d\n", cfg->refsel); + } + } + + /* Acquisition time */ + + switch (cfg->tacq) + { + case NRF53_ADC_TACQ_3US: + { + regval |= SAADC_CONFIG_TACQ_3US; + break; + } + + case NRF53_ADC_TACQ_5US: + { + regval |= SAADC_CONFIG_TACQ_5US; + break; + } + + case NRF53_ADC_TACQ_10US: + { + regval |= SAADC_CONFIG_TACQ_10US; + break; + } + + case NRF53_ADC_TACQ_15US: + { + regval |= SAADC_CONFIG_TACQ_15US; + break; + } + + case NRF53_ADC_TACQ_20US: + { + regval |= SAADC_CONFIG_TACQ_20US; + break; + } + + case NRF53_ADC_TACQ_40US: + { + regval |= SAADC_CONFIG_TACQ_40US; + break; + } + + default: + { + aerr("ERROR: invalid cfg->tacq: %d\n", cfg->tacq); + } + } + + /* Singe-ended or differential mode */ + + switch (cfg->mode) + { + case NRF53_ADC_MODE_SE: + { + regval |= SAADC_CONFIG_MODE_SE; + break; + } + + case NRF53_ADC_MODE_DIFF: + { + regval |= SAADC_CONFIG_MODE_DIFF; + break; + } + + default: + { + aerr("ERROR: invalid cfg->mode: %d\n", cfg->mode); + } + } + + /* Burst mode */ + + switch (cfg->burst) + { + case NRF53_ADC_BURST_DISABLE: + { + regval |= SAADC_CONFIG_BURS_DIS; + break; + } + + case NRF53_ADC_BURST_ENABLE: + { + regval |= SAADC_CONFIG_BURS_EN; + break; + } + + default: + { + aerr("ERROR: invalid cfg->burst: %d\n", cfg->burst); + } + } + + return regval; +} + +/**************************************************************************** + * Name: nrf53_adc_chanpsel + ****************************************************************************/ + +static uint32_t nrf53_adc_chanpsel(int psel) +{ + uint32_t regval = 0; + + switch (psel) + { + case NRF53_ADC_IN_NC: + { + regval = SAADC_CHPSEL_NC; + break; + } + + case NRF53_ADC_IN_IN0: + { + regval = SAADC_CHPSEL_IN0; + break; + } + + case NRF53_ADC_IN_IN1: + { + regval = SAADC_CHPSEL_IN1; + break; + } + + case NRF53_ADC_IN_IN2: + { + regval = SAADC_CHPSEL_IN2; + break; + } + + case NRF53_ADC_IN_IN3: + { + regval = SAADC_CHPSEL_IN3; + break; + } + + case NRF53_ADC_IN_IN4: + { + regval = SAADC_CHPSEL_IN4; + break; + } + + case NRF53_ADC_IN_IN5: + { + regval = SAADC_CHPSEL_IN5; + break; + } + + case NRF53_ADC_IN_IN6: + { + regval = SAADC_CHPSEL_IN6; + break; + } + + case NRF53_ADC_IN_IN7: + { + regval = SAADC_CHPSEL_IN7; + break; + } + + case NRF53_ADC_IN_VDD: + { + regval = SAADC_CHPSEL_VDD; + break; + } + + case NRF53_ADC_IN_VDDHDIV5: + { + regval = SAADC_CHPSEL_VDDHDIV5; + break; + } + + default: + { + aerr("ERROR: invalid psel: %d\n", psel); + } + } + + return regval; +} + +/**************************************************************************** + * Name: nrf53_adc_chancfg + * + * Description: + * Configure ADC channel + * + ****************************************************************************/ + +static int nrf53_adc_chancfg(struct nrf53_adc_s *priv, uint8_t chan, + struct nrf53_adc_channel_s *cfg) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(priv); + + /* Configure positive input */ + + regval = nrf53_adc_chanpsel(cfg->p_psel); + nrf53_adc_putreg(priv, NRF53_SAADC_CHPSELP_OFFSET(chan), regval); + + /* Configure negative input */ + + regval = nrf53_adc_chanpsel(cfg->n_psel); + nrf53_adc_putreg(priv, NRF53_SAADC_CHPSELN_OFFSET(chan), regval); + + /* Get channel configuration */ + + regval = nrf53_adc_ch_config(cfg); + + /* Write channel configuration */ + + nrf53_adc_putreg(priv, NRF53_SAADC_CHCONFIG_OFFSET(chan), regval); + +#ifdef CONFIG_NRF53_SAADC_LIMITS + /* Configure limits */ + + regval = (cfg->limith < 16) | (cfg->limith << 0); + nrf53_adc_putreg(priv, NRF53_SAADC_CHLIMIT_OFFSET(chan), regval); +#endif + + return ret; +} + +/**************************************************************************** + * Name: nrf53_adc_bind + * + * Description: + * Bind the upper-half driver callbacks to the lower-half implementation. + * This must be called early in order to receive ADC event notifications. + * + ****************************************************************************/ + +static int nrf53_adc_bind(struct adc_dev_s *dev, + const struct adc_callback_s *callback) +{ + struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv; + + DEBUGASSERT(dev); + DEBUGASSERT(priv); + + priv->cb = callback; + + return OK; +} + +/**************************************************************************** + * Name: nrf53_adc_reset + * + * Description: + * Reset the ADC device. Called early to initialize the hardware. + * This is called, before adc_setup() and on error conditions. + * + ****************************************************************************/ + +static void nrf53_adc_reset(struct adc_dev_s *dev) +{ + struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv; + + DEBUGASSERT(dev); + DEBUGASSERT(priv); + + /* TODO */ + + UNUSED(priv); +} + +/**************************************************************************** + * Name: nrf53_adc_setup + * + * Description: + * Configure the ADC. This method is called the first time that the ADC + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching ADC interrupts. + * Interrupts are all disabled upon return. + * + ****************************************************************************/ + +static int nrf53_adc_setup(struct adc_dev_s *dev) +{ + struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv; + int i = 0; + int ret = OK; + + DEBUGASSERT(dev); + DEBUGASSERT(priv); + + /* Disable ADC */ + + nrf53_adc_putreg(priv, NRF53_SAADC_ENABLE_OFFSET, 0); + + /* Configure ADC */ + + ret = nrf53_adc_configure(priv); + if (ret < 0) + { + aerr("ERROR: nrf53_adc_configure failed: %d\n", ret); + goto errout; + } + + /* Configure ADC channels */ + + for (i = 0; i < priv->chan_len; i += 1) + { + ret = nrf53_adc_chancfg(priv, i, &priv->channels[i]); + if (ret < 0) + { + aerr("ERROR: chancfg failed: %d %d\n", i, ret); + goto errout; + } + } + + /* Enable ADC */ + + nrf53_adc_putreg(priv, NRF53_SAADC_ENABLE_OFFSET, 1); + + /* Calibrate ADC */ + + ret = nrf53_adc_calibrate(priv); + if (ret < 0) + { + aerr("ERROR: adc calibration failed: %d\n", ret); + goto errout; + } + + /* Attach the ADC interrupt */ + + ret = irq_attach(priv->irq, nrf53_adc_isr, dev); + if (ret < 0) + { + aerr("ERROR: irq_attach failed: %d\n", ret); + goto errout; + } + + /* Enable the ADC interrupt */ + + up_enable_irq(priv->irq); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf53_adc_shutdown + * + * Description: + * Disable the ADC. This method is called when the ADC device is closed. + * This method reverses the operation the setup method. + * + ****************************************************************************/ + +static void nrf53_adc_shutdown(struct adc_dev_s *dev) +{ + struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv; + + DEBUGASSERT(dev); + DEBUGASSERT(priv); + + /* Stop SAADC */ + + nrf53_adc_putreg(priv, NRF53_SAADC_TASKS_STOP_OFFSET, 1); + + /* Wait for SAADC stopped */ + + while (nrf53_adc_getreg(priv, NRF53_SAADC_EVENTS_STOPPED_OFFSET) != 1); + + /* Disable SAADC */ + + nrf53_adc_putreg(priv, NRF53_SAADC_ENABLE_OFFSET, 0); +} + +/**************************************************************************** + * Name: nrf53_adc_rxint + * + * Description: + * Call to enable or disable RX interrupts. + * + ****************************************************************************/ + +static void nrf53_adc_rxint(struct adc_dev_s *dev, bool enable) +{ + struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv; + uint32_t regval = 0; + + DEBUGASSERT(dev); + DEBUGASSERT(priv); + + ainfo("RXINT enable: %d\n", enable ? 1 : 0); + + regval = SAADC_INT_END; + + if (enable) + { + nrf53_adc_putreg(priv, NRF53_SAADC_INTENSET_OFFSET, regval); + } + else + { + nrf53_adc_putreg(priv, NRF53_SAADC_INTENCLR_OFFSET, regval); + } +} + +/**************************************************************************** + * Name: nrf53_adc_ioctl + * + * Description: + * All ioctl calls will be routed through this method. + * + ****************************************************************************/ + +static int nrf53_adc_ioctl(struct adc_dev_s *dev, int cmd, + unsigned long arg) +{ + struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv; + int ret = OK; + + DEBUGASSERT(dev); + DEBUGASSERT(priv); + + switch (cmd) + { + case ANIOC_TRIGGER: + { + /* Start ADC */ + + nrf53_adc_putreg(priv, NRF53_SAADC_TASKS_START_OFFSET, 1); + + /* Trigger first sample */ + + nrf53_adc_putreg(priv, NRF53_SAADC_TASKS_SAMPLE_OFFSET, 1); + } + break; + + case ANIOC_GET_NCHANNELS: + { + /* Return the number of configured channels */ + + ret = priv->chan_len; + } + break; + + default: + { + aerr("ERROR: Unknown cmd: %d\n", cmd); + ret = -ENOTTY; + } + break; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_adcinitialize + * + * Description: + * Initialize the ADC. See nrf53_adc.c for more details. + * + * Input Parameters: + * chanlist - channels configuration + * nchannels - number of channels + * + * Returned Value: + * Valid ADC device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct adc_dev_s *nrf53_adcinitialize( + const struct nrf53_adc_channel_s *chan, int channels) +{ + struct adc_dev_s *dev = NULL; + struct nrf53_adc_s *priv = NULL; + int i = 0; + + DEBUGASSERT(chan != NULL); + DEBUGASSERT(channels <= CONFIG_NRF53_SAADC_CHANNELS); + +#ifdef CONFIG_NRF53_SAADC_TIMER + if (channels > 1) + { + aerr("ERORR: timer trigger works only for 1 channel!\n"); + goto errout; + } +#endif + + /* Get device */ + + dev = &g_nrf53_adc; + + /* Get private data */ + + priv = (struct nrf53_adc_s *) dev->ad_priv; + + /* Copy channels configuration */ + + ainfo("channels: %d\n", channels); + + for (i = 0; i < channels; i += 1) + { + memcpy(&priv->channels[i], &chan[i], + sizeof(struct nrf53_adc_channel_s)); + } + + priv->chan_len = channels; + +#ifdef CONFIG_NRF53_SAADC_TIMER +errout: +#endif + return dev; +} diff --git a/arch/arm/src/nrf53/nrf53_adc.h b/arch/arm/src/nrf53/nrf53_adc.h new file mode 100644 index 0000000000..3e31efc1ae --- /dev/null +++ b/arch/arm/src/nrf53/nrf53_adc.h @@ -0,0 +1,162 @@ +/**************************************************************************** + * arch/arm/src/nrf53/nrf53_adc.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_NRF53_NRF53_ADC_H +#define __ARCH_ARM_SRC_NRF53_NRF53_ADC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* ADC input */ + +enum nrf53_adc_ain_e +{ + NRF53_ADC_IN_NC = 0, /* Not connected */ + NRF53_ADC_IN_IN0 = 1, /* Analog input 0 */ + NRF53_ADC_IN_IN1 = 2, /* Analog input 1 */ + NRF53_ADC_IN_IN2 = 3, /* Analog input 2 */ + NRF53_ADC_IN_IN3 = 4, /* Analog input 3 */ + NRF53_ADC_IN_IN4 = 5, /* Analog input 4 */ + NRF53_ADC_IN_IN5 = 6, /* Analog input 5 */ + NRF53_ADC_IN_IN6 = 7, /* Analog input 6 */ + NRF53_ADC_IN_IN7 = 8, /* Analog input 7 */ + NRF53_ADC_IN_VDD = 9, /* VDD */ + NRF53_ADC_IN_VDDHDIV5 = 10, /* VDDH/5 */ +}; + +/* Resistor control */ + +enum nrf53_adc_res_e +{ + NRF53_ADC_RES_BYPASS = 0, /* Bypass resistor ladder */ + NRF53_ADC_RES_PULLDOWN = 1, /* Pull-down to GND */ + NRF53_ADC_RES_PULLUP = 2, /* Pull-up to VDD */ + NRF53_ADC_RES_VDD_2 = 3 /* Set input at VDD/2 */ +}; + +/* Gain control */ + +enum nrf53_adc_gain_e +{ + NRF53_ADC_GAIN_1_6 = 0, /* 1/6 */ + NRF53_ADC_GAIN_1_5 = 1, /* 1/5 */ + NRF53_ADC_GAIN_1_4 = 2, /* 1/4 */ + NRF53_ADC_GAIN_1_3 = 3, /* 1/3 */ + NRF53_ADC_GAIN_1_2 = 4, /* 1/2 */ + NRF53_ADC_GAIN_1 = 5, /* 1 */ + NRF53_ADC_GAIN_2 = 6, /* 2 */ + NRF53_ADC_GAIN_4 = 7 /* 4 */ +}; + +/* Reference control */ + +enum nrf53_adc_refsel_e +{ + NRF53_ADC_REFSEL_INTERNAL = 0, /* Internal reference (0.6V) */ + NRF53_ADC_REFSEL_VDD_4 = 1 /* VDD/4 as reference */ +}; + +/* Acquisition time control */ + +enum nrf53_adc_tacq_e +{ + NRF53_ADC_TACQ_3US = 0, /* 3 us */ + NRF53_ADC_TACQ_5US = 1, /* 5 us */ + NRF53_ADC_TACQ_10US = 2, /* 10 us */ + NRF53_ADC_TACQ_15US = 3, /* 15 us */ + NRF53_ADC_TACQ_20US = 4, /* 20 us */ + NRF53_ADC_TACQ_40US = 5 /* 40 us */ +}; + +/* ADC mode control */ + +enum nrf53_adc_mode_e +{ + NRF53_ADC_MODE_SE = 0, /* Single-ended mode */ + NRF53_ADC_MODE_DIFF = 1 /* Differentail mode */ +}; + +/* ADC burst control */ + +enum nrf53_adc_burst_e +{ + NRF53_ADC_BURST_DISABLE = 0, /* Disable burst mode */ + NRF53_ADC_BURST_ENABLE = 1 /* Enable burst mode */ +}; + +/* NRF53 ADC channel configuration */ + +struct nrf53_adc_channel_s +{ + uint32_t p_psel; /* P pin */ + uint32_t n_psel; /* N pin */ +#ifdef CONFIG_NRF53_SAADC_LIMITS + uint16_t limith; /* High limit */ + uint16_t limitl; /* Low limit */ +#endif + uint8_t resp:2; /* Positive chan resistor */ + uint8_t resn:2; /* Negative chan resistor */ + uint8_t gain:3; /* Gain control */ + uint8_t refsel:1; /* Reference control */ + uint8_t tacq:3; /* Acquisition time */ + uint8_t mode:1; /* Singe-ended or differential mode */ + uint8_t burst:1; /* Burst mode */ + uint8_t _res:3; /* Reserved */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_adcinitialize + * + * Description: + * Initialize the ADC. See nrf53_adc.c for more details. + * + * Input Parameters: + * chanlist - channels configuration + * nchannels - number of channels + * + * Returned Value: + * Valid ADC device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct adc_dev_s *nrf53_adcinitialize( + const struct nrf53_adc_channel_s *chan, + int channels); + +#endif /* __ARCH_ARM_SRC_NRF53_NRF53_ADC_H */