Article Index

Read A Register

As for writing to a register reading from a register is a very standard operation but it is slightly more complicated in that you need a write and a read operation.

That is to read a register you need a write operation to send the address of the register to the device and then a read operation to get the data that the device sends as the contents of the register. 

So for example to read a  register, with address reg, you would use something like:

char buf[]={registerAddress};
bcm2835_i2c_write(buf,1);
bcm2835_i2c_read(buf,1);

If the register sends multiple bytes then you can usually read these one after another without sending an address frame each time as a block transfer. 

This write/read combination is so common that there is a second read function designed just for this application but with an extra feature. The read_register_rs function will read any number of bytes from a register specified by its address. 

uint8_t bcm2835_i2c_read_register_rs (char *regaddr, char *buf, uint32_t len)

In other words this combines writing the registers address with reading it. 

In theory and mostly in practice a register read of this sort  can work with a stop-start separating the write and the read operation which is what you get if you use separate write and read function calls:

That is the transfer sequence is:

START| ADDR |ACK|REGADDR|ACK|STOP|
      START| DATA1|ACK|
        START| DATA2|ACK|
           ...
      |DATAn|NACK|STOP

If you look at the end of the write and the start of the read you will see that there is a STOP and START bit between them.

For some devices this is a problem. A STOP bit is a signal that another transaction can start and this might allow another master to take over the bus. To avoid this some devices demand a repeated START bit between the write and the read and no STOP bit. 

This is referred to as a repeated start bit transaction. 

That is the sequence for a repeated start bit register read is:

START|ADDR |ACK|REGADDR|ACK|
   START|DATA0|ACK|
       DATA1|ACK|
   ...
       |DATAn|NACK|STOP

Notice that there is now one ADDR frame and only one STOP bit. 

In theory either form of transaction should work but  in practice you will find that some slave devices state that they need a repeated start bit and no stop bits in continued transactions. In this case you need to be careful how you send and receive data.

For example to read a register from a device  that requires repeated START bits but no STOP bit you would use:

  char buf[] = {0xE7};
  bcm2835_i2c_setSlaveAddress(0x40);
  bcm2835_i2c_read_register_rs(buf,buf,1);    

You can see in the logic analyzer display that there is now just a single START bit between the write and the read. 

 

The read_register_rs function sends a single byte to select the register and then reads back as many bytes as the slave device specifies as a response. What if you need to send more than one byte to the slave? You can of course use use a separate write and read function call but there is a special function which will suppress the STOP bits between the write and read of any number of bytes.

uint8_t bcm2835_i2c_write_read_rs(char * cmds,
                uint32_t cmds_len,
                char * buf,
                uint32_t buf_len 
)

This writes cmd_len bytes from buf and then reads buf_len bytes from the slave without putting a STOP bit between the write and read.  Of course

  bcm2835_i2c_write_read_rs(buf,1,buf,1);

is the same as

bcm2835_i2c_read_register_rs(buf,buf,1);    

Not many devices need a repeated START transaction the documentation mentions the MLX90620 IR array but this is hardly a common peripheral.

In practice it usually doesn't make any difference if you send a STOP bit in the middle of a write/read transaction but you need to know about it just in case.  

Slow Read

The I2C clock is mostly controlled by the master and this raises the question of how we cope with the speed that a slave can or cannot respond to a request for data. 

There are two broad approaches to waiting for data on the I2C bus.

The first is simply to request the data and then perform reads in a polling loop. If the device isn't ready with the data then it sends a data frame with a NACK bit set.

The I2C functions return one of the following codes:

BCM2835_I2C_REASON_OK 

Success

BCM2835_I2C_REASON_ERROR_NACK 

Received a NACK

BCM2835_I2C_REASON_ERROR_CLKT 

Received Clock Stretch Timeout

BCM2835_I2C_REASON_ERROR_DATA 

Not all data is sent / received

 

So all we have to do is test for an ERROR_NACK response.

Of course the polling loop doesn't have to be "tight". The response time is often long enough to do other things and you can use the I2C bus to work with other slave devices while the one you activated gets on with trying to get you the data you requested. All you have to do is to remember to read its data at some later time.

The second way is to allow the slave to hold the clock line low after the master has released it. In most cases the master will simply wait before moving on to the next frame while the clock line is held low.

The I2C bus implements this clock stretching protocol but it  This is very simple and it means you don't have to implement a polling loop but also notice that your program is frozen until the slave releases the clock line. 

The Pi's implementation of I2C clock stretching has a flaw in that it fails if the clock stretching is very short. However there is also a problem with the Linux driver and with the bcm2835 library that may account for many of the reports that I2C doesn't work with clock stretching. The problem is that there is a clock stretch time out register that isn't much discussed and there isn't a library function to set it. By default it is set to 40 but the units are I2C clock pulses. If you are using a high clock rate then 40 clock pulses can be a very short time period and not long enough for devices such as AtoD converters to complete their task. 

To make clock stretching work you have to set the timeout - see how to do this in the example that follows. 

Many devices implement both types of slow read protocol and you can use which ever suits your application.