diff --git a/arch b/arch index 39dca5d1dc6..69b5f95ae5c 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit 39dca5d1dc63ca02a7f897ff7de0bb03fee86a60 +Subproject commit 69b5f95ae5c4b953be4b6e1598a4e71f794afe52 diff --git a/drivers/analog/Kconfig b/drivers/analog/Kconfig index 1bbc219f812..3245cc7c408 100644 --- a/drivers/analog/Kconfig +++ b/drivers/analog/Kconfig @@ -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 diff --git a/drivers/analog/ads1242.c b/drivers/analog/ads1242.c new file mode 100644 index 00000000000..6c80df4d2a2 --- /dev/null +++ b/drivers/analog/ads1242.c @@ -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 + * + * 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 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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 */ diff --git a/include/nuttx/analog/ads1242.h b/include/nuttx/analog/ads1242.h new file mode 100644 index 00000000000..b74b2a28b26 --- /dev/null +++ b/include/nuttx/analog/ads1242.h @@ -0,0 +1,202 @@ +/**************************************************************************** + * include/nuttx/sensors/ads1242.h + * + * Copyright (C) 2016, DS-Automotion GmbH. All rights reserved. + * Author: Alexander Entinger + * + * 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 +#include +#include + +#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_ */