Merge branch 'adcbind'

This commit is contained in:
Gregory Nutt 2016-05-26 12:40:17 -06:00
commit 01af4d1af1
10 changed files with 492 additions and 120 deletions

View File

@ -2,7 +2,9 @@
* arch/arm/src/efm32/efm32_adc.c
*
* Copyright (C) 2014 Bouteville Pierre-Noel. All rights reserved.
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Authors: Bouteville Pierre-Noel <pnb990@gmail.com>
* Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -100,6 +102,7 @@
struct efm32_dev_s
{
FAR const struct adc_callback_s *cb;
uint8_t irq; /* Interrupt generated by this ADC block */
uint8_t nchannels; /* Number of channels */
uint8_t current; /* Current ADC channel being converted */
@ -124,6 +127,8 @@ static int adc_interrupt(FAR struct adc_dev_s *dev);
/* ADC Driver Methods */
static int adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback);
static void adc_reset(FAR struct adc_dev_s *dev);
static int adc_setup(FAR struct adc_dev_s *dev);
static void adc_shutdown(FAR struct adc_dev_s *dev);
@ -148,6 +153,7 @@ static void adc_startconv(FAR struct efm32_dev_s *priv, bool enable);
static const struct adc_ops_s g_adcops =
{
.ao_bind = adc_bind,
.ao_reset = adc_reset,
.ao_setup = adc_setup,
.ao_shutdown = adc_shutdown,
@ -790,7 +796,7 @@ static void adc_startconv(struct efm32_dev_s *priv, bool enable)
#endif
/****************************************************************************
* Name: adc_reset
* Name: adc_hw_reset
*
* Description:
* Deinitializes the ADCx peripheral registers to their default
@ -873,6 +879,25 @@ static void adc_enable(FAR struct efm32_dev_s *priv, bool enable)
adc_putreg(priv, EFM32_ADC_CR2_OFFSET, regval);
}
/****************************************************************************
* Name: 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 adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback)
{
FAR struct efm32_dev_s *priv = (FAR struct efm32_dev_s *)dev->ad_priv;
DEBUGASSERT(priv != NULL);
priv->cb = callback;
return OK;
}
/****************************************************************************
* Name: adc_reset
*
@ -1180,14 +1205,21 @@ static int adc_interrupt(FAR struct adc_dev_s *dev)
value = adc_getreg(priv, EFM32_ADC_DR_OFFSET);
value &= ADC_DR_DATA_MASK;
/* Give the ADC data to the ADC driver. adc_receive accepts 3 parameters:
*
* 1) The first is the ADC device instance for this ADC block.
* 2) The second is the channel number for the data, and
* 3) The third is the converted data for the channel.
*/
/* Verify that the upper-half driver has bound its callback functions */
adc_receive(dev, priv->chanlist[priv->current], value);
if (priv->cb != NULL)
{
/* Give the ADC data to the ADC driver. The ADC receive method
* accepts 3 parameters:
*
* 1) The first is the ADC device instance for this ADC block.
* 2) The second is the channel number for the data, and
* 3) The third is the converted data for the channel.
*/
DEBUGASSERT(priv->cb->au_receive != NULL);
priv->cb->au_receive(dev, priv->chanlist[priv->current], value);
}
/* Set the channel number of the next channel that will complete conversion */
@ -1272,7 +1304,8 @@ struct adc_dev_s *efm32_adcinitialize(int intf, const uint8_t *chanlist, int nch
/* Configure the selected ADC */
priv = dev->ad_priv;
priv = dev->ad_priv;
priv->cb = NULL;
DEBUGASSERT(nchannels <= ADC_MAX_SAMPLES);
priv->nchannels = nchannels;

View File

@ -2,8 +2,9 @@
* arch/arm/src/lpc17xx/lpc17_adc.c
*
* Copyright (C) 2011 Li Zhuoyi. All rights reserved.
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Author: Li Zhuoyi <lzyy.cn@gmail.com>
* History: 0.1 2011-08-05 initial version
* Gregory Nutt <gnutt@nuttx.org>
*
* This file is a part of NuttX:
*
@ -50,6 +51,7 @@
#include <stdbool.h>
#include <semaphore.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <arch/board/board.h>
@ -87,6 +89,7 @@
struct up_dev_s
{
FAR const struct adc_callback_s *cb;
uint8_t mask;
uint32_t sps;
int irq;
@ -98,8 +101,12 @@ struct up_dev_s
* Private Function Prototypes
****************************************************************************/
static void adc_receive(FAR struct up_dev_s *priv, uint8_t ch, int32_t data);
/* ADC methods */
static int adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback);
static void adc_reset(FAR struct adc_dev_s *dev);
static int adc_setup(FAR struct adc_dev_s *dev);
static void adc_shutdown(FAR struct adc_dev_s *dev);
@ -113,6 +120,7 @@ static int adc_interrupt(int irq, void *context);
static const struct adc_ops_s g_adcops =
{
.ao_bind = adc_bind,
.ao_reset = adc_reset,
.ao_setup = adc_setup,
.ao_shutdown = adc_shutdown,
@ -137,6 +145,46 @@ static struct adc_dev_s g_adcdev =
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: adc_receive
*
* Description:
* Provide received ADC dat to the upper-half driver.
*
****************************************************************************/
static void adc_receive(FAR struct up_dev_s *priv, uint8_t ch, int32_t data)
{
/* Verify that the upper-half driver has bound its callback functions. */
if (priv->cb != NULL)
{
/* Perform the data received callback */
DEBUGASSERT(priv->cb->au_receive != NULL);
priv->cb->au_receive(&g_adcdev, ch, data);
}
}
/****************************************************************************
* Name: 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 adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv;
DEBUGASSERT(priv != NULL);
priv->cb = callback;
return OK;
}
/****************************************************************************
* Name: adc_reset
*
@ -384,7 +432,7 @@ static int adc_interrupt(int irq, void *context)
{
value = priv->buf[ch] / priv->count[ch];
value <<= 15;
adc_receive(&g_adcdev, ch, value);
adc_receive(priv, ch, value);
priv->buf[ch] = 0;
priv->count[ch] = 0;
}
@ -409,7 +457,7 @@ static int adc_interrupt(int irq, void *context)
{
value = priv->buf[ch] / priv->count[ch];
value <<= 15;
adc_receive(&g_adcdev, ch, value);
adc_receive(priv, ch, value);
priv->buf[ch] = 0;
priv->count[ch] = 0;
}
@ -446,7 +494,7 @@ static int adc_interrupt(int irq, void *context)
#else /* CONFIG_ADC_WORKER_THREAD */
if ((regVal) & (1 << 31))
{
adc_receive(&g_adcdev, 0, (regVal >> 4) & 0xFFF);
adc_receive(priv, 0, (regVal >> 4) & 0xFFF);
}
#endif /* CONFIG_ADC_WORKER_THREAD */
@ -473,7 +521,7 @@ static int adc_interrupt(int irq, void *context)
#else /* CONFIG_ADC_WORKER_THREAD */
if ((regVal) & (1 << 31))
{
adc_receive(&g_adcdev, 1, (regVal >> 4) & 0xFFF);
adc_receive(priv, 1, (regVal >> 4) & 0xFFF);
}
#endif /* CONFIG_ADC_WORKER_THREAD */
@ -500,7 +548,7 @@ static int adc_interrupt(int irq, void *context)
#else /* CONFIG_ADC_WORKER_THREAD */
if ((regVal) & (1 << 31))
{
adc_receive(&g_adcdev, 2, (regVal >> 4) & 0xFFF);
adc_receive(priv, 2, (regVal >> 4) & 0xFFF);
}
#endif /* CONFIG_ADC_WORKER_THREAD */
@ -512,7 +560,7 @@ static int adc_interrupt(int irq, void *context)
regVal = getreg32(LPC17_ADC_DR3);
if ((regVal) & (1 << 31))
{
adc_receive(&g_adcdev, 3, (regVal >> 4) & 0xFFF);
adc_receive(priv, 3, (regVal >> 4) & 0xFFF);
}
}
@ -521,7 +569,7 @@ static int adc_interrupt(int irq, void *context)
regVal = getreg32(LPC17_ADC_DR4);
if ((regVal) & (1 << 31))
{
adc_receive(&g_adcdev, 4, (regVal >> 4) & 0xFFF);
adc_receive(priv, 4, (regVal >> 4) & 0xFFF);
}
}
@ -530,7 +578,7 @@ static int adc_interrupt(int irq, void *context)
regVal = getreg32(LPC17_ADC_DR5);
if ((regVal) & (1 << 31))
{
adc_receive(&g_adcdev, 5, (regVal >> 4) & 0xFFF);
adc_receive(priv, 5, (regVal >> 4) & 0xFFF);
}
}
@ -539,7 +587,7 @@ static int adc_interrupt(int irq, void *context)
regVal = getreg32(LPC17_ADC_DR6);
if ((regVal) & (1 << 31))
{
adc_receive(&g_adcdev, 6, (regVal >> 4) & 0xFFF);
adc_receive(priv, 6, (regVal >> 4) & 0xFFF);
}
}
@ -548,7 +596,7 @@ static int adc_interrupt(int irq, void *context)
regVal = getreg32(LPC17_ADC_DR7);
if ((regVal) & (1 << 31))
{
adc_receive(&g_adcdev, 7, (regVal >> 4) & 0xFFF);
adc_receive(priv, 7, (regVal >> 4) & 0xFFF);
}
}

View File

@ -7,8 +7,9 @@
* Ported from from the LPC17 version:
*
* Copyright(C) 2011 Li Zhuoyi. All rights reserved.
* Copyright(C) 2016 Gregory Nutt. All rights reserved.
* Author: Li Zhuoyi <lzyy.cn@gmail.com>
* History: 0.1 2011-08-05 initial version
* Gregory Nutt
*
* This file is a part of NuttX:
*
@ -55,6 +56,7 @@
#include <stdbool.h>
#include <semaphore.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <arch/board/board.h>
@ -112,6 +114,7 @@
struct up_dev_s
{
FAR const struct adc_callback_s *cb;
uint8_t mask;
uint8_t mask_int;
uint32_t freq;
@ -126,6 +129,8 @@ struct up_dev_s
/* ADC methods */
static int adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback);
static void adc_reset(FAR struct adc_dev_s *dev);
static int adc_setup(FAR struct adc_dev_s *dev);
static void adc_shutdown(FAR struct adc_dev_s *dev);
@ -139,6 +144,7 @@ static int adc_interrupt(int irq, void *context);
static const struct adc_ops_s g_adcops =
{
.ao_bind = adc_bind,
.ao_reset = adc_reset,
.ao_setup = adc_setup,
.ao_shutdown = adc_shutdown,
@ -166,6 +172,25 @@ static struct adc_dev_s g_adcdev =
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: 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 adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv;
DEBUGASSERT(priv != NULL);
priv->cb = callback;
return OK;
}
/****************************************************************************
* Name: adc_reset
*
@ -454,8 +479,20 @@ static int adc_interrupt(int irq, void *context)
{
if (priv->mask & (1 << i))
{
int32_t data;
regval = getreg32(LPC43_ADC0_DR(i));
adc_receive(&g_adcdev, i,(regval&ADC_DR_VVREF_MASK)>>ADC_DR_VVREF_SHIFT);
data = (regval & ADC_DR_VVREF_MASK) >> ADC_DR_VVREF_SHIFT;
/* Verify that the upper-half driver has bound its callback functions */
if (priv->cb != NULL)
{
/* Perform the data received callback */
DEBUGASSERT(priv->cb->au_receive != NULL);
priv->cb->au_receive(&g_adcdev, i, data);
}
}
}

View File

@ -57,6 +57,7 @@
#include <stdbool.h>
#include <semaphore.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <arch/board/board.h>
@ -378,6 +379,7 @@
struct sam_adc_s
{
FAR const struct adc_callback_s *cb;
sem_t exclsem; /* Supports exclusive access to the ADC interface */
bool initialized; /* The ADC driver is already initialized */
uint32_t frequency; /* ADC clock frequency */
@ -446,6 +448,8 @@ static int sam_adc_interrupt(int irq, void *context);
/* ADC methods */
#ifdef SAMA5_ADC_HAVE_CHANNELS
static int sam_adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback);
static void sam_adc_reset(struct adc_dev_s *dev);
static int sam_adc_setup(struct adc_dev_s *dev);
static void sam_adc_shutdown(struct adc_dev_s *dev);
@ -477,6 +481,7 @@ static void sam_adc_channels(struct sam_adc_s *priv);
static const struct adc_ops_s g_adcops =
{
.ao_bind = sam_adc_bind,
.ao_reset = sam_adc_reset,
.ao_setup = sam_adc_setup,
.ao_shutdown = sam_adc_shutdown,
@ -664,9 +669,15 @@ static void sam_adc_dmadone(void *arg)
chan = (int)((*buffer & ADC_LCDR_CHANB_MASK) >> ADC_LCDR_CHANB_SHIFT);
sample = ((*buffer & ADC_LCDR_DATA_MASK) >> ADC_LCDR_DATA_SHIFT);
/* And give the sample data to the ADC upper half */
/* Verify that the upper-half driver has bound its callback functions */
(void)adc_receive(priv->dev, chan, sample);
if (priv->cb != NULL)
{
/* Give the sample data to the ADC upper half */
DEBUGASSERT(priv->cb->au_receive != NULL);
priv->cb->au_receive(priv->dev, chan, sample);
}
}
}
@ -858,7 +869,17 @@ static void sam_adc_endconversion(void *arg)
/* Read the ADC sample and pass it to the upper half */
regval = sam_adc_getreg(priv, SAM_ADC_CDR(chan));
(void)adc_receive(priv->dev, chan, regval & ADC_CDR_DATA_MASK);
/* Verify that the upper-half driver has bound its callback functions */
if (priv->cb != NULL)
{
/* Perform the data received callback */
DEBUGASSERT(priv->cb->au_receive != NULL);
priv->cb->au_receive(priv->dev, chan, regval & ADC_CDR_DATA_MASK);
}
pending &= ~bit;
}
}
@ -954,6 +975,26 @@ static int sam_adc_interrupt(int irq, void *context)
/****************************************************************************
* ADC methods
****************************************************************************/
/****************************************************************************
* Name: sam_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 sam_adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback)
{
struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv;
DEBUGASSERT(priv != NULL);
priv->cb = callback;
return OK;
}
/****************************************************************************
* Name: sam_adc_reset
*
@ -1980,6 +2021,7 @@ struct adc_dev_s *sam_adc_initialize(void)
/* Initialize the private ADC device data structure */
sem_init(&priv->exclsem, 0, 1);
priv->cb = NULL;
priv->dev = &g_adcdev;
#ifdef CONFIG_SAMA5_ADC_DMA

View File

@ -272,6 +272,7 @@
struct stm32_dev_s
{
FAR const struct adc_callback_s *cb;
uint8_t irq; /* Interrupt generated by this ADC block */
uint8_t nchannels; /* Number of channels */
uint8_t cchannels; /* Number of configured channels */
@ -364,6 +365,8 @@ static int adc123_interrupt(int irq, FAR void *context);
/* ADC Driver Methods */
static int adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback);
static void adc_reset(FAR struct adc_dev_s *dev);
static int adc_setup(FAR struct adc_dev_s *dev);
static void adc_shutdown(FAR struct adc_dev_s *dev);
@ -412,6 +415,7 @@ static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable);
static const struct adc_ops_s g_adcops =
{
.ao_bind = adc_bind,
#if defined(CONFIG_STM32_STM32L15XX) && \
(STM32_CFGR_PLLSRC != 0 || STM32_SYSCLK_SW != RCC_CFGR_SW_HSI)
.ao_reset = adc_reset_hsi_disable,
@ -1660,6 +1664,25 @@ static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg)
}
#endif
/****************************************************************************
* Name: 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 adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback)
{
FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv;
DEBUGASSERT(priv != NULL);
priv->cb = callback;
return OK;
}
/****************************************************************************
* Name: adc_reset
*
@ -2702,15 +2725,21 @@ static int adc_interrupt(FAR struct adc_dev_s *dev)
data = adc_getreg(priv, STM32_ADC_DR_OFFSET) & ADC_DR_RDATA_MASK;
/* Give the ADC data to the ADC driver. adc_receive() accepts 3
* parameters:
*
* 1) The first is the ADC device instance for this ADC block.
* 2) The second is the channel number for the data, and
* 3) The third is the converted data for the channel.
*/
/* Verify that the upper-half driver has bound its callback functions */
adc_receive(dev, priv->chanlist[priv->current], data);
if (priv->cb != NULL)
{
/* Give the ADC data to the ADC driver. The ADC receive() method
* accepts 3 parameters:
*
* 1) The first is the ADC device instance for this ADC block.
* 2) The second is the channel number for the data, and
* 3) The third is the converted data for the channel.
*/
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.
@ -2995,6 +3024,7 @@ struct adc_dev_s *stm32_adcinitialize(int intf, FAR const uint8_t *chanlist,
DEBUGASSERT(cchannels <= ADC_MAX_SAMPLES);
priv->cb = NULL;
priv->cchannels = cchannels;
memcpy(priv->chanlist, chanlist, cchannels);

View File

@ -125,32 +125,32 @@
struct tiva_adc_step_cfg_s
{
uint8_t adc; /* Parent peripheral */
uint8_t sse; /* Parent sample sequencer (SSE) */
uint8_t step; /* Which step in the sequencer */
uint8_t shold; /* Sample and hold time */
uint8_t flags; /* Last step? Interrupt enabled?
* Internal temperature sensor? */
uint8_t ain; /* Which analog input */
uint8_t adc; /* Parent peripheral */
uint8_t sse; /* Parent sample sequencer (SSE) */
uint8_t step; /* Which step in the sequencer */
uint8_t shold; /* Sample and hold time */
uint8_t flags; /* Last step? Interrupt enabled?
* Internal temperature sensor? */
uint8_t ain; /* Which analog input */
};
/* Sample Sequencer configuration options */
struct tiva_adc_sse_cfg_s
{
uint8_t priority; /* Conversion priority, 0-3 no duplicates */
uint8_t trigger; /* Trigger source */
uint8_t priority; /* Conversion priority, 0-3 no duplicates */
uint8_t trigger; /* Trigger source */
};
/* ADC peripheral configuration options */
struct tiva_adc_cfg_s
{
uint8_t adc; /* ADC peripheral number */
bool sse[4]; /* active SSEs in a bitmask */
struct tiva_adc_sse_cfg_s ssecfg[4]; /* SSE configuration */
uint8_t steps; /* Size of the stepcfg array */
struct tiva_adc_step_cfg_s *stepcfg; /* Step configuration array */
uint8_t adc; /* ADC peripheral number */
bool sse[4]; /* active SSEs in a bitmask */
struct tiva_adc_sse_cfg_s ssecfg[4]; /* SSE configuration */
uint8_t steps; /* Size of the stepcfg array */
struct tiva_adc_step_cfg_s *stepcfg; /* Step configuration array */
};
/****************************************************************************

View File

@ -1,8 +1,10 @@
/****************************************************************************
* arch/arm/src/tiva/tiva_adclow.c
*
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2015 TRD2 Inc. All rights reserved.
* Author: Calvin Maguranis <calvin.maguranis@trd2inc.com>
* Gregory Nutt <gnutt@nuttx.org>
*
* References:
*
@ -67,8 +69,8 @@
#include <stdbool.h>
#include <semaphore.h>
#include <errno.h>
#include <debug.h>
#include <assert.h>
#include <debug.h>
#include <arch/board/board.h>
@ -135,6 +137,8 @@
/* Upper level ADC driver ***************************************************/
static int tiva_adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback);
static void tiva_adc_reset(struct adc_dev_s *dev);
static int tiva_adc_setup(struct adc_dev_s *dev);
static void tiva_adc_shutdown(struct adc_dev_s *dev);
@ -149,6 +153,7 @@ static int tiva_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg);
static const struct adc_ops_s g_adcops =
{
.ao_bind = tiva_adc_bind,
.ao_reset = tiva_adc_reset,
.ao_setup = tiva_adc_setup,
.ao_shutdown = tiva_adc_shutdown,
@ -163,6 +168,7 @@ static const struct adc_ops_s g_adcops =
struct tiva_adc_s
{
struct adc_dev_s *dev;
const struct adc_callback_s *cb;
bool cfg; /* Configuration state */
bool ena; /* Operation state */
uint8_t devno; /* ADC device number */
@ -373,6 +379,25 @@ static void tiva_adc_irqinitialize(struct tiva_adc_cfg_s *cfg)
#endif
}
/****************************************************************************
* Name: tiva_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 tiva_adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback)
{
struct tiva_adc_s *priv = (struct tiva_adc_s *)dev->ad_priv;
DEBUGASSERT(priv != NULL);
priv->cb = callback;
return OK;
}
/****************************************************************************
* Name: tiva_adc_reset
*
@ -559,11 +584,20 @@ static int tiva_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg)
fifo_count = tiva_adc_sse_data(priv->devno, sse, buf);
for (i = 0; i < fifo_count; ++i)
/* Verify that the upper-half driver has bound its callback functions */
if (priv->cb != NULL)
{
(void)adc_receive(dev,
tiva_adc_get_ain(priv->devno, sse, i),
buf[i]);
DEBUGASSERT(priv->cb->au_receive != NULL);
for (i = 0; i < fifo_count; ++i)
{
/* Perform the data received callback */
priv->cb->au_receive(dev,
tiva_adc_get_ain(priv->devno, sse, i),
buf[i]);
}
}
/* Release our lock on the ADC structure */
@ -651,18 +685,28 @@ static void tiva_adc_read(void *arg)
/* This is a serious error: indicates invalid pointer indirection
* and should cause a full system stop.
*/
alldbg("PANIC!!! Invalid ADC device number given %d\n", sse->adc);
PANIC();
return;
}
for (i = 0; i < fifo_count; ++i)
/* Verify that the upper-half driver has bound its callback functions */
if (priv->cb != NULL)
{
(void)adc_receive(dev,
tiva_adc_get_ain(sse->adc, sse->num, i),
buf[i]);
avdbg("AIN%d=0x%04x\n",
tiva_adc_get_ain(sse->adc, sse->num, i), buf[i]);
DEBUGASSERT(priv->cb->au_receive != NULL);
for (i = 0; i < fifo_count; ++i)
{
/* Perform the data received callback */
priv->cb->au_receive(dev,
tiva_adc_get_ain(sse->adc, sse->num, i),
buf[i]);
avdbg("AIN%d = 0x%04x\n",
tiva_adc_get_ain(sse->adc, sse->num, i), buf[i]);
}
}
/* Exit, re-enabling ADC interrupts */
@ -858,6 +902,7 @@ int tiva_adc_initialize(const char *devpath, struct tiva_adc_cfg_s *cfg,
/* Now we are initialized */
adc->ena = true;
adc->cb = NULL;
#ifdef CONFIG_DEBUG_ANALOG
tiva_adc_runtimeobj_vals();

View File

@ -1,9 +1,10 @@
/****************************************************************************
* drivers/analog/adc.c
*
* Copyright (C) 2008-2009, 2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2011 Li Zhuoyi. All rights reserved.
* Author: Li Zhuoyi <lzyy.cn@gmail.com>
* History: 0.1 2011-08-04 initial version
* Gregory Nutt <gnutt@nuttx.org>
*
* Derived from drivers/can.c
*
@ -70,12 +71,14 @@ static int adc_close(FAR struct file *filep);
static ssize_t adc_read(FAR struct file *fielp, FAR char *buffer,
size_t buflen);
static int adc_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
static int adc_receive(FAR struct adc_dev_s *dev, uint8_t ch,
int32_t data);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations adc_fops =
static const struct file_operations g_adc_fops =
{
adc_open, /* open */
adc_close, /* close */
@ -88,6 +91,11 @@ static const struct file_operations adc_fops =
#endif
};
static const struct adc_callback_s g_adc_callback =
{
adc_receive /* au_receive */
};
/****************************************************************************
* Private Functions
****************************************************************************/
@ -361,15 +369,11 @@ static int adc_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: adc_receive
****************************************************************************/
int adc_receive(FAR struct adc_dev_s *dev, uint8_t ch, int32_t data)
static int adc_receive(FAR struct adc_dev_s *dev, uint8_t ch, int32_t data)
{
FAR struct adc_fifo_s *fifo = &dev->ad_recv;
int nexttail;
@ -408,12 +412,30 @@ int adc_receive(FAR struct adc_dev_s *dev, uint8_t ch, int32_t data)
return err;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: adc_register
****************************************************************************/
int adc_register(FAR const char *path, FAR struct adc_dev_s *dev)
{
int ret;
DEBUGASSERT(path != NULL && dev != NULL);
/* Bind the upper-half callbacks to the lower half ADC driver */
DEBUGASSERT(dev->ad_ops != NULL && dev->ad_ops->ao_bind != NULL);
ret = dev->ad_ops->ao_bind(dev, &g_adc_callback);
if (ret < 0)
{
adbg("ERROR: Failed to bind callbacks: %d\n", ret)
return ret;
}
/* Initialize the ADC device structure */
dev->ad_ocount = 0;
@ -421,7 +443,19 @@ int adc_register(FAR const char *path, FAR struct adc_dev_s *dev)
sem_init(&dev->ad_recv.af_sem, 0, 0);
sem_init(&dev->ad_closesem, 0, 1);
/* Reset the ADC hardware */
DEBUGASSERT(dev->ad_ops->ao_reset != NULL);
dev->ad_ops->ao_reset(dev);
return register_driver(path, &adc_fops, 0444, dev);
/* Register the ADC character driver */
ret = register_driver(path, &g_adc_fops, 0444, dev);
if (ret < 0)
{
sem_destroy(&dev->ad_recv.af_sem);
sem_destroy(&dev->ad_closesem);
}
return ret;
}

View File

@ -1,10 +1,10 @@
/************************************************************************************
* arch/drivers/analog/ads1255.c
*
* Copyright (C) 2010, 2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2011 Li Zhuoyi. All rights reserved.
* Author: Li Zhuoyi <lzyy.cn@gmail.com>
* History: 0.1 2011-08-05 initial version
* 0.2 2011-08-25 fix bug in g_adcdev (cd_ops -> ad_ops,cd_priv -> ad_priv)
* Gregory Nutt <gnutt@nuttx.org>
*
* This file is a part of NuttX:
*
@ -47,6 +47,7 @@
#include <stdbool.h>
#include <semaphore.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <arch/board/board.h>
@ -105,8 +106,9 @@
* ad_private Types
****************************************************************************/
struct up_dev_s
struct ads1255_dev_s
{
FAR const struct adc_callback_s *cb;
uint8_t channel;
uint32_t sps;
uint8_t pga;
@ -123,6 +125,8 @@ struct up_dev_s
/* ADC methods */
static int adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback);
static void adc_reset(FAR struct adc_dev_s *dev);
static int adc_setup(FAR struct adc_dev_s *dev);
static void adc_shutdown(FAR struct adc_dev_s *dev);
@ -136,14 +140,15 @@ static int adc_interrupt(int irq, void *context);
static const struct adc_ops_s g_adcops =
{
.ao_reset = adc_reset, /* ao_reset */
.ao_setup = adc_setup, /* ao_setup */
.ao_bind = adc_bind, /* ao_bind */
.ao_reset = adc_reset, /* ao_reset */
.ao_setup = adc_setup, /* ao_setup */
.ao_shutdown = adc_shutdown, /* ao_shutdown */
.ao_rxint = adc_rxint, /* ao_rxint */
.ao_ioctl = adc_ioctl /* ao_read */
.ao_rxint = adc_rxint, /* ao_rxint */
.ao_ioctl = adc_ioctl /* ao_read */
};
static struct up_dev_s g_adcpriv =
static struct ads1255_dev_s g_adcpriv =
{
.mux = (const uint8_t [])
{
@ -190,16 +195,44 @@ static uint8_t getspsreg(uint16_t sps)
}
/****************************************************************************
* ad_private Functions
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: 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 adc_bind(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback)
{
FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)dev->ad_priv;
DEBUGASSERT(priv != NULL);
priv->cb = callback;
return OK;
}
/****************************************************************************
* Name: adc_reset
*
* Description:
* Reset the ADC device. Called early to initialize the hardware. This
* is called, before ao_setup() and on error conditions.
*
****************************************************************************/
/* Reset the ADC device. Called early to initialize the hardware. This
* is called, before ao_setup() and on error conditions.
*/
static void adc_reset(FAR struct adc_dev_s *dev)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv;
FAR struct spi_dev_s *spi = priv->spi;
FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)dev->ad_priv;
FAR struct spi_dev_s *spi;
DEBUGASSERT(priv != NULL && priv->spi != NULL);
spi = priv->spi;
SPI_SETMODE(spi, SPIDEV_MODE1);
SPI_SETBITS(spi, 8);
@ -213,18 +246,27 @@ static void adc_reset(FAR struct adc_dev_s *dev)
SPI_SELECT(spi, priv->devno, false);
}
/* 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.
*/
/****************************************************************************
* Name: 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 adc_setup(FAR struct adc_dev_s *dev)
static int adc_setup(FAR struct adc_dev_s *dev)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv;
FAR struct spi_dev_s *spi = priv->spi;
int ret = irq_attach(priv->irq, adc_interrupt);
FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)dev->ad_priv;
FAR struct spi_dev_s *spi;
int ret;
DEBUGASSERT(priv != NULL && priv->spi != NULL);
spi = priv->spi;
ret = irq_attach(priv->irq, adc_interrupt);
if (ret == OK)
{
SPI_SELECT(spi, priv->devno, true);
@ -251,22 +293,39 @@ static int adc_setup(FAR struct adc_dev_s *dev)
return ret;
}
/* Disable the ADC. This method is called when the ADC device is closed.
* This method reverses the operation the setup method.
*/
/****************************************************************************
* Name: 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 adc_shutdown(FAR struct adc_dev_s *dev)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv;
FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)dev->ad_priv;
DEBUGASSERT(priv != NULL);
up_disable_irq(priv->irq);
irq_detach(priv->irq);
}
/* Call to enable or disable RX interrupts */
/****************************************************************************
* Name: adc_rxint
*
* Description:
* Call to enable or disable RX interrupts
*
****************************************************************************/
static void adc_rxint(FAR struct adc_dev_s *dev, bool enable)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv;
FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)dev->ad_priv;
DEBUGASSERT(priv != NULL);
if (enable)
{
up_enable_irq(priv->irq);
@ -277,21 +336,42 @@ static void adc_rxint(FAR struct adc_dev_s *dev, bool enable)
}
}
/* All ioctl calls will be routed through this method */
/****************************************************************************
* Name: adc_ioctl
*
* Description:
* All ioctl calls will be routed through this method
*
****************************************************************************/
static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
{
dbg("Fix me:Not Implemented\n");
return 0;
}
/****************************************************************************
* Name: adc_interrupt
*
* Description:
* ADC interrupt handler
*
****************************************************************************/
static int adc_interrupt(int irq, void *context)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)g_adcdev.ad_priv;
FAR struct spi_dev_s *spi = priv->spi;
FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)g_adcdev.ad_priv;
FAR struct spi_dev_s *spi;
unsigned char buf[4];
unsigned char ch;
DEBUGASSERT(priv != NULL && priv->spi != NULL);
spi = priv->spi;
/* REVISIT: Cannot perform SPI operations from an interrupt handler!
* Need to use the high priority work queue.
*/
SPI_SELECT(spi, priv->devno, true);
SPI_SEND(spi, ADS125X_RDATA);
up_udelay(10);
@ -316,7 +396,16 @@ static int adc_interrupt(int irq, void *context)
SPI_SEND(spi, ADS125X_WAKEUP);
SPI_SELECT(spi, priv->devno, false);
adc_receive(&g_adcdev, priv->channel, *(int32_t *)buf);
/* Verify that the upper-half driver has bound its callback functions */
if (priv->cb != NULL)
{
/* Perform the data received callback */
DEBUGASSERT(priv->cb->au_receive != NULL);
priv->cb->au_receive(&g_adcdev, priv->channel, *(int32_t *)buf);
}
return OK;
}
@ -341,10 +430,13 @@ static int adc_interrupt(int irq, void *context)
FAR struct adc_dev_s *up_ads1255initialize(FAR struct spi_dev_s *spi,
unsigned int devno)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)g_adcdev.ad_priv;
FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)g_adcdev.ad_priv;
DEBUGASSERT(spi != NULL);
/* Driver state data */
priv->cb = NULL;
priv->spi = spi;
priv->devno = devno;
return &g_adcdev;

View File

@ -75,6 +75,27 @@
/************************************************************************************
* Public Types
************************************************************************************/
/* These are callbacks to notify the upper-half driver of ADC events */
struct adc_dev_s;
struct adc_callback_s
{
/* This method is called from the lower half, platform-specific ADC logic when
* new ADC sample data is available.
*
* Input Parameters:
* dev - The ADC device structure that was previously registered by adc_register()
* ch - And ID for the ADC channel number that generated the data
* data - The actual converted data from the channel.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*/
CODE int (*au_receive)(FAR struct adc_dev_s *dev, uint8_t ch, int32_t data);
};
/* This describes on ADC message */
struct adc_msg_s
{
@ -82,6 +103,8 @@ struct adc_msg_s
int32_t am_data; /* ADC convert result (4 bytes) */
} packed_struct;
/* This describes a FIFO of ADC messages */
struct adc_fifo_s
{
sem_t af_sem; /* Counting semaphore */
@ -99,6 +122,13 @@ struct adc_fifo_s
struct adc_dev_s;
struct adc_ops_s
{
/* Bind the upper-half driver callbacks to the lower-half implementation. This
* must be called early in order to receive ADC event notifications.
*/
CODE int (*ao_bind)(FAR struct adc_dev_s *dev,
FAR const struct adc_callback_s *callback);
/* Reset the ADC device. Called early to initialize the hardware. This
* is called, before ao_setup() and on error conditions.
*/
@ -188,25 +218,6 @@ extern "C"
int adc_register(FAR const char *path, FAR struct adc_dev_s *dev);
/************************************************************************************
* Name: adc_receive
*
* Description:
* This function is called from the lower half, platform-specific ADC logic when
* new ADC sample data is available.
*
* Input Parameters:
* dev - The ADC device structure that was previously registered by adc_register()
* ch - And ID for the ADC channel number that generated the data
* data - The actualy converted data from the channel.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
************************************************************************************/
int adc_receive(FAR struct adc_dev_s *dev, uint8_t ch, int32_t data);
/************************************************************************************
* Platform-Independent "Lower Half" ADC Driver Interfaces
************************************************************************************/