This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

I2C SDA stuck low code for TM4C129/Tivaware

Hi,

Does anyone has C code to get the I2C/SDA line unstuck?

There are many suggestions and code on the different forums, but I would like to have one has been tested and used TivaWare commands (I2CMasterDataPut, I2CMasterDisable...)

thanks.

Khaled.

  • Hello Khaled

    The question to ask is why is the SDA line getting stuck if the transactions are happening? Can you please explain the use of the I2C with the slave device which causes the SDA to get stuck?
  • Hi Amit,
    As far as I can tell, The Master/Cortex is not waiting enough for the Slave/Sensor to complete. The Master/Cortex assumes that the Slave/Sensor is not present and tries to terminate the transaction too early.
    I could wait long, but its difficult to assess the time needed by the Slave/Sensor to complete. Thus I would like to have backup code that will get the bus unstuck.

    Khaled.
  • Hello Khaleed,

    Can you please point me to the slave device datasheet to see why the slave is not releasing the SDA line? do note that there is a clock low timeout which may be triggering if the slave takes too long.
  • Datasheet-TemperatureHumiditySensor.pdfHi Amit,

    The sensor is for temperature and humidity (Si7020-A10).

    The Humidity sensor take long time to finish and the only way to make sure that its done is to increase the wait time.

    Khaled.

  • The only way I know/heard of is to re-initialize the I2C pins as OD - GPIOs, and then manually clocking the SCL line until the slave releases SDA.
    This assumes the slave got stuck, and is in an unknown state.
    Does the TM4C support clock stretching in a proper way ? I never tried this, and the slave spec. mentions it explicitly.
    Anyway, I would try reducing clock rate first.
  • Hello Khaled,

    I would suggest first programming the Clock Low Timeput value to the maximum value possible. If the Slave still holds the SDA low, then configure the SCL pin in GPIO Open Drain mode and toggle the GPIO to force a Stop condition on the bus.
  • Hi Amit,
    I did that and I can get it to work.
    But, since this is happening very infrequently, I wanted to keep the timeout value to minimum and if the bus get stuck, then, if needed, execute the code to get it unstuck.

    My current, unstuck code consist on configuring the pin as an output GPIO (as f.m. and your self suggested), toggle the SCL 9 times, then switch back to I2C pin configuration.

    SysCtlPeripheralDisable(SYSCTL_PERIPH_I2C2);

    GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_1);
    GPIOPinTypeGPIOInput( GPIO_PORTN_BASE, GPIO_PIN_4);
    for(i = 0; i < 9; i++) {
    SysCtlDelay(gSysCtlClock * 5e-6); //wait 5us
    GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_1, 0x00); //SCL
    SysCtlDelay(gSysCtlClock * 5e-6); //wait 5us
    GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_1, 0xFF); //SCL
    SysCtlDelay(gSysCtlClock * 5e-6); //wait 5us
    }
    GPIOPinConfigure(GPIO_PL1_I2C2SCL); //I2C2 SCL
    GPIOPinConfigure(GPIO_PN4_I2C2SDA); //I2C2 SDA
  • Hello Khaled

    One strong care-about. When configuring the I2C IO's under GPIO control, GPIOPinTypeGPIOOutput is not the correct option. You must use GPIOPinTypeGPIOOutputOD as the bus is a open drain. Having a drive of 1 on a stuck condition would cause excessive current drain through the IO.
  • Hi Amit,
    I will make the change to GPIOPinTypeGPIOOutputOD.
    thanks.
    Khaled.
  • Hello Khaled

    Also, do make sure that Timeout condition is correctly set to the largest possible value to meet the slave device requirement. If that does not suffice, the other solution may be to check for a suitable slave device which meets the spec or move to I2C over bit banged IO's...
  • I2C bit banging is out of the question. Its going to be another can of worms and I don't want to open it!
    I extended the time and added the recovery code. I hope that should be enough.
    thanks Amit.
    Khaled.
  • Hi Amit & others,

    Would it not prove wise to add a peripheral reset of the I2C module during poster's recovery code?

    Over time - when multiple such recoveries occur - I believe there is (some) chance for the peripheral to "get out of order" and the peripheral reset returns the module to "normal."

  • Hello cb1

    Yes, if the stuck condition is at the I2C master. The right process in that case would be to call the Init routine which must be

    1. Disable, Reset and Enable the I2C module instance
    2. Check the IO state using the I2CMBMON.
    3. If stuck then perform SCL IO configuration to OpenDrain Output mode and toggle the SCL and configure the IO back to I2C mode,
    4. If still stuck, power cycle/reset the slave device if a provision is provided when designing the board.
  • Yes Amit, the completeness of your response is "best yet." (and by far)

    When the poster calls for "recovery" - I believe the thoroughness of your listing proves "best practice."