arch/arm/src/samv7: add support for AFEC (ADC) driver
This commit adds microcontroller support for Analog Front End driver to samv7 MCUs. Only software trigger via IOCTL is currently supported, averaging can be set by configuration option CONFIG_SAMV7_AFECn_RES. Signed-off-by: Michal Lenc <michallenc@seznam.cz>
This commit is contained in:
parent
eee85faab1
commit
e0cef411e1
@ -196,6 +196,10 @@ config SAMV7_HAVE_MCAN1
|
||||
bool
|
||||
default n
|
||||
|
||||
config SAMV7_AFEC
|
||||
bool
|
||||
default n
|
||||
|
||||
config SAMV7_DAC
|
||||
bool
|
||||
default n
|
||||
@ -313,10 +317,42 @@ config SAMV7_ADC
|
||||
config SAMV7_AFEC0
|
||||
bool "Analog Front End 0 (AFEC0)"
|
||||
default n
|
||||
select SAMV7_AFEC
|
||||
|
||||
if SAMV7_AFEC0
|
||||
|
||||
config SAMV7_AFEC0_RES
|
||||
int "AFEC0 Resolution"
|
||||
default 0
|
||||
range 0 5
|
||||
---help---
|
||||
0 no average
|
||||
1 low resolution
|
||||
2 OSR4
|
||||
3 OSR16
|
||||
4 OSR64
|
||||
5 OSR256
|
||||
endif
|
||||
|
||||
config SAMV7_AFEC1
|
||||
bool "Analog Front End 1 (AFEC1)"
|
||||
default n
|
||||
select SAMV7_AFEC
|
||||
|
||||
if SAMV7_AFEC1
|
||||
|
||||
config SAMV7_AFEC1_RES
|
||||
int "AFEC1 Resolution"
|
||||
default 0
|
||||
range 0 5
|
||||
---help---
|
||||
0 no average
|
||||
1 low resolution
|
||||
2 OSR4
|
||||
3 OSR16
|
||||
4 OSR64
|
||||
5 OSR256
|
||||
endif
|
||||
|
||||
config SAMV7_MCAN0
|
||||
bool "CAN controller 0 (MCAN0)"
|
||||
|
@ -166,6 +166,10 @@ ifeq ($(CONFIG_SAMV7_MCAN),y)
|
||||
CHIP_CSRCS += sam_mcan.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SAMV7_AFEC),y)
|
||||
CHIP_CSRCS += sam_afec.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SAMV7_USBDEVHS),y)
|
||||
CHIP_CSRCS += sam_usbdevhs.c
|
||||
endif
|
||||
|
@ -222,7 +222,9 @@
|
||||
# define AFEC_EMR_CMPFILTER(n) ((uint32_t)(n) << AFEC_EMR_CMPFILTER_SHIFT)
|
||||
#define AFEC_EMR_RES_SHIFT (16) /* Bits 16-18: Resolution */
|
||||
#define AFEC_EMR_RES_MASK (7 << AFEC_EMR_RES_SHIFT)
|
||||
#define AFEC_EMR_RES(n) ((uint32_t)(n) << AFEC_EMR_RES_SHIFT)
|
||||
# define AFEC_EMR_RES_NOAVG (0 << AFEC_EMR_RES_SHIFT) /* 12-bit resolution, AFEC sample rate is maximum (no averaging) */
|
||||
# define AFEC_EMR_RES_LOWRES (1 << AFEC_EMR_RES_SHIFT) /* 10-bit resolution, AFEC sample rate is maximum (no averaging) */
|
||||
# define AFEC_EMR_RES_OSR4 (2 << AFEC_EMR_RES_SHIFT) /* 13-bit resolution, AFEC sample rate divided by 4 (averaging) */
|
||||
# define AFEC_EMR_RES_OSR16 (3 << AFEC_EMR_RES_SHIFT) /* 14-bit resolution, AFEC sample rate divided by 16 (averaging) */
|
||||
# define AFEC_EMR_RES_OSR64 (4 << AFEC_EMR_RES_SHIFT) /* 15-bit resolution, AFEC sample rate divided by 64 (averaging) */
|
||||
@ -368,10 +370,10 @@
|
||||
/* Compare Window Register */
|
||||
|
||||
#define AFEC_CWR_LOWTHRES_SHIFT (0) /* Bits 0-11: Low Threshold */
|
||||
#define AFEC_CWR_LOWTHRES_MASK (0xfff << AFEC_CWR_LOWTHRES_SHIFT)
|
||||
#define AFEC_CWR_LOWTHRES_MASK (0xffff << AFEC_CWR_LOWTHRES_SHIFT)
|
||||
# define AFEC_CWR_LOWTHRES(n) ((uint32_t)(n) << AFEC_CWR_LOWTHRES_SHIFT)
|
||||
#define AFEC_CWR_HIGHTHRES_SHIFT (16) /* Bits 16-27: High Threshold */
|
||||
#define AFEC_CWR_HIGHTHRES_MASK (0xfff << AFEC_CWR_LOWTHRES_SHIFT)
|
||||
#define AFEC_CWR_HIGHTHRES_MASK (0xffff << AFEC_CWR_LOWTHRES_SHIFT)
|
||||
# define AFEC_CWR_HIGHTHRES(n)K ((uint32_t)(n) << AFEC_CWR_LOWTHRES_SHIFT)
|
||||
|
||||
/* Channel Gain Register */
|
||||
@ -453,7 +455,7 @@
|
||||
/* Channel Selection Register */
|
||||
|
||||
#define AFEC_CSELR_CSEL_SHIFT (0) /* Bits 0-3: Channel Selection */
|
||||
#define AFEC_CSELR_CSEL_MASK (15 << AFEC_CSELR_CSEL_SHIFT)
|
||||
#define AFEC_CSELR_CSEL_MASK (0xf << AFEC_CSELR_CSEL_SHIFT)
|
||||
# define AFEC_CSELR_CSEL(n) ((uint32_t)(n) << AFEC_CSELR_CSEL_SHIFT)
|
||||
|
||||
/* Channel Data Register */
|
||||
@ -462,7 +464,7 @@
|
||||
|
||||
/* Channel Offset Compensation Register */
|
||||
|
||||
#define AFEC_COCR_MASK (0x00000fff) /* Bits 0-12: Analog Offset */
|
||||
#define AFEC_COCR_MASK (0x000003ff) /* Bits 0-9: Analog Offset */
|
||||
|
||||
/* Temperature Sensor Mode Register */
|
||||
|
||||
@ -487,7 +489,7 @@
|
||||
|
||||
#define AFEC_ACR_PGA0EN (1 << 2) /* Bit 2: PGA0 Enable */
|
||||
#define AFEC_ACR_PGA1EN (1 << 3) /* Bit 3: PGA1 Enable */
|
||||
#define AFEC_ACR_IBCTL_SHIFT (9) /* Bits 8-9: AFEC Bias Current Control */
|
||||
#define AFEC_ACR_IBCTL_SHIFT (8) /* Bits 8-9: AFEC Bias Current Control */
|
||||
#define AFEC_ACR_IBCTL_MASK (3 << AFEC_ACR_IBCTL_SHIFT)
|
||||
# define AFEC_ACR_IBCTL(n) ((uint32_t)(n) << AFEC_ACR_IBCTL_SHIFT)
|
||||
|
||||
|
599
arch/arm/src/samv7/sam_afec.c
Normal file
599
arch/arm/src/samv7/sam_afec.c
Normal file
@ -0,0 +1,599 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/samv7/sam_afec.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 <nuttx/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/analog/adc.h>
|
||||
#include <nuttx/analog/ioctl.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "arm_arch.h"
|
||||
|
||||
#include "hardware/sam_matrix.h"
|
||||
#include "hardware/sam_pinmap.h"
|
||||
#include "hardware/sam_pio.h"
|
||||
#include "sam_periphclks.h"
|
||||
#include "sam_gpio.h"
|
||||
#include "sam_afec.h"
|
||||
|
||||
#ifdef CONFIG_ADC
|
||||
|
||||
#if defined(CONFIG_SAMV7_AFEC0) || defined(CONFIG_SAMV7_AFEC1)
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define ADC_MAX_CHANNELS 11
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct samv7_dev_s
|
||||
{
|
||||
FAR const struct adc_callback_s *cb; /* Upper driver callback */
|
||||
uint8_t intf; /* ADC number (i.e. ADC1, ADC2) */
|
||||
uint32_t base; /* ADC register base */
|
||||
uint8_t initialized; /* ADC initialization counter */
|
||||
uint8_t resolution; /* ADC resolution (SAMV7_AFECn_RES) */
|
||||
int irq; /* ADC IRQ number */
|
||||
int nchannels; /* Number of configured channels */
|
||||
uint8_t chanlist[ADC_MAX_CHANNELS]; /* ADC channel list */
|
||||
uint8_t current; /* Current channel being converted */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void afec_putreg(FAR struct samv7_dev_s *priv, uint32_t offset,
|
||||
uint32_t value);
|
||||
static uint32_t afec_getreg(FAR struct samv7_dev_s *priv, uint32_t offset);
|
||||
|
||||
/* ADC methods */
|
||||
|
||||
static int afec_bind(FAR struct adc_dev_s *dev,
|
||||
FAR const struct adc_callback_s *callback);
|
||||
static void afec_reset(FAR struct adc_dev_s *dev);
|
||||
static int afec_setup(FAR struct adc_dev_s *dev);
|
||||
static void afec_shutdown(FAR struct adc_dev_s *dev);
|
||||
static void afec_rxint(FAR struct adc_dev_s *dev, bool enable);
|
||||
static int afec_ioctl(FAR struct adc_dev_s *dev,
|
||||
int cmd, unsigned long arg);
|
||||
static int afec_interrupt(int irq, void *context, FAR void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct adc_ops_s g_adcops =
|
||||
{
|
||||
.ao_bind = afec_bind,
|
||||
.ao_reset = afec_reset,
|
||||
.ao_setup = afec_setup,
|
||||
.ao_shutdown = afec_shutdown,
|
||||
.ao_rxint = afec_rxint,
|
||||
.ao_ioctl = afec_ioctl,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SAMV7_AFEC0
|
||||
static struct samv7_dev_s g_adcpriv0 =
|
||||
{
|
||||
.irq = SAM_IRQ_AFEC0,
|
||||
.intf = 0,
|
||||
.initialized = 0,
|
||||
.resolution = CONFIG_SAMV7_AFEC0_RES,
|
||||
.base = SAM_AFEC0_BASE,
|
||||
};
|
||||
|
||||
static struct adc_dev_s g_adcdev0 =
|
||||
{
|
||||
.ad_ops = &g_adcops,
|
||||
.ad_priv = &g_adcpriv0,
|
||||
};
|
||||
|
||||
gpio_pinset_t g_adcpinlist0[ADC_MAX_CHANNELS] =
|
||||
{
|
||||
GPIO_AFE0_AD0,
|
||||
GPIO_AFE0_AD1,
|
||||
GPIO_AFE0_AD2,
|
||||
GPIO_AFE0_AD3,
|
||||
GPIO_AFE0_AD4,
|
||||
GPIO_AFE0_AD5,
|
||||
GPIO_AFE0_AD6,
|
||||
GPIO_AFE0_AD7,
|
||||
GPIO_AFE0_AD8,
|
||||
GPIO_AFE0_AD0,
|
||||
GPIO_AFE0_AD10,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SAMV7_AFEC1
|
||||
static struct samv7_dev_s g_adcpriv1 =
|
||||
{
|
||||
.irq = SAM_IRQ_AFEC1,
|
||||
.intf = 1,
|
||||
.initialized = 0,
|
||||
.resolution = CONFIG_SAMV7_AFEC1_RES,
|
||||
.base = SAM_AFEC1_BASE,
|
||||
};
|
||||
|
||||
static struct adc_dev_s g_adcdev1 =
|
||||
{
|
||||
.ad_ops = &g_adcops,
|
||||
.ad_priv = &g_adcpriv0,
|
||||
};
|
||||
|
||||
gpio_pinset_t g_adcpinlist1[ADC_MAX_CHANNELS] =
|
||||
{
|
||||
GPIO_AFE1_AD0,
|
||||
GPIO_AFE1_AD1,
|
||||
GPIO_AFE1_AD2,
|
||||
GPIO_AFE1_AD3,
|
||||
GPIO_AFE1_AD4,
|
||||
GPIO_AFE1_AD5,
|
||||
GPIO_AFE1_AD6,
|
||||
GPIO_AFE1_AD7,
|
||||
GPIO_AFE1_AD8,
|
||||
GPIO_AFE1_AD0,
|
||||
GPIO_AFE1_AD10,
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static void afec_putreg(FAR struct samv7_dev_s *priv, uint32_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
putreg32(value, priv->base + offset);
|
||||
}
|
||||
|
||||
static uint32_t afec_getreg(FAR struct samv7_dev_s *priv, uint32_t offset)
|
||||
{
|
||||
return getreg32(priv->base + offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: afec_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 afec_bind(FAR struct adc_dev_s *dev,
|
||||
FAR const struct adc_callback_s *callback)
|
||||
{
|
||||
FAR struct samv7_dev_s *priv = (FAR struct samv7_dev_s *)dev->ad_priv;
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
priv->cb = callback;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: afec_reset
|
||||
*
|
||||
* Description:
|
||||
* Reset the ADC device. Called early to initialize the hardware. This
|
||||
* is called, before afec_setup() and on error conditions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void afec_reset(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
FAR struct samv7_dev_s *priv = (FAR struct samv7_dev_s *)dev->ad_priv;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Do nothing if ADC instance is currently in use */
|
||||
|
||||
if (priv->initialized > 0)
|
||||
{
|
||||
goto exit_leave_critical;
|
||||
}
|
||||
|
||||
/* Configure clock gating */
|
||||
|
||||
switch (priv->intf)
|
||||
{
|
||||
#ifdef CONFIG_SAMV7_AFEC0
|
||||
case 0:
|
||||
sam_afec0_enableclk();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SAMV7_AFEC1
|
||||
case 1:
|
||||
sam_afec1_enableclk();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
aerr("ERROR: Tried to reset non-existing ADC: %d\n", priv->intf);
|
||||
goto exit_leave_critical;
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
/* Software reset */
|
||||
|
||||
afec_putreg(priv, SAM_AFEC_CR_OFFSET, AFEC_CR_SWRST);
|
||||
|
||||
/* Configure Mode Register */
|
||||
|
||||
uint32_t afec_mr = AFEC_MR_STARTUP_64 | AFEC_MR_PRESCAL(2) | AFEC_MR_ONE;
|
||||
afec_putreg(priv, SAM_AFEC_MR_OFFSET, afec_mr);
|
||||
|
||||
/* Configure Extended Mode register */
|
||||
|
||||
uint32_t afec_emr = AFEC_EMR_TAG | AFEC_EMR_STM | \
|
||||
AFEC_EMR_RES(priv->resolution);
|
||||
afec_putreg(priv, SAM_AFEC_EMR_OFFSET, afec_emr);
|
||||
|
||||
/* Configure Analog Control Register */
|
||||
|
||||
uint32_t afec_acr = AFEC_ACR_PGA0EN | AFEC_ACR_PGA1EN | AFEC_ACR_IBCTL(2);
|
||||
afec_putreg(priv, SAM_AFEC_ACR_OFFSET, afec_acr);
|
||||
|
||||
/* Pad configuration */
|
||||
|
||||
gpio_pinset_t *pinlist = NULL;
|
||||
switch (priv->intf)
|
||||
{
|
||||
#ifdef CONFIG_SAMV7_AFEC0
|
||||
case 0:
|
||||
pinlist = g_adcpinlist0;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SAMV7_AFEC1
|
||||
case 1:
|
||||
pinlist = g_adcpinlist1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* We have already checked the intf number earlier in this function,
|
||||
* so we should never get here.
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Desible write protection (should already be disabled by default) */
|
||||
|
||||
afec_putreg(priv, SAM_AFEC_WPMR_OFFSET, AFEC_WPMR_WPKEY);
|
||||
|
||||
/* Disable all channels */
|
||||
|
||||
afec_putreg(priv, SAM_AFEC_CHDR_OFFSET, AFEC_CHALL);
|
||||
|
||||
gpio_pinset_t pinset = 0;
|
||||
uint32_t afec_cher = 0;
|
||||
for (int i = 0; i < priv->nchannels; i++)
|
||||
{
|
||||
DEBUGASSERT(priv->chanlist[i] < ADC_MAX_CHANNELS);
|
||||
pinset = pinlist[priv->chanlist[i]];
|
||||
sam_configgpio(pinset);
|
||||
|
||||
afec_putreg(priv, SAM_AFEC_CSELR_OFFSET,
|
||||
AFEC_CSELR_CSEL(priv->chanlist[i]));
|
||||
afec_putreg(priv, SAM_AFEC_COCR_OFFSET, 0x200);
|
||||
|
||||
afec_cher |= AFEC_CH(priv->chanlist[i]);
|
||||
}
|
||||
|
||||
/* Enable channels */
|
||||
|
||||
afec_putreg(priv, SAM_AFEC_CHER_OFFSET, afec_cher);
|
||||
|
||||
return;
|
||||
|
||||
exit_leave_critical:
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: afec_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 afec_setup(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
FAR struct samv7_dev_s *priv = (FAR struct samv7_dev_s *)dev->ad_priv;
|
||||
|
||||
/* Do nothing when the ADC device is already set up */
|
||||
|
||||
if (priv->initialized > 0)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
priv->initialized++;
|
||||
|
||||
int ret = irq_attach(priv->irq, afec_interrupt, dev);
|
||||
if (ret < 0)
|
||||
{
|
||||
ainfo("irq_attach failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
up_enable_irq(priv->irq);
|
||||
|
||||
/* Start the first conversion */
|
||||
|
||||
priv->current = 0;
|
||||
|
||||
uint32_t afec_cselr = AFEC_CSELR_CSEL(priv->chanlist[priv->current]);
|
||||
afec_putreg(priv, SAM_AFEC_CSELR_OFFSET, afec_cselr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: afec_rxint
|
||||
*
|
||||
* Description:
|
||||
* Call to enable or disable RX interrupts
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void afec_rxint(FAR struct adc_dev_s *dev, bool enable)
|
||||
{
|
||||
FAR struct samv7_dev_s *priv = (FAR struct samv7_dev_s *)dev->ad_priv;
|
||||
uint32_t afec_ixr = 0;
|
||||
|
||||
for (int i = 0; i < priv->nchannels; i++)
|
||||
{
|
||||
afec_ixr |= AFEC_INT_EOC(priv->chanlist[i]);
|
||||
}
|
||||
|
||||
/* Enable interrupts */
|
||||
|
||||
if (enable)
|
||||
{
|
||||
afec_putreg(priv, SAM_AFEC_IER_OFFSET, afec_ixr);
|
||||
}
|
||||
else
|
||||
{
|
||||
afec_putreg(priv, SAM_AFEC_IDR_OFFSET, afec_ixr);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: afec_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 afec_shutdown(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
FAR struct samv7_dev_s *priv = (FAR struct samv7_dev_s *)dev->ad_priv;
|
||||
|
||||
/* Shutdown the ADC device only when not in use */
|
||||
|
||||
priv->initialized--;
|
||||
|
||||
if (priv->initialized > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable ADC interrupts */
|
||||
|
||||
up_disable_irq(priv->irq);
|
||||
|
||||
/* Then detach the ADC interrupt handler. */
|
||||
|
||||
irq_detach(priv->irq);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: afec_ioctl
|
||||
*
|
||||
* Description:
|
||||
* All ioctl calls will be routed through this method.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - pointer to device structure used by the driver
|
||||
* cmd - command
|
||||
* arg - arguments passed with command
|
||||
*
|
||||
* Returned Value:
|
||||
* OK in success or error value
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int afec_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
|
||||
{
|
||||
FAR struct samv7_dev_s *priv = (FAR struct samv7_dev_s *)dev->ad_priv;
|
||||
int ret = OK;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case ANIOC_TRIGGER:
|
||||
{
|
||||
afec_putreg(priv, SAM_AFEC_CR_OFFSET, AFEC_CR_START);
|
||||
}
|
||||
break;
|
||||
case ANIOC_GET_NCHANNELS:
|
||||
{
|
||||
/* Return the number of configured channels */
|
||||
|
||||
ret = priv->nchannels;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
aerr("ERROR: Unknown cmd: %d\n", cmd);
|
||||
ret = -ENOTTY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: afec_interrupt
|
||||
*
|
||||
* Description:
|
||||
* ADC interrupt handler
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int afec_interrupt(int irq, void *context, FAR void *arg)
|
||||
{
|
||||
FAR struct adc_dev_s *dev = (FAR struct adc_dev_s *)arg;
|
||||
FAR struct samv7_dev_s *priv = (FAR struct samv7_dev_s *)dev->ad_priv;
|
||||
int32_t data;
|
||||
|
||||
if ((afec_getreg(priv, SAM_AFEC_ISR_OFFSET) & \
|
||||
AFEC_CH(priv->chanlist[priv->current])) != 0)
|
||||
{
|
||||
/* Read data */
|
||||
|
||||
data = (int32_t)afec_getreg(priv, SAM_AFEC_CDR_OFFSET);
|
||||
|
||||
if (priv->cb != NULL)
|
||||
{
|
||||
DEBUGASSERT(priv->cb->au_receive != NULL);
|
||||
priv->cb->au_receive(dev, priv->chanlist[priv->current], data);
|
||||
}
|
||||
|
||||
/* Set the channel number of the next channel that will complete
|
||||
* conversion.
|
||||
*/
|
||||
|
||||
priv->current++;
|
||||
|
||||
if (priv->current >= priv->nchannels)
|
||||
{
|
||||
/* Restart the conversion sequence from the beginning */
|
||||
|
||||
priv->current = 0;
|
||||
}
|
||||
|
||||
/* Start the next conversion */
|
||||
|
||||
uint32_t afec_cselr = AFEC_CSELR_CSEL(priv->chanlist[priv->current]);
|
||||
afec_putreg(priv, SAM_AFEC_CSELR_OFFSET, afec_cselr);
|
||||
}
|
||||
|
||||
/* There are no interrupt flags left to clear */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_afec_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the adc
|
||||
*
|
||||
* Input Parameters:
|
||||
* intf - ADC number (0 or 1)
|
||||
* chanlist - The list of channels
|
||||
* nchannels - Number of channels
|
||||
*
|
||||
* Returned Value:
|
||||
* Valid can device structure reference on success; a NULL on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct adc_dev_s *sam_afec_initialize(int intf,
|
||||
FAR const uint8_t *chanlist,
|
||||
int nchannels)
|
||||
{
|
||||
FAR struct adc_dev_s *dev;
|
||||
FAR struct samv7_dev_s *priv;
|
||||
|
||||
DEBUGASSERT(nchannels > 0);
|
||||
|
||||
switch (intf)
|
||||
{
|
||||
#ifdef CONFIG_SAMV7_AFEC0
|
||||
case 0:
|
||||
{
|
||||
dev = &g_adcdev0;
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_SAMV7_AFEC0 */
|
||||
|
||||
#ifdef CONFIG_SAMV7_AFEC1
|
||||
case 1:
|
||||
{
|
||||
dev = &g_adcdev1;
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_SAMV7_AFEC1 */
|
||||
|
||||
default:
|
||||
{
|
||||
aerr("ERROR: Tried to initialize invalid ADC: %d\n", intf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
priv = (FAR struct samv7_dev_s *)dev->ad_priv;
|
||||
|
||||
priv->nchannels = nchannels;
|
||||
memcpy(priv->chanlist, chanlist, nchannels);
|
||||
|
||||
ainfo("intf: %d nchannels: %d\n", priv->intf, priv->nchannels);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SAMV7_AFEC0 || CONFIG_SAMV7_AFEC1 */
|
||||
|
||||
#endif /* CONFIG_ADC */
|
91
arch/arm/src/samv7/sam_afec.h
Normal file
91
arch/arm/src/samv7/sam_afec.h
Normal file
@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/samv7/sam_afec.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_SAMV7_SAM_AFEC_H
|
||||
#define __ARCH_ARM_SRC_SAMV7_SAM_AFEC_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "hardware/sam_afec.h"
|
||||
|
||||
#if defined(CONFIG_ADC) && (defined(CONFIG_SAMV7_AFEC0) || \
|
||||
defined(CONFIG_SAMV7_AFEC1))
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Port numbers for use with sam_mcan_initialize() */
|
||||
|
||||
#define AFEC0 0
|
||||
#define AFEC1 1
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_afec_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the adc
|
||||
*
|
||||
* Input Parameters:
|
||||
* intf - ADC number (1 or 2)
|
||||
* chanlist - The list of channels
|
||||
* nchannels - Number of channels
|
||||
*
|
||||
* Returned Value:
|
||||
* Valid can device structure reference on success; a NULL on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct adc_dev_s *sam_afec_initialize(int intf,
|
||||
FAR const uint8_t *chanlist,
|
||||
int nchannels);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* CONFIG_ADC && (CONFIG_SAMV7_AFEC0 || CONFIG_SAMV7_AFEC1) */
|
||||
#endif /* __ARCH_ARM_SRC_SAMV7_SAM_AFEC_H */
|
Loading…
Reference in New Issue
Block a user