Search code examples
cembeddedmicrocontrolleri2cpic18

I2C is not working, slave is not acknowledging. after receiving address


As a beginner I am trying to send data between two pic18f4550 where master sends and slave receives data and prints data bits on LED(PORTD). But I don't know where the issue is, the slave is not acknowledging and data is not transferred.

    //==================== Master I2C code=========================
    bit I2C_Write(unsigned char address, unsigned char \*data, unsigned char datasize) {
        SSPCON2bits.SEN = 1; //  Initiate Start condition on SDA and SCL pins. Automatically cleared by hardware
        while (!SSPIF);
        PIR1bits.SSPIF = 0;
        LED1 = 1;
        
        SSPBUF = address;
        while (!SSPIF);
        PIR1bits.SSPIF = 0;
        LED2 = 1;  /// ---------------> This turns ON 
        if (SSPCON2bits.ACKSTAT) {
            SSPCON2bits.PEN = 1;
            while (PEN);
            ACK = 1;
            return WriteSuccessful = 0;
        }             
        LED3 = 1; /// -----------------> but This remains off
        int i;
        for (i = 0; i < datasize; i++) {
            SSPBUF = *data;
            while (!SSPIF);
            PIR1bits.SSPIF = 0;
        
            if (SSPCON2bits.ACKSTAT) {
                SSPCON2bits.PEN = 1;
                while (PEN);
                ERROR = 1;
                return WriteSuccessful = 0;
            }
            LED = *data;
            data++;
        }
        LED4 = 1;
        
        PEN = 1; // I2C Stop
        while (PEN);
        PIR1bits.SSPIF = 0;
        
        return WriteSuccessful = 1;

    }

    //-----here is i2c initalization---------
    void I2C_INIT(void) {
        SDA_dir = 1;
        SCL_dir = 1;
        ADCON1bits.PCFG = 0b1111;

        SSPADD = _XTAL_FREQ / (4 * (Baud_Rate)) - 1;
        SSPSTATbits.SMP = 0; // Slew rate control disabled for Standard Speed mode (100 kHz and 1 MHz)
        SSPCON1bits.SSPEN = 1;
        SSPCON1bits.SSPM = 0b1000; //  I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))(2,3)

    )

    //------- i2c master call--------
    unsigned char data\[5\] = {0xA1, 0xB1, 0xC1, 0xD1, 0xE1};
    I2C_Write(0b00111100, data, 5);

In the slave I only use ISR to read SSPBUF:

    //=======================Slave I2c code===========================

    void __interrupt() ISR(void) {
        if (PIR1bits.SSPIF) {
            if (SSPSTATbits.D_NOT_A) {
                // This means the received byte is data
                Read_data = SSPBUF; // Read the received data
                LED = Read_data;  //-----------------------\> these remains blank!
            } else if (!SSPSTATbits.D_NOT_A) {
                MATCH = 1;    //----------------------------\> This Turns On
            }
            PIR1bits.SSPIF = 0;
        }
    }

    //--------slave init---------------------
    void I2C_INIT(void) {
        SDA_dir = 1; //
        SCL_dir = 1; //
        ADCON1bits.PCFG = 0b1111;

        SSPADD = 0b00111100; // Writing address for slave mode
        SSPSTATbits.SMP = 1; // Slew rate control disabled for Standard Speed mode (100 kHz and 1 MHz)
        
        SSPCON1bits.SSPEN = 1; //
        // SSPCON1bits.SSPM = 0b1000; //  I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))(2,3)
        SSPCON1bits.SSPM = 0b1110; //I2C Slave mode, 7-bit address with Start and Stop bit interrupts enabled(2)
        SSPCON2bits.ACKEN = 1;
    }

I tried to send data via I2C protocol between two pic18f4550 devices, and it failed i.e slave is not sending acknowledge bit. It slows address matched!


Solution

  • This Problem has been resolved

    Here are the identified issues and their solutions:

    For the Master:

    1. Disable Slew Rate Control for Standard Speed mode (100 kHz and 1 MHz) by setting it to '1'.
    2. There's no need to enable ACKEN for sending data.
    3. Avoid sending data in a loop if RSEN (Repeated Start) is not enabled. It's good practice to call a function like 'tx_data' from another function.
    4. Always double-check the address of the slave to which you want to send data.
    5. If you use left shift in the address, make sure to consider it when addressing the slave.
    6. Disable the Watchdog Timer (WDT) if it's not needed.
    7. Enable LVP (Low Voltage Programming) if required.

    For the Slave:

    1. Verify the address in the slave to ensure it matches the expected address.
    2. Disable Slew Rate Control for Standard Speed mode (100 kHz and 1 MHz) by setting it to '1'.
    3. There's no need to use 'ACKEN' in the slave code, as the slave automatically sends ACK/NACK to the master.
    4. Enable interrupts in the slave code to handle incoming data or events.
    5. In the Interrupt Service Routine (ISR), check if SSPOV (Receive Overflow) or WCOL (Write Collision) occur. You can connect LEDs to indicate these conditions.
    6. Use clock stretching in the ISR to ensure that data is processed correctly, and release it at the end of the ISR.
    7. Utilize the R_nW (Read/Write) and D_NOT_A (Data/Address) bits in the ISR to determine the operation being performed.

    Important Note:

    1. Make New project: I cleaned and built the same projects again and again over 50 times and removed some files from my project in MPLAB X IDE but when I saw the folder, it was still there. then I created a new project and it pasted the only files I wanted to build and it worked in proteus
    2. Use Protues Debugger for debugging

    You can find the updated code in my repository at Github

    If anyone finds any errors or has additional insights, please feel free to provide corrections or suggestions, as I am a student and a beginner. Your feedback is valuable!