mirror of
https://github.com/apache/nuttx.git
synced 2026-10-13 17:20:20 +00:00
drivers/analog/ads1115: Add support for the Texas Instruments ADS1115
This patch adds initial support for the Texas Instruments ADS1115 ADC. Please read the documentation for more details. Signed-off-by: Tony Lin <99093620+justapotato213@users.noreply.github.com>
This commit is contained in:
parent
85d9078a98
commit
1f2f910ccd
5 changed files with 1098 additions and 0 deletions
|
|
@ -257,6 +257,109 @@ config ADC_MCP3008_DIFFERENTIAL
|
|||
|
||||
endif # ADC_MCP3008
|
||||
|
||||
config ADC_ADS1115
|
||||
bool "ADS1115 support"
|
||||
default n
|
||||
select I2C
|
||||
---help---
|
||||
Enable driver support for the Texas Instruments ADS1115 16-bit ADC.
|
||||
Currently support is experimental, especially the comparator and ALRT/RDY
|
||||
pin functions.
|
||||
|
||||
if ADC_ADS1115
|
||||
|
||||
config ADC_ADS1115_I2C_FREQUENCY
|
||||
int "ADS1115 I2C frequency"
|
||||
default 100000
|
||||
---help---
|
||||
ADS1115 I2C frequency.
|
||||
|
||||
config ADC_ADS1115_ADDR
|
||||
hex "ADS1115 I2C address"
|
||||
default 0x48
|
||||
---help---
|
||||
ADS1115 I2C address. Default is 0x48.
|
||||
|
||||
config ADC_ADS1115_CHANNEL
|
||||
int "ADS1115 channel"
|
||||
default 0
|
||||
range 0 7
|
||||
---help---
|
||||
Default ADS1115 channel/mux configuration.
|
||||
0-3 are the differential channels.
|
||||
4-7 are the single ended channels for A0 to A3
|
||||
See the datasheet or ads1115.h for more info.
|
||||
|
||||
config ADC_ADS1115_PGA
|
||||
int "ADS1115 PGA"
|
||||
default 2
|
||||
range 0 7
|
||||
---help---
|
||||
ADS1115 PGA configuration.
|
||||
0 is +/-6.144V, 1 is +/-4.096V, 2 is +/-2.048V, 3 is +/-1.024V,
|
||||
4 is +/-0.512V, 5 is +/-0.256V, 6 is +/-0.256V, 7 is +/-0.256V.
|
||||
|
||||
config ADC_ADS1115_CONTINOUS
|
||||
bool "ADS1115 continuous mode"
|
||||
default n
|
||||
---help---
|
||||
ADS1115 continuous mode. The ADS1115 will repeatedly take conversions.
|
||||
If changing channels in this mode, there is a chance of old data being
|
||||
read. To avoid this, use one shot mode or use the ALERT/RDY pin.
|
||||
|
||||
config ADC_ADS1115_DR
|
||||
int "ADS1115 data rate"
|
||||
default 4
|
||||
range 0 7
|
||||
---help---
|
||||
ADS1115 data rate.
|
||||
0 is 8sps, 1 is 16sps, 2 is 32sps, 3 is 64sps,
|
||||
4 is 128sps, 5 is 250sps, 6 is 475sps, 7 is 860sps.
|
||||
|
||||
config ADC_ADS1115_COMP_MODE
|
||||
bool "ADS1115 window comparator mode"
|
||||
default n
|
||||
---help---
|
||||
ADS1115 window comparator mode.
|
||||
|
||||
config ADC_ADS1115_COMP_POL
|
||||
bool "ADS1115 comparator polarity"
|
||||
default n
|
||||
---help---
|
||||
ADS1115 comparator polarity. n is active low, y is active high.
|
||||
|
||||
config ADC_ADS1115_COMP_LAT
|
||||
bool "ADS1115 comparator latching"
|
||||
default n
|
||||
---help---
|
||||
ADS1115 comparator latching. n is non-latching, y is latching.
|
||||
Note that this is cleared when reading from the conversion register.
|
||||
|
||||
config ADC_ADS1115_COMP_QUE
|
||||
int "ADS1115 comparator queue"
|
||||
default 3
|
||||
range 0 3
|
||||
---help---
|
||||
ADS1115 comparator queue. 0 is assert after 1 conversion, 1, is
|
||||
assert after 2 conversions, 2 is assert after 4 conversions, 3
|
||||
is disable comparator, and set ALERT/RDY to high-impedence.
|
||||
|
||||
config ADC_ADS1115_HI_THRESH
|
||||
int "ADS1115 high threshold"
|
||||
default 32767
|
||||
range 0 65536
|
||||
---help---
|
||||
ADS1115 high threshold.
|
||||
|
||||
config ADC_ADS1115_LO_THRESH
|
||||
int "ADS1115 low threshold"
|
||||
range 0 65536
|
||||
default 32768
|
||||
---help---
|
||||
ADS1115 low threshold.
|
||||
|
||||
endif # ADC_ADS1115
|
||||
|
||||
endif # ADC
|
||||
|
||||
config COMP
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ endif
|
|||
ifeq ($(CONFIG_ADC_MCP3008),y)
|
||||
CSRCS += mcp3008.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ADC_ADS1115),y)
|
||||
CSRCS += ads1115.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_LMP92001),y)
|
||||
|
|
|
|||
827
drivers/analog/ads1115.c
Normal file
827
drivers/analog/ads1115.c
Normal file
|
|
@ -0,0 +1,827 @@
|
|||
/****************************************************************************
|
||||
* drivers/analog/ads1115.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/nuttx.h>
|
||||
#include <nuttx/signal.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <nuttx/analog/adc.h>
|
||||
#include <nuttx/analog/ads1115.h>
|
||||
#include <nuttx/analog/ioctl.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Preprocessor definitions
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_ADC_ADS1115)
|
||||
|
||||
#ifndef CONFIG_ADC_ADS1115_I2C_FREQUENCY
|
||||
#define CONFIG_ADC_ADS1115_I2C_FREQUENCY 100000
|
||||
#endif
|
||||
|
||||
#define ADS1115_NUM_CHANNELS 8
|
||||
|
||||
#define ADS1115_OS_SHIFT (1 << 15)
|
||||
#define ADS1115_MUX_SHIFT 12
|
||||
#define ADS1115_MUX_MASK (7 << ADS1115_MUX_SHIFT)
|
||||
#define ADS1115_PGA_SHIFT 9
|
||||
#define ADS1115_PGA_MASK (7 << ADS1115_PGA_SHIFT)
|
||||
#define ADS1115_MODE_MASK (1 << 8)
|
||||
#define ADS1115_DR_SHIFT 5
|
||||
#define ADS1115_DR_MASK (7 << ADS1115_DR_SHIFT)
|
||||
#define ADS1115_COMP_MODE_MASK (1 << 4)
|
||||
#define ADS1115_COMP_POL_MASK (1 << 3)
|
||||
#define ADS1115_COMP_LAT_MASK (1 << 2)
|
||||
#define ADS1115_COMP_QUE_SHIFT 0
|
||||
#define ADS1115_COMP_QUE_MASK (3 << ADS1115_COMP_QUE_SHIFT)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct ads1115_dev_s
|
||||
{
|
||||
FAR struct i2c_master_s *i2c;
|
||||
FAR const struct adc_callback_s *cb;
|
||||
uint8_t addr;
|
||||
|
||||
/* Current configuration of ADC. */
|
||||
|
||||
uint16_t cmdbyte;
|
||||
};
|
||||
|
||||
enum ads1115_registers_e
|
||||
{
|
||||
ADS1115_CONVERSION_REGISTER = 0x00,
|
||||
ADS1115_CONFIG_REGISTER = 0x01,
|
||||
ADS1115_LO_THRESH_REGISTER = 0x02,
|
||||
ADS1115_HI_THRESH_REGISTER = 0x03,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1115_bind(FAR struct adc_dev_s *dev,
|
||||
FAR const struct adc_callback_s *callback);
|
||||
static void ads1115_reset(FAR struct adc_dev_s *dev);
|
||||
static int ads1115_setup(FAR struct adc_dev_s *dev);
|
||||
static void ads1115_shutdown(FAR struct adc_dev_s *dev);
|
||||
static void ads1115_rxint(FAR struct adc_dev_s *dev, bool enable);
|
||||
static int ads1115_ioctl(FAR struct adc_dev_s *dev, int cmd,
|
||||
unsigned long arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct adc_ops_s g_ads1115ops =
|
||||
{
|
||||
.ao_bind = ads1115_bind,
|
||||
.ao_reset = ads1115_reset,
|
||||
.ao_setup = ads1115_setup,
|
||||
.ao_shutdown = ads1115_shutdown,
|
||||
.ao_rxint = ads1115_rxint,
|
||||
.ao_ioctl = ads1115_ioctl,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_write_register
|
||||
*
|
||||
* Description:
|
||||
* Writes a value to a register in the ADS1115.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - An ADS1115 device structure
|
||||
* reg - The register to write to.
|
||||
* value - The value to write to the register, in big endian.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1115_write_register(FAR struct ads1115_dev_s *priv,
|
||||
enum ads1115_registers_e reg,
|
||||
uint16_t value)
|
||||
{
|
||||
int ret = OK;
|
||||
|
||||
if (priv == NULL)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct i2c_msg_s i2cmsg[2];
|
||||
|
||||
/* Write the register into the address pointer register. */
|
||||
|
||||
i2cmsg[0].frequency = CONFIG_ADC_ADS1115_I2C_FREQUENCY;
|
||||
i2cmsg[0].addr = priv->addr;
|
||||
i2cmsg[0].flags = 0;
|
||||
i2cmsg[0].buffer = ®
|
||||
i2cmsg[0].length = sizeof(reg);
|
||||
|
||||
/* Write the value into the register. */
|
||||
|
||||
i2cmsg[1].frequency = CONFIG_ADC_ADS1115_I2C_FREQUENCY;
|
||||
i2cmsg[1].addr = priv->addr;
|
||||
i2cmsg[1].flags = I2C_M_NOSTART;
|
||||
i2cmsg[1].buffer = (FAR uint8_t *)&value;
|
||||
i2cmsg[1].length = sizeof(value);
|
||||
|
||||
ret = I2C_TRANSFER(priv->i2c, i2cmsg, 2);
|
||||
if (ret < 0)
|
||||
{
|
||||
aerr("ADS1115 I2C transfer failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_read_register
|
||||
*
|
||||
* Description:
|
||||
* Reads a value from a register in the ADS1115 in big endian.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - An ADS1115 device structure
|
||||
* reg - The register to read from.
|
||||
* buf - A pointer to a buffer to store the value read from the register.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1115_read_register(FAR struct ads1115_dev_s *priv, uint8_t reg,
|
||||
uint16_t *buf)
|
||||
{
|
||||
int ret = OK;
|
||||
|
||||
if (priv == NULL || buf == NULL)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct i2c_msg_s i2cmsg[2];
|
||||
|
||||
/* Write the register into the address pointer register. */
|
||||
|
||||
i2cmsg[0].frequency = CONFIG_ADC_ADS1115_I2C_FREQUENCY;
|
||||
i2cmsg[0].addr = priv->addr;
|
||||
i2cmsg[0].flags = 0;
|
||||
i2cmsg[0].buffer = (FAR uint8_t *)(®);
|
||||
i2cmsg[0].length = sizeof(reg);
|
||||
|
||||
/* Read from the register. */
|
||||
|
||||
i2cmsg[1].frequency = CONFIG_ADC_ADS1115_I2C_FREQUENCY;
|
||||
i2cmsg[1].addr = priv->addr;
|
||||
i2cmsg[1].flags = I2C_M_READ;
|
||||
i2cmsg[1].buffer = (FAR uint8_t *)(buf);
|
||||
i2cmsg[1].length = sizeof(*buf);
|
||||
|
||||
ret = I2C_TRANSFER(priv->i2c, i2cmsg, 2);
|
||||
if (ret < 0)
|
||||
{
|
||||
aerr("ADS1115 I2C transfer failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_read_current_register
|
||||
*
|
||||
* Description:
|
||||
* Reads from the current register in the ADS1115 in big endian.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - An ADS1115 device structure
|
||||
* buf - A pointer to a buffer to store the value read from the register.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1115_read_current_register(FAR struct ads1115_dev_s *priv,
|
||||
uint16_t *buf)
|
||||
{
|
||||
int ret = OK;
|
||||
|
||||
if (priv == NULL || buf == NULL)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct i2c_msg_s i2cmsg[1];
|
||||
|
||||
i2cmsg[0].frequency = CONFIG_ADC_ADS1115_I2C_FREQUENCY;
|
||||
i2cmsg[0].addr = priv->addr;
|
||||
i2cmsg[0].flags = I2C_M_READ;
|
||||
i2cmsg[0].buffer = (FAR uint8_t *)(buf);
|
||||
i2cmsg[0].length = sizeof(*buf);
|
||||
|
||||
ret = I2C_TRANSFER(priv->i2c, i2cmsg, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
aerr("ADS1115 I2C transfer failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cmdbyte_init
|
||||
*
|
||||
* Description:
|
||||
* Initializes the command byte with the default settings, and writes to the
|
||||
* high and low threshold registers.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - An ADS1115 device structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int cmdbyte_init(FAR struct ads1115_dev_s *priv)
|
||||
{
|
||||
int ret = OK;
|
||||
|
||||
/* Set the default channel. */
|
||||
|
||||
priv->cmdbyte = CONFIG_ADC_ADS1115_CHANNEL << ADS1115_MUX_SHIFT;
|
||||
|
||||
/* Set the default pga setting. */
|
||||
|
||||
priv->cmdbyte |= CONFIG_ADC_ADS1115_PGA << ADS1115_PGA_SHIFT;
|
||||
|
||||
/* Set the default mode. */
|
||||
|
||||
#ifndef CONFIG_ADC_ADS1115_CONTINOUS
|
||||
priv->cmdbyte |= ADS1115_MODE_MASK;
|
||||
#endif
|
||||
|
||||
/* Set the default data rate. */
|
||||
|
||||
priv->cmdbyte |= CONFIG_ADC_ADS1115_DR << ADS1115_DR_SHIFT;
|
||||
|
||||
/* Set the default comparator mode. */
|
||||
|
||||
#ifdef CONFIG_ADC_ADS1115_COMP_MODE
|
||||
priv->cmdbyte |= ADS1115_COMP_MODE_MASK;
|
||||
#endif
|
||||
|
||||
/* Set the default comparator polarity. */
|
||||
|
||||
#ifdef CONFIG_ADC_ADS1115_COMP_POL
|
||||
priv->cmdbyte |= ADS1115_COMP_POL_MASK;
|
||||
#endif
|
||||
|
||||
/* Set the default comparator latching. */
|
||||
|
||||
#ifdef CONFIG_ADC_ADS1115_COMP_LAT
|
||||
priv->cmdbyte |= ADS1115_COMP_LAT_MASK;
|
||||
#endif
|
||||
|
||||
/* Set the comparator queue. */
|
||||
|
||||
priv->cmdbyte |= CONFIG_ADC_ADS1115_COMP_QUE << ADS1115_COMP_QUE_SHIFT;
|
||||
|
||||
ret = ads1115_write_register(priv, ADS1115_HI_THRESH_REGISTER,
|
||||
htobe16(CONFIG_ADC_ADS1115_HI_THRESH));
|
||||
if (ret != OK)
|
||||
{
|
||||
aerr("Failed to write high threshold register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ads1115_write_register(priv, ADS1115_LO_THRESH_REGISTER,
|
||||
htobe16(CONFIG_ADC_ADS1115_LO_THRESH));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_readchannel
|
||||
*
|
||||
* Description:
|
||||
* Reads a conversion from the ADC.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - An ADS1115 device structure
|
||||
* msg - An ADC message struct where the am_channel member contains the
|
||||
* channel number to be read, and where the am_data member is where the
|
||||
* reading is stored.
|
||||
*
|
||||
* NOTE:
|
||||
* When switching between channels in continous mode, old data may be read.
|
||||
* Using the ALERT/RDY pin can avoid this.
|
||||
*
|
||||
* Each channel corrseponds to a differing mux configuration as defined in
|
||||
* the datasheet.
|
||||
*
|
||||
* msg->am_channel MUX Configuration
|
||||
* 0 AINP = AIN0, AINN = AIN1
|
||||
* 1 AINP = AIN0, AINN = AIN3
|
||||
* 2 AINP = AIN1, AINN = AIN3
|
||||
* 3 AINP = AIN2, AINN = AIN3
|
||||
* 4 AINP = AIN0, AINN = GND
|
||||
* 5 AINP = AIN0, AINN = GND
|
||||
* 6 AINP = AIN1, AINN = GND
|
||||
* 7 AINP = AIN2, AINN = GND
|
||||
* 8 AINP = AIN3, AINN = GND
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1115_readchannel(FAR struct ads1115_dev_s *priv,
|
||||
FAR struct adc_msg_s *msg)
|
||||
{
|
||||
int ret = OK;
|
||||
|
||||
if (priv == NULL || msg == NULL || msg->am_channel >= ADS1115_NUM_CHANNELS)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t buf;
|
||||
uint16_t channel_bits = msg->am_channel << ADS1115_MUX_SHIFT;
|
||||
|
||||
bool one_shot =
|
||||
((priv->cmdbyte & ADS1115_MODE_MASK) == ADS1115_MODE_MASK);
|
||||
bool new_channel =
|
||||
((priv->cmdbyte & ADS1115_MUX_MASK) != channel_bits);
|
||||
|
||||
/* check if our current channel is the same as the one that
|
||||
* is set or if in one shot mode.
|
||||
*/
|
||||
|
||||
if (new_channel || one_shot)
|
||||
{
|
||||
/* Clear the current mux bits. */
|
||||
|
||||
priv->cmdbyte &= ~(ADS1115_MUX_MASK);
|
||||
|
||||
/* Set the new mux bits. */
|
||||
|
||||
priv->cmdbyte |= channel_bits;
|
||||
|
||||
/* Set the OS bit to start conversion. */
|
||||
|
||||
priv->cmdbyte |= ADS1115_OS_SHIFT;
|
||||
|
||||
/* Write to the configuration register. */
|
||||
|
||||
ainfo("cmdbyte: %x\n", priv->cmdbyte);
|
||||
ret = ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
}
|
||||
|
||||
if (one_shot)
|
||||
{
|
||||
/* Read the configuration register until OS has been set to 1. */
|
||||
|
||||
int count = 0;
|
||||
do
|
||||
{
|
||||
/* ADS1115 takes ~25 usec to wake up */
|
||||
|
||||
nxsig_usleep(25);
|
||||
ret = ads1115_read_current_register(priv, &buf);
|
||||
count++;
|
||||
}
|
||||
while ((be16toh(buf) & ADS1115_OS_SHIFT) == 0 && ret == OK &&
|
||||
count < 3);
|
||||
ainfo("config register: %x\n", (be16toh(buf)));
|
||||
|
||||
if (count >= 3)
|
||||
{
|
||||
aerr("ADS1115 timed out waiting for conversion to finish\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the conversion register. */
|
||||
|
||||
ret = ads1115_read_register(priv, ADS1115_CONVERSION_REGISTER, &buf);
|
||||
ainfo("output: %d\n", (int16_t)betoh16(buf));
|
||||
msg->am_data = (uint32_t)betoh16(buf);
|
||||
|
||||
priv->cmdbyte &= ~(ADS1115_OS_SHIFT); /* Clear the OS bit. */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_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 ads1115_bind(FAR struct adc_dev_s *dev,
|
||||
FAR const struct adc_callback_s *callback)
|
||||
{
|
||||
FAR struct ads1115_dev_s *priv = (FAR struct ads1115_dev_s *)dev->ad_priv;
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
priv->cb = callback;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_reset
|
||||
*
|
||||
* Description:
|
||||
* Reset the ADC device. Called early to initialize the hardware. This
|
||||
* is called, before ao_setup() and on error conditions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1115_reset(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
FAR struct ads1115_dev_s *priv = (FAR struct ads1115_dev_s *)dev->ad_priv;
|
||||
|
||||
cmdbyte_init(priv);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_setup
|
||||
*
|
||||
* Description:
|
||||
* Configure the ADC. This method is called the first time that the ADC
|
||||
* device is opened. This method will write the default configuration into
|
||||
* the configuration register.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1115_setup(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
FAR struct ads1115_dev_s *priv = (FAR struct ads1115_dev_s *)dev->ad_priv;
|
||||
|
||||
int ret = ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_shutdown
|
||||
*
|
||||
* Description:
|
||||
* Disable the ADC. This method is called when the ADC device is closed.
|
||||
* This method should reverse the operation of the setup method. The
|
||||
* ADS1115 can be put into a power-down state by setting the mode bit to
|
||||
* single-shot. This will stop the ADC from converting and reduce power
|
||||
* consumption.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1115_shutdown(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
FAR struct ads1115_dev_s *priv = (FAR struct ads1115_dev_s *)dev->ad_priv;
|
||||
|
||||
priv->cmdbyte |= ADS1115_MODE_MASK;
|
||||
ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_rxint
|
||||
*
|
||||
* Description:
|
||||
* Needed for ADC upper-half compatibility but conversion interrupts
|
||||
* are not supported by the ADS1115.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ads1115_rxint(FAR struct adc_dev_s *dev, bool enable)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_ioctl
|
||||
*
|
||||
* Description:
|
||||
* All ioctl calls will be routed through this method.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ads1115_ioctl(FAR struct adc_dev_s *dev, int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
FAR struct ads1115_dev_s *priv = (FAR struct ads1115_dev_s *)dev->ad_priv;
|
||||
int ret = OK;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case ANIOC_TRIGGER:
|
||||
{
|
||||
struct adc_msg_s msg;
|
||||
|
||||
for (uint8_t i = 0; i < ADS1115_NUM_CHANNELS && (ret == 0); i++)
|
||||
{
|
||||
msg.am_channel = i;
|
||||
ainfo("Channel: %d\n", i);
|
||||
ret = ads1115_readchannel(priv, &msg);
|
||||
if (ret == 0)
|
||||
{
|
||||
priv->cb->au_receive(dev, i, msg.am_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
aerr("Error reading channel %d with error %d \n", i, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_SET_PGA:
|
||||
{
|
||||
if (arg >= ADS1115_PGA1 && arg <= ADS1115_PGA8)
|
||||
{
|
||||
priv->cmdbyte &= ~ADS1115_PGA_MASK;
|
||||
priv->cmdbyte |= arg << ADS1115_PGA_SHIFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_SET_MODE:
|
||||
{
|
||||
if (arg == ADS1115_MODE1)
|
||||
{
|
||||
priv->cmdbyte &= ~ADS1115_MODE_MASK;
|
||||
}
|
||||
else if (arg == ADS1115_MODE2)
|
||||
{
|
||||
priv->cmdbyte |= ADS1115_MODE_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_SET_DR:
|
||||
{
|
||||
if (arg >= ADS1115_DR1 && arg <= ADS1115_DR8)
|
||||
{
|
||||
priv->cmdbyte &= ~ADS1115_DR_MASK;
|
||||
priv->cmdbyte |= arg << ADS1115_DR_SHIFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_SET_COMP_POL:
|
||||
{
|
||||
if (arg == ADS1115_COMP_POL1)
|
||||
{
|
||||
priv->cmdbyte &= ~ADS1115_COMP_POL_MASK;
|
||||
}
|
||||
else if (arg == ADS1115_COMP_POL2)
|
||||
{
|
||||
priv->cmdbyte |= ADS1115_COMP_POL_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_SET_COMP_MODE:
|
||||
{
|
||||
if (arg == ADS1115_COMP_MODE1)
|
||||
{
|
||||
priv->cmdbyte &= ~ADS1115_COMP_MODE_MASK;
|
||||
}
|
||||
else if (arg == ADS1115_COMP_MODE2)
|
||||
{
|
||||
priv->cmdbyte |= ADS1115_COMP_MODE_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_SET_COMP_LAT:
|
||||
{
|
||||
if (arg == ADS1115_COMP_LAT1)
|
||||
{
|
||||
priv->cmdbyte &= ~ADS1115_COMP_LAT_MASK;
|
||||
}
|
||||
else if (arg == ADS1115_COMP_LAT2)
|
||||
{
|
||||
priv->cmdbyte |= ADS1115_COMP_LAT_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_SET_COMP_QUEUE:
|
||||
{
|
||||
if (arg >= ADS1115_COMP_QUEUE1 && arg <= ADS1115_COMP_QUEUE4)
|
||||
{
|
||||
priv->cmdbyte &= ~ADS1115_COMP_QUE_MASK;
|
||||
priv->cmdbyte |= arg << ADS1115_COMP_QUE_SHIFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ads1115_write_register(priv, ADS1115_CONFIG_REGISTER,
|
||||
htobe16(priv->cmdbyte));
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_READ_CHANNEL:
|
||||
{
|
||||
FAR struct adc_msg_s *msg = (FAR struct adc_msg_s *)arg;
|
||||
ret = ads1115_readchannel(priv, msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_SET_HI_THRESH:
|
||||
{
|
||||
if (arg >= 0 && arg <= UINT16_MAX)
|
||||
{
|
||||
ret = ads1115_write_register(priv, ADS1115_HI_THRESH_REGISTER,
|
||||
htobe16(arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_ADS1115_SET_LO_THRESH:
|
||||
{
|
||||
if (arg >= 0 && arg <= UINT16_MAX)
|
||||
{
|
||||
ret = ads1115_write_register(priv, ADS1115_LO_THRESH_REGISTER,
|
||||
htobe16(arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIOC_GET_NCHANNELS:
|
||||
{
|
||||
ret = ADS1115_NUM_CHANNELS;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ads1115_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the selected ADC
|
||||
*
|
||||
* Input Parameters:
|
||||
* i2c - Pointer to a valid I2C master struct.
|
||||
* addr - I2C device address.
|
||||
*
|
||||
* Returned Value:
|
||||
* Valid ADC device structure reference on success; a NULL on failure
|
||||
*
|
||||
* **************************************************************************/
|
||||
|
||||
FAR struct adc_dev_s *ads1115_initialize(FAR struct i2c_master_s *i2c,
|
||||
uint8_t addr)
|
||||
{
|
||||
FAR struct ads1115_dev_s *priv;
|
||||
FAR struct adc_dev_s *adcdev;
|
||||
|
||||
DEBUGASSERT(i2c != NULL);
|
||||
|
||||
priv = kmm_malloc(sizeof(struct ads1115_dev_s));
|
||||
if (priv == NULL)
|
||||
{
|
||||
aerr("ERROR: Failed to allocate ads1115_dev_s instance\n");
|
||||
free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
priv->cb = NULL;
|
||||
priv->i2c = i2c;
|
||||
priv->addr = addr;
|
||||
priv->cmdbyte = 0;
|
||||
|
||||
int ret = cmdbyte_init(priv);
|
||||
if (ret != OK)
|
||||
{
|
||||
aerr("Failed to initialize ADS1115\n");
|
||||
free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
adcdev = kmm_malloc(sizeof(struct adc_dev_s));
|
||||
if (adcdev == NULL)
|
||||
{
|
||||
aerr("ERROR: Failed to allocate adc_dev_s instance\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(adcdev, 0, sizeof(struct adc_dev_s));
|
||||
adcdev->ad_ops = &g_ads1115ops;
|
||||
adcdev->ad_priv = priv;
|
||||
|
||||
return adcdev;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ADC_ADS1115 */
|
||||
159
include/nuttx/analog/ads1115.h
Normal file
159
include/nuttx/analog/ads1115.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/analog/ads1115.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_ANALOG_ADS1115_H
|
||||
#define __INCLUDE_NUTTX_ANALOG_ADS1115_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/analog/ioctl.h>
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* IOCTL Commands
|
||||
* Cmd: ANIOC_ADS1115_SET_PGA Arg: enum ads1115_pga_e
|
||||
* Cmd: ANIOC_ADS1115_SET_MODE Arg: enum ads1115_mode_e
|
||||
* Cmd: ANIOC_ADS1115_SET_DR Arg: enum ads1115_dr_e
|
||||
* Cmd: ANIOC_ADS1115_SET_COMP_MODE Arg: enum ads1115_comp_mode_e
|
||||
* Cmd: ANIOC_ADS1115_SET_COMP_POL Arg: enum ads1115_comp_pol_e
|
||||
* Cmd: ANIOC_ADS1115_SET_COMP_LAT Arg: enum ads1115_comp_lat_e
|
||||
* Cmd: ANIOC_ADS1115_SET_COMP_QUEUE Arg: enum ads1115_comp_queue_e
|
||||
* Cmd: ANIOC_ADS1115_READ_CHANNEL Arg: struct adc_msg_s *channel
|
||||
* Cmd: ANIOC_ADS1115_SET_HI_THRESH Arg: uint16_t value
|
||||
* Cmd: ANIOC_ADS1115_SET_LO_THRESH Arg: uint16_t value
|
||||
*/
|
||||
|
||||
#define ANIOC_ADS1115_SET_PGA _ANIOC(AN_ADS1115_FIRST + 0)
|
||||
#define ANIOC_ADS1115_SET_MODE _ANIOC(AN_ADS1115_FIRST + 1)
|
||||
#define ANIOC_ADS1115_SET_DR _ANIOC(AN_ADS1115_FIRST + 2)
|
||||
#define ANIOC_ADS1115_SET_COMP_MODE _ANIOC(AN_ADS1115_FIRST + 3)
|
||||
#define ANIOC_ADS1115_SET_COMP_POL _ANIOC(AN_ADS1115_FIRST + 4)
|
||||
#define ANIOC_ADS1115_SET_COMP_LAT _ANIOC(AN_ADS1115_FIRST + 5)
|
||||
#define ANIOC_ADS1115_SET_COMP_QUEUE _ANIOC(AN_ADS1115_FIRST + 6)
|
||||
#define ANIOC_ADS1115_READ_CHANNEL _ANIOC(AN_ADS1115_FIRST + 7)
|
||||
#define ANIOC_ADS1115_SET_HI_THRESH _ANIOC(AN_ADS1115_FIRST + 8)
|
||||
#define ANIOC_ADS1115_SET_LO_THRESH _ANIOC(AN_ADS1115_FIRST + 9)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* Input Multiplexer configuration. */
|
||||
|
||||
enum ads1115_mux_e
|
||||
{
|
||||
ADS1115_MUX1 = 0u, /* AINP = AIN0 and AINN = AIN1 (default) */
|
||||
ADS1115_MUX2, /* AINP = AIN0 and AINN = AIN3 */
|
||||
ADS1115_MUX3, /* AINP = AIN1 and AINN = AIN3 */
|
||||
ADS1115_MUX4, /* AINP = AIN2 and AINN = AIN3 */
|
||||
ADS1115_MUX5, /* AINP = AIN0 and AINN = GND */
|
||||
ADS1115_MUX6, /* AINP = AIN1 and AINN = GND */
|
||||
ADS1115_MUX7, /* AINP = AIN2 and AINN = GND */
|
||||
ADS1115_MUX8, /* AINP = AIN3 and AINN = GND */
|
||||
};
|
||||
|
||||
/* Programmable gain amplifier configuration */
|
||||
|
||||
enum ads1115_pga_e
|
||||
{
|
||||
ADS1115_PGA1 = 0u, /* FSR = ±6.144V */
|
||||
ADS1115_PGA2, /* FSR = ±4.096V */
|
||||
ADS1115_PGA3, /* FSR = ±2.048V (default) */
|
||||
ADS1115_PGA4, /* FSR = ±1.024V */
|
||||
ADS1115_PGA5, /* FSR = ±0.512V */
|
||||
ADS1115_PGA6, /* FSR = ±0.256V */
|
||||
ADS1115_PGA7, /* FSR = ±0.256V */
|
||||
ADS1115_PGA8, /* FSR = ±0.256V */
|
||||
};
|
||||
|
||||
/* Device Operating Mode */
|
||||
|
||||
enum ads1115_mode_e
|
||||
{
|
||||
ADS1115_MODE1 = 0u, /* Continuous conversion mode */
|
||||
ADS1115_MODE2 /* Power-down single-shot mode (default) */
|
||||
};
|
||||
|
||||
/* Data rate */
|
||||
|
||||
enum ads1115_dr_e
|
||||
{
|
||||
ADS1115_DR1 = 0u, /* 8 SPS */
|
||||
ADS1115_DR2, /* 16 SPS */
|
||||
ADS1115_DR3, /* 32 SPS */
|
||||
ADS1115_DR4, /* 64 SPS */
|
||||
ADS1115_DR5, /* 128 SPS (default) */
|
||||
ADS1115_DR6, /* 250 SPS */
|
||||
ADS1115_DR7, /* 475 SPS */
|
||||
ADS1115_DR8, /* 860 SPS */
|
||||
};
|
||||
|
||||
/* Comparator mode */
|
||||
|
||||
enum ads1115_comp_mode_e
|
||||
{
|
||||
ADS1115_COMP_MODE1 = 0u, /* Traditional comparator (default) */
|
||||
ADS1115_COMP_MODE2 /* Window comparator */
|
||||
};
|
||||
|
||||
/* Comparator Polarity */
|
||||
|
||||
enum ads1115_comp_pol_e
|
||||
{
|
||||
ADS1115_COMP_POL1 = 0u, /* Active low (default) */
|
||||
ADS1115_COMP_POL2 /* Active high */
|
||||
};
|
||||
|
||||
/* Latching comparator */
|
||||
|
||||
enum ads1115_comp_lat_e
|
||||
{
|
||||
ADS1115_COMP_LAT1 = 0u, /* Nonlatching comparator. The ALERT/RDY pin does
|
||||
* not latch when asserted (default) */
|
||||
ADS1115_COMP_LAT2 /* Latching comparator. See datasheet. */
|
||||
};
|
||||
|
||||
/* Comparator queue and disable */
|
||||
|
||||
enum ads1115_comp_queue_e
|
||||
{
|
||||
ADS1115_COMP_QUEUE1 = 0u, /* Assert after one conversion */
|
||||
ADS1115_COMP_QUEUE2, /* Assert after two conversions */
|
||||
ADS1115_COMP_QUEUE3, /* Assert after four conversions */
|
||||
ADS1115_COMP_QUEUE4, /* Disable comparator and set ALERT/RDY pin to
|
||||
* high-impedance (default) */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct adc_dev_s *ads1115_initialize(struct i2c_master_s *i2c,
|
||||
uint8_t addr);
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_ANALOG_ADS1115_H */
|
||||
|
|
@ -116,6 +116,11 @@
|
|||
#define AN_MCP3008_FIRST (AN_SAMV7_AFEC_FIRST + AN_SAMV7_AFEC_NCMDS)
|
||||
#define AN_MCP3008_NCMDS 1
|
||||
|
||||
/* See include/nuttx/analog/ads1115.h */
|
||||
|
||||
#define AN_ADS1115_FIRST (AN_MCP3008_FIRST + AN_MCP3008_NCMDS)
|
||||
#define AN_ADS1115_NCMDS 10
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue