|
- /*
- * ads1115.c:
- * Extend wiringPi with the ADS1115 I2C 16-bit ADC
- * Copyright (c) 2016 Gordon Henderson
- ***********************************************************************
- * This file is part of wiringPi:
- * https://github.com/WiringPi/WiringPi/
- *
- * wiringPi is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * wiringPi is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with wiringPi.
- * If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************
- */
-
- /*
- *********************************************************************************
- * We're going to work in a hybrid mode to fit in with the wiringPi way of
- * doing things, so there will be 4 analog pin which read the 4 single-ended
- * channels as usual, also some fake digitalOutputs - these are the control
- * registers that allow the user to put it into single/diff mode, set the
- * gain and data rates.
- *********************************************************************************
- */
-
- #include <byteswap.h>
- #include <stdio.h>
- #include <stdint.h>
-
- #include <wiringPi.h>
- #include <wiringPiI2C.h>
-
- #include "ads1115.h"
-
- // Bits in the config register (it's a 16-bit register)
-
- #define CONFIG_OS_MASK (0x8000) // Operational Status Register
- #define CONFIG_OS_SINGLE (0x8000) // Write - Starts a single-conversion
- // Read 1 = Conversion complete
-
- // The multiplexor
-
- #define CONFIG_MUX_MASK (0x7000)
-
- // Differential modes
-
- #define CONFIG_MUX_DIFF_0_1 (0x0000) // Pos = AIN0, Neg = AIN1 (default)
- #define CONFIG_MUX_DIFF_0_3 (0x1000) // Pos = AIN0, Neg = AIN3
- #define CONFIG_MUX_DIFF_1_3 (0x2000) // Pos = AIN1, Neg = AIN3
- #define CONFIG_MUX_DIFF_2_3 (0x3000) // Pos = AIN2, Neg = AIN3 (2nd differential channel)
-
- // Single-ended modes
-
- #define CONFIG_MUX_SINGLE_0 (0x4000) // AIN0
- #define CONFIG_MUX_SINGLE_1 (0x5000) // AIN1
- #define CONFIG_MUX_SINGLE_2 (0x6000) // AIN2
- #define CONFIG_MUX_SINGLE_3 (0x7000) // AIN3
-
- // Programmable Gain Amplifier
-
- #define CONFIG_PGA_MASK (0x0E00)
- #define CONFIG_PGA_6_144V (0x0000) // +/-6.144V range = Gain 2/3
- #define CONFIG_PGA_4_096V (0x0200) // +/-4.096V range = Gain 1
- #define CONFIG_PGA_2_048V (0x0400) // +/-2.048V range = Gain 2 (default)
- #define CONFIG_PGA_1_024V (0x0600) // +/-1.024V range = Gain 4
- #define CONFIG_PGA_0_512V (0x0800) // +/-0.512V range = Gain 8
- #define CONFIG_PGA_0_256V (0x0A00) // +/-0.256V range = Gain 16
-
- #define CONFIG_MODE (0x0100) // 0 is continuous, 1 is single-shot (default)
-
- // Data Rate
-
- #define CONFIG_DR_MASK (0x00E0)
- #define CONFIG_DR_8SPS (0x0000) // 8 samples per second
- #define CONFIG_DR_16SPS (0x0020) // 16 samples per second
- #define CONFIG_DR_32SPS (0x0040) // 32 samples per second
- #define CONFIG_DR_64SPS (0x0060) // 64 samples per second
- #define CONFIG_DR_128SPS (0x0080) // 128 samples per second (default)
- #define CONFIG_DR_475SPS (0x00A0) // 475 samples per second
- #define CONFIG_DR_860SPS (0x00C0) // 860 samples per second
-
- // Comparator mode
-
- #define CONFIG_CMODE_MASK (0x0010)
- #define CONFIG_CMODE_TRAD (0x0000) // Traditional comparator with hysteresis (default)
- #define CONFIG_CMODE_WINDOW (0x0010) // Window comparator
-
- // Comparator polarity - the polarity of the output alert/rdy pin
-
- #define CONFIG_CPOL_MASK (0x0008)
- #define CONFIG_CPOL_ACTVLOW (0x0000) // Active low (default)
- #define CONFIG_CPOL_ACTVHI (0x0008) // Active high
-
- // Latching comparator - does the alert/rdy pin latch
-
- #define CONFIG_CLAT_MASK (0x0004)
- #define CONFIG_CLAT_NONLAT (0x0000) // Non-latching comparator (default)
- #define CONFIG_CLAT_LATCH (0x0004) // Latching comparator
-
- // Comparitor queue
-
- #define CONFIG_CQUE_MASK (0x0003)
- #define CONFIG_CQUE_1CONV (0x0000) // Assert after one conversions
- #define CONFIG_CQUE_2CONV (0x0001) // Assert after two conversions
- #define CONFIG_CQUE_4CONV (0x0002) // Assert after four conversions
- #define CONFIG_CQUE_NONE (0x0003) // Disable the comparator (default)
-
- #define CONFIG_DEFAULT (0x8583) // From the datasheet
-
-
- static const uint16_t dataRates [8] =
- {
- CONFIG_DR_8SPS, CONFIG_DR_16SPS, CONFIG_DR_32SPS, CONFIG_DR_64SPS, CONFIG_DR_128SPS, CONFIG_DR_475SPS, CONFIG_DR_860SPS
- } ;
-
- static const uint16_t gains [6] =
- {
- CONFIG_PGA_6_144V, CONFIG_PGA_4_096V, CONFIG_PGA_2_048V, CONFIG_PGA_1_024V, CONFIG_PGA_0_512V, CONFIG_PGA_0_256V
- } ;
-
-
- /*
- * analogRead:
- * Pin is the channel to sample on the device.
- * Channels 0-3 are single ended inputs,
- * channels 4-7 are the various differential combinations.
- *********************************************************************************
- */
-
- static int myAnalogRead (struct wiringPiNodeStruct *node, int pin)
- {
- int chan = pin - node->pinBase ;
- int16_t result ;
- uint16_t config = CONFIG_DEFAULT ;
-
- chan &= 7 ;
-
- // Setup the configuration register
-
- // Set PGA/voltage range
-
- config &= ~CONFIG_PGA_MASK ;
- config |= node->data0 ;
-
- // Set sample speed
-
- config &= ~CONFIG_DR_MASK ;
- config |= node->data1 ;
-
- // Set single-ended channel or differential mode
-
- config &= ~CONFIG_MUX_MASK ;
-
- switch (chan)
- {
- case 0: config |= CONFIG_MUX_SINGLE_0 ; break ;
- case 1: config |= CONFIG_MUX_SINGLE_1 ; break ;
- case 2: config |= CONFIG_MUX_SINGLE_2 ; break ;
- case 3: config |= CONFIG_MUX_SINGLE_3 ; break ;
-
- case 4: config |= CONFIG_MUX_DIFF_0_1 ; break ;
- case 5: config |= CONFIG_MUX_DIFF_2_3 ; break ;
- case 6: config |= CONFIG_MUX_DIFF_0_3 ; break ;
- case 7: config |= CONFIG_MUX_DIFF_1_3 ; break ;
- }
-
- // Start a single conversion
-
- config |= CONFIG_OS_SINGLE ;
- config = __bswap_16 (config) ;
- wiringPiI2CWriteReg16 (node->fd, 1, config) ;
-
- // Wait for the conversion to complete
-
- for (;;)
- {
- result = wiringPiI2CReadReg16 (node->fd, 1) ;
- result = __bswap_16 (result) ;
- if ((result & CONFIG_OS_MASK) != 0)
- break ;
- delayMicroseconds (100) ;
- }
-
- result = wiringPiI2CReadReg16 (node->fd, 0) ;
- result = __bswap_16 (result) ;
-
- // Sometimes with a 0v input on a single-ended channel the internal 0v reference
- // can be higher than the input, so you get a negative result...
-
- if ( (chan < 4) && (result < 0) )
- return 0 ;
- else
- return (int)result ;
- }
-
-
- /*
- * digitalWrite:
- * It may seem odd to have a digital write here, but it's the best way
- * to pass paramters into the chip in the wiringPi way of things.
- * We have 2 digital registers:
- * 0 is the gain control
- * 1 is the data rate control
- *********************************************************************************
- */
-
- static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int data)
- {
- int chan = pin - node->pinBase ;
- chan &= 3 ;
-
- if (chan == 0) // Gain Control
- {
- if ( (data < 0) || (data > 6) ) // Use default if out of range
- data = 2 ;
- node->data0 = gains [data] ;
- }
- else // Data rate control
- {
- if ( (data < 0) || (data > 7) ) // Use default if out of range
- data = 4 ;
- node->data1 = dataRates [data] ; // Bugfix 0-1 by "Eric de jong (gm)" <ericdejong@gmx.net> - Thanks.
- }
-
- }
-
-
- /*
- * analogWrite:
- * We're using this to write to the 2 comparitor threshold registers.
- * We could use a digitalWrite here but as it's an analog comparison
- * then it feels better to do it this way.
- *********************************************************************************
- */
-
- static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int data)
- {
- int chan = pin - node->pinBase ;
- int reg ;
- int16_t ndata ;
-
- chan &= 3 ;
-
- reg = chan + 2 ;
-
- /**/ if (data < -32767)
- ndata = -32767 ;
- else if (data > 32767)
- ndata = 32767 ;
- else
- ndata = (int16_t)data ;
-
- ndata = __bswap_16 (ndata) ;
- wiringPiI2CWriteReg16 (node->fd, reg, data) ;
- }
-
-
-
- /*
- * ads1115Setup:
- * Create a new wiringPi device node for an ads1115 on the Pi's
- * I2C interface.
- *********************************************************************************
- */
-
- int ads1115Setup (const int pinBase, int i2cAddr)
- {
- struct wiringPiNodeStruct *node ;
- int fd ;
-
- if ((fd = wiringPiI2CSetup (i2cAddr)) < 0)
- return FALSE ;
-
- node = wiringPiNewNode (pinBase, 8) ;
-
- node->fd = fd ;
- node->data0 = CONFIG_PGA_4_096V ; // Gain in data0
- node->data1 = CONFIG_DR_128SPS ; // Samples/sec in data1
- node->analogRead = myAnalogRead ;
- node->analogWrite = myAnalogWrite ;
- node->digitalWrite = myDigitalWrite ;
-
- return TRUE ;
- }
|