Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Probably one of the least painful digital buses.

If anyone is wondering how to access an I2C bus from a Linux computer, say, a raspberry pi:

int fd = open("/dev/i2c-1", O_RDWR);

ioctl(fd, I2C_SLAVE, [slave address here]);

Then you can read() and write() to the device with the kernel taking care of all the transmission details. Usually all that's exposed is a few bytes for the registers. To set a register, write two bytes: first the register address, and then the value. To read a register, write the register address and then read a byte. Most of the devices have linear address spaces, so reading out multiple registers is as simple as reading multiple bytes.

The i2c-tools package has some very handy CLI tools for exploring an I2C bus.

Electrically, the bus is an open-collector design on both ends, so devices can only pull the lines to low, and they release them to set them high. Don't forget pull-up resistors!



A quick note: buy one of the really cheap (~$10) logic analyzers on ebay and use Sigrok/Pulseview to to watch the bits get sent over the wire! It's an absolutely invaluable tool for the price.

The hardware inside those logic analyzers is fascinating in its own right, too!


I've found the [I2CDriver](https://www.adafruit.com/product/4267) device to be really useful with debugging, poking, and otherwise prodding I2C devices.


Interesting. This intro to Sigrok looks like it covers things pretty well too:

https://www.youtube.com/watch?v=dobU-b0_L1I

That, and a cheapo Saldae clone might be all I need for learning how to use a logic analyser finally. :)


To avoid clock-stretching problems, using one of the small Arduinos that support USB serial to handle the I2C bus can help considerably, at the expense of a bit more programming complexity.


I'm not at all familiar with this space, but I'm a bit surprised the kernel isn't wrapping the I2C transmission and helping to work around clock stretching issues anyway. Can someone who's more familiar with this implementation weigh in? It seems like that'd be the primary feature of writing to the /dev/i2c* device instead of manually bit-banging the GPIO pins from userland.


The Pi's hardware i2c has buggy silicon and does not handle clock stretching properly. There's also a kernel driver to bitbang i2c over the GPIO pins and clock stretching does work properly with that.


Does the PI 4 also have this problem?


There's a claim that it was fixed here:

https://www.raspberrypi.org/forums/viewtopic.php?p=1484482#p...

Apparent confirmation here (by mapping a different I2C bus?):

https://www.raspberrypi.org/forums/viewtopic.php?p=1544123&s...


I'm not sure about the 4, though it was present at least from the original up through the 3B+.


Not all i2c devices can be read that way. There are several devices that require an address (on top of the device address) to be written before data can be read, but without a second stop bit after writing the address. You end up with like double start condition. These require either using the smbus stuff or I2C_RDWR ioctl.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: