2016-01-29 14:41:23 +01:00
|
|
|
/****************************************************************************
|
2021-03-08 22:39:04 +01:00
|
|
|
* drivers/analog/ads1242.c
|
2016-01-29 14:41:23 +01:00
|
|
|
*
|
2021-03-31 12:04:06 +02:00
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
|
|
* this work for additional information regarding copyright ownership. The
|
|
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
|
|
* "License"); you may not use this file except in compliance with the
|
|
|
|
* License. You may obtain a copy of the License at
|
2016-01-29 14:41:23 +01:00
|
|
|
*
|
2021-03-31 12:04:06 +02:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2016-01-29 14:41:23 +01:00
|
|
|
*
|
2021-03-31 12:04:06 +02:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
* under the License.
|
2016-01-29 14:41:23 +01:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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 */
|
|
|
|
|
2016-05-26 22:56:10 +02:00
|
|
|
static void ads1242_lock(FAR struct spi_dev_s *spi);
|
|
|
|
static void ads1242_unlock(FAR struct spi_dev_s *spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
static void ads1242_reset(FAR struct ads1242_dev_s *dev);
|
2019-12-05 22:13:55 +01:00
|
|
|
static void ads1242_perform_selfgain_calibration(
|
2016-01-29 14:41:23 +01:00
|
|
|
FAR struct ads1242_dev_s *dev);
|
2019-12-05 22:13:55 +01:00
|
|
|
static void ads1242_perform_selfoffset_calibration(
|
2016-01-29 14:41:23 +01:00
|
|
|
FAR struct ads1242_dev_s *dev);
|
2019-12-05 22:13:55 +01:00
|
|
|
static void ads1242_perform_systemoffset_calibration(
|
2016-01-29 14:41:23 +01:00
|
|
|
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);
|
|
|
|
|
2016-06-11 22:14:08 +02:00
|
|
|
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_INFO)
|
2020-03-10 13:25:22 +01:00
|
|
|
static void ads1242_print_regs(FAR struct ads1242_dev_s *dev,
|
|
|
|
char const *msg);
|
2016-06-11 22:14:08 +02:00
|
|
|
#endif /* CONFIG_DEBUG_FEATURES && CONFIG_DEBUG_INFO */
|
2016-01-29 14:41:23 +01:00
|
|
|
|
|
|
|
/* 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,
|
2019-05-22 02:57:54 +02:00
|
|
|
ads1242_ioctl,
|
|
|
|
NULL
|
2016-01-29 14:41:23 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
2016-05-26 22:56:10 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: ads1242_lock
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Lock and configure the SPI bus.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void ads1242_lock(FAR struct spi_dev_s *spi)
|
|
|
|
{
|
2020-01-02 17:49:34 +01:00
|
|
|
SPI_LOCK(spi, true);
|
2016-05-26 22:56:10 +02:00
|
|
|
SPI_SETMODE(spi, ADS1242_SPI_MODE);
|
|
|
|
SPI_SETBITS(spi, 8);
|
2020-01-02 17:49:34 +01:00
|
|
|
SPI_HWFEATURES(spi, 0);
|
2016-05-26 22:56:10 +02:00
|
|
|
SPI_SETFREQUENCY(spi, ADS1242_SPI_FREQUENCY);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: ads1242_unlock
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Unlock the SPI bus.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void ads1242_unlock(FAR struct spi_dev_s *spi)
|
|
|
|
{
|
2020-01-02 17:49:34 +01:00
|
|
|
SPI_LOCK(spi, false);
|
2016-05-26 22:56:10 +02:00
|
|
|
}
|
|
|
|
|
2016-01-29 14:41:23 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: ads1242_reset
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void ads1242_reset(FAR struct ads1242_dev_s *dev)
|
|
|
|
{
|
2016-05-26 22:56:10 +02:00
|
|
|
ads1242_lock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
|
2019-12-05 22:13:55 +01:00
|
|
|
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 */
|
2016-05-26 22:56:10 +02:00
|
|
|
|
|
|
|
ads1242_unlock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2019-12-05 22:13:55 +01:00
|
|
|
* Name: ads1242_perform_selfgain_calibration
|
2016-01-29 14:41:23 +01:00
|
|
|
****************************************************************************/
|
|
|
|
|
2020-03-10 13:25:22 +01:00
|
|
|
static void ads1242_perform_selfgain_calibration(FAR struct ads1242_dev_s
|
|
|
|
*dev)
|
2016-01-29 14:41:23 +01:00
|
|
|
{
|
2016-05-26 22:56:10 +02:00
|
|
|
ads1242_lock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
|
2016-05-26 22:56:10 +02:00
|
|
|
SPI_SELECT(dev->spi, 0, true);
|
2016-01-29 14:41:23 +01:00
|
|
|
SPI_SEND(dev->spi, ADS1242_CMD_SELF_GAIN_CALIB);
|
|
|
|
SPI_SELECT(dev->spi, 0, false);
|
2016-05-26 22:56:10 +02:00
|
|
|
|
|
|
|
ads1242_unlock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2019-12-05 22:13:55 +01:00
|
|
|
* Name: ads1242_perform_selfoffset_calibration
|
2016-01-29 14:41:23 +01:00
|
|
|
****************************************************************************/
|
|
|
|
|
2020-03-10 13:25:22 +01:00
|
|
|
static void ads1242_perform_selfoffset_calibration(FAR struct ads1242_dev_s
|
|
|
|
*dev)
|
2016-01-29 14:41:23 +01:00
|
|
|
{
|
2016-05-26 22:56:10 +02:00
|
|
|
ads1242_lock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
|
2016-05-26 22:56:10 +02:00
|
|
|
SPI_SELECT(dev->spi, 0, true);
|
2016-01-29 14:41:23 +01:00
|
|
|
SPI_SEND(dev->spi, ADS1242_CMD_SELF_OFFSET_CALIB);
|
|
|
|
SPI_SELECT(dev->spi, 0, false);
|
2016-05-26 22:56:10 +02:00
|
|
|
|
|
|
|
ads1242_unlock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2019-12-05 22:13:55 +01:00
|
|
|
* Name: ads1242_perform_systemoffset_calibration
|
2016-01-29 14:41:23 +01:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void
|
2019-12-05 22:13:55 +01:00
|
|
|
ads1242_perform_systemoffset_calibration(FAR struct ads1242_dev_s *dev)
|
2016-01-29 14:41:23 +01:00
|
|
|
{
|
2016-05-26 22:56:10 +02:00
|
|
|
ads1242_lock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
|
2016-05-26 22:56:10 +02:00
|
|
|
SPI_SELECT(dev->spi, 0, true);
|
2016-01-29 14:41:23 +01:00
|
|
|
SPI_SEND(dev->spi, ADS1242_CMD_SYSTEM_OFFSET_CALIB);
|
|
|
|
SPI_SELECT(dev->spi, 0, false);
|
2016-05-26 22:56:10 +02:00
|
|
|
|
|
|
|
ads1242_unlock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: ads1242_read_conversion_result
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void ads1242_read_conversion_result(FAR struct ads1242_dev_s *dev,
|
|
|
|
FAR uint32_t *conversion_result)
|
|
|
|
{
|
2016-05-26 22:56:10 +02:00
|
|
|
ads1242_lock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
|
2016-05-26 22:56:10 +02:00
|
|
|
SPI_SELECT(dev->spi, 0, true);
|
2016-01-29 14:41:23 +01:00
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
2019-12-05 22:13:55 +01:00
|
|
|
*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;
|
2016-01-29 14:41:23 +01:00
|
|
|
|
|
|
|
SPI_SELECT(dev->spi, 0, false);
|
2016-05-26 22:56:10 +02:00
|
|
|
|
|
|
|
ads1242_unlock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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,
|
2020-03-10 13:25:22 +01:00
|
|
|
uint8_t const reg_addr,
|
|
|
|
uint8_t const reg_value)
|
2016-01-29 14:41:23 +01:00
|
|
|
{
|
2016-05-26 22:56:10 +02:00
|
|
|
ads1242_lock(dev->spi);
|
|
|
|
|
2016-01-29 14:41:23 +01:00
|
|
|
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);
|
2016-05-26 22:56:10 +02:00
|
|
|
|
|
|
|
ads1242_unlock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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)
|
|
|
|
{
|
2016-05-26 22:56:10 +02:00
|
|
|
ads1242_lock(dev->spi);
|
|
|
|
|
2016-01-29 14:41:23 +01:00
|
|
|
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);
|
|
|
|
|
2019-12-05 22:13:55 +01:00
|
|
|
*reg_value = SPI_SEND(dev->spi, 0xff);
|
2016-01-29 14:41:23 +01:00
|
|
|
|
|
|
|
SPI_SELECT(dev->spi, 0, false);
|
2016-05-26 22:56:10 +02:00
|
|
|
|
|
|
|
ads1242_unlock(dev->spi);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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);
|
|
|
|
|
2016-06-11 22:14:08 +02:00
|
|
|
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_INFO)
|
2016-01-29 14:41:23 +01:00
|
|
|
ads1242_print_regs(dev, "ads1242_set_gain");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* It is necessary to perform a offset calibration after setting the gain */
|
|
|
|
|
2019-12-05 22:13:55 +01:00
|
|
|
ads1242_perform_selfoffset_calibration(dev);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: ads1242_set_positive_input
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-03-10 13:25:22 +01:00
|
|
|
static void ads1242_set_positive_input(FAR struct ads1242_dev_s *dev,
|
|
|
|
ADS1242_POSITIVE_INPUT_SELECTION const pos_in_sel)
|
2016-01-29 14:41:23 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2016-06-11 22:14:08 +02:00
|
|
|
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_INFO)
|
2016-01-29 14:41:23 +01:00
|
|
|
ads1242_print_regs(dev, "ads1242_set_positive_input");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: ads1242_set_negative_input
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-03-10 13:25:22 +01:00
|
|
|
static void ads1242_set_negative_input(FAR struct ads1242_dev_s *dev,
|
|
|
|
ADS1242_NEGATIVE_INPUT_SELECTION const neg_in_sel)
|
2016-01-29 14:41:23 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2016-06-11 22:14:08 +02:00
|
|
|
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_INFO)
|
2016-01-29 14:41:23 +01:00
|
|
|
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)
|
|
|
|
{
|
2019-12-05 22:13:55 +01:00
|
|
|
uint8_t acr_reg_value = 0xff;
|
2016-01-29 14:41:23 +01:00
|
|
|
|
|
|
|
ads1242_read_reg(dev, ADS1242_REG_ACR, &acr_reg_value);
|
2020-03-10 13:25:22 +01:00
|
|
|
return (acr_reg_value & ADS1242_REG_ACR_BIT_NDRDY) == 0;
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: ads1242_print_regs
|
|
|
|
****************************************************************************/
|
|
|
|
|
2016-06-11 22:14:08 +02:00
|
|
|
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_INFO)
|
2020-03-10 13:25:22 +01:00
|
|
|
static void ads1242_print_regs(FAR struct ads1242_dev_s *dev,
|
|
|
|
char const *msg)
|
2016-01-29 14:41:23 +01:00
|
|
|
{
|
2019-12-05 22:13:55 +01:00
|
|
|
uint8_t setup_reg_value = 0;
|
|
|
|
uint8_t mux_reg_value = 0;
|
|
|
|
uint8_t acr_reg_value = 0;
|
2016-01-29 14:41:23 +01:00
|
|
|
|
2019-12-05 22:13:55 +01:00
|
|
|
ainfo("%s\n", msg);
|
2016-01-29 14:41:23 +01:00
|
|
|
|
2019-12-05 22:13:55 +01:00
|
|
|
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);
|
2016-01-29 14:41:23 +01:00
|
|
|
|
2019-12-05 22:13:55 +01:00
|
|
|
ainfo("SETUP %02X\n", setup_reg_value);
|
|
|
|
ainfo("MUX %02X\n", mux_reg_value);
|
|
|
|
ainfo("ACR %02X\n", acr_reg_value);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
2016-06-11 22:14:08 +02:00
|
|
|
#endif /* CONFIG_DEBUG_FEATURES && CONFIG_DEBUG_INFO */
|
2016-01-29 14:41:23 +01:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* 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);
|
|
|
|
|
2019-12-05 22:13:55 +01:00
|
|
|
ads1242_perform_selfgain_calibration(priv);
|
2016-01-29 14:41:23 +01:00
|
|
|
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);
|
|
|
|
|
2019-12-05 22:13:55 +01:00
|
|
|
ads1242_perform_selfoffset_calibration(priv);
|
2016-01-29 14:41:23 +01:00
|
|
|
up_mdelay(100);
|
|
|
|
|
2016-06-11 22:14:08 +02:00
|
|
|
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_INFO)
|
2016-01-29 14:41:23 +01:00
|
|
|
ads1242_print_regs(priv, "ads1242_open");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
2019-12-05 22:13:55 +01:00
|
|
|
|
2016-01-29 14:41:23 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* 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)
|
|
|
|
{
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: ads1242_write
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static ssize_t ads1242_write(FAR struct file *filep,
|
|
|
|
FAR const char *buffer, size_t buflen)
|
|
|
|
{
|
|
|
|
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:
|
|
|
|
{
|
2019-12-05 22:13:55 +01:00
|
|
|
ads1242_perform_systemoffset_calibration(priv);
|
2016-01-29 14:41:23 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Command was not recognized */
|
|
|
|
|
|
|
|
default:
|
2016-06-16 20:33:32 +02:00
|
|
|
_err("ERROR: Unrecognized cmd: %d\n", cmd);
|
2016-01-29 14:41:23 +01:00
|
|
|
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"
|
2020-03-10 13:25:22 +01:00
|
|
|
* 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.
|
2016-01-29 14:41:23 +01:00
|
|
|
*
|
|
|
|
* 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 */
|
|
|
|
|
2020-03-10 13:25:22 +01:00
|
|
|
priv =
|
|
|
|
(FAR struct ads1242_dev_s *)kmm_malloc(sizeof(struct ads1242_dev_s));
|
2016-01-29 14:41:23 +01:00
|
|
|
if (priv == NULL)
|
|
|
|
{
|
2016-06-16 20:33:32 +02:00
|
|
|
_err("ERROR: Failed to allocate instance\n");
|
2016-01-29 14:41:23 +01:00
|
|
|
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)
|
|
|
|
{
|
2016-06-16 20:33:32 +02:00
|
|
|
_err("ERROR: Failed to register driver: %d\n", ret);
|
2016-01-29 14:41:23 +01:00
|
|
|
kmm_free(priv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_SPI && CONFIG_ADC_ADS1242 */
|