ADS1255 Driver: Must not do SPI access from interrupt handler. Use the worker thread instead.

This commit is contained in:
Gregory Nutt 2016-05-26 13:42:35 -06:00
parent 1571575d54
commit d2caa93f1a
2 changed files with 51 additions and 9 deletions

View File

@ -46,6 +46,7 @@ config ADC_ADS125X
bool "TI ADS1255/ADS1256 support" bool "TI ADS1255/ADS1256 support"
default n default n
select SPI select SPI
select SCHED_HPWORK
if ADC_ADS125X if ADC_ADS125X

View File

@ -39,6 +39,10 @@
* *
************************************************************************************/ ************************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h> #include <nuttx/config.h>
#include <stdio.h> #include <stdio.h>
@ -50,13 +54,17 @@
#include <assert.h> #include <assert.h>
#include <debug.h> #include <debug.h>
#include <arch/board/board.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
#include <nuttx/wqueue.h>
#include <nuttx/spi/spi.h> #include <nuttx/spi/spi.h>
#include <nuttx/analog/adc.h> #include <nuttx/analog/adc.h>
#if defined(CONFIG_ADC_ADS1255) #if defined(CONFIG_ADC_ADS1255)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ADS125X_BUFON 0x02 #define ADS125X_BUFON 0x02
#define ADS125X_BUFOFF 0x00 #define ADS125X_BUFOFF 0x00
@ -103,12 +111,14 @@
#endif #endif
/**************************************************************************** /****************************************************************************
* ad_private Types * Private Types
****************************************************************************/ ****************************************************************************/
struct ads1255_dev_s struct ads1255_dev_s
{ {
FAR const struct adc_callback_s *cb; FAR const struct adc_callback_s *cb;
FAR struct spi_dev_s *spi; /* Cached SPI device reference */
struct work_s work;
uint8_t channel; uint8_t channel;
uint32_t sps; uint32_t sps;
uint8_t pga; uint8_t pga;
@ -116,11 +126,10 @@ struct ads1255_dev_s
const uint8_t *mux; const uint8_t *mux;
int irq; int irq;
int devno; int devno;
FAR struct spi_dev_s *spi; /* Cached SPI device reference */
}; };
/**************************************************************************** /****************************************************************************
* ad_private Function Prototypes * Private Function Prototypes
****************************************************************************/ ****************************************************************************/
/* ADC methods */ /* ADC methods */
@ -132,10 +141,14 @@ static int adc_setup(FAR struct adc_dev_s *dev);
static void adc_shutdown(FAR struct adc_dev_s *dev); static void adc_shutdown(FAR struct adc_dev_s *dev);
static void adc_rxint(FAR struct adc_dev_s *dev, bool enable); static void adc_rxint(FAR struct adc_dev_s *dev, bool enable);
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);
/* Interrupt handling */
static void adc_worker(FAR void *arg);
static int adc_interrupt(int irq, void *context); static int adc_interrupt(int irq, void *context);
/**************************************************************************** /****************************************************************************
* ad_private Data * Private Data
****************************************************************************/ ****************************************************************************/
static const struct adc_ops_s g_adcops = static const struct adc_ops_s g_adcops =
@ -351,16 +364,16 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
} }
/**************************************************************************** /****************************************************************************
* Name: adc_interrupt * Name: adc_worker
* *
* Description: * Description:
* ADC interrupt handler * ADC interrupt work
* *
****************************************************************************/ ****************************************************************************/
static int adc_interrupt(int irq, void *context) static void adc_worker(FAR void *arg)
{ {
FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)g_adcdev.ad_priv; FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)arg;
FAR struct spi_dev_s *spi; FAR struct spi_dev_s *spi;
unsigned char buf[4]; unsigned char buf[4];
unsigned char ch; unsigned char ch;
@ -406,6 +419,34 @@ static int adc_interrupt(int irq, void *context)
priv->cb->au_receive(&g_adcdev, priv->channel, *(int32_t *)buf); priv->cb->au_receive(&g_adcdev, priv->channel, *(int32_t *)buf);
} }
/* Re-enable ADC interrupts */
up_enable_irq(priv->irq);
}
/****************************************************************************
* Name: adc_interrupt
*
* Description:
* ADC interrupt handler
*
****************************************************************************/
static int adc_interrupt(int irq, void *context)
{
FAR struct ads1255_dev_s *priv = (FAR struct ads1255_dev_s *)g_adcdev.ad_priv;
DEBUGASSERT(priv != NULL);
/* Disable further ADC interrupts until the worker thread has executed. */
up_disable_irq(priv->irq);
/* Schedule the ADC work for the worker thread. Whent he sample has been
* processed, the ADC interrupt will be re-enabled.
*/
DEBUGVERIFY(work_queue(HPWORK, &priv->work, adc_worker, priv, 0));
return OK; return OK;
} }