altosz
Posts: 8
Joined: Sat Dec 31, 2016 4:38 pm

Access 16-bit register address on I2C via python

Tue Jan 03, 2017 6:32 pm

Is there a python module to read/write data to/from register 0x010A of device on I2C bus?
I'm interfacing VL6180X proximity sensor (datasheet is here http://www.st.com/content/ccc/resource/ ... 112632.pdf) and it uses 16-bit address for registers.

As far as I understand python smbus and smbus2 packages use 8-bit address, and i2cdump too.

The workaround that I've found is here:

Code: Select all

    import io
    import fcntl

    IOCTL_I2C_SLAVE = 0x0703

    fr = io.open("/dev/i2c-1", "rb", buffering=0)
    fcntl.ioctl(fr, IOCTL_I2C_SLAVE, 0x29)

    fw = io.open("/dev/i2c-1", "wb", buffering=0)
    fcntl.ioctl(fw, IOCTL_I2C_SLAVE, 0x29)

    fw.write(bytearray([0x00, 0x00]))
    v = fr.read(1)
    print type(v), ord(v), hex(ord(v))
This code correctly reads chip id from register 0x0000 every time. If I read register 0x00 using packages smbus or smbus2, it returns correct response (0xB4) only after sensor boot and afterwards it returns random bytes.

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 6895
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: Access 16-bit register address on I2C via python

Tue Jan 03, 2017 7:39 pm

Opening two file handles is a slightly quirky way to do things.
The cleaner way would be to use the I2C_RDWR ioctl to do the register select write and the read as one atomic operation. Docs at https://www.kernel.org/doc/Documentatio ... -interface

Code: Select all

#include <linux/i2c.h>
static void i2c_rd(int fd, uint16_t reg, uint8_t *values, uint32_t n)
{
   int err;
   uint8_t buf[2] = { reg >> 8, reg & 0xff };
   struct i2c_rdwr_ioctl_data msgset;
   struct i2c_msg msgs[2] = {
      {
         .addr = 0x29,
         .flags = 0,
         .len = 2,
         .buf = buf,
      },
      {
         .addr = 0x29,
         .flags = I2C_M_RD,
         .len = n,
         .buf = values,
      },
   };

   msgset.msgs = msgs;
   msgset.nmsgs = 2;

   err = ioctl(fd, I2C_RDWR, &msgset);
}
Sets the register ID to "reg", and then reads "n" bytes back into the array of "values"
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

User avatar
joan
Posts: 14013
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Access 16-bit register address on I2C via python

Tue Jan 03, 2017 8:12 pm

That looks like some of my Python code to allow direct access to the underlying I2C device from Python.

You might be able to find an SMBus command to do what you want, although I don't think SMBus allows you to use all I2C commands (which is strange as I2C is a much simpler interface).

altosz
Posts: 8
Joined: Sat Dec 31, 2016 4:38 pm

Re: Access 16-bit register address on I2C via python

Tue Jan 03, 2017 9:56 pm

Thanks everyone for the answers.
The only question that's left is why does not smbus support 16-bit addresses out of the box? Any ideas? Are there only few i2c devices with 16-bit eeprom? And why does i2cdump does support only 8-bit addressing?

P.S. The idea of previous code sample is taken from here - https://github.com/vitiral/i2cdev/blob/master/i2cdev.py

Another way to achieve the same functionality using smbus is:

Code: Select all

from smbus import SMBus

bus = SMBus()
bus.open(1)

bus.write_byte_data(0x29, 0x00, 0x00)
v = bus.read_byte(0x29)
print type(v), hex(v)

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 6895
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: Access 16-bit register address on I2C via python

Tue Jan 03, 2017 10:28 pm

altosz wrote:Thanks everyone for the answers.
The only question that's left is why does not smbus support 16-bit addresses out of the box? Any ideas? Are there only few i2c devices with 16-bit eeprom? And why does i2cdump does support only 8-bit addressing?
SMBus is defining a System Management Bus for certain sensor and controller types, and includes some definition of how the data is to be formatted. It doesn't include EEPROMs (or camera modules), therefore it doesn't need to support 16 bit addressing.
Maxim actually have a fairly nice comparison of SMBus vs I2C - https://www.maximintegrated.com/en/app- ... mvp/id/476 - I wasn't aware that there are actually electrical differences between I2C and SMBus until I read that, but for the vast majority of devices I2C can talk SMBus.

i2cdump is using the SMBus API under the hood (https://fossies.org/dox/i2c-tools-3.1.2 ... ource.html), so won't support 16 bit addresses.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

altosz
Posts: 8
Joined: Sat Dec 31, 2016 4:38 pm

Re: Access 16-bit register address on I2C via python

Wed Jan 04, 2017 10:17 am

6by9, thank you for the answer.

Return to “Interfacing (DSI, CSI, I2C, etc.)”