This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Sample I2C Code

Can anyone provide me with some sample application code written to communicate with I2C devices on any of the I2C buses? This would significantly help to jump start my efforts. I am not looking for a tutorial on I2C bus technology and communicating with I2C devices. I have done that in the past with Windows, where a 3rd party provided a DLL that provided easy access to the I2C driver. I am looking for Linux code that demonstrates how to access the I2C driver for reading/writing I2C registers. I can take the rest from there.

Thanks!

  • http://bunniestudios.com/blog/images/infocast_i2c.c

  • thank you. this is very helpful. is there documentation on how to use the driver? the stuff you provide is very straight forward, but I would not have known how to pack the data, for instance, or known about the dummy write before the read, etc.

    answers to some additional questions would be helpful:

    1) what other flags are available

    2) is the addr value encoded? I.e., do I shift the actual slave address to the upper 7 bits, or does the driver do that?

  • Hello, Joseph!

    1. /usr/include/linux/i2c.h or linux/include/linux/i2c.h
    2. it depends on you, you can write driver and command via it or you can send command from user-space

  • Kirill,

    Thanks! I am unclear with respect to your answer to for 2. What do you mean by this?

    Thanks

  • Joseph, sorry, I do not understand you question. Can you expand it?

  • The Linux i2c driver uses 7-bit addressing. The R/W bit is handled in the driver. The example code noted uses just ioctl(I2C_RDWR). You can use read() and write() as well as setting the slave address with ioctl(I2C_SLAVE_FORCE), ie

    file = open("/dev/i2c0", O_RDWR);
    ioctl(file,I2C_SLAVE_FORCE,addr);
    write(file,buf,n);
    read(file,buf,n);
    close(file);

    The slave address is "global" to the open file. You can open the "/dev/i2c" more than once and set a different address for each open file. The caveat on using read/write is that the a stop occurs in each read() and write(). It you need a repeated start with no stop between operations, then you need to use the ioctl(I2C_RDWR) form. There are a lot examples out there. Search for "/dev/i2c-0".

  • Hello, Norman!

    You describe common way. I try it on DM368 for read/write registers on CMOS-matrix and it not work, I get incorrect values.

  • I am not familiar with the CMOS-matrix. Odds are that the CMOS-matrix relies on repeated start transactions. Probably a write/read combination with no stop between. Typically, the write sets the register address and the read gets the value from that address. A lot of I2C devices will reset or forget the register address on stop. Such write/read repeated start transactions are usually used on devices where multiple masters are expected. You don't want a one master overwriting the other masters write register address.

  • Kirill,

    I believe Norman Wong has helped to clarify my remaining issue.

    Thanks

  • What is the format of the buffer for the read() and write() calls? Given that the I2C_SLAVE_FORCE IOCTL is used to force the slave address for the file, how do I specify the register? Is it something like this:

    buf[0] = register offset

    buf[1] = byte to read/write

    Examples I've found use the function calls in the form of "i2c_smbus_read_byte", but I don't not have those defined in my environment. Are they defined in some I2C toolset somewhere?

    Thanks

  • linux/Documentation/i2c/dev-interface

  • The format of bytes to read() and write() are dependent upon the device you are talking to. Some devices do not have register addressing. The read() and write() access will handle the start-addr-rw and stop parts. You have to handle the middle data part. In your example buf[0]=offset, buf[1]=data implies a 8 bit offset and 8 bit data. There are devices out there use 16 or 32 bit address and data.

    Functions like i2c_smbus_read_byte() are usually called from within kernel code such drivers. User space code is limited to file operations like open(), ioctl(), read(), write() and close(). Everything is a file in Linux.

  • Norman

    Using the standard character file read/write functions did not work for me from user mode. I had a bus analyzer on the I2C bus and it appeared that the write worked fine (i.e. followed proper I2C protocol for a single byte register write), but a read did not. It was very clear from the bus analyzer that the host was not following protocol for the read.

    The way I got it to work was via the method specified by  Kirill Brilliantov on Jun 22, 2012 2:21 PM. He posted a snippet of code that used the I2C_RDWR IOCTL instead. This worked fine to both set and get I2C registers.

    I now have working user mode code that controls devices on the I2C bus for the 816x platform just perfectly.


    Just wanted to follow up and provide this final data point.

  • Good to hear. I like the read() / write() form for esthetics but the ioctl(RDWR) form does give a lot more control. Avoids the double buffering for devices where an offset and large number of data bytes are written...eg eeproms. Thanks for closing the loop.