I2C SDA Goes LOW - Cant Recover

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
KevinE
Level 3
Level 3
10 sign-ins 10 replies posted 5 sign-ins

Hello, 

I am using the PSoC5 I2C Multi Master Slave implementation and seem to be experiencing an event that causes the SDA line to go low and never return high. When this happens, an infinite while loop is entered from one of the autogenerated APIs from PSoC creator. 

I have tried implementing some "fixes" although I'm not too sure how well they are working because I'm still getting failures. 

My test is to basically have the code running and see how long it takes to fault(SDA line being held low) My code is talking to sensors, ICs via I2C at a periodic time interval. My "Fixes" have made it to where instead of failing within an hour, it takes about a day or two to fail. 

I would like to share some of my "fixes" / Findings to ensure that I am moving in the right direction - ultimately I'm looking for some advice on how to recover the I2C when this event is happening. I would also like to know if there is more that I can do to narrow the problem to actually find what is happening to cause this issue. 

Hardware Setup:
This is a custom board with a CY8C5868AXI. I2C is configured with 1k pullups and has the following parts in the I2C bus:
 - DS2484 I2C slave to 1Wire Master

 - MCP9902 Temp Sensor


Observations, 

If I reset the PSoC using XRES (Pushbutton), the SDA line returns high and the fault goes away. After pushing the reset button from a faulted state, the issue does not appear to happen again.  This makes me think that this may be some kind of first time power on issue, as the issue does not happen again after performing a hard reset. Software resets do not have the same effect - the SDA line remains low. 

The pushbutton we have attached to XRES is only attached to XRES - that is, it is only resetting the PSoC5. This leads me to believe the issue is not with another slave device and that the issue is in the PSoC5. 

The Signal integrity appears to be "good enough" - there is slight rounding, but could that be why at some point we see failures on the SDA line? We were experiencing some undershoot before adding RC to fix that. The undershoot would go below -0.5 volts - could this mean the part would now have reliability issues?

KevinE_1-1658720267583.png



Fixes:

1. Before performing any I2C transactions, I use CyGlobalIntDisable / CyGlobalIntEnable - this is the latest item that I added - I haven't been able to stress test this, as I just did the change, so I will have to wait and see if this remedies the issue. Not sure if this is actually doing what I think it's doing - ensuring that once an I2C start condition has been successfully issued, it can not be interrupted by timers / interrupts, until the transaction is complete.

 

2. When calling I2C API, I conditionally call each successive function always ending with a stop. This was a major fix that greatly increased the reliability of the I2C:

KevinE_2-1658720617445.png
3. In the I2C_Master.C file that gets auto generated, I modified the source in API calls that have an infinite while loop

Originally, the code is autogenerated to have the while loop empty, meaning that if the I2C_WAIT_BYTE_COMPLETE never returns "OK", the while loop will never be broken. So I wrote in a counter that allows the while loop to be broken if this event occurs. At first, I would just break from the loop, Then I added a "bus reset" function to try to help recover the SDA line. 

The code circled in red is added by me, the rest of the code is autogenerated from PSoC creator.

KevinE_5-1658721389910.png


4. The bus reset function is supposed to re-assign the I2C pins as Output Push Pull, drive the SDA and SCL high and low 16 times, then "reconnect" the pins to I2C. 

This was the fix that made the code run for days instead of hours. I was almost sure that this would be the fix, but unfortunately I returned to my system to find the SDA line low some days later. 

This fix was taken from another post, where the user reassigns the SDA as High Z and the SCL and Strong Drive, but I found it to work for me when assigning both SDA and SCL and strong drive and toggling both. 


https://community.infineon.com/t5/Code-Examples/PSoC-5LP-I2C-Bus-Reset-Sample/td-p/138721

 

KevinE_3-1658721012108.png

KevinE_4-1658721067015.png

KevinE_6-1658721478320.png

Thank you for your help with this issue, 

 

 - Kevin





0 Likes
1 Solution
ncbs
Moderator
Moderator
Moderator
500 replies posted 50 likes received 250 sign-ins

Hi @KevinE,

  • I hope you are operating both the masters and the slave(s) at the same potential.
  • If you have any other high priority interrupts than I2C, then I2C is kept on hold. Using CyGlobalIntDisable / CyGlobalIntEnable might help you here.
    You could also increase the priority of I2C over other interrupts.
  • Are you following the "Manual Function Operation" approach in controlling I2C communication? In manual function operation, a stop command has to be explicitly sent to complete the transaction, and you have implemented that in your code. This is the right way to do. Refer to the v3.50 component datasheet for more details. 
    Interrupt management too has been shown in the below picture:
    ncbs_0-1658756984758.png

     

  • Point 3 and 4 provide debugging options for others in the community too. Thanks for mentioning all the debug steps followed by you.

Regards,
Nikhil

View solution in original post

0 Likes
1 Reply
ncbs
Moderator
Moderator
Moderator
500 replies posted 50 likes received 250 sign-ins

Hi @KevinE,

  • I hope you are operating both the masters and the slave(s) at the same potential.
  • If you have any other high priority interrupts than I2C, then I2C is kept on hold. Using CyGlobalIntDisable / CyGlobalIntEnable might help you here.
    You could also increase the priority of I2C over other interrupts.
  • Are you following the "Manual Function Operation" approach in controlling I2C communication? In manual function operation, a stop command has to be explicitly sent to complete the transaction, and you have implemented that in your code. This is the right way to do. Refer to the v3.50 component datasheet for more details. 
    Interrupt management too has been shown in the below picture:
    ncbs_0-1658756984758.png

     

  • Point 3 and 4 provide debugging options for others in the community too. Thanks for mentioning all the debug steps followed by you.

Regards,
Nikhil

0 Likes