Article Index

In Detail

If you have a logic analyzer that can interpret the I2C protocol connected, what you will see is:

 

You can see that the write_byte function sends an address packet set to the device's 7-bit address 0x40 as the high order bits and the low order bit set to zero to indicate a write i.e 0x80. After this you get a data packet sent containing 0xE7 the address of the register. After a few microseconds it sends the address frame again only this time with the low order bit set to 1 to indicate a read and it then receives back a single byte of data from the device - 0x02.

This all demonstrates that the external device is working properly and we can move on to getting some data of interest.

Reading the raw temperature data

Now we come to reading one of the two quantities that the device measures - temperature.

If you look back at the command table you will see that there are two possible commands for reading the temperature: 

 

Command  Code  Comment 
Trigger Temperature Measurement 0xE3  Hold master
Trigger Temperature Measurement 0xF3  No Hold master

 

What is the difference between Hold master and No Hold master?

This was discussed earlier in a general context. The device cannot read the temperature instantaneously and the master can either opt to be held waiting for the data, i.e. hold master, or released to do something else and poll for the data until it is ready.

The hold master option works by allowing the device to stretch the clock pulse by holding the line low after the master has released it. In this mode the master will wait until the device releases the line.

Not all masters support this mode but the Pi does and this makes this the simplest option. 

To read the temperature using the Hold master mode you simply send 0xE3 and then read three bytes.

bcm2835_i2c_read_register_rs(buf, buf, 3);
uint8_t msb = buf[0];
uint8_t lsb = buf[1];
uint8_t check = buf[2];
printf("msb %d \n\r lsb %d \n\r checksum %d \n\r", msb, lsb, check);

The buffer is unpacked into three variables with more meaningful names - the msb most significant byte, lsb - least significant byte and the check(sum). 

If you try this you will find that it doesn't work. The reason is that it almost certainly times out with the default setting of clock stretch time out of 40 clock pulses. At the default clock speed of 1.666MHz this gives a time out of 24 microseconds which is very short. The HTU21D takes something in the region of 40 milliseconds or more to complete a temperature conversion - a timeout is inevitable. 

Setting The Clock Stretching Timeout

In most cases when using clock stretching we have to modify the clock stretching timeout. Unfortunately the library doesn't provide a function to do this. It is however fairly easy to create a function to do the job:

void setTimeout(uint16_t timeout) {
 volatile uint32_t* stimeout = bcm2835_bsc1 + BCM2835_BSC_CLKT / 4;
 bcm2835_peri_write(stimeout, timeout);
}

This simply writes to the timeout register using the address constants created by the library. 

Now we can make clock stretching work by disabling the timeout by setting a value of zero. 

 bcm2835_i2c_begin();
 bcm2835_i2c_setClockDivider(BCM2835_I2C_CLOCK_DIVIDER_150);

 setTimeout(0);
 char buf[4] = {0xE3};
 uint8_t status = bcm2835_i2c_read_register_rs(buf, buf, 3);
 uint8_t msb = buf[0];
 uint8_t lsb = buf[1];
 uint8_t check = buf[2];
 printf("msb %d \n\r lsb %d \n\r checksum %d \n\r", msb, lsb, check);

If you try this out you should find that it works and it prints something like

msb 97 
lsb 232
checksum 217

with the temperature in the 20C range. 

The logic analyzer reveals what is happening.

First we send the usual address frame and write the 0xE3. Then after a short pause the read address frame is sent and the clock line is held low by the device (lower trace):

 

The clock line is held low by the device for over 42ms while it gets the data ready. It is released and the three data frames are sent:  

 

This response really is a long way down the logic analyzers trace so keep scrolling until you find it. 

Working with a clock stretch timeout disabled isn't a good idea for a production program but at the default clock rate the longest timeout that can be set using 16 bits  is 24.5 milliseconds which is not long enough. To set a timeout of 100 milliseconds the clock has to be at most 1.5 microseconds. 

A standard clock rate of  BCM2835_I2C_CLOCK_DIVIDER_626 gives a clock time of 2.5 microseconds and a timeout count of 40,000 for 100ms. 

The complete program is:

bcm2835_i2c_begin();
bcm2835_i2c_setClockDivider(BCM2835_I2C_CLOCK_DIVIDER_626);

setTimeout(40000);

bcm2835_i2c_setSlaveAddress(0x40);
char buf[4] = {0xE3};
uint8_t status = bcm2835_i2c_read_register_rs(buf, buf, 3);
printf("status=%d\n\r",status);
uint8_t msb = buf[0];
uint8_t lsb = buf[1];
uint8_t check = buf[2];
printf("msb %d \n\r lsb %d \n\r checksum %d \n\r", msb, lsb, check);

This now works reliably and will timeout if anything goes wrong with the slave.