Repeated I2C Timeouts

I have a Photon connected to an APDS-9960 I2C gesture sensor, and while it’s mostly working, I’m able to manufacture a situation that causes the I2C driver to time out repeatedly without recovery.

I was essentially able to copy and paste SparkFun’s APDS-9960 driver into the Particle IDE and run it without any hitches. While the library works fine, there is one shortcoming in that it busy waits for gesture data as long as there is data present in the sensor’s FIFO buffer. Thus, by continuously holding my hand over the sensor, I can cause the processor to be trapped in the library’s read loop for as long as I want (muahaha?).

Nothing wrong so far, but I happen to have a UDP server in my main sketch that is supposed to be receiving a stream of data. When this stream is inactive, I can hold my hand over the sensor for as long as I want and bask in the light of the LED on D7, which tells me that data is being read from the device. Here’s the logic trace showing normal bus activity:

When the UDP stream is turned on, the I2C driver seems to repeatedly time out after anywhere between 3 and 15 seconds. The exact data rate doesn’t seem to matter too much, but there is a Python file I’ve uploaded that can trigger it, and here’s a logic trace of how that looks (a bit more zoomed in this time):

Data reads succeed for a few seconds, but after a seemingly ordinary read of buffer data, there is a period of time that indicates an I2C timeout with no bus activity to prove what operation actually timed out, followed by a sequence of I2C START -> STOP conditions spaced apart by 100ms or 130ms (100ms timeout + 30ms delay between I2C reads), with no actual data transfers in between. Here’s a shot of what that looks like.

At this point, the D7 LED just blinks helplessly and while the Photon is still responsive, it only responds in hiccups between I2C timeouts. The only thing I can think of is that the Wifi module/UDP server has somehow been overloaded by packets leading up to the first timeout (since reading the data doesn’t happen for a while) and that causes some kind of bad state to result, but that could merely be a stressing factor that triggers or exacerbates some kind of actual I2C driver bug.

Separately, I tried overload the Photon with data it’s not prepared to read using the same Python script and Photon sketch but it didn’t choke, so the issue seems centered around I2C and timing, but I can’t narrow it further.

I’ve uploaded the aforementioned good and bad logic traces, a Photon app, and the python UDP code here. To recreate the issue, you’d need a SparkFun APDS-9960 breakout board with the IRQ line attached to D2, which is maybe asking too much unless you happen to have one already.

I updated the firmware with the recent I2C fixes in the 0.4.3-rc2 release but that didn’t solve the problem. I can also trigger this behavior with a Spark Core running exactly the same sketch, but it does take longer to happen.

Thanks in advance!

While my hardware may be too esoteric for anyone else to assist me in tracking this issue down, I think there is a good chance this is an issue with the underlying I2C driver. I’m now on the 0.4.4-rc2 release and the fundamental problem is that in the middle of a perfectly ordinary read, there is a sudden START->STOP condition followed by a series of 100ms timeouts.

Here is the first START->STOP:

Here are the timeouts that follow:

Since even the slave address doesn’t get clocked out, based on my understanding of the HAL driver, the place it times out at must be around I2C_CheckEvent here:

Unfortunately, I don’t have a way to see the code but based on a quick Google search, it seems that I2C_CheckEvent is a lowel-level STM/Wiced-provided function that probably checks some hw registers. Why the bus would suddenly stall like that or why the RequestData function would time out, is beyond me.

There is a few threads on this now… and I am told they have some guys looking into it, and I have been digging trying to find the solution for 5 or 6 weeks now too.

I2C has been addressed in the latest release, https://github.com/spark/firmware/releases/