Photon i2c doesn't work, Arduino i2c works, with oscilloscope waveform

So I’m trying to use the Photon to read a HTU21D sensor from SparkFun, and I never get a response from the sensor. So I hooked it up to an Arduino Uno, and it reads the sensor fine every time.

I happen to have an Xprotolab Portable sitting around that I’ve never used before, so I decided to hook it up and see what it can show me. In I2C sniffing mode, it is reading “40) 40(” , which is “write to 40, NACK; read from 40, NACK” which sounds like a sensor problem. When the sensor is hooked to the Arduino however, the sniffer reads “40> f3+ 40< 66+ 84+ b1-”, where the > and < are ACK, and basically means reading and writing data is working correctly.

Now to figure out what is wrong, I hooked up the oscilloscope channels to SDA and SCL and grabbed some waveforms. I did some fancy image editing to put the Arduino and Photon waveforms on the same image:

As far as I can tell, the biggest difference here is simply that the Arduino waits longer after pulling SDA low to start transmission, where the Photon doesn’t wait very long. I’ve looked in the Photon firmware to see if I can find where the code is for the i2c protocol, and I think it needs to go around here but I’m not sure with all the interrupts. Would it be bad to just busy-wait before the I2C_Send7bitAddress function until a certain amount of time has passed?

If someone has any insight, I’d love to hear it. I’m happy to try modifications to the firmware.

Hi @ricochet1k

There have been some changes to the Photon software to work around problems in the hardware implementation of i2c in the ST Micro ARM processor, so it makes a difference which version of the system software you are running. You should be running 0.4.7.

Some folks using this sensor have said that there are differences between the Adafruit and Sparkfun libraries and that they might not be inter-operable. Search the forum for details.

Finally, you don’t mention much about your electrical environment. The SparkFun board has pull-ups (which are required on Photon) but how long are your wires, what is your power supply like, etc.? Long wires and low voltage can require special handling, so it can make a big difference.

1 Like

Here you can see the address byte NOT being ACKed in the 9th clock period, even though the address is the same.

Some thoughts:

  • the waveforms are very sine-wavey. Whilst on any open-drain bus, you’d expect the rising edge to be curved (as this is an RC curve set by the pull-up resistor and the parasitic capacitance on the line), I’m surprised that the falling edges are so smooth. This implies there’s a LOT of capacitance on the bus (as @bko says - do you have very long wires here?). Decreasing the value of the pullup resistors will help on the rising edge, but for the falling edge if you can’t reduce the capacitance then you should drop the bus speed to give more margin.

  • arduinos are usually 5v. If the device requires 5v thresholds for i2c then ensure your pullups are to 5v in both cases.

1 Like

Thanks for the input!

I am using firmware 0.4.7.

I am using the Sparkfun sensor. I am using the HTU21D library the Photon web IDE had listed, so I’m not sure which sensor it was developed for, but I don’t think that’s the problem at this stage. Both libraries are trying to write and read the same address, yet the Photon is failing.

Here’s my electrical environment:

Power comes from a powered USB hub also connected to my computer.

I’m plugging the sensor into the 3v3 pin on both the Photon and the Arduino. I suspect that the capacitance comes from the long wires to the oscilloscope. Do you think the other wires are too long? The Photon still doesn’t work with the oscilloscope removed.

So it seems that the Arduino is generating higher voltages on the pins, and I guess I didn’t realize that the Arduino is 5v where the Photon is 3.3v. Does that mean I’m going to need to use a logic level converter? Or is there an easier solution, like reducing the bus speed? I’ve seen that mentioned before, is there documentation on it somewhere?

The sensor appears to be 3.3v only, so this should be powered from that (sounds like you are doing so). The sparkfun board has 4.7k pull-ups to 3.3v on SCL and SDA, so that’s all dealt with on the sparkfun board.

As I remember, the Atmel chips have a Vih(min) of 3.0v, so the pullups to 3.3v should be fine on both devices. You should not be seeing any higher voltage than 3.3v on SCL/SDA even when used with the arduino, because it’s an open-drain bus (ie any participant on the bus can only ground a line, never drive it high - so the high levels will always come from the pullups, which as noted above, are to 3.3v)

The actual address (read from 7-bit address 0x40) seems well formed, just the device isn’t responding. Have you tried writing first? Generally devices need to have a subaddress set before they can be read from - can you post the code?

The write does happen before the read, but trigger mode on the oscilloscope picks up the second one before the long pause, so that’s what I captured. The write looks identical to the read except for the one bit that should be different. is what I’m using, but I don’t see how that even matters at this point.

The other possibility is that the address is not getting an ACK because the chip is busy (maybe the delays are different between platforms). Tried reading a register which doesn’t require a conversion delay, eg the user register?

1 Like