Driver for the 24-Bit Differential Input ADC ADS1242 that communicates via SPI with a MCU. Reading the ADC conversion result as well as configuring the ADC, setting the input channel, etc. is implemented via ioctl calls. However, it does not yet implement the standard ADC interface.
This commit is contained in:
parent
61819c0e3e
commit
dc8c14aa53
2
arch
2
arch
@ -1 +1 @@
|
||||
Subproject commit 39dca5d1dc63ca02a7f897ff7de0bb03fee86a60
|
||||
Subproject commit 69b5f95ae5c4b953be4b6e1598a4e71f794afe52
|
@ -43,6 +43,13 @@ config ADS1255_FREQUENCY
|
||||
|
||||
endif # ADC_ADS125X
|
||||
|
||||
config ADC_ADS1242
|
||||
bool "ADS1242"
|
||||
default n
|
||||
select SPI
|
||||
---help---
|
||||
Enable driver support for the ADS1242 24-Bit SPI powered ADC.
|
||||
|
||||
config ADC_PGA11X
|
||||
bool "TI PGA112/3/6/7 support"
|
||||
default n
|
||||
|
584
drivers/analog/ads1242.c
Normal file
584
drivers/analog/ads1242.c
Normal file
@ -0,0 +1,584 @@
|
||||
/****************************************************************************
|
||||
* drivers/sensors/ads1242.c
|
||||
* Character driver for the MCP3426 Differential Input 16 Bit Delta/Sigma ADC
|
||||
*
|
||||
* Copyright (C) 2015 DS-Automotion GmbH. All rights reserved.
|
||||
* Author: Alexander Entinger <a.entinger@ds-automotion.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <fixedmath.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/spi/spi.h>
|
||||
|
||||
#include <nuttx/analog/ads1242.h>
|
||||
|
||||
#if defined(CONFIG_SPI) && defined(CONFIG_ADC_ADS1242)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct ads1242_dev_s
|
||||
{
|
||||
FAR struct spi_dev_s *spi; /* Pointer to the SPI instance */
|
||||
uint32_t osc_period_us; /* Period of the oscillator attached to the ADS1242 in us */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* SPI Helpers */
|
||||
|
||||
static void ads1242_reset(FAR struct ads1242_dev_s *dev);
|
||||
static void ads1242_performSelfGainCalibration(
|
||||
FAR struct ads1242_dev_s *dev);
|
||||
static void ads1242_performSelfOffsetCalibration(
|
||||
FAR struct ads1242_dev_s *dev);
|
||||
static void ads1242_performSystemOffsetCalibration(
|
||||
FAR struct ads1242_dev_s *dev);
|
||||
static void ads1242_read_conversion_result(FAR struct ads1242_dev_s *dev,
|
||||
FAR uint32_t *conversion_result);
|
||||
|
||||
static void ads1242_write_reg(FAR struct ads1242_dev_s *dev,
|
||||
uint8_t const reg_addr, uint8_t const reg_value);
|
||||
static void ads1242_read_reg(FAR struct ads1242_dev_s *dev,
|
||||
uint8_t const reg_addr, FAR uint8_t *reg_value);
|
||||
|
||||
static void ads1242_set_gain(FAR struct ads1242_dev_s *dev,
|
||||
ADS1242_GAIN_SELECTION const gain_selection);
|
||||
static void ads1242_set_positive_input(FAR struct ads1242_dev_s *dev,
|
||||
ADS1242_POSITIVE_INPUT_SELECTION const pos_in_sel);
|
||||
static void ads1242_set_negative_input(FAR struct ads1242_dev_s *dev,
|
||||
ADS1242_NEGATIVE_INPUT_SELECTION const neg_in_sel);
|
||||
static bool ads1242_is_data_ready(FAR struct ads1242_dev_s *dev);
|
||||
|
||||
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE)
|
||||
static void ads1242_print_regs(FAR struct ads1242_dev_s *dev, char const *msg);
|
||||
#endif / defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE) */
|
||||
|
||||
/* Character driver methods */
|
||||
|
||||
static int ads1242_open(FAR struct file *filep);
|
||||
static int ads1242_close(FAR struct file *filep);
|
||||
static ssize_t ads1242_read(FAR struct file *, FAR char *, size_t);
|
||||
static ssize_t ads1242_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen);
|
||||
static int ads1242_ioctl(FAR struct file *filep, int cmd,
|
||||
unsigned long arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct file_operations g_ads1242_fops =
|
||||
{
|
||||
ads1242_open,
|
||||
ads1242_close,
|
||||
ads1242_read,
|
||||
ads1242_write,
|
||||
NULL,
|
||||
ads1242_ioctl
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
, NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_reset
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1242_reset(FAR struct ads1242_dev_s *dev)
|
||||
{
|
||||
SPI_SELECT(dev->spi, 0, true); /* Set nADC_SPI_CS to low which selects the ADS1242 */
|
||||
|
||||
SPI_SEND(dev->spi, ADS1242_CMD_RESET);/* Issue reset command */
|
||||
|
||||
SPI_SELECT(dev->spi, 0, false); /* Set nADC_SPI_CS to high which deselects the ADS1242 */
|
||||
|
||||
up_mdelay(100); /* Wait a little so the device has time to perform a proper reset */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_performSelfGainCalibration
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1242_performSelfGainCalibration(FAR struct ads1242_dev_s *dev)
|
||||
{
|
||||
SPI_SELECT(dev->spi, 0, true);
|
||||
|
||||
SPI_SEND(dev->spi, ADS1242_CMD_SELF_GAIN_CALIB);
|
||||
|
||||
SPI_SELECT(dev->spi, 0, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_performSelfOffsetCalibration
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1242_performSelfOffsetCalibration(FAR struct ads1242_dev_s *dev)
|
||||
{
|
||||
SPI_SELECT(dev->spi, 0, true);
|
||||
|
||||
SPI_SEND(dev->spi, ADS1242_CMD_SELF_OFFSET_CALIB);
|
||||
|
||||
SPI_SELECT(dev->spi, 0, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_performSystemOffsetCalibration
|
||||
****************************************************************************/
|
||||
|
||||
static void
|
||||
ads1242_performSystemOffsetCalibration(FAR struct ads1242_dev_s *dev)
|
||||
{
|
||||
SPI_SELECT(dev->spi, 0, true);
|
||||
|
||||
SPI_SEND(dev->spi, ADS1242_CMD_SYSTEM_OFFSET_CALIB);
|
||||
|
||||
SPI_SELECT(dev->spi, 0, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_read_conversion_result
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1242_read_conversion_result(FAR struct ads1242_dev_s *dev,
|
||||
FAR uint32_t *conversion_result)
|
||||
{
|
||||
SPI_SELECT(dev->spi, 0, true);
|
||||
|
||||
SPI_SEND(dev->spi, ADS1242_CMD_READ_DATA);
|
||||
|
||||
/* Delay between last SCLK edge for DIN and first SCLK edge for DOUT:
|
||||
* RDATA, RDATAC, RREG, WREG: Min 50 x tOSC Periods
|
||||
*/
|
||||
|
||||
up_udelay(50 * dev->osc_period_us);
|
||||
|
||||
*conversion_result = 0;
|
||||
|
||||
/* 1st Byte = MSB
|
||||
* 2nd Byte = Mid-Byte
|
||||
* 3rd Byte = LSB
|
||||
*/
|
||||
|
||||
*conversion_result |= ((uint32_t)(SPI_SEND(dev->spi, 0xFF))) << 16;
|
||||
*conversion_result |= ((uint32_t)(SPI_SEND(dev->spi, 0xFF))) << 8;
|
||||
*conversion_result |= ((uint32_t)(SPI_SEND(dev->spi, 0xFF))) << 0;
|
||||
|
||||
SPI_SELECT(dev->spi, 0, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_write_reg
|
||||
*
|
||||
* Description:
|
||||
* Write to the registers starting with the register address specified as
|
||||
* part of the instruction. The number of registers that will be written
|
||||
* is one plus the value of the second byte.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1242_write_reg(FAR struct ads1242_dev_s *dev,
|
||||
uint8_t const reg_addr, uint8_t const reg_value)
|
||||
{
|
||||
SPI_SELECT(dev->spi, 0, true);
|
||||
SPI_SEND(dev->spi, ADS1242_CMD_WRITE_REGISTER | reg_addr);
|
||||
SPI_SEND(dev->spi, 0x00); /* Write 1 Byte */
|
||||
SPI_SEND(dev->spi, reg_value);
|
||||
SPI_SELECT(dev->spi, 0, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_read_reg
|
||||
*
|
||||
* Description:
|
||||
* Output the data from up to 16 registers starting with the register
|
||||
* address specified as part of the instruction. The number of registers
|
||||
* read will be one plus the second byte count. If the count exceeds the
|
||||
* remaining registers, the addresses wrap back to the beginning.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1242_read_reg(FAR struct ads1242_dev_s *dev,
|
||||
uint8_t const reg_addr, FAR uint8_t *reg_value)
|
||||
{
|
||||
SPI_SELECT(dev->spi, 0, true);
|
||||
SPI_SEND(dev->spi, ADS1242_CMD_READ_REGISTER | reg_addr);
|
||||
SPI_SEND(dev->spi, 0x00); /* Read 1 Byte */
|
||||
|
||||
/* Delay between last SCLK edge for DIN and first SCLK edge for DOUT:
|
||||
* RDATA, RDATAC, RREG, WREG: Min 50 x tOSC Periods
|
||||
*/
|
||||
|
||||
up_udelay(50 * dev->osc_period_us);
|
||||
|
||||
*reg_value = SPI_SEND(dev->spi, 0xFF);
|
||||
|
||||
SPI_SELECT(dev->spi, 0, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_set_gain
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1242_set_gain(FAR struct ads1242_dev_s *dev,
|
||||
ADS1242_GAIN_SELECTION const gain_selection)
|
||||
{
|
||||
uint8_t setup_reg_value = 0;
|
||||
|
||||
ads1242_read_reg(dev, ADS1242_REG_SETUP, &setup_reg_value);
|
||||
setup_reg_value &= ~(ADS1242_REG_SETUP_BIT_PGA2 |
|
||||
ADS1242_REG_SETUP_BIT_PGA1 |
|
||||
ADS1242_REG_SETUP_BIT_PGA0);
|
||||
setup_reg_value |= (uint8_t)(gain_selection);
|
||||
ads1242_write_reg(dev, ADS1242_REG_SETUP, setup_reg_value);
|
||||
|
||||
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE)
|
||||
ads1242_print_regs(dev, "ads1242_set_gain");
|
||||
#endif
|
||||
|
||||
/* It is necessary to perform a offset calibration after setting the gain */
|
||||
|
||||
ads1242_performSelfOffsetCalibration(dev);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_set_positive_input
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1242_set_positive_input(FAR struct ads1242_dev_s *dev,
|
||||
ADS1242_POSITIVE_INPUT_SELECTION const pos_in_sel)
|
||||
{
|
||||
uint8_t mux_reg_value = 0;
|
||||
|
||||
ads1242_read_reg(dev, ADS1242_REG_MUX, &mux_reg_value);
|
||||
mux_reg_value &= ~(ADS1242_REG_MUX_BIT_PSEL3 | ADS1242_REG_MUX_BIT_PSEL2 |
|
||||
ADS1242_REG_MUX_BIT_PSEL1 | ADS1242_REG_MUX_BIT_PSEL0);
|
||||
mux_reg_value |= (uint8_t)(pos_in_sel);
|
||||
ads1242_write_reg(dev, ADS1242_REG_MUX, mux_reg_value);
|
||||
|
||||
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE)
|
||||
ads1242_print_regs(dev, "ads1242_set_positive_input");
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_set_negative_input
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1242_set_negative_input(FAR struct ads1242_dev_s *dev,
|
||||
ADS1242_NEGATIVE_INPUT_SELECTION const neg_in_sel)
|
||||
{
|
||||
uint8_t mux_reg_value = 0;
|
||||
|
||||
ads1242_read_reg(dev, ADS1242_REG_MUX, &mux_reg_value);
|
||||
mux_reg_value &= ~(ADS1242_REG_MUX_BIT_NSEL3 | ADS1242_REG_MUX_BIT_NSEL2 |
|
||||
ADS1242_REG_MUX_BIT_NSEL1 | ADS1242_REG_MUX_BIT_NSEL0);
|
||||
mux_reg_value |= (uint8_t)(neg_in_sel);
|
||||
ads1242_write_reg(dev, ADS1242_REG_MUX, mux_reg_value);
|
||||
|
||||
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE)
|
||||
ads1242_print_regs(dev, "ads1242_set_negative_input");
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_set_negative_input
|
||||
****************************************************************************/
|
||||
|
||||
static bool ads1242_is_data_ready(FAR struct ads1242_dev_s *dev)
|
||||
{
|
||||
uint8_t acr_reg_value = 0xFF;
|
||||
bool const is_data_ready;
|
||||
|
||||
ads1242_read_reg(dev, ADS1242_REG_ACR, &acr_reg_value);
|
||||
is_data_ready = (acr_reg_value & ADS1242_REG_ACR_BIT_nDRDY) == 0;
|
||||
return is_data_ready;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_print_regs
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE)
|
||||
static void ads1242_print_regs(FAR struct ads1242_dev_s *dev, char const *msg)
|
||||
{
|
||||
uint8_t setup_reg_value = 0;
|
||||
uint8_t mux_reg_value = 0;
|
||||
uint8_t acr_reg_value = 0;
|
||||
|
||||
dbg("%s\n", msg);
|
||||
|
||||
ads1242_read_reg(dev, ADS1242_REG_SETUP, &setup_reg_value);
|
||||
ads1242_read_reg(dev, ADS1242_REG_MUX, &mux_reg_value);
|
||||
ads1242_read_reg(dev, ADS1242_REG_ACR, &acr_reg_value);
|
||||
|
||||
dbg("SETUP %02X\n", setup_reg_value);
|
||||
dbg("MUX %02X\n", mux_reg_value);
|
||||
dbg("ACR %02X\n", acr_reg_value);
|
||||
}
|
||||
#endif /* defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE) */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_open
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1242_open(FAR struct file *filep)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct ads1242_dev_s *priv = inode->i_private;
|
||||
|
||||
ads1242_reset(priv);
|
||||
up_mdelay(100);
|
||||
|
||||
ads1242_performSelfGainCalibration(priv);
|
||||
up_mdelay(100);
|
||||
|
||||
/* SPEED = 1 -> fMod = fOsc / 256 (fMod = Modulator Clock Speed)
|
||||
* BUFEN = 1 -> Internal input buffer enabled -> results in a very high
|
||||
* impedance input for the ADC ~ 5 GOhm
|
||||
*/
|
||||
|
||||
ads1242_write_reg(priv, ADS1242_REG_ACR,
|
||||
ADS1242_REG_ACR_BIT_SPEED | ADS1242_REG_ACR_BIT_BUFEN);
|
||||
|
||||
ads1242_performSelfOffsetCalibration(priv);
|
||||
up_mdelay(100);
|
||||
|
||||
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE)
|
||||
ads1242_print_regs(priv, "ads1242_open");
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
/****************************************************************************
|
||||
* Name: ads1242_close
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1242_close(FAR struct file *filep)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct ads1242_dev_s *priv = inode->i_private;
|
||||
|
||||
ads1242_reset(priv);
|
||||
up_mdelay(100);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_read
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t ads1242_read(FAR struct file *filep,
|
||||
FAR char *buffer, size_t buflen)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct ads1242_dev_s *priv = inode->i_private;
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_write
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t ads1242_write(FAR struct file *filep,
|
||||
FAR const char *buffer, size_t buflen)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct ads1242_dev_s *priv = inode->i_private;
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_ioctl
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1242_ioctl (FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct ads1242_dev_s *priv = inode->i_private;
|
||||
|
||||
int ret = OK;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
/* Read the result of an analog conversion */
|
||||
|
||||
case ANIOC_ADS2142_READ:
|
||||
{
|
||||
FAR uint32_t *data = (FAR uint32_t *)((uintptr_t)arg);
|
||||
ads1242_read_conversion_result(priv, data);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Set the gain of the ADC */
|
||||
|
||||
case ANIOC_ADS2142_SET_GAIN:
|
||||
{
|
||||
ads1242_set_gain(priv, (ADS1242_GAIN_SELECTION)(arg));
|
||||
}
|
||||
break;
|
||||
|
||||
/* Set the positive input of the ADC */
|
||||
|
||||
case ANIOC_ADS2142_SET_POSITIVE_INPUT:
|
||||
{
|
||||
ads1242_set_positive_input(priv,
|
||||
(ADS1242_POSITIVE_INPUT_SELECTION)(arg));
|
||||
}
|
||||
break;
|
||||
|
||||
/* Set the negative input of the ADC */
|
||||
|
||||
case ANIOC_ADS2142_SET_NEGATIVE_INPUT:
|
||||
{
|
||||
ads1242_set_negative_input(priv,
|
||||
(ADS1242_NEGATIVE_INPUT_SELECTION)(arg));
|
||||
}
|
||||
break;
|
||||
|
||||
/* Check if data is ready to be read */
|
||||
|
||||
case ANIOC_ADS2142_IS_DATA_READY:
|
||||
{
|
||||
FAR bool *is_data_ready = (FAR bool *)((uintptr_t)arg);
|
||||
*is_data_ready = ads1242_is_data_ready(priv);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Perform a system offset calibration - Note: Zero input signal must
|
||||
* be applied.
|
||||
*/
|
||||
|
||||
case ANIOC_ADS2142_DO_SYSTEM_OFFSET_CALIB:
|
||||
{
|
||||
ads1242_performSystemOffsetCalibration(priv);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Command was not recognized */
|
||||
|
||||
default:
|
||||
dbg ("Unrecognized cmd: %d\n", cmd);
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_register
|
||||
*
|
||||
* Description:
|
||||
* Register the ADS1242 character device as 'devpath'
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - The full path to the driver to register. E.g., "/dev/ads1242"
|
||||
* spi - An instance of the SPI interface to use to communicate with ADS1242
|
||||
* osc_freq_hz - The frequency of the ADS1242 oscillator in Hz. Required for
|
||||
* calculating the minimum delay periods when accessing the device via SPI.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ads1242_register(FAR const char *devpath, FAR struct spi_dev_s *spi,
|
||||
uint32_t const osc_freq_hz)
|
||||
{
|
||||
FAR struct ads1242_dev_s *priv;
|
||||
int ret;
|
||||
|
||||
/* Sanity check */
|
||||
|
||||
DEBUGASSERT(spi != NULL);
|
||||
|
||||
/* Initialize the ADS1242 device structure */
|
||||
|
||||
priv = (FAR struct ads1242_dev_s *)kmm_malloc(sizeof(struct ads1242_dev_s));
|
||||
if (priv == NULL)
|
||||
{
|
||||
dbg ("Failed to allocate instance\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->spi = spi;
|
||||
|
||||
float const osc_period_us = (1000.0 * 1000.0) / ((float)(osc_freq_hz));
|
||||
priv->osc_period_us = (uint32_t)(osc_period_us);
|
||||
|
||||
/* Register the character driver */
|
||||
|
||||
ret = register_driver(devpath, &g_ads1242_fops, 0666, priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
dbg ("Failed to register driver: %d\n", ret);
|
||||
kmm_free(priv);
|
||||
}
|
||||
|
||||
/* setup SPI frequency */
|
||||
|
||||
SPI_SETFREQUENCY(spi, ADS1242_SPI_FREQUENCY);
|
||||
|
||||
/* Setup SPI mode */
|
||||
|
||||
SPI_SETMODE(spi, ADS1242_SPI_MODE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SPI && CONFIG_ADC_ADS1242 */
|
202
include/nuttx/analog/ads1242.h
Normal file
202
include/nuttx/analog/ads1242.h
Normal file
@ -0,0 +1,202 @@
|
||||
/****************************************************************************
|
||||
* include/nuttx/sensors/ads1242.h
|
||||
*
|
||||
* Copyright (C) 2016, DS-Automotion GmbH. All rights reserved.
|
||||
* Author: Alexander Entinger <a.entinger@ds-automotion.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef NUTTX_INCLUDE_NUTTX_ANALOG_ADS1242_H_
|
||||
#define NUTTX_INCLUDE_NUTTX_ANALOG_ADS1242_H_
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
#include <nuttx/spi/spi.h>
|
||||
|
||||
#if defined(CONFIG_SPI) && defined(CONFIG_ADC_ADS1242)
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* IOCTL Commands ***********************************************************/
|
||||
|
||||
#define ANIOC_ADS2142_READ _ANIOC(0x0001) /* Arg: uint32_t *value */
|
||||
#define ANIOC_ADS2142_SET_GAIN _ANIOC(0x0002) /* Arg: uint8_t value */
|
||||
#define ANIOC_ADS2142_SET_POSITIVE_INPUT _ANIOC(0x0003) /* Arg: uint8_t value */
|
||||
#define ANIOC_ADS2142_SET_NEGATIVE_INPUT _ANIOC(0x0004) /* Arg: uint8_t value */
|
||||
#define ANIOC_ADS2142_IS_DATA_READY _ANIOC(0x0005) /* Arg: bool *value */
|
||||
#define ANIOC_ADS2142_DO_SYSTEM_OFFSET_CALIB _ANIOC(0x0006) /* Arg: None */
|
||||
|
||||
/* ADS1242 REGISTER *********************************************************/
|
||||
|
||||
#define ADS1242_REG_SETUP (0x00) /* Setup Register */
|
||||
#define ADS1242_REG_MUX (0x01) /* Multiplexer Control Register */
|
||||
#define ADS1242_REG_ACR (0x02) /* Analog Control Register */
|
||||
#define ADS1242_REG_ODAC (0x03) /* Offset DAC */
|
||||
#define ADS1242_REG_DIO (0x04) /* Data I/O */
|
||||
#define ADS1242_REG_DIR (0x05) /* Direction Control for Data I/O */
|
||||
#define ADS1242_REG_IOCON (0x06) /* I/O Configuration Register */
|
||||
|
||||
/* ADS1242 REGISTER Bit Definitions *****************************************/
|
||||
|
||||
/* SETUP */
|
||||
#define ADS1242_REG_SETUP_BIT_BOCS (1 << 3)
|
||||
#define ADS1242_REG_SETUP_BIT_PGA2 (1 << 2)
|
||||
#define ADS1242_REG_SETUP_BIT_PGA1 (1 << 1)
|
||||
#define ADS1242_REG_SETUP_BIT_PGA0 (1 << 0)
|
||||
/* MUX */
|
||||
#define ADS1242_REG_MUX_BIT_PSEL3 (1 << 7)
|
||||
#define ADS1242_REG_MUX_BIT_PSEL2 (1 << 6)
|
||||
#define ADS1242_REG_MUX_BIT_PSEL1 (1 << 5)
|
||||
#define ADS1242_REG_MUX_BIT_PSEL0 (1 << 4)
|
||||
#define ADS1242_REG_MUX_BIT_NSEL3 (1 << 3)
|
||||
#define ADS1242_REG_MUX_BIT_NSEL2 (1 << 2)
|
||||
#define ADS1242_REG_MUX_BIT_NSEL1 (1 << 1)
|
||||
#define ADS1242_REG_MUX_BIT_NSEL0 (1 << 0)
|
||||
/* ACR */
|
||||
#define ADS1242_REG_ACR_BIT_nDRDY (1 << 7)
|
||||
#define ADS1242_REG_ACR_BIT_UnB (1 << 6)
|
||||
#define ADS1242_REG_ACR_BIT_SPEED (1 << 5)
|
||||
#define ADS1242_REG_ACR_BIT_BUFEN (1 << 4)
|
||||
#define ADS1242_REG_ACR_BIT_BITORDER (1 << 3)
|
||||
#define ADS1242_REG_ACR_BIT_RANGE (1 << 2)
|
||||
#define ADS1242_REG_ACR_BIT_DR1 (1 << 1)
|
||||
#define ADS1242_REG_ACR_BIT_DR0 (1 << 0)
|
||||
|
||||
/* ADS1242 SPI COMMANDS *****************************************************/
|
||||
|
||||
#define ADS1242_CMD_READ_DATA (0x01)
|
||||
#define ADS1242_CMD_READ_REGISTER (0x10)
|
||||
#define ADS1242_CMD_WRITE_REGISTER (0x50)
|
||||
#define ADS1242_CMD_SELF_OFFSET_CALIB (0xF1)
|
||||
#define ADS1242_CMD_SELF_GAIN_CALIB (0xf2)
|
||||
#define ADS1242_CMD_SYSTEM_OFFSET_CALIB (0xf3)
|
||||
#define ADS1242_CMD_RESET (0xfe)
|
||||
|
||||
/* SPI BUS PARAMETERS *******************************************************/
|
||||
|
||||
/* 100 kHz, SCLK period has to be at least 4 x tOsc period of ADS1242
|
||||
* oscillator circuit.
|
||||
*/
|
||||
|
||||
#define ADS1242_SPI_FREQUENCY (100000)
|
||||
|
||||
/* Device uses SPI Mode 1: CKPOL = 0, CKPHA = 1 */
|
||||
|
||||
#define ADS1242_SPI_MODE (SPIDEV_MODE1)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ADS1242_x1 = 0,
|
||||
ADS1242_x2 = ADS1242_REG_SETUP_BIT_PGA0,
|
||||
ADS1242_x4 = ADS1242_REG_SETUP_BIT_PGA1,
|
||||
ADS1242_x8 = ADS1242_REG_SETUP_BIT_PGA1 | ADS1242_REG_SETUP_BIT_PGA0,
|
||||
ADS1242_x16 = ADS1242_REG_SETUP_BIT_PGA2,
|
||||
ADS1242_x32 = ADS1242_REG_SETUP_BIT_PGA2 | ADS1242_REG_SETUP_BIT_PGA0,
|
||||
ADS1242_x64 = ADS1242_REG_SETUP_BIT_PGA2 | ADS1242_REG_SETUP_BIT_PGA1,
|
||||
ADS1242_x128 = ADS1242_REG_SETUP_BIT_PGA2 | ADS1242_REG_SETUP_BIT_PGA1 |
|
||||
ADS1242_REG_SETUP_BIT_PGA0
|
||||
} ADS1242_GAIN_SELECTION;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ADS1242_P_AIN0 = 0,
|
||||
ADS1242_P_AIN1 = ADS1242_REG_MUX_BIT_PSEL0,
|
||||
ADS1242_P_AIN2 = ADS1242_REG_MUX_BIT_PSEL1,
|
||||
ADS1242_P_AIN3 = ADS1242_REG_MUX_BIT_PSEL1 | ADS1242_REG_MUX_BIT_PSEL0,
|
||||
ADS1242_P_AIN4 = ADS1242_REG_MUX_BIT_PSEL2,
|
||||
ADS1242_P_AIN5 = ADS1242_REG_MUX_BIT_PSEL2 | ADS1242_REG_MUX_BIT_PSEL0,
|
||||
ADS1242_P_AIN6 = ADS1242_REG_MUX_BIT_PSEL2 | ADS1242_REG_MUX_BIT_PSEL1,
|
||||
ADS1242_P_AIN7 = ADS1242_REG_MUX_BIT_PSEL2 | ADS1242_REG_MUX_BIT_PSEL1 |
|
||||
ADS1242_REG_MUX_BIT_PSEL0,
|
||||
} ADS1242_POSITIVE_INPUT_SELECTION;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ADS1242_N_AIN0 = 0,
|
||||
ADS1242_N_AIN1 = ADS1242_REG_MUX_BIT_NSEL0,
|
||||
ADS1242_N_AIN2 = ADS1242_REG_MUX_BIT_NSEL1,
|
||||
ADS1242_N_AIN3 = ADS1242_REG_MUX_BIT_NSEL1 | ADS1242_REG_MUX_BIT_NSEL0,
|
||||
ADS1242_N_AIN4 = ADS1242_REG_MUX_BIT_NSEL2,
|
||||
ADS1242_N_AIN5 = ADS1242_REG_MUX_BIT_NSEL2 | ADS1242_REG_MUX_BIT_NSEL0,
|
||||
ADS1242_N_AIN6 = ADS1242_REG_MUX_BIT_NSEL2 | ADS1242_REG_MUX_BIT_NSEL1,
|
||||
ADS1242_N_AIN7 = ADS1242_REG_MUX_BIT_NSEL2 | ADS1242_REG_MUX_BIT_NSEL1 |
|
||||
ADS1242_REG_MUX_BIT_NSEL0,
|
||||
} ADS1242_NEGATIVE_INPUT_SELECTION;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1242_register
|
||||
*
|
||||
* Description:
|
||||
* Register the ADS1242 character device as 'devpath'
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - The full path to the driver to register. E.g., "/dev/ads1242"
|
||||
* spi - An instance of the SPI interface to use to communicate with ADS1242
|
||||
* osc_freq_hz - The frequency of the ADS1242 oscillator in Hz. Required for
|
||||
* calculating the minimum delay periods when accessing the device via SPI.
|
||||
*
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ads1242_register(FAR const char *devpath, FAR struct spi_dev_s *spi,
|
||||
uint32_t const osc_freq_hz);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_SPI && CONFIG_ADC_ADS1242 */
|
||||
#endif /* NUTTX_INCLUDE_NUTTX_ANALOG_ADS1242_H_ */
|
Loading…
x
Reference in New Issue
Block a user