Issue with I2C Driver

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Issue with I2C Driver

2,988 Views
__invited__hari
Contributor V

Hi,

I am seeing a problem with I2C Driver of S32K148.

Driver is properly initialized and I could see that the peripherals connected on I2C bus are communicating. That gives me confidence that the interrupts are working and Hardware is correctly connected.

But here is the problem:

After sometime (may be after a minutes of continuous communication), the driver stops communicating with peripherals by hitting the break condition through DEV_ASSERT at master->rxBuff != NULL as highlighted in the source code below.

I modified this driver code with a microsecond resolution counter instead of OSIF calls for timeouts for these blocking calls. Modified Driver files are attached with this post for reference.

static void LPI2C_DRV_MasterHandleReceiveDataReadyEvent(uint32_t instance, LPI2C_Type *baseAddr, lpi2c_master_state_t *master)
{
DEV_ASSERT(g_semI2cMasterFlag[instance] != FLAG_UNKNOWN);

/* Received data ready */
DEV_ASSERT(master->rxBuff != NULL);

FYI, I am working with S32K148EVB using S32DS.

Please suggest your recommendations to solve this issue.

Thanks,

Hari

Labels (1)
0 Kudos
7 Replies

2,233 Views
cristianzamfire
NXP Employee
NXP Employee

   Hello Hari,

   We reproduced the issue, it happens when there is a timeout during a reception, followed by a transmission. The driver attempts to abort the reception when the timeout is detected, but the LPI2C module continues to receive data and store it in the Rx FIFO. The subsequent transmission will detect the receive data event and attempt to handle it, hence the error you saw.
   Unfortunately we could not find an easy workaround for all cases. The simplest thing you can try is to increase the timeout value. In our tests this behavior occurs if there are only a few bytes left to receive when the timeout happens, so increasing the timeout might fix the problem by allowing the reception to end.
   You could also de-init and re-init the driver after a timeout, but this may abort the reception in mid-byte and risk blocking the I2C bus. You can do this only if you have a way to reset the slave in order to remove the blockage, or send 9 dummy clock pulses, per "Bus clear" chapter in the I2C standard, but you must use a GPIO for this, LPI2C does not have this feature.

   Best regards,
   Cristian

0 Kudos

2,233 Views
__invited__hari
Contributor V

Hello Cristian,

Rightly pointed out and Much appreciated!

Yes, I observed the same behavior as you explained. I also observed a behavior of shifting of data through this issue because of queued data in RxBuffers.

You know, I already implemented those cases of 1) deinit and init of I2C Driver and 2) recovering the 'bus clear' in GPIO mode by sending dummy clock signals. Everything seems working with that solution. But as you know, this is just a work around and the system I am design is time critical. Recovering the bus and initializing the driver every time is definitely consuming more time. This is one reason I shifted my timeouts to micro seconds resolution.

Luckily you found the problem, and I look forward for a fixed solution to overcome this issue.

Thanks,

Hari

0 Kudos

2,233 Views
__invited__hari
Contributor V

Please let me know if you have any update on this.

0 Kudos

2,233 Views
cristianzamfire
NXP Employee
NXP Employee

   Hello Hari,

   We are working on a solution, but this issue is not a simple one. Once a multi-byte reception is started, the LPI2C module will continue it until it finishes. One option would be to allow the reception to complete, but this may take a long time, depending on the number of received bytes. The second option is to stop the reception by resetting the LPI2C module, but this may happen in mid-byte and risk to block the I2C bus, as you already experienced.

   The solution we are currently working on is to delay the module reset until the next byte is received. This way the communication interruption will take place inside the ACK bit and the slave will not drive SDA. But even this may not be 100% safe, because if the handling of the LPI2C interrupt is delayed by other higher-priority interrupts the reset might be too late and still block the I2C bus. This should be an exceptional case, but you might still need to keep your bus clear code.   We plan to include this fix in the next SDK release.

 

   Best regards,

   Cristian

0 Kudos

2,233 Views
cristianzamfire
NXP Employee
NXP Employee

Hello Hari,

What S32DS and S32 SDK version are you using? Also, could you describe in more detail what your application does? Are both LPI2C instances used? In which mode, master or slave? Do you use both transmit and receive? Do you use only blocking functions, or both blocking and non-blocking functions? Do you use the abort functions?
Also, did you see any error status returned by any of the functions, for example STATUS_TIMEOUT or STATUS_I2C_TX_UNDERRUN?

I took a look at the attached code, especially at the replacement of OSIF calls with the g_semI2cMasterFlag flags. I suggest that you also reset the flags before starting any blocking communications, for example add the code:

g_semI2cMasterFlag[instance] = FLAG_CLEAR;

at line 1491 (in function LPI2C_DRV_MasterSendDataBlocking, before the call to LPI2C_DRV_MasterSendData). Same for the other blocking functions. This would prevent corner cases like timeout and normal transfer end occurring at the same time, causing the transfer to end with timeout return code but the flag to remain set, thus causing the next blocking call to end prematurely.

Best regards,
Cristian

0 Kudos

2,233 Views
__invited__hari
Contributor V

Hello Cristian,

Please find my responses to your questions below:

What S32DS and S32 SDK version are you using? 2018.R1 / Version 0.8.6 EAR.

Also, could you describe in more detail what your application does? I am using I2C1 to communicate with multiple slaves at same speed in blocking mode.

Are both LPI2C instances used? Only Instance 1 (I2C1) is used

In which mode, master or slave? Master

Do you use both transmit and receive? Yes

Do you use only blocking functions, or both blocking and non-blocking functions? Only blocking functions

Do you use the abort functions? Not used in my application.
Also, did you see any error status returned by any of the functions, for example STATUS_TIMEOUT or STATUS_I2C_TX_UNDERRUN? Not seen any of these errors

I will clear the flag as suggested and let you know if I see this issue again

Best regards,
Hari

0 Kudos

2,233 Views
__invited__hari
Contributor V

Hello Cristian,

I just made those changes and ran a quick test.

It failed again at the same point I mentioned in my initial post. But this time I could see ERROR_TIMEOUT before reaching to that point.

static void LPI2C_DRV_MasterHandleReceiveDataReadyEvent(uint32_t instance, LPI2C_Type *baseAddr, lpi2c_master_state_t *master)
{
DEV_ASSERT(g_semI2cMasterFlag[instance] != FLAG_UNKNOWN);

/* Received data ready */
DEV_ASSERT(master->rxBuff != NULL);

Thanks,

Hari

0 Kudos