• AVR Freaks

Hot!I2C Read with PIC16LF1827

Author
grmcwilliams
New Member
  • Total Posts : 27
  • Reward points : 0
  • Joined: 2009/04/30 06:07:37
  • Location: 0
  • Status: offline
2021/01/19 08:14:12 (permalink)
0

I2C Read with PIC16LF1827

I am working to get the I2C Master Mode Reception sequence to work and I am having some difficulties with my code. I am following section "25.6.7.4 Typical Receive Sequence" from this datasheet. I am able to successfully transmit code and get ACKs from my slave device so I feel very confident that I have configured the MSSP1 device correctly. 
 
I am having difficulties with the first ACK after I read the register from my slave device. The master device first writes <0xEC><0x40> to the slave to initiate a pressure conversion in the sensor. Then I write a <0xEC><0x00> to initiate an ADC read sequence (see page 14 of MS8607-02BA01 datasheet for specifics). Finally, I write <0xED> to initiate the read from ASIC. I get my first 8 bits of data and then the master responds with a NACK. The funny thing is that the 9th clock cycle for the ACK/NACK cycle does not happen the first time I set the ACKEN bit. I have attached a screen shot of a logic analyzer showing the I2C messages between master and slave.
 
Is there anything that might cause the first ACK to not happen? 
 
 

Attached Image(s)

#1

6 Replies Related Threads

    grmcwilliams
    New Member
    • Total Posts : 27
    • Reward points : 0
    • Joined: 2009/04/30 06:07:37
    • Location: 0
    • Status: offline
    Re: I2C Read with PIC16LF1827 2021/01/19 08:17:23 (permalink)
    +1 (1)
    The forum does not like me posting the i2c_receive function so I tried to attach my main.c file to this post 
    #2
    grmcwilliams
    New Member
    • Total Posts : 27
    • Reward points : 0
    • Joined: 2009/04/30 06:07:37
    • Location: 0
    • Status: offline
    Re: I2C Read with PIC16LF1827 2021/01/22 07:12:17 (permalink)
    0
    Anyone able to help me with this issue? I can't figure out why my design won't ACK the first databit from the pressure temp sensor. 
    #3
    KTrenholm
    Super Member
    • Total Posts : 830
    • Reward points : 0
    • Joined: 2012/08/08 14:04:23
    • Location: Connecticut, USA
    • Status: offline
    Re: I2C Read with PIC16LF1827 2021/01/22 13:00:54 (permalink)
    0
    Just providing a second set of eyes, your code to read and ack/nack a byte from the slave device looks OK to me.  The code I typically use for my PIC24 projects differs only in that I wait for RBF (Receive Buffer Full, on PIC24, I think your device only has a single BF - Buffer Full status bit) as well as the interrupt flag before reading the byte in.  No errata on this part for the MSSP either.  Maybe someone else knows if there's some secret I2C sauce for this PIC.
     
    I've run into problems with using the hardware I2C on PIC parts that seem to crop up for no reason, and my solution usually ends up being to switch over to some bit-banged I2C to see if it changes anything.  I've attached the code I use for bit-banged I2C (Start/Stop/Byte Read/Byte Write) if you would like to give it a shot and see if it changes anything for you.
     
     
    /*Modify these to your SDA/SCL pins*/
    #define SCL TRISBbits.TRISB8 //I2C clock out
    #define SDA TRISBbits.TRISB9 //I2C data out
    #define SCL_IN PORTBbits.RB8 //I2C clock in
    #define SDA_IN PORTBbits.RB9 //I2C data in
    #define SCL_OUT LATBbits.LATB8 //Set to zero to enable I2C system
    #define SDA_OUT LATBbits.LATB9 //Set to zero to enable I2C system
    #define I2C_DELAY __delay_us(10); //100KHz --Ensure _XTAL_FREQ is defined for built in delay functions to work in XC8
     
    /**************************************************************
     * FUNCTION: Init_I2C
     * PURPOSE: Initializes I2C lines to idle state
     **************************************************************/
    void Init_I2C(void){
         SDA = 1;
         SCL = 1;
         SCL_OUT = 0;
         SDA_OUT = 0;
    }


    /**************************************************************
     * FUNCTION: I2C_Start
     * PURPOSE: Asserts a "Start" Condition on the I2C Bus.
     **************************************************************/
    void I2C_Start(void){
         //Bit-Banged I2C Start Condtion
         SDA = 1; //tristate data bus
         I2C_DELAY;
         SCL = 1; //tristate clock to set it to 1
         I2C_DELAY;
         SDA = 0; //set data low, indicates start condition with clock high
         I2C_DELAY;
         SCL = 0; //set clock low
         I2C_DELAY;
    }

    /**************************************************************
     * FUNCTION: I2C_Restart
     * PURPOSE: Asserts a "Restart" Condition on the I2C Bus.
     **************************************************************/
    void I2C_Restart(void){
        SCL = 0; // Set clock line low
        SDA = 1; // Set data line high
        SCL = 1; // Set clock line high
        I2C_DELAY;
        SDA = 0; // Set data line low (START SIGNAL)
        I2C_DELAY;
        SCL = 0; // Set clock line low
     I2C_DELAY;
    }

    /**************************************************************
     * FUNCTION: I2C_Stop
     * PURPOSE: Asserts a "Stop" Condition on the I2C Bus.
     **************************************************************/
    void I2C_Stop(void){
     I2C_DELAY;
     SDA = 0;
     I2C_DELAY;
     SCL = 1;
     I2C_DELAY;
     SDA = 1;
     I2C_DELAY;
    }

    /**************************************************************
     * FUNCTION: I2C_Write
     * PURPOSE: Writes a single byte to the I2C Bus.
     * - Waits for completion of transmission before continuing.
     * ARGS: uint8_t byte -> Byte to be sent
     * RETURNS: uint8_t -> ACK bit. 0 = ACK
     * 1 = NACK
     **************************************************************/
    uint8_t I2C_Write(uint8_t byte){
        uint8_t x;
        static uint8_t b;

        SCL = 0;
      
        for(x=8; x; x--)
        {
       
            if(byte&0x80){
                SDA = 1;
            } else {
                SDA = 0;
            }
             I2C_DELAY;
             SCL = 1;
             byte <<= 1;
             I2C_DELAY;
             SCL = 0;
        }
      
        SDA = 1;
        I2C_DELAY;
        SCL = 1;
        I2C_DELAY;
        b = SDA_IN; // Read ACK bit
        SCL = 0;
        return b;
    }

    /**************************************************************
     * FUNCTION: I2C_Read
     * PURPOSE: Reads a single byte from I2C Bus.
     * - Waits for completion of transmission before continuing.
     * ARGS: uint8_t ack -> 1 = ACK the incoming byte (will be requesting more data)
     * 0 = NACK the incoming byte (final byte in transmission)
     **************************************************************/
    uint8_t I2C_Read(uint8_t ack){
     char x, d=0;
     SDA = 1; //Tristate data line
     SCL = 0; // Clock low
       
     for(x=0; x<8; x++)
     {
      I2C_DELAY;
      d <<= 1;
      
      do
      {
       SCL = 1; //Clock high
      } while(SCL_IN==0); // wait for any SCL clock stretching
      
      I2C_DELAY;
      
      if(SDA_IN){
       d |= 1;
      }
      
      SCL = 0; //Clock low
     }
       
     if(ack){
      SDA = 0; // Set ACK response
     } else {
      SDA = 1; // Set NAK response
     }
       
     I2C_DELAY; //At least this low time
     SCL = 1; // Clock high
     I2C_DELAY; // send (N)ACK bit
     SCL = 0; // Clock low
     SDA = 1; // Tristate data line
     return d;
    }

    post edited by KTrenholm - 2021/01/22 13:35:29
    #4
    KTrenholm
    Super Member
    • Total Posts : 830
    • Reward points : 0
    • Joined: 2012/08/08 14:04:23
    • Location: Connecticut, USA
    • Status: offline
    Re: I2C Read with PIC16LF1827 2021/01/22 13:22:27 (permalink)
    +1 (1)
    I also found this weirdness in the MS8607-02BA01 datasheet:

    It looks like it's expecting the I2C slave device to ack all the data bytes, not just the address (and also showing a 0 for the nack at the end?).  This has got to be an error in the datasheet right?
     

    Attached Image(s)

    #5
    grmcwilliams
    New Member
    • Total Posts : 27
    • Reward points : 0
    • Joined: 2009/04/30 06:07:37
    • Location: 0
    • Status: offline
    Re: I2C Read with PIC16LF1827 2021/01/22 13:37:31 (permalink)
    0
    Thanks KTrenholm,
     
    I will check out this bit bang version of I2C. You know I hadn't noticed that the Slave was supposed to be ACKing per the sensor datasheet. I'm also going to try just initiating the RCEN bit 3 times and see if that works. Thanks for pointing that out!
     
    Greg
    #6
    ric
    Super Member
    • Total Posts : 29861
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: I2C Read with PIC16LF1827 2021/01/22 14:09:00 (permalink)
    0
    KTrenholm
    I also found this weirdness in the MS8607-02BA01 datasheet:

    It looks like it's expecting the I2C slave device to ack all the data bytes, not just the address (and also showing a 0 for the nack at the end?).  This has got to be an error in the datasheet right?

    Agree.
    Only the first (address) ACK cycle should be grey, the next three should be white.
    The text in the grid correctly shows "N" for the last one, but the value row above incorrectly shows "0" rather than "1" for the "N".
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #7
    Jump to:
    © 2021 APG vNext Commercial Version 4.5