From c79e92ceffd9665632b58a6fb884178a4f4c71a2 Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 19 Mar 2013 14:45:26 +0000 Subject: 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 --- nuttx/arch/arm/src/lpc17xx/Kconfig | 29 +++++++++++++++++++ nuttx/arch/arm/src/lpc17xx/lpc17_adc.c | 53 ++++++++++++++++++++++++++++++++-- nuttx/arch/arm/src/lpc17xx/lpc17_adc.h | 40 +++++++++++++++++++++++-- nuttx/arch/arm/src/lpc17xx/lpc17_spi.c | 25 ++++++++++------ nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c | 23 ++++++++++----- 5 files changed, 148 insertions(+), 22 deletions(-) (limited to 'nuttx/arch/arm/src') diff --git a/nuttx/arch/arm/src/lpc17xx/Kconfig b/nuttx/arch/arm/src/lpc17xx/Kconfig index db76eeb77..0b482540f 100644 --- a/nuttx/arch/arm/src/lpc17xx/Kconfig +++ b/nuttx/arch/arm/src/lpc17xx/Kconfig @@ -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" diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_adc.c b/nuttx/arch/arm/src/lpc17xx/lpc17_adc.c index a3d20d8eb..bcc42f153 100644 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_adc.c +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_adc.c @@ -4,7 +4,7 @@ * Copyright (C) 2011 Li Zhuoyi. All rights reserved. * Author: Li Zhuoyi * 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 } /**************************************************************************** diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_adc.h b/nuttx/arch/arm/src/lpc17xx/lpc17_adc.h index 5a1bef14a..ecca04446 100644 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_adc.h +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_adc.h @@ -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 diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_spi.c b/nuttx/arch/arm/src/lpc17xx/lpc17_spi.c index 05e791434..d87e6c1ec 100644 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_spi.c +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_spi.c @@ -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: * diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c b/nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c index 96b66d7a1..151efbd89 100644 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c @@ -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: * -- cgit v1.2.3