Raspberry Pi IoT In C Using Linux Drivers - The I2C Linux Driver |
Written by Harry Fairhead | |||||
Monday, 25 July 2022 | |||||
Page 1 of 4 Linux drivers make working with devices so easy - assuming you know how. Here's how to get a Raspberry Pi to work with the i2c bus using the standard driver. This content comes from my newly published book: Raspberry Pi IoT In C Using Linux DriversBy Harry FairheadBuy from Amazon. Contents
<ASIN:1871962641> <ASIN:B08W9V7TP9> If you want to program in Python see Raspberry Pi IoT In Python Using Linux Drivers. There are many specific device drivers which make use of the I2C bus and, as in the case of the SPI bus, there is usually a choice of hand-coding the interaction using the I2C driver or using the specific device driver. In this chapter we will look at the basics of making use of the driver for BSC1 which works on all versions of the Pi. Enabling The DriverTo make use of the Linux I2C driver you have to enable it by adding dtparam=i2c_arm=on to the /boot/config.txt file. Alternatively you can load it dynamically: 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; } This is slightly different to the earlier driver loading functions. The first part of the function uses dtparam -1 to get a list of loaded overlays. If it finds ic2_arm=on as the last ic2_arm overlay then it does nothing. If it doesn’t find it then it activates the overlay. As you can also use ic2_arm=off and it is the last overlay that controls the state of the system we need to find the last occurrence of ic2_arm and make sure it is “=on”. Both actions enable BSC1 and create a device file: /dev/i2c-1 You can check that the driver has been installed using: ls /dev/i2c* which will return a list of I2C devices. Using The I2C Driver From CAs is the case for all Linux devices, the I2C device /dev/i2c-x, where x is the I2C bus number, looks like a file. You can do a block read by simply opening the file for reading and reading an array of bytes: int i2cfd = open("/dev/i2c-1", O_RDWR); read(i2cfd,buf,n); This reads a maximum of n bytes of data and returns it as an array of bytes. The only problem is how do you specify the address of the device? Opening the file only opens the I2C channel and there might be multiple devices connected to it. As in the case of other /dev character devices we need to use the standard Linux ioctl function to send a command to it. In the case of the I2C driver the most important ioctl command is: I2C_SLAVE This is used to set the address of the slave that subsequent read and writes apply to. So to set the address of the device you want to read from to 0x40 you would use: #include <linux/i2c-dev.h> ioctl(i2cfd, I2C_SLAVE, 0x40); Finally to reset the hardware and return all GPIO lines to their default modes you have to close the file: close(i2cfd); Putting all of the together a block read/write is: #define _DEFAULT_SOURCE #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> #include <unistd.h> #include<fcntl.h> #include <linux/i2c-dev.h> void checkI2CBus(); FILE * doCommand(char *cmd); int main(int argc, char** argv) { checkI2CBus(); int i2cfd = open("/dev/i2c-1", O_RDWR); ioctl(i2cfd, I2C_SLAVE, 0x40); char buf[4] = {0xE7}; write(i2cfd,buf,1); read(i2cfd,buf,1); close(i2cfd return (EXIT_SUCCESS); } By default stop bits not are sent between each byte read, a stop bit is only sent at the end of the block of data that is written. If you try these programs out you will discover that the I2C clock frequency is the default 100KHz. You can’t change the clock frequency dynamically but you can add: dtparam=i2c_arm=on,i2c_arm_baudrate=10000 to the /boot/config.txt file and after a reboot the I2C clock will be set to the frequency specified as the baudrate. The baud rate is simply the clock speed in Hz. Notice that the I2C clock speed depends on the core clock rate and this can be slower than the maximum possible when the device is idling or under heat pressure. To run at the fastest clock speed, even when idling, use the command: sudo sh -c "echo performance > |
|||||
Last Updated ( Monday, 25 July 2022 ) |