adc: add IOCTL commands ANIOC_RESET_FIFO and ANIOC_SAMPLES_ON_READ

This commit adds two new IOCTL commnands for ADC driver. Command
ANIOC_RESET_FIFO resets FIFO head and tail which causes the driver
to wait for the new data to be received. Calling this command before
reading ADC data in user space ensures that the read data are newly
sampled.

Command ANIOC_SAMPLES_ON_READ return the number of read channels in
the buffer. This can be useful in nonblocking mode when the application
needs to get the samples received before the app was started.

Both IOCTL commands are used only in generic driver section only and do
not have any effect on existing architecture specific drivers.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
This commit is contained in:
Michal Lenc 2021-08-04 20:27:31 +02:00 committed by Xiang Xiao
parent b145ad82b7
commit 87c5cc1a5d
2 changed files with 98 additions and 17 deletions

View File

@ -59,6 +59,7 @@
#include <nuttx/fs/fs.h>
#include <nuttx/arch.h>
#include <nuttx/analog/adc.h>
#include <nuttx/analog/ioctl.h>
#include <nuttx/random.h>
#include <nuttx/irq.h>
@ -78,6 +79,8 @@ static int adc_receive(FAR struct adc_dev_s *dev, uint8_t ch,
static void adc_notify(FAR struct adc_dev_s *dev);
static int adc_poll(FAR struct file *filep, struct pollfd *fds,
bool setup);
static int adc_reset_fifo(FAR struct adc_dev_s *dev);
static int adc_samples_on_read(FAR struct adc_dev_s *dev);
/****************************************************************************
* Private Data
@ -431,7 +434,29 @@ static int adc_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
FAR struct adc_dev_s *dev = inode->i_private;
int ret;
ret = dev->ad_ops->ao_ioctl(dev, cmd, arg);
switch (cmd)
{
case ANIOC_RESET_FIFO:
{
ret = adc_reset_fifo(dev);
}
break;
case ANIOC_SAMPLES_ON_READ:
{
ret = adc_samples_on_read(dev);
}
break;
default:
{
/* Those IOCTLs might be used in arch specific section */
ret = dev->ad_ops->ao_ioctl(dev, cmd, arg);
}
break;
}
return ret;
}
@ -613,6 +638,54 @@ return_with_irqdisabled:
return ret;
}
/****************************************************************************
* Name: adc_reset_fifo
****************************************************************************/
static int adc_reset_fifo(FAR struct adc_dev_s *dev)
{
irqstate_t flags;
FAR struct adc_fifo_s *fifo = &dev->ad_recv;
/* Interrupts must be disabled while accessing the ad_recv FIFO */
flags = enter_critical_section();
fifo->af_head = fifo->af_tail;
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: adc_samples_on_read
****************************************************************************/
static int adc_samples_on_read(FAR struct adc_dev_s *dev)
{
irqstate_t flags;
FAR struct adc_fifo_s *fifo = &dev->ad_recv;
int16_t ret;
/* Interrupts must be disabled while accessing the ad_recv FIFO */
flags = enter_critical_section();
ret = fifo->af_tail - fifo->af_head;
leave_critical_section(flags);
if (ret < 0)
{
/* Increment return value by the size of FIFO */
ret += CONFIG_ADC_FIFOSIZE;
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/

View File

@ -40,24 +40,32 @@
/* DAC/ADC */
#define ANIOC_TRIGGER _ANIOC(0x0001) /* Trigger one conversion
* IN: None
* OUT: None */
#define ANIOC_WDOG_UPPER _ANIOC(0x0002) /* Set upper threshold for
* watchdog
* IN: Threshold value
* OUT: None */
#define ANIOC_WDOG_LOWER _ANIOC(0x0003) /* Set lower threshold for
* watchdog
* IN: Threshold value
* OUT: None */
#define ANIOC_GET_NCHANNELS _ANIOC(0x0004) /* Get the number of
* configured channels
* IN: None
* OUT: Number of channels */
#define ANIOC_TRIGGER _ANIOC(0x0001) /* Trigger one conversion
* IN: None
* OUT: None */
#define ANIOC_WDOG_UPPER _ANIOC(0x0002) /* Set upper threshold for
* watchdog
* IN: Threshold value
* OUT: None */
#define ANIOC_WDOG_LOWER _ANIOC(0x0003) /* Set lower threshold for
* watchdog
* IN: Threshold value
* OUT: None */
#define ANIOC_GET_NCHANNELS _ANIOC(0x0004) /* Get the number of
* configured channels
* IN: None
* OUT: Number of channels */
#define ANIOC_RESET_FIFO _ANIOC(0x0005) /* Clear data receive FIFO
* IN: None
* OUT: None */
#define ANIOC_SAMPLES_ON_READ _ANIOC(0x0006) /* Get the number of
* samples to be read
* IN: None
* OUT: Number of samples
* waiting to be read */
#define AN_FIRST 0x0001 /* First common command */
#define AN_NCMDS 4 /* Number of common commands */
#define AN_NCMDS 6 /* Number of common commands */
/* User defined ioctl commands are also supported. These will be forwarded
* by the upper-half driver to the lower-half driver via the ioctl()