i2c again

All about the Raspberry Pi SBC and Rpi projects,hints, etc.

i2c again

Postby Richard-TX » Tue Aug 26, 2014 6:57 am

To correct some points in the previous discussion, there are devices that absolutely need repeated start to function correctly. Examples of such are early EEPROM memories, which hang internally if one writes an address and then generates a stop condition. Only way to reset such device is to power-cycle it.

The BCM2835 ARM Peripherals document claims that the BSC (the I2C controller in BMC2835) is I2C 2.1 compliant so it must support repeated start. And indeed, it does. However, the documentation of that feature is quite minimal, limited to the one example of how the 10-bit addressing can be achieved with BSC. The procedure in section 3.3 (pages 36-37) describing reading of 10-bit-addressed slave is an example of the more general one.

In brief, the procedure is that a write is started and then a read is queued before the write is completed. When a read is available to the device's state machine when the write ends, BSC does not generate stop condition but a repeated start, re-addressing, and read.

That functionality, naturally, was known to the authors of the RPi's I2C driver and is implemented in there (i2c-bcm2708.c). The catch here is that the feature, called as "combined" transaction, is disabled by deafault and has to be enabled to work.

So, once one has the i2c driver installed (insmod i2c-dev.ko, insmod i2c-bcm2708.ko), and made available (chmod 666 /dev/i2c-*), then one needs to turn on the combined transactions (chmod 666 /sys/module/i2c_bcm2708/parameters/combined, echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined).

Now one can read even those old, repeated-start-picky EEPROMs like XR24C02 like

Code: Select all
...
struct i2c_msg rdwr_msgs[2] = {
{ // Start address
.addr = 0x50,
.flags = 0, // write
.len = 1,
.buf = &reg_address
},
{ // Read buffer
.addr = 0x50,
.flags = I2C_M_RD, // read
.len = 16,
.buf = buffer
}
};

struct i2c_rdwr_ioctl_data rdwr_data = {
.msgs = rdwr_msgs,
.nmsgs = 2
};

file = open( "/dev/i2c-1", O_RDWR );
...

result = ioctl( file, I2C_RDWR, &rdwr_data );

if ( result < 0 ) {
printf( "rdwr ioctl error: %d\n", errno );
perror( "reason" );
} else {
printf( "rdwr ioctl OK\n" );
for ( i = 0; i < 16; ++i ) {
printf( "%c", buffer[i] );
}
printf( "\n" );
}
...
User avatar
Richard-TX
Site Admin
 
Posts: 208
Images: 6
Joined: Sat Feb 04, 2012 8:10 pm

Return to Raspberry Pi

Who is online

Users browsing this forum: No registered users and 1 guest

cron