Helpful ReplyHot!16 bit I2C communication problem - PIC16F877A

Author
Roberto93
New Member
  • Total Posts : 16
  • Reward points : 0
  • Joined: 2018/04/27 09:24:18
  • Location: 0
  • Status: offline
2018/05/01 16:14:29 (permalink)
0

16 bit I2C communication problem - PIC16F877A

Hi, I'm having trouble with communicating my PIC16F877A with a 16 bit ADC (ADS1115) via I2C. I understand the basic principles of the I2C communication, but I'm no expert, so maybe anyone here can help.
I tried to make a simple threshold detector, by reading the analog input from some electrodes, digitalizing them and sending them to the PIC, but had no luck, as I couldn't get any response from the MCU.
So I start by initializing the PIC in master mode (as the ADS1115 is only allowed to be slave, according to the datasheet), setting and clearing the bits shown in I2C_Master_Init.
[/code]void I2C_Master_Init(const unsigned long clock)
{
  TRISC3 = 1;                       //Setting as input as given in datasheet
  TRISC4 = 1;                       //Setting as input as given in datasheet
  SSPCON2 = 0b00000000;
  SSPADD = (_XTAL_FREQ/(4*clock))-1;//Setting Clock Speed
  SSPSTAT = 0b10000000;
  SSPCON = 0b00101000;              //SSP module como master
}[/code]
I'm using a 100kHz clock for this, so I don't need slew rate control (SSPSTAT[8] = 1), and then I wait until everything is done with the routine I2C_Master_Wait.
[/code]void I2C_Master_Wait()
{
  while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); //Transmit is in progress
}[/code]
Then I send the start condition with I2C_Master_Start, which is a pretty simple routine.
[/code]void I2C_Master_Start()
{
  I2C_Master_Wait();    
  SEN = 1;             //Initiate start condition
}[/code]
So, the next step is to communicate to the ADC with it's address, in this case, 0b1001000. First, I configure the ADC to continuous conversion, and some other configurations specified in the datasheet. I do all of this following the instructions in the ADC's datasheet attached, except for one bit, which is the Programmable Gain Amplifier range (doesn't change the process). I do this with the ADS1115_config routine shown below.
[/code]void I2C_Master_Write(unsigned d)
{
  I2C_Master_Wait();
  SSPBUF = d;         //Write data to SSPBUF
}
 
void ADS1115_config()
{
    I2C_Master_Write(0b10010000);   //Write to slave
    I2C_Master_Wait();
    I2C_Master_Write(0b00000001);   //Config register of ADS1115
    I2C_Master_Wait();
    //8 MSB of Config register, PGA: +-6.144V, Inputs: default (A0), continuous conv. mode
    I2C_Master_Write(0b10000000);  
    I2C_Master_Wait();
    //8 LSB of Config register, 128 SPS, Traditional comparator, active low, nonlatching, dis. ALERT/RDY
    I2C_Master_Write(0b10000011);   //8 LSB of Config register
}[/code]
Then, as the datasheet shows, I have to tell the device I want to read from it. Following the datasheet, this would be:
[/code]unsigned int I2C_Master_Read(unsigned short a)
{
  unsigned int temp;
  RCEN = 1;             //Receive mode enabled
  I2C_Master_Wait();
  temp = SSPBUF;      //Read data from SSPBUF.
  I2C_Master_Wait();
  ACKDT = (a)?0:1;    //Acknowledge bit
  ACKEN = 1;          //Acknowledge sequence
  return temp;
}
 
unsigned int ADS1115_read(){
    I2C_Master_Write(0b10010000);   //ADS1115 address 0x48 + 0 (write)
    I2C_Master_Wait();
    I2C_Master_Write(0b00000000);   //Conversion register pointer + 0 (write)
    I2C_Master_Wait();
    I2C_Master_Write(0b10010001);   //ADS1115 address 0x48 + 1 (read)
    I2C_Master_Wait();
    int adc = I2C_Master_Read(0);
    //adc = adc << 8;
    //adc = I2C_Master_Read(0);
    return adc;
}[/code]
The main is simply a comparison between the value read (adc) and a threshold (which I varied to test the output, with no luck).
I think the code has no mistakes, as I followed the datasheets every step. (Steps for master receive for PIC16F877A attached too). So, what could be the problem? Do you know any debugging strategies that I can use?
Thank you in advance, and sorry for the long post!
 
PS: As the ADS1115 is a 16 bit ADC, but the SSPBUF is 8 bit, would it be correct to use the // lines in ADS1115_read()? I mean shifting the 8 MSB (sent first by the ADS1115 according to the datasheet) and then re-reading the buffer?
post edited by Roberto93 - 2018/05/03 10:08:09

Attached Image(s)

#1
qɥb
Monolothic Member
  • Total Posts : 3329
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: 16 bit I2C communication problem - PIC16F877A 2018/05/06 18:32:21 (permalink) ☄ Helpfulby Roberto93 2018/05/06 20:16:07
+1 (1)
It's a shame Microchip admins took so long to approve your first post.
Many people won't see it because it was so old by the time they did.
 
In that list you followed, step#5 says that the PIC receives the ACK status and saves it in the SSPCON2 register.
(They really should mention the bit by name, it is ACKSTAT)
What they don't make clear is that your software should check this bit to see if the Slave sent an ACK.
If it didn't, it is pointless proceeding any further, there's no-one listening.
So after this bit of code:
 
void ADS1115_config()
{
    I2C_Master_Write(0b10010000);   //Write to slave
    I2C_Master_Wait();

You should have
    if (SSPCON2bits.ACKSTAT)
    {    //1 => NAK
        //add some code here to indicate the chip is not responding, and return immediately.
    }

 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#2
qɥb
Monolothic Member
  • Total Posts : 3329
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: 16 bit I2C communication problem - PIC16F877A 2018/05/06 18:35:05 (permalink) ☄ Helpfulby Roberto93 2018/05/06 20:14:48
+1 (1)
FYI, your code tags did not work, because you should not have "/" in the opening tag, only the closing one.
 
I was going to PM you with other ways to get help while you were waiting for approval, but you have PMs from other members disabled in your personal settings.
 
Edit: fixed "\" to "/"
post edited by qɥb - 2018/05/06 20:18:55

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#3
Mysil
Super Member
  • Total Posts : 2887
  • Reward points : 0
  • Joined: 2012/07/01 04:19:50
  • Location: Norway
  • Status: offline
Re: 16 bit I2C communication problem - PIC16F877A 2018/05/06 20:08:03 (permalink)
+1 (1)
Hi,
There is at least one error in code shown in message #1.
In the function to Read from I2C slave:  ADS1115_read()
there must be Repeat Start signal before sending Read address:
unsigned int ADS1115_read(){
    I2C_Master_Write(0b10010000);   //ADS1115 address 0x48 + 0 (write)
    I2C_Master_Wait();
                                    /* Here Check that address was ACKnowledged by slave device. */
    I2C_Master_Write(0b00000000);   //Conversion register pointer + 0 (write)
    I2C_Master_Wait();
    I2C_RepeatStart();              /* Here must be Repeat Start signal,  */
    I2C_Master_Wait;                /* and corresponding wait. */
    I2C_Master_Write(0b10010001);   //ADS1115 address 0x48 + 1 (read)
    I2C_Master_Wait();
    unsigned int adc;
    adc = I2C_Master_Read(1);       /* This function must send ACK signal, ACKDT = 0; to continue transfer. */
    adc = adc << 8;
    adc = adc | I2C_Master_Read(0); /* This call must send NACK signal, ACKDT = 1; to terminate transfer. */
    I2C_Master_Stop();    /* Send Stop signal sequence, to release Bus and prepare for next transfer. */
    I2C_Master_Wait();    /* Wait for Stop signal sequence to complete. This may be postponed to before next transfer is to be started */
    return adc;
}

Then Start signaling is not as simple as you might think,
It is during Start signaling and Address transfer that disturbances and mistakes are encountered.
void I2C_Master_Start()
{
    I2C_Master_Wait();        /* Ensure that any previous transfer is completed. */
    if (SSPSTATbits.S != 0)   /* Check that I2C Bus is not occupied. */
    {           ....  };      /* Wait and test again, or Report error. */
    SEN = 1;             //Initiate start condition
    I2C_Master_Wait();        /* Wait for Start signal procedure. */
    if ( PIR1bits.BCLIF )     /* Check if Bus Collision have been observed. */
    {   PIR1bits.BCLIF = 0;
        ...    };             /* Back to square one. */
    if (SSPSTATbits.S != 1)   /* Check that Started state have been acheieved. */
    {    ...   }              /* Error handling. */

 
    Mysil
#4
Roberto93
New Member
  • Total Posts : 16
  • Reward points : 0
  • Joined: 2018/04/27 09:24:18
  • Location: 0
  • Status: offline
Re: 16 bit I2C communication problem - PIC16F877A 2018/05/06 20:19:25 (permalink)
0
Thanks for the replies! I'll activate the PM's for further posts and check the ACKSTAT bit to test aknowledge.
By the way, I tested the code tags the way you said and worked like a charm.
Thanks!
#5
Roberto93
New Member
  • Total Posts : 16
  • Reward points : 0
  • Joined: 2018/04/27 09:24:18
  • Location: 0
  • Status: offline
Re: 16 bit I2C communication problem - PIC16F877A 2018/05/06 20:28:14 (permalink)
0
Thanks for the help! I'll test it again with the changes!
#6
MarcoRM
New Member
  • Total Posts : 5
  • Reward points : 0
  • Joined: 2018/11/05 12:10:58
  • Location: 0
  • Status: offline
Re: 16 bit I2C communication problem - PIC16F877A 2018/11/07 16:41:02 (permalink)
0
Dear sir:
 
How did you resolve this problem?, I'm trying to do the same but I don't understand how to take the data from ads1115 and insert it into a vector in main function. I want to send it to pc via usart, I can do that but I don't know how to take data before. I will appreciate any help.
 
Thanks
#7
Aussie Susan
Super Member
  • Total Posts : 3355
  • Reward points : 0
  • Joined: 2008/08/18 22:20:40
  • Location: Melbourne, Australia
  • Status: offline
Re: 16 bit I2C communication problem - PIC16F877A 2018/11/07 18:27:32 (permalink)
+2 (2)
Marco - please do not hijack an old thread. Start a new one tells us the problem, what you have done, what you expected ad what you get.
Also I suspect that your question has little to do with the subject matter of this thread (analog peripherals) although it does reference data from an ADC. Try in the I2C forum (if it really is I2C related) probably in the XC8 forum or PIC16/18 forum as I suspect it is all about how to program (i.e. create a vector and write to it) rather than interact with the ADC itself.
Susan
#8
Jump to:
© 2018 APG vNext Commercial Version 4.5