cancel
Showing results for 
Search instead for 
Did you mean: 

I2C errors handling in EFT

sireevenkat1
Senior

 

Hi,I am working with stm32g491re.I am communicating with TCA9537(Ioexpander) from stm32 through I2C. It will control a realy. For my product EFT(Electrical Fast Transient) testing, After starting EFT teat relay getting turned off and not recovering.

Through oscilloscope we observed, after EFT test,sclk and sda lines not recovering

Io expander it self resetting.master and slave both side issues are there.so I tried below code.

So i modified the code.

 

 

 

void ioexpandercheck(){ 

		uint8_t check[1]; 

		HAL_StatusTypeDef status=tca9537_read(&hmcp, TCA9537_REGISTER_INPUT,check); 

		HAL_Delay(10); 

		if(status!=HAL_OK){ 

			HAL_I2C_DeInit(&hi2c3); 

			HAL_Delay(10); 

			HAL_I2C_Init(&hi2c3); 

			HAL_Delay(50); 

			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, 0); 

			HAL_Delay(5); 

			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, 1); 

			HAL_Delay(5); 

			tca9537_init(&hmcp, &hi2c3, TCA9537_I2C_ADDR); 

			tca9537_iodir(&hmcp, TCA9537_CONFIG_IO12_OUTPUT); 



		} 

} 

 

Here continuously I am reading the expander pin if read is not ok I am resetting both I2C and ioexpander and reinitializing the ioexpander. With this i can able to recover the relay operation in EFT but its not stable.
In above ioexpander reset i done using reset pin of ioexpander.Which is not part of our present h/w set up.We made it now gor testing is there any other way can we reset instead of using reset pin.

 

In datasheet also they mentioned how to do with software.but i am conused about implementation.

Since I am reinitializing the i2c in above code,i2c lines are active so,can I do softreset
Can anyone suggest.

sireevenkat1_0-1724937646761.png

 

uint8_t reset_command = 0x06;  
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(&hi2c3, 0x00, &reset_command, 1, 100);

 

Thanks

6 REPLIES 6
Karl Yamashita
Lead III

Sounds like what you're doing is a band aid. 

Unless there is a HW issue, it's very rare that an I2C bus would lock up and need resetting. 

  • Are there other devices on the same I2C bus? It would help to see a schematic of your connections, including pull-ups.
  • Are you using polling or interrupt when reading the I/O expander? How often are you reading the I/O expander to check the GPIO status?
  • is ioexpandercheckIs() the actual function to check the I/O status or is it just to check if the I/O expander is communicating? I can't tell what tca9537_read() is doing. If not, we need to see the rest of the code.  
If smoke escapes your device, put the smoke back in. It'll still work as a conversation piece. If you find my answers useful, click the Accept as Solution button so that way others can see the solution.
TDK
Guru

Agree with what @Karl Yamashita has to say except that this is during EFT testing, so errors due to spikes on the line are somewhat more expected.

 

The following situations can happen:

  • Both SDA and SCL are held low by a slave--should never happen, no recovery mechanism other than power cycle.
  • SCL held low--should rarely happen, indicates slave is stretching the clock, which is allowed in I2C but has limits in SMBUS. If slave doesn't release the line, there is no recover other than a power cycle.
  • SDA held low--by far the most likely of these scenarios. Can happens if transients occur on SCL line and slave is stuck mid-transaction while the master thinks the transaction is complete.
  • And potentially: Master I2C state is misbehaving (but slaves are fine) due to inadequate code and/or complicated and misunderstood peripheral details. One solution is to de-initialize and re-initialize the peripheral and hi2cx software state machine.

 

To recover from a situation in which SDA is stuck low:

  • Deinitialize the I2C peripheral.
  • Re-initialize the SDA pin as a GPIO open-drain output.
  • Send 9 negative-going pulses on this line with a frequency of 100 kHz or less.
  • Re-initialize the SDA pin as an I2C pin and re-intiailize the I2C peripheral.

You are not doing step 2 or step 3 here. You cannot send pulses while the pin is still initialized in I2C mode.

 

The software reset mechanism involves a normal write transaction to the chip, which is not possible when SDA is held low, so it can't help you here. However, if you bus is functioning normally, send a single 0x06 byte to the 0x00 slave address to reset the chip.

 

uint8_t data = 0x06;
HAL_I2C_Master_Transmit(&hi2cx, 0x00 << 1, &data, 1, HAL_MAX_DELAY);

 

 

If you feel a post has answered your question, please click "Accept as Solution".

Hi @Karl Yamashita ,


@Karl Yamashita wrote:

Unless there is a HW issue, it's very rare that an I2C bus would lock up and need resetting. 


I checked with Hardware team ,they are saying no hardware issue. So, that's why I am trying to 


  • Are there other devices on the same I2C bus? It would help to see a schematic of your connections, including pull-ups.

No other devices on the I2C bus, only one slave (Ioexpander).

  • Are you using polling or interrupt when reading the I/O expander? How often are you reading the I/O expander to check the GPIO status?


I am using polling only when reading the expander. Aroung 100msec delay I am reading the ioexpander pin.


  • is ioexpandercheckIs() the actual function to check the I/O status or is it just to check if the I/O expander is communicating? I can't tell what tca9537_read() is doing. If not, we need to see the rest of the code.  

ioexpandercheckIs() function is to check ioexpander is communicating with stm32 or not .This I implemented for EFT.
tca9537_read(): function reads the input pin  value.

Thanks




 

Hi @TDK ,
Thanks for suggestion.


To recover from a situation in which SDA is stuck low:

  • Deinitialize the I2C peripheral.
  • Re-initialize the SDA pin as a GPIO open-drain output.
  • Send 9 negative-going pulses on this line with a frequency of 100 kHz or less.
  • Re-initialize the SDA pin as an I2C pin and re-intiailize the I2C peripheral.

 

void I2C_Recovery_SDA_Stuck() {
    // 1. Deinitialize the I2C peripheral
    HAL_I2C_DeInit(&hi2c3);

    // 2. Re-initialize the SDA pin as a GPIO open-drain output
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    // 3. Send 9 clock pulses on SDA with a frequency of 100 kHz or less
    for (int i = 0; i < 9; i++) {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);
        HAL_Delay(1);  // Pulse LOW (1 us for ~100 kHz)
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);
        HAL_Delay(1);  // Pulse HIGH (1 us for ~100 kHz)
    }

    // 4. Re-initialize the SDA pin as an I2C pin
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;    // Alternate function open-drain mode for I2C
    GPIO_InitStruct.Pull = GPIO_PULLUP;        // Pull-up resistor for I2C
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // High speed for I2C
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C3; // Set alternate function for I2C3
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    // 5. Reinitialize the I2C peripheral
    HAL_I2C_Init(&hi2c3);
}

 

I implemented this for testing. Is this fine??
I will test it when i go for EFT test again.


  • And potentially: Master I2C state is misbehaving (but slaves are fine) due to inadequate code and/or complicated and misunderstood peripheral details. One solution is to de-initialize and re-initialize the peripheral and hi2cx software state machine.


While EFT what I observed through oscilloscope is, sometimes SCLK(no clock) and SDA (HIGH value) after the test.
Sometimes both clock and data lines are normally working.
So, that's why i thought slave and master sides both needs to be reset.



Thanks for response.

That code looks good to me, should work.

If you feel a post has answered your question, please click "Accept as Solution".
Christian N
ST Employee
This post has been escalated to the ST Online Support Team for additional assistance. We'll contact you directly.