Add workaround for ADC errata from Chris Taglia

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5760 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-03-19 14:45:26 +00:00
parent ffd85ebe97
commit 1f3846afd5
5 changed files with 148 additions and 22 deletions

View File

@ -392,6 +392,35 @@ config ADC0_SPS
depends on LPC17_ADC
default 1000
config ADC_CHANLIST
bool "Use ADC channel list"
default n
---help--
The errata that states: "A/D Global Data register should not be used
with burst mode or hardware triggering". If this option is selected,
then the ADC driver will grab from the individual channel registers
rather than from the global data register as this is the stated
workaround in the errata.
The ADC interrupt will trigger on conversion complete on the last
channel listed in the array g_adc_chanlist[] (as opposed to
triggering interrupt from the global DONE flag).
If this option is enabled, then the platform specific code must do
two things: (1) define ADC_NCHANNELS in the configuration file and
(2) provide an array g_adc_chanlist[] with the channel numbers
matching the ADC0_MASK within the board-specific library.
config ADC_NCHANNELS
int "ADC0 number of channels"
depends on LPC17_ADC
default 0
---help--
If CONFIG_ADC_CHANLIST is enabled, then the platform specific code
must do two things: (1) define ADC_NCHANNELS in the configuration
file and (2) provide an array g_adc_chanlist[] with the channel
numbers matching the ADC0_MASK within the board-specific library.
endmenu
menu "CAN driver options"

View File

@ -4,7 +4,7 @@
* Copyright (C) 2011 Li Zhuoyi. All rights reserved.
* Author: Li Zhuoyi <lzyy.cn@gmail.com>
* History: 0.1 2011-08-05 initial version
*
*
* This file is a part of NuttX:
*
* Copyright (C) 2010, 2013 Gregory Nutt. All rights reserved.
@ -202,7 +202,7 @@ static void adc_reset(FAR struct adc_dev_s *dev)
{
lpc17_configgpio(GPIO_AD0p7);
}
irqrestore(flags);
}
@ -276,7 +276,18 @@ static void adc_rxint(FAR struct adc_dev_s *dev, bool enable)
if (enable)
{
#ifdef CONFIG_ADC_CHANLIST
/* Trigger interrupt at the end of conversion on the last A/D channel
* in the channel list.
*/
putreg32(ADC_INTEN_CHAN(g_adc_chanlist[CONFIG_ADC_NCHANNELS - 1]),
LPC17_ADC_INTEN);
#else
/* Trigger interrupt using the global DONE flag. */
putreg32(ADC_INTEN_GLOBAL, LPC17_ADC_INTEN);
#endif
}
else
{
@ -309,11 +320,45 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
static int adc_interrupt(int irq, void *context)
{
#ifdef CONFIG_ADC_CHANLIST
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)g_adcdev.ad_priv;
uint32_t regval;
unsigned char ch;
int32_t value;
int i;
regval = getreg32(LPC17_ADC_GDR);
for(i = 0; i < CONFIG_ADC_NCHANNELS; i++
{
ch = g_adc_chanlist[i];
regval = getreg32(LPC17_ADC_DR(ch));
if(regval&ADC_DR_DONE)
{
priv->count[ch]++;
priv->buf[ch] += regval & 0xfff0;
if (priv->count[ch] >= CONFIG_ADC0_AVERAGE)
{
value = priv->buf[ch] / priv->count[ch];
value <<= 15;
adc_receive(&g_adcdev,ch,value);
priv->buf[ch] = 0;
priv->count[ch] = 0;
}
}
}
return OK;
#else
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)g_adcdev.ad_priv;
uint32_t regval;
unsigned char ch;
int32_t value;
regval = getreg32(LPC17_ADC_GDR);
ch = (regval >> 24) & 0x07;
priv->buf[ch] += regval & 0xfff0;
@ -329,6 +374,8 @@ static int adc_interrupt(int irq, void *context)
}
return OK;
#endif
}
/****************************************************************************

View File

@ -46,6 +46,20 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* If CONFIG_ADC_CHANLIST is enabled, then the platform specific code must do
* two things: (1) define CONFIG_ADC_NCHANNELS in the configuration file and
* (2) provide an array g_adc_chanlist[] with the channel numbers matching
* the ADC0_MASK within the board-specific library.
*/
#ifdef CONFIG_ADC_CHANLIST
# if !defined(CONFIG_ADC_NCHANNELS)
# error "CONFIG_ADC_CHANLIST must defined in this configuration"
# elif CONFIG_ADC_NCHANNELS < 1
# error "The value of CONFIG_ADC_NCHANNELS is invalid"
# endif
#endif
/****************************************************************************
* Public Types
@ -55,12 +69,33 @@
* Public Data
****************************************************************************/
#ifndef __ASSEMBLY__
#ifdef __cplusplus
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/* The errata that states: "A/D Global Data register should not be used with
* burst mode or hardware triggering". The configuration option
* CONFIG_ADC_CHANLIST is a workaround for this errata. If this option is
* selected, then the ADC driver will grab from the individual channel
* registers rather than from the global data register as this is the stated
* workaround in the errata.
*
* If this option is enabled, then the platform specific code must do two
* things: (1) define CONFIG_ADC_NCHANNELS in the configuration file and
* (2) provide an array g_adc_chanlist[] with the channel numbers matching
* the ADC0_MASK within the board-specific library.
*/
#ifdef CONFIG_ADC_CHANLIST
EXTERN uint8_t g_adc_chanlist[CONFIG_ADC_NCHANNELS];
#endiff
/****************************************************************************
* Public Functions
****************************************************************************/
@ -80,6 +115,7 @@ extern "C"
FAR struct adc_dev_s *lpc17_adcinitialize(void);
#endif
#undef EXTERN
#ifdef __cplusplus
}
#endif

View File

@ -63,28 +63,35 @@
/****************************************************************************
* Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* This driver does not support the SPI exchange method. */
/* Enables debug output from this file (needs CONFIG_DEBUG too) */
#ifdef CONFIG_SPI_EXCHANGE
# error "CONFIG_SPI_EXCHANGE must not be defined in the configuration"
#endif
#undef SPI_DEBUG /* Define to enable debug */
#undef SPI_VERBOSE /* Define to enable verbose debug */
/* Debug ********************************************************************/
/* The following enable debug output from this file:
*
* CONFIG_DEBUG - Define to enable general debug features
* CONFIG_DEBUG_SPI - Define to enable basic SSP debug (needs CONFIG_DEBUG)
* CONFIG_DEBUG_VERBOSE - Define to enable verbose SSP debug
*/
#ifdef SPI_DEBUG
#ifdef CONFIG_DEBUG_SPI
# define spidbg lldbg
# ifdef SPI_VERBOSE
# ifdef CONFIG_DEBUG_VERBOSE
# define spivdbg lldbg
# else
# define spivdbg(x...)
# endif
#else
# undef SPI_VERBOSE
# define spidbg(x...)
# define spivdbg(x...)
#endif
/* SPI Clocking.
*
* The CPU clock by 1, 2, 4, or 8 to get the SPI peripheral clock (SPI_CLOCK).
/* SSP Clocking *************************************************************/
/* The CPU clock by 1, 2, 4, or 8 to get the SPI peripheral clock (SPI_CLOCK).
* SPI_CLOCK may be further divided by 8-254 to get the SPI clock. If we
* want a usable range of 4KHz to 25MHz for the SPI, then:
*

View File

@ -63,16 +63,24 @@
/****************************************************************************
* Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* This driver does not support the SPI exchange method. */
/* The following enable debug output from this file (needs CONFIG_DEBUG too).
#ifdef CONFIG_SPI_EXCHANGE
# error "CONFIG_SPI_EXCHANGE must not be defined in the configuration"
#endif
/* Debug ********************************************************************/
/* The following enable debug output from this file:
*
* CONFIG_SPI_DEBUG - Define to enable basic SSP debug
* CONFIG_VERBOSE - Define to enable verbose SSP debug
* CONFIG_DEBUG - Define to enable general debug features
* CONFIG_DEBUG_SPI - Define to enable basic SSP debug (needs CONFIG_DEBUG)
* CONFIG_DEBUG_VERBOSE - Define to enable verbose SSP debug
*/
#ifdef CONFIG_SPI_DEBUG
#ifdef CONFIG_DEBUG_SPI
# define sspdbg lldbg
# ifdef CONFIG_VERBOSE
# ifdef CONFIG_DEBUG_VERBOSE
# define spivdbg lldbg
# else
# define spivdbg(x...)
@ -82,9 +90,8 @@
# define spivdbg(x...)
#endif
/* SSP Clocking.
*
* The CPU clock by 1, 2, 4, or 8 to get the SSP peripheral clock (SSP_CLOCK).
/* SSP Clocking *************************************************************/
/* The CPU clock by 1, 2, 4, or 8 to get the SSP peripheral clock (SSP_CLOCK).
* SSP_CLOCK may be further divided by 2-254 to get the SSP clock. If we
* want a usable range of 4KHz to 25MHz for the SSP, then:
*