Add bind method to the ADC lower-half interface

This commit is contained in:
Gregory Nutt 2016-05-26 11:32:26 -06:00
parent 001715d57b
commit b630d48175
3 changed files with 194 additions and 58 deletions

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);
@ -143,7 +147,7 @@ static const struct adc_ops_s g_adcops =
.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 +194,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 +245,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 +292,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 +335,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 +395,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 +429,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
************************************************************************************/