IIC (Inter-Integrated Circuit) was proposed by Philips in the 1980s. This interface uses two signal lines to achieve one master and multiple slaves communication, one is the bidirectional data line SDA, and the other is the clock line SCL. All serial data SDA connected to the I2C bus devices are connected to the bus SDA, and the clock line SCL of each device is connected to the bus SCL.
Rockchip I2C controller supports the following functions:
The following takes the operation of I2C3 hanging an at24c32 as an example to introduce how to read and write I2C. at24c32 is a 32kbit EEPROM. The I2C address of this device is 0x50, and the register is 16 bits long. Each register is a byte storage unit. The wiring diagram is as follows
The nodes of "/dev/i2c-*" require root privileges to perform read and write operations. Using the command line or a program compiled in C language to operate i2c also requires root privileges. If you are using ssh or LX terminal, execute the following command to obtain root privileges first.
sudo su
Linux provides i2ctool to operate i2c. The two more practical tools are i2cdetect and i2ctransfer. In addition, i2cget and i2cset are actually simplified versions of i2ctransfer. The system on the board comes with these commands
Detect which devices are under i2c3
i2cdetect -y 3
The operation results are as follows
Continuously write three bytes of data 0x03 0x04 0x05 starting from 0x0000 to at24c32. Among them, w5 means that 5 bytes are to be written continuously. Since the register address is 2 bytes, that is, 16 bits, there are three bytes of data, and 0x50 is its I2C device address
i2ctransfer -f -y 3 w5@0x50 0x00 0x00 0x03 0x04 0x05
Continuously read three bytes of data starting from 0x0000 from at24c32. Among them, w2 means to write 2 bytes continuously. Since the register address is 2 bytes, that is, 16 bits, 0x50 is its I2C device address, and r3 means to read 3 registers continuously
i2ctransfer -f -y 5 w2@0x50 0x00 0x00 r3
The operation result is as shown below
By connecting to the libperipheral_api.a static library, you can use C language to call the following interface to operate I2C
/**
* @name: user_i2c_open
* @description: Open i2c device
* @param i2c_num: i2c number, the i2c led out on the board includes 1 5
* @return greater than or equal to 0 - success, the return value is the file descriptor less than 0 - failure
*/
int user_i2c_open(int i2c_num);
/**
* @name: user_i2c_read
* @description: Read data from i2c device
* @param fd: file descriptor, user_i2c_open return value
* @param slave_addr: i2c device address
* @param reg_addr: pointer to register address
* @param addr_len: length of register address
* @param buf: pointer to read data
* @param len: length of read data
*
* @return equal to 0 - success less than 0 - failure
*/
int user_i2c_read(int fd, unsigned short slave_addr, unsigned char *reg_addr, unsigned char addr_len, unsigned char *buf, unsigned short len);
/**
* @name: user_i2c_read
* @description: Read data from i2c device
* @param fd: file descriptor, user_i2c_open return value
* @param slave_addr: i2c device address
* @param reg_addr: pointer to register address
* @param addr_len: length of register address
* @param buf: pointer to write data
* @param len: length of write data
*
* @return equal to 0 - success less than 0 - failure
*/
int user_i2c_write(int fd, unsigned short slave_addr, unsigned char *reg_addr, unsigned char addr_len, unsigned char *buf, unsigned short len);
/**
* @name: user_i2c_close
* @description: close i2c
* @param fd: file descriptor, user_i2c_open return value
* @return always equal to 0, meaningless
*/
int user_i2c_close(int fd);
The test demo is as follows, taking the operation of AT24C32 under I2C3 as an example
#include "peripheral_api.h"
void i2c_api_test(void)
{
int fd = -1;
int ret = 0;
unsigned char reg[2] = {0x00, 0x00};
unsigned char buf_write[5] = {0x01, 0x02, 0x03, 0x04, 0x05};
unsigned char buf_read[5] = {0};
fd = user_i2c_open(3);
if (fd < 0) {
printf("user_i2c_open fail\n");
return;
}
ret = user_i2c_write(fd, 0x50, reg, 2, buf_write, 5);
if (ret < 0) {
printf("user_i2c_write fail\n");
user_i2c_close(fd);
return;
}
usleep(100 * 1000);
ret = user_i2c_read(fd, 0x50, reg, 2, buf_read, 5);
if (ret < 0) {
printf("user_i2c_read fail\n");
user_i2c_close(fd);
return;
}
user_i2c_close(fd);
if (memcmp(buf_write, buf_read, 5) == 0) {
printf("buf_write buf_read same\n");
} else {
printf("buf_write buf_read diff %d %d %d %d %d %d\n", buf_read[0], buf_read[1], buf_read[2], buf_read[3], buf_read[4]);
}
return;
}
int main()
{
i2c_api_test();
return 0;
}
Put the peripheral_api.a static library, peripheral_api.h and test demo source code test.c in the same path, and the compilation command is as follows
aarch64-none-linux-gnu-gcc test.c peripheral_api.a -I. -o i2ctest
The running results are as follows
root@linaro-alip:/home/linaro# ./i2ctest
buf_write buf_read same