ADS1115 HAL modul I2c communication

More
11 Jun 2015 20:48 - 11 Jun 2015 20:58 #59706 by fupeama
Hi,
I upgraded my old HX711 modul.
Now I used another one adc converter. ADS1115. 4x single-ended or 2xdifferential inputs.
It is possible to used it with parport (2x out pins 1x in pin)
two resistors and one NPN transistor are needed.
All files are included in zip file. ads1115.hal and config file for parport
Martin





File Attachment:

File Name: ads1115_a.zip
File Size:408 KB


File Attachment:

File Name: ads1115.pdf
File Size:1,349 KB










Last edit: 11 Jun 2015 20:58 by fupeama.
The following user(s) said Thank You: mehdidadash

Please Log in or Create an account to join the conversation.

More
15 Jun 2015 18:53 #59840 by fupeama
Hi,
I change output value from raw (0-32767) to +-volts depends on GAIN sets up on [11:9] bits in MSB parrametr.
I tried connect load cell dirrect to ads1115 without any amplifier, and result is good for my purpose. There is 10bits resolutin.
Modul update value every 10ms/channel. It means every 40ms for all 4 configured channels.
I want use this modul in my different project like feadback spindle speed from VFD.
0-10V VFD ->convert 0-5V -> ads1115 -> linuxcnc
Martin



//   This is a component for EMC2 HAL
//   Copyright 2015 Martin Kaplan <fupeama@gmail.com>
//
//   This program is free software; you can redistribute it and/or modify
//   it under the terms of the GNU General Public License as published by
//   the Free Software Foundation; either version 2 of the License, or
//   (at your option) any later version.
//
//   This program 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 General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program; if not, write to the Free Software
//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

component ads1115  "I2C Interface for ADC ADS1115 (ADS1113 and ADS1114)";

description """
This component is designed as an interface between ADC analog-digital-converter ADS1115 16bit and LINUXCNC through I2C protocol

.SH SYNOPSIS
(ignore the auto-generated SYNOPSIS above)
.SH
.HP
.B loadrt ads1115 cfg=ssd,dd\\fB
Means load two component ads1115. First with two single-ended inputs on pins A0 A1 and one differential input on pins A2 A3.
Second with two differetial inputs on A0 A1 and A2 A3.
Each instance of the component is defined by a group of letters describing the
type of analog inputs. A comma separates individual instances of the component.

.SH Tags
Input type definitions are all lower-case.
s=single-ended (used one pin on ads1115)
d=differencial (used two pins on ads1115)
ADS1115 has 4 input pins A0-A3

The  ADS1115 operate from a single power supply VOLTAGE REFERENCE ranging from 2.0V to 5.5V.

An onboard PGA is available on the ADS1114 and ADS1115 that  offers input ranges from the supply to as low as ±256mV, allowing both large and small signals to be measured with high resolution.

The ADS1115 communicate with the master (LINUXCNC) through an I2C interface. The master provides a clock signal on the SCL pin and data are transferred via the SDA pin.

.B QUICKSTART GUIDE

 Modul automacally generated appropriated pins and parameters for ADS based on cfg sequence. 
 Communication with ads1115 repeats in cycles:A

 Select input (A0-A3) 
 Send i2c address folowed by write bit to ADC
 Send Pointer register for write to Config register (BIT1=0 BIT0=1)
 Send MSB Byte  (default value are generated by cfg string) 
 Send LSB Byte
 Send address folowed by write bit to ADC
 Send Pointer register for read Conversion register (BIT1=0 BIT0=0)
 Send i2c address followed by read bit 
 Read MSB
 Read LSB
 Go to start with next input

 For example to set up gain amplifier to 4.096V (default value = 2.048V) on single-ended input on A0 change A0msb parameter from default value 0xc5 to 0xc3. 
 0xc5 1100 0101     bit[15]=1 bits[14:12]=100 bits[11:9]=010 bit[8]=1  
 0xc3 1100 0011     bit[15]=1 bits[14:12]=100 bits[11:9]=001 bit[8]=1
 See  Config Register
 
.B REGISTERS

The ADS1115 have four registers that are accessible via the I2C port. The Conversion register contains the result of the last conversion. The Config register allows the user to change the ADS1115 operating modes and query the status of the devices. Two registers, Lo_thresh and Hi_thresh, set the threshold values used for the comparator function.

.B POINTER REGISTER
The four registers are accessed by writing to the Pointer register byte.

 BIT 1         BIT 0        REGISTER
   0             0          Conversion register
   0             1          Config register
   1             0          LO_Treshold register
   1             1          HI_Treshold register

.B CONVERSION REGISTER

The 16-bit register contains the result of the last conversion in binary twos complement format.

.B CONFIG REGISTER

The 16-bit register can be used to control the ADS1115 operating mode, input selection, data rate, PGA settings, and comparator modes.

Pointer Register Byte (Write-Only)

BIT_7 BIT_6 BIT_5 BIT_4 BIT_3 BIT_2  BIT_1 BIT_0
  0     0     0     0     0     0    Reg address

Conversion Register (Read-Only)

 BIT  15  14  13  12  11  10  9  8  7  6  5  4  3  2  1  0
 NAME D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0

Config Register (Read/Write)

 MSB 
 BIT  15 14   13   12   11   10   9    8
 NAME OS MUX2 MUX1 MUX0 PGA2 PGA1 PGA0 MODE
 
 LSB
 BIT  7   6   5   4         3        2        1         0
 NAME DR2 DR1 DR0 COMP_MODE COMP_POL COMP_LAT COMP_QUE1 COMP_QUE0

.B Bit[15] OS: Operation Status
             For a write status:
             0 : No effect
             1 : Begin a single conversion (when in power-down mode)
             For a read status:
             0 : Device is currently performing a conversion
             1 : Device is not currently performing a conversion

.B Bits [14:12] MUX[2:0]: Input multiplexer configuration
             These bits configure the input multiplexer. 
             000 : AINP = AIN0 and AINN = AIN1                    100 : AINP = AIN0 and AINN = GND
             001 : AINP = AIN0 and AINN = AIN3                    101 : AINP = AIN1 and AINN = GND
             010 : AINP = AIN1 and AINN = AIN3                    110 : AINP = AIN2 and AINN = GND
             011 : AINP = AIN2 and AINN = AIN3                    111 : AINP = AIN3 and AINN = GND

.B Bits [11:9] PGA[2:0]: Programmable gain amplifier configuration
             These bits configure the programmable gain amplifier. They serve no function on the ADS1113.
             000 : FS = ±6.144V(1)                                100 : FS = ±0.512V
             001 : FS = ±4.096V(1)                                101 : FS = ±0.256V
             010 : FS = ±2.048V (default)                         110 : FS = ±0.256V
             011 : FS = ±1.024V                                   111 : FS = ±0.256V

.B Bit [8] MODE: Device operating mode
             This bit controls the current operational mode 
             0 : Continuous conversion mode
             1 : Power-down single-shot mode (default)
 
.B Bits [7:5] DR[2:0]: Data rate
             These bits control the data rate setting.
             000 : 8SPS                                           100 : 128SPS (default)
             001 : 16SPS                                          101 : 250SPS
             010 : 32SPS                                          110 : 475SPS
             011 : 64SPS                                          111 : 860SPS

.B Bit [4] COMP_MODE: Comparator mode 
             This bit controls the comparator mode of operation. It changes whether the comparator is implemented as a
             traditional comparator (COMP_MODE = '0') or as a window comparator (COMP_MODE = '1'). 
             0 : Traditional comparator with hysteresis (default)
             1 : Window comparator

.B Bit [3] COMP_POL: Comparator polarity 
             This bit controls the polarity of the ALERT/RDY pin. When COMP_POL = '0' the comparator output is active
             low. When COMP_POL='1' the ALERT/RDY pin is active high.
             0 : Active low (default)
             1 : Active high

.B Bit [2] COMP_LAT: Latching comparator 
             This bit controls whether the ALERT/RDY pin latches once asserted or clears once conversions are within the
             margin of the upper and lower threshold values. When COMP_LAT = '0', the ALERT/RDY pin does not latch
             when asserted. When COMP_LAT = '1', the asserted ALERT/RDY pin remains latched until conversion data
             are read by the master or an appropriate SMBus alert response is sent by the master, the device responds with
             its address, and it is the lowest address currently asserting the ALERT/RDY bus line.
             0 : Non-latching comparator (default)
             1 : Latching comparator

.B Bits [1:0] COMP_QUE: Comparator queue and disable 
            These bits perform two functions. When set to '11', they disable the comparator function and put the
            ALERT/RDY pin into a high state. When set to any other value, they control the number of successive
            conversions exceeding the upper or lower thresholds required before asserting the ALERT/RDY pin. 
            00 : Assert after one conversion
            01 : Assert after two conversions
            10 : Assert after four conversions
            11 : Disable comparator (default)

.B Lo_thresh AND Hi_thresh REGISTERS
            Set up tresholds registers are not inplemented on this modul.



 """;

pin in  bit SDAIn  "SDA Input pin";
pin out bit SDAOut "SDA Output pin";
pin out bit SCLOut "SCL Output pin";
pin in bit enable=1 "Turn communication on or offi (default=on)";
pin out bit communication"Communication is ok. True when ADC send Acknowledge bits";


pin out float outA0 if (personality & 0x01)"Analog value between A0 single-ended and GND pins";
pin out float outA1 if (personality & 0x02)"Analog value between A1 single-ended and GND pins";
pin out float outA0-A1 if (personality & 0x04)"Analog value between A0 and A1 pins";
pin out float outA2 if (personality & 0x08)"Analog value between A2 single-ended and GND pins";
pin out float outA3 if (personality & 0x10)"Analog value between A3 single-ended and GND pins";
pin out float outA2-A3 if (personality & 0x20)"Analog value between A2 and A3 pins";


param rw unsigned A0msb=0xc5 if (personality & 0x01) "MSB byte for A0";
param rw unsigned A0lsb=0x83 if (personality & 0x01) "LSB byte for A0";
param rw unsigned A1msb=0xd5 if (personality & 0x02) "MSB byte for A1";
param rw unsigned A1lsb=0x83 if (personality & 0x02) "LSB byte for A1";
param rw unsigned A0-A1msb=0x85 if (personality & 0x04)"MSB byte for A0-A1";
param rw unsigned A0-A1lsb=0x83 if (personality & 0x04)"LSB byte for A0-A1";
param rw unsigned A2msb=0xe5 if (personality & 0x08) "MSB byte for A2";
param rw unsigned A2lsb=0x83 if (personality & 0x08) "LSB byte for A2";
param rw unsigned A3msb=0xf5 if (personality & 0x10) "MSB byte for A3";
param rw unsigned A3lsb=0x83 if (personality & 0x10) "LSB byte for A3";
param rw unsigned A2-A3msb=0xb5 if (personality & 0x20)"MSB byte for A2-A3";
param rw unsigned A2-A3lsb=0x83 if (personality & 0x20)"LSB byte for A2-A3";
param rw unsigned address = 0x48 "address selector-ADDR PIN  0x48=GROUND,0x49=VDD";

function make_puls nofp	"Fast thread for generating puls";
function read fp        "Slow thread for read value from ADC";

option extra_setup yes;
option count_function yes;
option personality;

license "GPL";
author "Martin Kaplan";
variable u32 ACKcount=0;
variable int ByteStatus = 0;
variable int BitStatus = 0;
variable int ByteNum = 8;
variable u16 TXByte;
variable u16 TXBit;
variable u16 RXByte;
variable u16 RXBit;
variable u16 RxWord [10];
variable int wordnum =0;
variable int lastwordnum;
variable int sentense=0;
variable int lastsentense;
variable int CmdByte = 0; 
variable int RxByteNum = 0;
variable u32 wait;
variable double timer;
variable float fs;
;;

    enum I2C_mask
    {
        StartBit        = 0x0100,	//Generate SDA High>Low on SCL is High
        AckBit          = 0x0200,	//Send low on SDA if Dir=Read
        StopBit         = 0x0400,	//Genarate SDA Low>High on SCL is High
        DirBit          = 0x0800,	// Direction 0=write 1=read
        WaitBit         = 0x1000,	//Wait for ms on 0xffff position
        AddressBit      = 0x2000,	//Write address to byte
        ParamMSBBit     = 0x4000,	//mask byte by parameter MSB
        ParamLSBBit     = 0x8000	//mask byte by parameter LSB
    };

    enum I2C_Byte_status
    {
        ByteIdle        = 0, 		//Idle    
        ByteNew         = 1,		//New byte
        ByteStart       = 2,		//Start byte
        Byte7_1         = 3,		//Bytes 1-7
        Byte0           = 4,		//Last Byte
        ByteAck         = 5,		//ACK
        ByteStop        = 6		//Stop  byte
    };

    enum I2C_Bit_Status
    {
        BitIdle         = 0,		//Bit is IDLE
        BitNew          = 1,		//Send TXbit to SDA
        BitData         = 2,		//Send High  to SCL
        BitLow          = 3,		//SCL is Low
        BitHigh         = 4,		//SCL is Hig
        BitStart        = 5,		//Send SDA High->Low while SCL is High
        BitStop         = 6		//Send SDA Lowi->High while SCL is High
    };

#define MAX_CHAN 4
#define MAX_TXWORDS 10 
const u16 TXWord[MAX_TXWORDS] = {0x2100, 0x01, 0x4000, 0x8400, 0x1002, 0x2100, 0x400, 0x2101, 0xa00, 0xe00};
const float GAIN[] = {6.144, 4.096, 2.048, 1.024, 0.512, 0.256, 0.256, 0.256};

static char *cfg[MAX_CHAN];
RTAPI_MP_ARRAY_STRING(cfg, MAX_CHAN, "Description of each channel");

FUNCTION(make_puls)
{
if (enable) {

    // Cycles through Bytes

    if (BitStatus == BitIdle){
        switch (ByteStatus) {
        case ByteNew :
        if ((TXByte & StartBit) == StartBit){
         ByteStatus=ByteStart;
          TXBit = 1;
        BitStatus = BitNew;
        } else {
             ByteStatus=Byte7_1;
        }
    break;

    case ByteStart :
        ByteStatus = Byte7_1;
    break;
    
    case Byte7_1 :
        ByteNum--;
        TXBit = ((TXByte & DirBit)==0) ? (TXByte >> ByteNum) & 0x01 : 1;
        RXByte = (RXByte << 1) | RXBit;
        if (ByteNum == 0){
        ByteNum=8;
        ByteStatus=Byte0;
        }
        BitStatus = BitNew;
    break;

    case Byte0 :
            TXBit=((TXByte & DirBit)==0) ? 1 : ((TXByte>>9) & 0x01) ^0x01;   //ACK
        RXByte = (RXByte << 1) | RXBit;
        BitStatus = BitNew;
        ByteStatus = ByteAck;

    break;

    case ByteAck :
        RXByte = (RXBit==0) ? RXByte|0x0200 : RXByte;
        if ((TXByte & StopBit) == StopBit){
                        ByteStatus=ByteStop;
                } else {
                ByteStatus=ByteIdle;
                }
    break;
    case ByteStop :
        TXBit = 0;
        BitStatus =BitNew;
    break;
    default :
        ByteStatus=ByteIdle;
    }
    }


    // Cycles through bits

    switch (BitStatus) {

    case BitNew :
        BitStatus = BitData;
        SDAOut = TXBit;
        break;
    case BitData :
        BitStatus = BitHigh;
        SCLOut = 1; 
        break;
    case BitHigh : 
    RXBit = (SDAIn && ByteStatus!=ByteStart) ? 1 : 0;
        if (ByteStatus==ByteStart) {
            BitStatus = BitStart;
            SDAOut = 0;
        } else {
            if (ByteStatus==ByteStop) {
                BitStatus = BitStop;
                SDAOut = 1;
            } else {
            BitStatus = BitLow;
                    SCLOut = 0; 
            }
        }
        break;
    case BitLow : 
        BitStatus = BitIdle;
        break;
    case BitStart :
        BitStatus = BitLow;
        SCLOut = 0;
        break;
    case BitStop :
        BitStatus = BitIdle;
        SCLOut = 1;
    ByteStatus=ByteIdle;
        break;
    case BitIdle :
    break;
    default :
        BitStatus = BitIdle;
        SCLOut = 1;
        SDAOut = 1;
    }
}
}

FUNCTION(read)
{   
    if (ByteStatus == 0 && BitStatus == 0){
    RxWord[lastwordnum]=RXByte;
    if (((TXByte & DirBit) == 0x00) && (( TXByte & WaitBit) !=  WaitBit)) {      //write and non wait 
        if ((RXByte & AckBit) == AckBit) {					//ACK returned by client- communication is ok
        ACKcount++;
        } else {
        ACKcount=0;
        }
    }
    if (ACKcount>=5){
        communication=1;
    }else {
        communication=0;
    }
    TXByte = TXWord[wordnum];
    lastwordnum=wordnum;
        if ((TXByte & WaitBit) == WaitBit) {
            timer += period;
            wait=(TXByte & 0xfff)*1000*1000;  //ns to ms
            if(timer >= wait) {
                timer = 0.0;
                wordnum++;
            }
        if (wordnum==MAX_TXWORDS){
            wordnum=0;
            }
        } else {
            wordnum++;
    TXByte=((TXByte & AddressBit)==AddressBit) ? TXByte|(address<<1) : TXByte ; 	//mask by address moved 1 bit left

    switch (lastsentense){
    case 0:
        TXByte=((TXByte & ParamMSBBit)==ParamMSBBit) ? TXByte|A0msb :  TXByte ;
        TXByte=((TXByte & ParamLSBBit)==ParamLSBBit) ? TXByte|A0lsb :  TXByte ;
        fs=GAIN[((A0msb>>1) & 0x7)] /0x7FFF;
        break;
    case 1:
        TXByte=((TXByte & ParamMSBBit)==ParamMSBBit) ? TXByte|A1msb :  TXByte ;
        TXByte=((TXByte & ParamLSBBit)==ParamLSBBit) ? TXByte|A1lsb :  TXByte ;
        fs=GAIN[((A1msb>>1) & 0x7)] /0x7FFF;
        break;
    case 2:
        TXByte=((TXByte & ParamMSBBit)==ParamMSBBit) ? TXByte|A0_A1msb :  TXByte ;
        TXByte=((TXByte & ParamLSBBit)==ParamLSBBit) ? TXByte|A0_A1lsb :  TXByte ;
        fs=GAIN[((A0_A1msb>>1) & 0x7)] /0x7FFF;
        break;
    case 3:
        TXByte=((TXByte & ParamMSBBit)==ParamMSBBit) ? TXByte|A2msb :  TXByte ;
        TXByte=((TXByte & ParamLSBBit)==ParamLSBBit) ? TXByte|A2lsb :  TXByte ;
	fs=GAIN[((A2msb>>1) & 0x7)] /0x7FFF;
        break;
    case 4:
        TXByte=((TXByte & ParamMSBBit)==ParamMSBBit) ? TXByte|A3msb :  TXByte ;
        TXByte=((TXByte & ParamLSBBit)==ParamLSBBit) ? TXByte|A3lsb :  TXByte ;
        fs=GAIN[((A3msb>>1) & 0x7)] /0x7FFF;
        break;    
    case 5:
        TXByte=((TXByte & ParamMSBBit)==ParamMSBBit) ? TXByte|A2_A3msb :  TXByte ;
        TXByte=((TXByte & ParamLSBBit)==ParamLSBBit) ? TXByte|A2_A3lsb :  TXByte ;
        fs=GAIN[((A2_A3msb>>1) & 0x7)] /0x7FFF;
        break;
    }
        if (lastwordnum==0){
        if((personality & 0x01) && (lastsentense==0))  outA0=(((RxWord[8]&0xff)<<8)|(RxWord[9]&0xff))*fs*(((RxWord[8]&0xff)>>7)^0x01);
        if((personality & 0x02) && (lastsentense==1))  outA1=(((RxWord[8]&0xff)<<8)|(RxWord[9]&0xff))*fs*(((RxWord[8]&0xff)>>7)^0x01);
        if((personality & 0x04) && (lastsentense==2))  outA0_A1=fs*((((RxWord[8]&0xff)>>7)^0x01) ?  ((RxWord[8]&0xff)<<8)|(RxWord[9]&0xff) : (((RxWord[8]&0xff)<<8)|(RxWord[9]&0xff))-0xffff);
        if((personality & 0x08) && (lastsentense==3))  outA2=(((RxWord[8]&0xff)<<8)|(RxWord[9]&0xff))*fs*(((RxWord[8]&0xff)>>7)^0x01);
        if((personality & 0x10) && (lastsentense==4))  outA3=(((RxWord[8]&0xff)<<8)|(RxWord[9]&0xff))*fs*(((RxWord[8]&0xff)>>7)^0x01);
        if((personality & 0x20) && (lastsentense==5))  outA2_A3=fs*((((RxWord[8]&0xff)>>7)^0x01) ?  ((RxWord[8]&0xff)<<8)|(RxWord[9]&0xff) : (((RxWord[8]&0xff)<<8)|(RxWord[9]&0xff))-0xffff);
        lastsentense=sentense;
        do {
            sentense++;
            if (sentense>=6) sentense=0;
        }while (!((personality>>sentense)&0x01));
            }   
            if (wordnum==MAX_TXWORDS) wordnum=0;
    ByteStatus = ByteNew;
    RXByte=0;
    }
    
    }
}

EXTRA_SETUP(){
    int i,nextbit=0;
    char c;
    for (i = 0; cfg[extra_arg][i] != 0 && i < MAX_CHAN ; i++){
        c = cfg[extra_arg][i];
        if (c == 's' )  {
            if (i==2 && nextbit==0)  nextbit=1;
            if (i==3 && nextbit!=0)  nextbit=1;
            personality |= 0x01<<(i+nextbit);
        }
        if (c == 'd' && (i==1 || i==2)) {
            personality |= 0x01<<5;
            nextbit=5;
        }
        if (c == 'd' && i==0) {
            personality |= 0x01<<2;
            nextbit=2;
            }
    }
    personality&=0x3f; 				// only first 6 bits
    return 0;
}

int get_count(void){
    int i;
    for (i=0; cfg[i] != NULL && i < MAX_CHAN; i++){}
    if (i == 0){
        rtapi_print_msg(RTAPI_MSG_ERR, "The ads1115 component needs at least one "
                    "feedback type tag.\nValid tags are  s and d \nexample: loadrt ads1115 cfg=ssd" );
        return 0;
    }
    return i;
}

M
Attachments:
The following user(s) said Thank You: mehdidadash

Please Log in or Create an account to join the conversation.

Time to create page: 0.305 seconds
Powered by Kunena Forum