Electronic – bitbanging i2c problem with ACK from slave

bit-bangembeddedi2cserial

I am trying to implement bit-banging i2c to communicate between an atmega128A's GPIO and an SHT21 (I2C bus was used for some other devices). The first task is to send a write sequence to the SHT21. Using an oscilloscope, I can see that the sequence sending out from the atmega has the correct start signal, correct order of bits, correct stop signal, signal levels looks correct. The serial analyzer from the scope reads out correct I2C message: S80W~A (SHT21 address is 0x80, writing so last bit is 0). Yet there is not any ACK response from the SHT21. The SDA and SCL are both pulled up to 3.3V via 6.7K resistors.

I really need help finding out what is wrong.

code sending the first byte repeatly if no ACK receive:

 i2c_start();
  while(!i2c_send(0x80)){
    i2c_stop();
    i2c_start();
  }

code of i2c protocol:

void i2c_start ()
{
    // Pull data high and sck low to ensure transition of start sequence
    DATA_HIGH ();

    SCK_HIGH ();
    DATA_LOW ();
    SCK_LOW ();
}
void i2c_stop ()
{
    DATA_LOW ();
    SetBit (DDRD, 7);
    //pull data high while clck is high to end transmission.
    SCK_HIGH ();
    DATA_HIGH ();
}

uchar i2c_send (uchar command)
{
    uchar i;

    for (i = 0; i < 8; i++)     // Send command
    {


        if ((command & 0x80) == 0x80)
            DATA_HIGH ();
        else
            DATA_LOW ();
        SCK_LOW ();
        SCK_HIGH ();
        SCK_LOW ();

        command = command << 1;
    }

    Delay(5);
    ClrBit (DDRD, 7);       // Change Data Direction
    //SetBit (PORTD, 7);      // Turn on internal pull-up

    //SCK_LOW ();
    SCK_HIGH ();

    if (!CheckBit (PIND, 7))     // Read ACK
    {
        SCK_LOW ();
        SetBit (DDRD, 7);
        return 1;
    }
    else
    {
        SCK_LOW ();
        SetBit (DDRD, 7);
        return 0;               // NO ACK
    }

}

Best Answer

Per your comment, your GPIO pins are not open-collector but are forcing both high and low. I2C requires open-collector on both the clock and data lines. Without this, the slave cannot, for example, ACK by pulling the data line low (since the master is actively pulling it high).

If you cannot set open-collector mode, another way is to leave the output data bit low and switch the pin mode between output (low) and input (effectively open-collector).

Related Topic