注意点:
- 如果在设置I2C_SLAVE的时候,提示device_busy,可以使用I2C_SLAVE_FORCE, 在驱动里面二者对应同一个case语句
- 应用层可以调用接口:i2c_smbus_write_word_data(fd, __, __);和i2c_smbus_read_word_data(fd,__);
分享:
问题如下:
1. 应用程序中直接fd句柄是整个I2C0总线的文件句柄,而只是在set地址的时候,将I2C address设置下去,后面操作该芯片还是操作全局I2C0总线上这个文件,并没有指定去操作该芯片,这其中是怎么做到的?这样的话,如果在一个main程序中, 操作同一总线上不同i2c设备,而文件句柄是同一个,这要如何操作?
--------------------------------------------------------------------------------------------
驱动方面:
首先配置I2C内核驱动,将pca9555的源码built-in进入(这里根据需要可能要配thermal的驱动),然后在devicetree中根据pca9555硬件I2C地址配置节点。
测试源码:
// I2C test program for a PCA9555 #include <stdint.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <linux/i2c-dev.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <fcntl.h> // I2C Linux device handle int g_i2cFile; // open the Linux device void i2cOpen() { g_i2cFile = open("/dev/i2c-0", O_RDWR); if (g_i2cFile < 0) { perror("i2cOpen"); exit(1); } } // close the Linux device void i2cClose() { close(g_i2cFile); } // set the I2C slave address for all subsequent I2C device transfers void i2cSetAddress(int address) { if (ioctl(g_i2cFile, I2C_SLAVE, address) < 0) { perror("i2cSetAddress"); exit(1); } } // write a 16 bit value to a register pair // write low byte of value to register reg, // and high byte of value to register reg+1 void pca9555WriteRegisterPair(uint8_t reg, uint16_t value) { uint8_t data[3]; data[0] = reg; data[1] = value & 0xff; data[2] = (value >> 8) & 0xff; if (write(g_i2cFile, data, 3) != 3) { perror("pca9555SetRegisterPair"); } } // read a 16 bit value from a register pair uint16_t pca9555ReadRegisterPair(uint8_t reg) { uint8_t data[3]; data[0] = reg; if (write(g_i2cFile, data, 1) != 1) { perror("pca9555ReadRegisterPair set register"); } if (read(g_i2cFile, data, 2) != 2) { perror("pca9555ReadRegisterPair read value"); } return data[0] | (data[1] << 8); } // set IO ports to input, if the corresponding direction bit is 1, // otherwise set it to output void pca9555SetInputDirection(uint16_t direction) { pca9555WriteRegisterPair(6, direction); } // set the IO port outputs void pca9555SetOutput(uint16_t value) { pca9555WriteRegisterPair(2, value); } // read the IO port inputs uint16_t pca9555GetInput() { return pca9555ReadRegisterPair(0); } int main(int argc, char** argv) { // test output value int v = 3; // direction of the LED animation int directionLeft = 1; // open Linux I2C device i2cOpen(); // set address of the PCA9555 i2cSetAddress(0x20); // set input for IO pin 15, rest output pca9555SetInputDirection(1 << 15); // LED animation loop while (1) { // if button is pressed, invert output int xor; if (pca9555GetInput() & 0x8000) { xor = 0; } else { xor = 0xffff; } // set current output pca9555SetOutput(v ^ xor); // animate LED position if (directionLeft) { v <<= 1; } else { v >>= 1; } if (v == 0x6000) { directionLeft = 0; } if (v == 3) { directionLeft = 1; } // wait 100 ms for next animation step usleep(100000); } // close Linux I2C device i2cClose(); return 0; }