Raspberry Pi and I2C

Update: July 2018

Working with the RPi Zero W board.

There are two problems with the I2C bus as far as I know, one is to do with timeout and the other is a quirk that may only be apparent when using I2C with the PIC16F series.

Timing and Clock Stretch

Clock stretching is implemented on the RPi, however there is a timeout of about 0.6mS by which time if the slave has not released the clock results in a timeout error. This is fine for most devices such as an RTC however in real work applications that have to operate say relays or LCD's, this time out can be too short.

I have 3 solutions:

1) Buffering the I2C. This works because the slave device will immediately release the bus and work on the data in the buffer. This woks well but the master must not let the buffer get full.

2) This is to change the value of a register on the BCM chip.There is no way to do this with IOCTL or any I2C command so a program has to be run to do this. A word of warning here, the register addresses vary depending on the type of chip used.

Rasphats uses the solution below which essentially runs a program at the initialisation of the RPi

https://raspihats.com/i2c-hat/2016/02/16/raspberry-pi-i2c-clock-stretch-timeout.html

This is very similar but much better developed to the work I did in 2012

3) This is for Python and is exactly the same as above but will only run when it is needed and is part of the i2crpi.py module. http://www.pichips.co.uk/index.php/RPi_I2C_2018

How to use the i2crpi.py Module

import i2crpi
dev = i2crpi.IIC(timeout=3000) # default works with, bus 1 and BCM2835

The timeout value is the number of clock cycles to wait so will depend on the clock frequency and 3000 will give about 30mS. The dev can now be used to send and receive values as follows, assume the slave is address 0xd0

When running this module for the first time it will compile the i2c_set_tout.c file and thereafter just run it. The c program is responsible for changing the register value and can be changed at any time. The value is RAM so will remain until the RPi is power-cycled.

x = dev.i2c(0xd0,[1,2,3],5) # sends 1,2,3 to slave and receives 5 bytes into x as a list of numbers
dev.i2c(0xd0,[51],0) # sends byte 51 to slave
x = dev.i2c(0xd0,[],10) # just read 10 bytes

See the text below for more details

Bit 7 Set to 1 When Reading

Now this really is a puzzler and seems only to relate to PIC16F hardware I2C but could occur elsewhere I suppose.

Above is a read from a device that returns 0, there is nothing wrong with the read and indeed the Saleae logic analyser correctly shows 0, however the RPi interprets this as 128 or 0x80. In other words it has set the MSB to 1. In detail the clock width is between 5 and 6 uS, however at the NAK of read the clock is only 4uS and it is this that seems to cause the problem.

For I2C to read it sends a read address and then clocks the data out. From the slave point of view when a read address is received, the buffer needs to be loaded so that it can later be clocked out. The slave can hold the clock low after a read address is received for about 5uS and this works.

With this waveform the RPi correctly interprets the value as 0.

smBUS

The smBUS is for smBUS devices so lets leave it at that, not much use (but can be used) for none smBUS devices.

Python and I2C

import i2crpi  # get module from http://www.pichips.co.uk/index.php/RPi_I2C_2018
dev = i2crpi.IIC(timeout=40000)

Function / class  format:

dev.i2c(address,[list to send],bytes to receive,optional general call

Some examples:

dev.i2c(34,[1,2,3],0)  # send 1,2,3 to device with I2C address 34

dev.i2c(34,[1,2],3) # send 1,2 to device with address 34 and read 3 bytes from that device

dev.i2c(34,[],2) # read 2 bytes from device with i2c address 34

General Call

This is a special address 0 that will address ALL of the devices on the i2c bus. To implement a general call add a 0 to the parameter list, thus:

x = dev.i2c(34,[1,2,3],3,0)

The above will send 1,2,3 to ALL devices on the bus and read 3 bytes from device 34