Raspberry Pi IoT In C Using Linux Drivers - The I2C Linux Driver
Monday, 25 July 2022
Article Index
Raspberry Pi IoT In C Using Linux Drivers - The I2C Linux Driver
A Real Device
Checksum

## Checksum Calculation

Although computing a checksum isn't specific to I2C, it is another common task. The datasheet explains that the polynomial used is:

X8 + X5 + X4 + 1

Once you have this information you can work out the divisor by writing a binary number with a one in each location corresponding to a power of X in the polynomial. In this case the 8th, 5th, 4th and 1st bit. Hence the divisor is:

0x0131

What you do next is roughly the same for all CRCs. First you put the data that was used to compute the checksum together with the checksum value as the low order bits:

```uint32_t data32 = ((uint32_t) msb << 16) |                     ((uint32_t) lsb << 8) |
(uint32_t) check;```

Now you have three bytes, i.e 24 bits in a 32-bit value. Next you adjust the divisor so that its most significant non-zero bit aligns with the most significant bit of the three bytes. As this divisor has a 1 at bit eight it needs to be shifted 15 places to the right to move it to be the 24th bit:

`uint32_t divisor = 0x988000;`

Now that you have both the data and the divisor aligned, you step through the top-most 16 bits, i.e. you don't process the low order eight bits which is the received checksum. For each bit you check to see if it is a 1 - if it is you replace the data with the data XOR divisor. In either case you shift the divisor one place to the right:

```    for (int i = 0; i < 16; i++) {
if (data32 & (uint32_t) 1 << (23 - i))                                data32 ^= divisor;
divisor >>= 1;
};```

When the loop ends, if there was no error, the `data32` should be zeroed and the received checksum is correct and as computed on the data received.

A complete function to compute the checksum is:

```uint8_t crcCheck(uint8_t msb, uint8_t lsb,                                  uint8_t check) {
uint32_t data32 = ((uint32_t) msb << 16) |                           ((uint32_t) lsb << 8) |
(uint32_t) check;
uint32_t divisor = 0x988000;
for (int i = 0; i < 16; i++) {
if (data32 & (uint32_t) 1 << (23 - i))                             data32 ^= divisor;
divisor >>= 1;
};
return (uint8_t) data32;
}```

It is rare to get a CRC error on an I2C bus unless it is overloaded or subject to a lot of noise.

## The Complete Program

```#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
void checkI2CBus();
FILE * doCommand(char *cmd);
uint8_t crcCheck(uint8_t msb, uint8_t lsb,                                 uint8_t check);
int main(int argc, char** argv) {
checkI2CBus();
int i2cfd = open("/dev/i2c-1", O_RDWR);
ioctl(i2cfd, I2C_SLAVE, 0x40);
char buf[3] = {0xF3};
write(i2cfd, buf, 1);
while (1) {
int result = read(i2cfd, buf, 3);
if (result > 0) break;
usleep(10 * 1000);
}
uint8_t msb = buf[0];
uint8_t lsb = buf[1];
uint8_t check = buf[2];
printf("msb %d \n\rlsb %d \n\rchecksum %d \n\r",                            msb, lsb, check);
unsigned int data16 = ( (unsigned int) msb << 8) |
(unsigned int) (lsb & 0xFC);
float temp = (float) (-46.85 + (175.72 * data16 /
(float) 65536));
printf("Temperature %f C \n\r", temp);
printf("crc = %d\n\r", crcCheck(msb, lsb, check));
buf[0] = 0xF5;
write(i2cfd, buf, 1);
while (1) {
int result = read(i2cfd, buf, 3);
if (result > 0) break;
usleep(10 * 1000);
}
msb = buf[0];
lsb = buf[1];
check = buf[2];
printf("crc = %d\n\r", crcCheck(msb, lsb, check));
data16 = ((unsigned int) msb << 8) |
(unsigned int) (lsb & 0xFC);
float hum = -6 + (125.0 * (float) data16) / 65536;
printf("Humidity %f %% \n\r", hum);
close(i2cfd);
return (EXIT_SUCCESS);
}
uint8_t crcCheck(uint8_t msb, uint8_t lsb,                                  uint8_t check) {
uint32_t data32 = ((uint32_t) msb << 16) |
((uint32_t) lsb << 8) | (uint32_t) check;
uint32_t divisor = 0x988000;
for (int i = 0; i < 16; i++) {
if (data32 & (uint32_t) 1 << (23 - i))                               data32 ^= divisor;
divisor >>= 1;
};
return (uint8_t) data32;
}
void checkI2CBus() {
FILE *fd = doCommand("sudo dtparam -l");
char output[1024];
int txfound = 0;
while (fgets(output, sizeof (output), fd) != NULL) {
printf("%s\n\r", output);
fflush(stdout);
if (strstr(output, "i2c_arm=on") != NULL) {
txfound = 1;
}
if (strstr(output, "i2c_arm=off") != NULL) {
txfound = 0;
}
}
pclose(fd);
if (txfound == 0) {
fd = doCommand("sudo dtparam i2c_arm=on");
pclose(fd);
}
}
FILE * doCommand(char *cmd) {
FILE *fp = popen(cmd, "r");
if (fp == NULL) {
printf("Failed to run command %s \n\r", cmd);
exit(1);
}
return fp;
}```

• I2C Tools

## Summary

• The I2C driver can be loaded dynamically and it provides the basic facilities to interface with any I2C device.

• The I2C driver creates a number of new folder and it also accepts ioctl commands.

• As an example of using the driver, the HTU21D is easy to set up and read. It also has a dedicated Linux driver which is discussed in Chapter 14.

• Without clock stretching support, all we can do is to poll for data to be ready to read.

• Computing a CRC is something every IoT programmer needs to know how to do in the general case.

• There are a number of command line tools that let you work with I2C, but they need to be used with caution.

## Raspberry Pi IoT In C Using Linux Drivers

#### Contents

1.  Choosing A Pi For IoT

2. C and Visual Studio Code

3.  Drivers: A First Program

4.  The GPIO Character Driver
Extract: GPIO Character Driver

5. GPIO Using I/O Control

6.  GPIO Events

7.  The Device Tree
Extract: The DHT22

8.  Some Electronics

9.  Pulse Width Modulation
Extract:  The PWM Driver

10. SPI Devices
Extract: The SPI Driver

11. I2C Basics

12. The I2C Linux Driver ***NEW!

14. Sensor Drivers – Linux IIO & Hwmon
Extract: Hwmon

15. 1-Wire Bus
Extract: 1-Wire And The DS18B20

16. Going Further With Drivers

17. Appendix I

<ASIN:1871962641>

<ASIN:B08W9V7TP9>

 Training and Mentorship Promote Job Satisfaction02/08/2022Results of the EDB Open Source Talent Survey 2022 indicate that employees value the opportunity to work with and be trained in cutting edge technologies. Security training is also highly prized. + Full Story ScyllaDB Optimizes Mixed Workload Latency18/07/2022There's a major new version of ScyllaDB with improvements aimed at improving performance and ease of use. These start with support for running on the AWS EC2 servers that are powered by Intel Xeon pro [ ... ] + Full Story More News

<ASIN:187196265X>

<ASIN:1871962692>

<ASIN:1871962609>

<ASIN:1871962617>

<ASIN:1871962455>

<ASIN:1871962463>

Last Updated ( Monday, 25 July 2022 )