• AVR Freaks

Hot!PIC18: I2C read - BF not cleared after reading SSPBUF

Author
navado
New Member
  • Total Posts : 3
  • Reward points : 0
  • Joined: 2018/07/14 03:07:45
  • Location: 0
  • Status: offline
2020/09/11 05:15:49 (permalink)
0

PIC18: I2C read - BF not cleared after reading SSPBUF

I'm trying to bring up I2C on MSSP2 on PIC18F66k40 to read fuel gauge and RTC chip.
 
During the read, after sending control addresses sequence , reading the first byte returns the read address. It seems that I'm forgeting something preparing to read the byte, but cannot figure out what's exactly.
 
Solution, Ideas or pointer to proper documentation, example, etc. appreciated.

The code below:

#include <xc.h>
#include "pic18_i2c.h"

void pic18_i2c_enable(void) {
    TRISD |= 0b11000000; //our MMSP2 uses RD7 as SCL, RD6 as SDA, both set as inputs
    SSP2DATPPS = 0x1E; // RD6
    SSP2CLKPPS = 0x1F; // RD7
    RD7PPS = 0x1C; // MSSP2 SDA
    RD6PPS = 0x1B; // MSSP2 SCL
    SSP2ADD = 39; //400kHz with 64MHz clock
    SSP2CON1bits.SSPM = 0b1000; //I2C Master mode
    SSP2CON1bits.SSPEN = 1; //Enable MSSP
}

void pic18_i2c_disable(void) {
    SSP2CON1bits.SSPEN = 0; //Disable MSSP
}

int8_t pic18_i2c_read(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint16_t length) {
    SSP2CON2bits.SEN = 1;
    while (SSP2CON2bits.SEN == 1);
    SSP2BUF = slave_addr << 1;
    while (SSP2STATbits.R_W);
    if (SSP2CON2bits.ACKSTAT) goto i2c_rx_err;
    
    SSP2BUF = reg_addr;
    while (SSP2STATbits.R_W);
    if (SSP2CON2bits.ACKSTAT) goto i2c_rx_err;
    SSP2CON2bits.RSEN = 1;
    while (SSP2CON2bits.RSEN);
    SSP2BUF = (slave_addr << 1) + 1; //address with R/W set for read
    while (SSP2STATbits.R_W);
    if (SSP2CON2bits.ACKSTAT) goto i2c_rx_err;
    while (length > 0) {
        SSP2CON2bits.RCEN = 1;
        while (!SSP2STATbits.BF);
        *data = SSP2BUF; // ----------------> Here SSP2STATbits.BF not cleared, SSP2BUF contains device address with read bit
        if (length > 1) {
            SSP2CON2bits.ACKDT = 0;
        } else {
            SSP2CON2bits.ACKDT = 1;
        }
        SSP2CON2bits.ACKEN = 1;
        while (SSP2CON2bits.ACKEN); // ------------------> And the program is stuck forever here, ACK not sent
        --length;
        ++data;
    }
    SSP2CON2bits.PEN = 1;
    while (SSP2CON2bits.PEN);
    return 0;
i2c_rx_err:
    SSP2CON2bits.PEN = 1;
    while (SSP2CON2bits.PEN);
    return -1;
}

#1

5 Replies Related Threads

    ric
    Super Member
    • Total Posts : 28677
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: PIC18: I2C read - BF not cleared after reading SSPBUF 2020/09/11 17:46:42 (permalink)
    +2 (2)
    Are you single stepping this code in the debugger while watching the SSPBUF register?
    The debugger reading a register is the same as your code reading the register. Reading SSPBUF after every instruction WILL disrupt the sequence.
    I am not sure how this generates exactly what you observe, but I would try it again with no watch windows open.
     
    (Oh and congratulations. This is just about the first time I have seen a new user ask about I2C who is actually doing everything correctly in the code!)
     

    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!
    #2
    navado
    New Member
    • Total Posts : 3
    • Reward points : 0
    • Joined: 2018/07/14 03:07:45
    • Location: 0
    • Status: offline
    Re: PIC18: I2C read - BF not cleared after reading SSPBUF 2020/09/14 01:27:25 (permalink)
    0
    Of cause not.
    I look at the *data when the code paused on while (SSP2CON2bits.ACKEN);
    (Oh and congratulations. This is just about the first time I have seen a new user ask about I2C who is actually doing everything correctly in the code!) 
    Thanks, most of this code is derived from another library somewhere on Github, but also was not working as is. I afraid that I may miss-configure MSSP and it does something that I don't understand.
    post edited by navado - 2020/09/14 01:33:59
    #3
    navado
    New Member
    • Total Posts : 3
    • Reward points : 0
    • Joined: 2018/07/14 03:07:45
    • Location: 0
    • Status: offline
    Re: PIC18: I2C read - BF not cleared after reading SSPBUF 2020/09/14 01:29:29 (permalink)
    0
     As I understand from the documentation SSP2CON2bits.RCEN = 1; may have no effect if MSSP doesn't detect that the I2C is IDLE but I'm not sure what condition to enforce and what else should be handled between write of the address and the read
    #4
    cabletie
    Starting Member
    • Total Posts : 42
    • Reward points : 0
    • Joined: 2011/07/02 06:21:46
    • Location: Zulu -5
    • Status: offline
    Re: PIC18: I2C read - BF not cleared after reading SSPBUF 2020/09/27 07:02:37 (permalink)
    0
    edit: add development environment.  edit2: added I2C command(s) code and a L.A. screen shot.
    Development Environment: MPLABX 5.35, XC8 2.00, PIC18LF2580
     
    If I read this post correctly, I think I am experiencing the same issue.
    I overcame it by adding an additional read between the slave read command
    and performing the read_device_byte() command.  But is this the way things
    are supposed to work?  The slave datasheet (NT3H2211) seems to indicate
    -> perform the slave read command
    -> read_device_byte
      when I do this then I get the slave read command address in the buffer.
    (returned from the slave as Data0    (or is it the 2580 ??)  )
    the command function(s) code:

    // I2C
    void wait_for_idle(void) {
    //        ACKen/RXen/Pen/RSen/Sen
        while ( ( SSPCON2 & 0x1F ) || (SSPSTAT & 0x04));
        PIR1bits.SSPIF = 0x0;
        SSPCON1bits.WCOL = 0x0;
    };

    void start(void) {// Start I2C comm's
        wait_for_idle();
        SSPCON2bits.SEN = 0x1;
    };

    // Stop I2C comm's
    void stop(void){
        wait_for_idle();
        SSPCON2bits.PEN = 0x1;
    };

    // write address constants: write(slave_R); write(SRAM_BLK) *OR* data bytes
    void write(unsigned char in_byte) {
        wait_for_idle();
        SSPBUF = in_byte;
    };

    //  returns one byte. Call it in a loop, 2211 returns 16 bytes per block.
    unsigned char read_device_byte(void) {
        volatile unsigned char in_data;
        wait_for_idle();
        SSPCON2bits.RCEN = 0x1;
        in_data = SSPBUF;
        wait_for_idle();
        SSPCON2bits.ACKDT = 0x0;  // have to set the ack bit
        SSPCON2bits.ACKEN = 0x1;  // then initiate the acknowledge
       return(in_data);
    };

     
    here is my code example:

    for (dev_addr=0xf8; dev_addr<=0xfb; dev_addr++) {
         start();
         write(0xaa);      // slave address write mode
         write(dev_addr);  // point to SRAM block.
         stop();
         i = dly_cntr_R;
         while (i > 0x0) {i--;}; // need >= ~50usec delay here
         start(); // slave imposed >50usec delay before start
         write(0xab);

        // 0xAB IN SSPBUF ??
         read_device_byte(); // EXTRA READ TO CLEAR BUFFER
        // NOW CANNED_DATA GETS POPULATED CORRECTLY
                    
         for (i = 0x00; i < 0x10; i++) {
             canned_data[offset][i] = read_device_byte(); };
         stop();
         offset++;
    };
                    

     
    Logic analyzer screen shot:

    post edited by cabletie - 2020/09/28 05:47:53

    Attached Image(s)

    #5
    cabletie
    Starting Member
    • Total Posts : 42
    • Reward points : 0
    • Joined: 2011/07/02 06:21:46
    • Location: Zulu -5
    • Status: offline
    Re: PIC18: I2C read - BF not cleared after reading SSPBUF 2020/10/17 10:53:19 (permalink)
    0
    @navado
    I am curious, have you made any progress with your experience?
    #6
    Jump to:
    © 2020 APG vNext Commercial Version 4.5