This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

  • TI Thinks Resolved

ADS1115: unable to read 16 bit, able to read only MSB 8 bit in LSB getting 00 or ff constant

Prodigy 60 points

Replies: 8

Views: 72

Part Number: ADS1115

HELLO JOSEPF WU,

I hope you will help me, i am using atmel 8052 micro-controller IC. i have connected SCL PIN TO PORT 1.0 OF 8052 AND SDA PIN TO PORT 1.1 OF 8052. In program you can see that. i am tring this from last 3 to 4 days. i have followed the same time diagram as shown in datasheet. still i am unable to read 16 bit. i am getting only msb 8 bit data correct and it varies as i change the input voltage. i am calling it correct coz it gives me 7F as per set gain.. when i set gain to ±2.048 i got 7F at 2v.. so basically my half operation is absolutely correct. even i tried to read config register there also i am getting msb 8 bit correctly.. i am not getting what i am doing wrong here which is affecting my lsb 8 bit data. please take out some time and help me.

 

#include <REGX52.H>


sbit SCL=P1^0;
sbit SDA=P1^1;
sbit D7= B^7; //MSBbit


bit flag=0,RT=1,BIT=0;
unsigned char i,ini_char,t,STRING,STX=02,CR=0X0D,AD1,AD2,AD3,AD4,DATA0,DATA1,E,ADC_L,OK,ADS;
unsigned int ADC_M;
unsigned char check [5];
unsigned char nibble [5];

void main();
void port_ini();
void serial_ISR(void);
void go(ini_char);
void SEND_ADC_READING();
void HEX_TO_BCD();
void ADC_WRITE();
void ADC_WR();
void SPI();
void ADCM();
void ADCL();


//----------------------------------------------------------------------
//--------- MAIN PROGRAM ---------------------------------------------
//----------------------------------------------------------------------
void main()
{
//
port_ini();
ADC_WRITE();
while(1)
{
ADC_WRITE();
if (RT==0)
{
for(i=0;i<5;i++)
{
nibble[i]=check[i];
}
RT=1;
ini_char=nibble[0];
go(ini_char);
}
}
}

void port_ini()
{
EA=1; //all_interrupt_enable
ES=1; //serial_interrupt_enable
TMOD=0x20; //TIMER 1 MODE 2(auto reload)
TH1=0xFD; //9600 Baudrate
SCON=0x50; // REN enable, 8bit 1 stop bit
TR1=1;
SCL=1;
SDA=1;
}

void ADC_WRITE()
{
ADC_M=0x00; //clear previous data to collect new
ADC_L=0x00; //clear previous data to collect new

//WRITE OPERAION

SCL=1;
SDA=1;
SDA=0; //START

B=0x90; //SLAVE ADDRESS+WR
ADC_WR();
SCL=0;
SCL=1;

B=0x01; //CONFIGURE REG
ADC_WR();
SCL=0;
SCL=1;

B=0xC3; //OS=1, A0 CH, ONE SHOT MODE
ADC_WR();
SCL=0;
SCL=1;
SCL=0;
SCL=0;
SCL=0;

B=0x83; //128SPS
ADC_WR();
SCL=0;
SCL=1;

SCL=0; //STOP
SCL=1;
SDA=1; //STOP

TH0=0xDC; //DC
TL0=0x00;
TR0=1;
while(TF0==0); //DELAY OF 10MS
TR0=0;
TF0=0;

SCL=1;
SDA=1;
SDA=0; //START

//READ OPERAION
B=0x90; //SLAVE ADDRESS+WR
ADC_WR();
SCL=0;
SCL=1;

B=0x00; //CONVERSION REG
ADC_WR();
SCL=0;
SCL=1;

SCL=0;
SCL=1;
SDA=1; //STOP

SCL=1;
SDA=1;
SDA=0; //START

B=0x91; //SLAVE ADDRESS+RD
ADC_WR();
SCL=0;
SCL=1;

ADCM(); //call ADCM subroutine
SCL=0;
SCL=1;

SCL=0;
SCL=1;
SDA=1; //STOP

E=ADC_M/256; //MSB
HEX_TO_BCD();
AD4=DATA1;
AD3=DATA0;
E=ADC_M%256; //LSB
HEX_TO_BCD();
AD2=DATA1;
AD1=DATA0;
}


void ADC_WR()
{
for (i=0; i<8; i++)
{
SCL=0;
SDA=D7;
SCL=1;

B = B<<1; //rotate left B reg into MSB to detect next bit
}
}


void ADCM()
{
for(i=0; i<16; i++)
{
SCL=0; //high to low pulse to receive digital data from analog
if (SDA==1) //first rotate then add
{
ADC_M= ADC_M << 1; //every rotate 0 will occure at LSB
ADC_M=ADC_M+1;
}
else if(SDA==0) //only rotate
{
ADC_M=ADC_M << 1; //every rotate 0 will occure at LSB
}
SCL=1;
}

}
//**********************************************************************


void ADCL()
{
for(i=0; i<8; i++)
{
SCL=0; //high to low pulse to receive digital data from analog
if (SDA==1) //first rotate then add
{
ADC_L= ADC_L << 1; //every rotate 0 will occure at LSB
ADC_L=ADC_L+1;
}
else if(SDA==0) //only rotate
{
ADC_L=ADC_L << 1; //every rotate 0 will occure at LSB
}
SCL=1;
}
SCL=0;
OK=0;
SCL=1;
}
//**********************************************************************

//-------------------------------------------------//
//------- SERIAL_COMMUNICATION -------------------//
//-------------------------------------------------//
void serial_ISR(void) interrupt 4
{
if(RI==1) //if RI is set
{
STRING=SBUF; //move content of SBUF into STRING
RI=0; //clear RI to reset

if(STRING==CR) //if carrige return is detected (CR=0x0D)
{
flag=0; //clear flag
t=0; //clear t
RT=0;
}

else if (flag==1) //if flag is set
{
check[t]=STRING; //transfer data into array
t++; //increment array pointer
}

else if (STRING==STX && RT==1) //if STX=0x02 is detected & RT is set
{
flag=1; //set flag 1
t=0; //start pointer from 0 location
}
}
}
//****************************************


//----------------------------------------
//-------- GO BYTE0 AND BREAK ------------
//----------------------------------------
void go(int ini_char) // 1st received char
{
switch(ini_char)
{
case 'R': //if R
{
SEND_ADC_READING();
break;
}
}
}
//****************************************

//----------------------------------------
//-------- SEND_ADC_READING ------------
//----------------------------------------
void SEND_ADC_READING()
{
SBUF= STX;
while(TI==0);
TI=0;
SBUF= 'R';
while(TI==0);
TI=0;
SBUF= AD4;
while(TI==0);
TI=0;
SBUF= AD3;
while(TI==0);
TI=0;
SBUF= AD2;
while(TI==0);
TI=0;
SBUF= AD1;
while(TI==0);
TI=0;
SBUF= CR;
while(TI==0);
TI=0;
}
//****************************************

//----------------------------------------//
//----------- HEX_TO_BCD -----------------//
//----------------------------------------//
void HEX_TO_BCD()
{
DATA1=E/16; //6A/10=6 MSB
if(DATA1>9)
{
DATA1=DATA1+0x37;
}
else
{
DATA1=DATA1+0x30;
}

DATA0=E%16; //A LSB
if(DATA0>9)
{
DATA0=DATA0+0x37;
}
else
{
DATA0=DATA0+0x30;
}
}
//****************************************

 

  • Snehal,

    Instead of reading through your code (which I'm not very good at), can you please put up a scope shot or logic analyzer plot of your I2C communications? It's always best to look at the waveforms when trying to debug the communications.

    My first guess is that somehow you're accidentally sending a stop condition somewhere between the MSB and LSB data. I think that would stop the data transfer, and you might get FF afterwards.

    Joseph Wu

  • In reply to Joseph Wu:

    Dear Joseph,

    Firstly, thanks for the reply. I don't have scope and that is the big problem. I know it is very difficult to read the code written by somebody else. I will explain you the program from write operation to how I have read. I have followed the same time diagram as shown in datasheet that you can compare it. if you have still doubt or not getting anything please revert me.

    SCL=1;
    SDA=1;
    SDA=0;              //Start CONDITION

    B=0x90;             //SLAVE ADDRESS+WR
    ADC_WR();       //8 bit sending by making [ SCL=0 ,(SAD 1 OR 0), SCL=1]
    SCL=0;
    SCL=1;             //9th bit Extra one clock pulse 

    B=0x01;           //CONFIG REG
    ADC_WR();     //8 bit sending by making [ SCL=0 ,(SAD 1 OR 0), SCL=1]
    SCL=0;
    SCL=1;            //9th bit Extra one clock pulse 

    B=0xC3;          //OS=1, A0 CH, ONE SHOT MODE
    ADC_WR();     //8 bit sending by making [ SCL=0 ,(SAD 1 OR 0), SCL=1]
    SCL=0;
    SCL=1;            //9th bit Extra one clock pulse 
    SCL=0;            //Extra SCL=0 
    SCL=0;            //Extra SCL=0 
    SCL=0;            //Extra SCL=0   //EVEN I SKIP THIS EXTRA 3 TIMES SCL=0 THEN ALSO I AM GETTING SAME MSB PART RESULT

    B=0x83;           //DEFAULT
    ADC_WR();     //8 bit sending by making [ SCL=0 ,(SAD 1 OR 0), SCL=1]
    SCL=0;
    SCL=1;            //9th bit Extra one clock pulse

    SCL=0;        
    SCL=1;
    SDA=1;           //STOP CONDITION

     //DELAY OF 10MS

    TH0=0xDC;   
    TL0=0x00;
    TR0=1;
    while(TF0==0); 
    TR0=0;
    TF0=0;

    //////////////////////////////////////////////

    SCL=1;
    SDA=1;
    SDA=0;         //Start CONDITION

    //READ OPERAION


    B=0x90;           //SLAVE ADDRESS+WR
    ADC_WR();     //8 bit sending by making [ SCL=0 ,(SAD 1 OR 0), SCL=1]
    SCL=0;    
    SCL=1;           //9th bit Extra one clock pulse

    B=0x00;          //CONVERSION REG
    ADC_WR();    //8 bit sending by making [ SCL=0 ,(SAD 1 OR 0), SCL=1]
    SCL=0;
    SCL=1;          //9th bit Extra one clock pulse

    SCL=0;
    SCL=1;
    SDA=1;          //STOP CONDITION

    SCL=1;
    SDA=1;
    SDA=0;              //START CONDITION

    B=0x91;             //SLAVE ADDRESS+RD
    ADC_WR();       //8 bit sending by making [ SCL=0 ,(SAD 1 OR 0), SCL=1]
    SCL=0;
    SCL=1;             //9th bit Extra one clock pulse

    ADCM();          //READING 16 BIT AT A TIME [SCL=0, (16BITREG=SDA(LOAD SDA VALUE INTO REG)), SCL=1]
    SCL=0;
    SCL=1;           //9th bit Extra one clock pulse

    SCL=0;
    SCL=1;
    SDA=1;           //STOP CONDITION

     

    QUICK VIEW

    START

    90

    01

    C383

    STOP

    DELAY 10MS

    START

    90

    00

    STOP

    START

    91

    MSB+LSB

     

     

  • In reply to SNEHAL WARKE:

    Snehal,


    First, I really think it is necessary to get an oscilloscope or logic analyzer. It's important to see what is communication is really going on between the device and the master.

    Looking at your code, I don't see anything specifically wrong, but I'm not a coding expert and I don't do much coding at all. If you're using the 8052 to code up an I2C interface, there are definitely examples online. I suggest that you put I2C bus responses into functions so they can also be easily called. I found this online in a quick example on I2C Implementation on 8051:

    #define SDA P0_0
    #define SCL P0_1

    void I2CInit()
    {
    SDA = 1;
    SCL = 1;
    }

    void I2CStart()
    {
    SDA = 0;
    SCL = 0;
    }

    void I2CRestart()
    {
    SDA = 1;
    SCL = 1;
    SDA = 0;
    SCL = 0;
    }

    void I2CStop()
    {
    SCL = 0;
    SDA = 0;
    SCL = 1;
    SDA = 1;
    }

    void I2CAck()
    {
    SDA = 0;
    SCL = 1;
    SCL = 0;
    SDA = 1;
    }

    void I2CNak()
    {
    SDA = 1;
    SCL = 1;
    SCL = 0;
    SDA = 1;
    }

    unsigned char I2CSend(unsigned char Data)
    {
    unsigned char i, ack_bit;
    for (i = 0; i < 8; i++) {
    if ((Data & 0x80) == 0)
    SDA = 0;
    else
    SDA = 1;
    SCL = 1;
    SCL = 0;
    Data<<=1;
    }
    SDA = 1;
    SCL = 1;
    ack_bit = SDA;
    SCL = 0;
    return ack_bit;
    }

    unsigned char I2CRead()
    {
    unsigned char i, Data=0;
    for (i = 0; i < 8; i++) {
    SCL = 1;
    if(SDA)
    Data |=1;
    if(i<7)
    Data<<=1;
    SCL = 0;
    }
    return Data;
    }


    Joseph Wu

  • In reply to Joseph Wu:

    Dear Joseph Wu,

    your code will definitely help me. i will make changes and let you know. thank you so much for your reply. and sorry that i open one more same query. 

  • In reply to SNEHAL WARKE:

    Dear Joseph Wu,

    i got the output of 16bit data. should i share my corrected code, so that, that will help others. thank you so much for your response.

  • In reply to SNEHAL WARKE:

    Snehal,

    If you're willing to share your code, then please do so!

    I'm glad that you were able to get data out of the ADC. I'll close this post for now, but if you have further questions, start a new thread and post back.

    Joseph Wu

  • In reply to Joseph Wu:

    Dear joseph wu,

    when i try to read all 4 channels that time other channel reading get affected when i try to change any channel. for eg when i am rotating pot i am expecting to see change  in only that channel, but here i can see fluctuation in next channel too. 

    ADC_CH=0x42;     //CH0 & PGA=±4.096 & MODE-CONTINUOUS-CONVERSION
    ADC_WRITE();
    delay(); //10MS
    ADC_avg();          //adc read 200 times and divide by 200 for constant reading
    delay(); //10MS
    delay(); //10MS

    ADC_CH=0x52; //CH1 & PGA=±4.096 & MODE-CONTINUOUS-CONVERSION
    ADC_WRITE();
    delay(); //10MS
    ADC_avg();       //adc read 200 times and divide by 200 for constant reading
    delay(); //10MS
    delay(); //10MS

    ADC_CH=0x62; //CH2 & PGA=±4.096 & MODE-CONTINUOUS-CONVERSION
    ADC_WRITE();
    delay(); //10MS
    ADC_avg();      //adc read 200 times and divide by 200 for constant reading
    delay(); //10MS
    delay(); //10MS

    ADC_CH=0x72; //CH3 & PGA=±4.096 & MODE-CONTINUOUS-CONVERSION
    ADC_WRITE();
    delay(); //10MS
    ADC_avg();      //adc read 200 times and divide by 200 for constant reading
    delay(); //10MS
    delay(); //10MS

    here i am changing adc channel number then i am performing its write operation then ( i am writing 91 and reading conversion reg) for 200 times (16 bit *200 )and dividing it by 200 as averaging.  

    i am using continuous mode so i have assumed no need to do write operation again and again. suggest me best method to do. 

  • In reply to SNEHAL WARKE:

    Snehal,


    I'm not sure how you have your circuit set up, so I'm not sure what you are measuring and how the different inputs are driven. You may need to show a basic schematic and what data values you are getting for each case (including all the raw data, not just the averaged values).

    I would note that one issue is that changing channels in continuous conversion mode is not an immediate change. Writing the configuration register to start a new channel, the device completes the conversion in progress and THEN makes the configuration change in the subsequent conversion. For this reason, I often suggest using single-shot conversion mode for multichannel measurements.


    Joseph Wu

This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.