5.5 使用用戶態接口訪問I2C設備
i2c-tools幫我們封裝好了用戶態訪問I2C設備的接口,它是一套好用的工具,也是一套示例代碼。
5.5.1體驗I2C-Tools
使用一句話概括I2C傳輸:APP通過I2C Controller與I2CDevice傳輸數據。
所以使用I2C-Tools時也需要指定:
? 哪個I2C控制器(或稱為I2C BUS、I2C Adapter)
? 哪個I2C設備(設備地址)
? 數據:讀還是寫、數據本身
1. 交叉編譯
? 配置環境:
source /opt/remi-sdk/environment-setup-aarch64-poky-linux
在Makefile中,“?=”在第一次設置變量時才會起效果,如果之前設置過該變量,則不會起效果。
注意:
①執行make時,是動態鏈接,需要把libi2c.so也放到單板上。
②想靜態鏈接的話,執行:make USE_STATIC_LIB=1
2. 用法
? i2cdetect:I2C檢測。
// 列出當前的 I2C Adapter(或稱為 I2C Bus、I2C Controller)i2cdetect -l// 打印某個 I2C Adapter 的 Functionalities, I2CBUS 為 0、1、2 等整數i2cdetect -F I2CBUS// 看看有哪些 I2C 設備, I2CBUS 為 0、1、2 等整數i2cdetect -y -a I2CBUS// 效果如下# i2cdetect -li2c-3 i2c Renesas RIIC adapter I2C adapteri2c-1 i2c Renesas RIIC adapter I2C adapteri2c-0 i2c Renesas RIIC adapter I2C adapter# i2cdetect -F 0Functionalities implemented by /dev/i2c-0:I2C yesSMBus Quick Command yesSMBus Send Byte yesSMBus Receive Byte yesSMBus Write Byte yesSMBus Read Byte yesSMBus Write Word yesSMBus Read Word yesSMBus Process Call yesSMBus Block Write yesSMBus Block Read yesSMBus Block Process Call yesSMBus PEC yesI2C Block Write yesI2C Block Read yes// --表示沒有該地址對應的設備, UU 表示有該設備并且它已經有驅動程序,// 數值表示有該設備但是沒有對應的設備驅動# i2cdetect -y -a 0 ?0 1 2 3 4 5 6 7 8 9 a b c d e f00: 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --10: -- -- -- -- -- -- -- -- -- -- UU -- -- -- 1e --20: -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- --30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
? i2cget:I2C讀
使用說明如下:
# i2cgetUsage: i2cget [-f] [-y] [-a] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]I2CBUS is an integer or an I2C bus nameADDRESS is an integer (0x03 - 0x77, or 0x00 - 0x7f if -a is given)MODE is one of:b (read byte data, default)w (read word data)c (write byte/read byte)Append p for SMBus PEC
使用示例:
// 讀一個字節: I2CBUS 為 0、1、2 等整數, 表示 I2C Bus; CHIP-ADDRESS 表示設備地址i2cget -f -y I2CBUS CHIP-ADDRESS// 讀某個地址上的一個字節:// I2CBUS 為 0、1、2 等整數, 表示 I2C Bus// CHIP-ADDRESS 表示設備地址// DATA-ADDRESS: 芯片上寄存器地址// MODE:有 2 個取值, b-使用`SMBus Read Byte`先發出 DATA-ADDRESS, 再讀一個字節, 中間無P 信號// c-先 write byte, 在 read byte,中間有 P 信號i2cget -f -y I2CBUS CHIP-ADDRESS DATA-ADDRESS MODE // 讀某個地址上的 2 個字節: // I2CBUS 為 0、1、2 等整數, 表示 I2C Bus// CHIP-ADDRESS 表示設備地址// DATA-ADDRESS: 芯片上寄存器地址// MODE:w-表示先發出 DATA-ADDRESS,再讀 2 個字節i2cget -f -y I2CBUS CHIP-ADDRESS DATA-ADDRESS MODE
? i2cset:I2C寫
使用說明如下:
# i2csetUsage: i2cset [-f] [-y] [-m MASK] [-r] [-a] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE]... [MODE]I2CBUS is an integer or an I2C bus nameADDRESS is an integer (0x03 - 0x77, or 0x00 - 0x7f if -a is given)MODE is one of:c (byte, no value)b (byte data, default)w (word data)i (I2C block data)s (SMBus block data)Append p for SMBus PEC
使用示例:
// 寫一個字節: I2CBUS 為 0、1、2 等整數, 表示 I2C Bus; CHIP-ADDRESS 表示設備地址// DATA-ADDRESS 就是要寫的數據i2cset -f -y I2CBUS CHIP-ADDRESS DATA-ADDRESS// 給 address 寫 1 個字節(address, value):// I2CBUS 為 0、1、2 等整數, 表示 I2C Bus; CHIP-ADDRESS 表示設備地址// DATA-ADDRESS: 8 位芯片寄存器地址;// VALUE: 8 位數值// MODE: 可以省略,也可以寫為 bi2cset -f -y I2CBUS CHIP-ADDRESS DATA-ADDRESS VALUE [b]// 給 address 寫 2 個字節(address, value):// I2CBUS 為 0、1、2 等整數, 表示 I2C Bus; CHIP-ADDRESS 表示設備地址// DATA-ADDRESS: 8 位芯片寄存器地址;// VALUE: 16 位數值// MODE: wi2cset -f -y I2CBUS CHIP-ADDRESS DATA-ADDRESS VALUE w// SMBus Block Write:給 address 寫 N 個字節的數據// 發送的數據有:address, N, value1, value2, ..., valueN// 跟`I2C Block Write`相比, 需要發送長度 N// I2CBUS 為 0、1、2 等整數, 表示 I2C Bus; CHIP-ADDRESS 表示設備地址// DATA-ADDRESS: 8 位芯片寄存器地址;// VALUE1~N: N 個 8 位數值// MODE: si2cset -f -y I2CBUS CHIP-ADDRESS DATA-ADDRESS VALUE1 ... VALUEN s// I2C Block Write:給 address 寫 N 個字節的數據// 發送的數據有:address, value1, value2, ..., valueN// 跟`SMBus Block Write`相比, 不需要發送長度 N// I2CBUS 為 0、1、2 等整數, 表示 I2C Bus; CHIP-ADDRESS 表示設備地址// DATA-ADDRESS: 8 位芯片寄存器地址;// VALUE1~N: N 個 8 位數值// MODE: ii2cset -f -y I2CBUS CHIP-ADDRESS DATA-ADDRESS VALUE1 ... VALUEN i
? i2ctransfer:I2C傳輸(不是基于SMBus)
使用說明如下:
# i2ctransferUsage: i2ctransfer [-f] [-y] [-v] [-V] [-a] I2CBUS DESC [DATA] [DESC [DATA]]...I2CBUS is an integer or an I2C bus nameDESC describes the transfer in the form: {r|w}LENGTH[@address]1) read/write-flag 2) LENGTH (range 0-65535) 3) I2C address (use last one if omitted)DATA are LENGTH bytes for a write message. They can be shortened by a suffix:= (keep value constant until LENGTH)+ (increase value by 1 until LENGTH)- (decrease value by 1 until LENGTH)p (use pseudo random generator until LENGTH with value as seed)Example (bus 0, read 8 byte at offset 0x64 from EEPROM at 0x50):# i2ctransfer 0 w1@0x50 0x64 r8Example (same EEPROM, at offset 0x42 write 0xff 0xfe ... 0xf0):# i2ctransfer 0 w17@0x50 0x42 0xff
使用舉例:
// Example (bus 0, read 8 byte at offset 0x64 from EEPROM at 0x50):# i2ctransfer -f -y 0 w1@0x50 0x64 r8// Example (bus 0, write 3 byte at offset 0x64 from EEPROM at 0x50):# i2ctransfer -f -y 0 w9@0x50 0x64 val1 val2 val3// Example// first: (bus 0, write 3 byte at offset 0x64 from EEPROM at 0x50)// and then: (bus 0, read 3 byte at offset 0x64 from EEPROM at 0x50)# i2ctransfer -f -y 0 w9@0x50 0x64 val1 val2 val3 r3@0x50# i2ctransfer -f -y 0 w9@0x50 0x64 val1 val2 val3 r3 //如果設備地址不變,后面的設備地址可省略
5.5.2 I2C-Tools訪問I2C設備的2種方式
I2C-Tools可以通過SMBus來訪問I2C設備,也可以使用一般的I2C協議來訪問I2C設備。
使用一句話概括I2C傳輸:APP通過I2C Controller與I2C Device傳輸數據。
在APP里,有這幾個問題:
①怎么指定I2C控制器?
? i2c-dev.c為每個I2C控制器(I2C Bus、I2C Adapter)都生成一個設備節點:/dev/i2c-0、/dev/i2c-1等等;
? open某個/dev/i2c-X節點,就是去訪問該I2C控制器下的設備;
②怎么指定I2C設備?
通過ioctl指定I2C設備的地址
? ioctl(file,I2C_SLAVE,address)
? 如果該設備已經有了對應的設備驅動程序,則返回失敗。
? ioctl(file,I2C_SLAVE_FORCE,address)
? 如果該設備已經有了對應的設備驅動程序但是還是想通過i2cdev驅動來訪問它,則使用這個ioctl來指定I2C設備地址。
怎么傳輸數據?
③兩種方式
? 一般的I2C方式:ioctl(file,I2C_RDWR,&rdwr)
? SMBus方式:ioctl(file,I2C_SMBUS,&args)
5.5.3 源碼流程分析
1. 使用I2C方式
示例代碼:i2ctransfer.c

圖I2C 讀寫源碼流程
2. 使用SMBus方式
示例代碼:i2cget.c、i2cset.c

圖SMBus讀寫源碼流程
5.6 編寫APP
在開始前,請先按照下圖所示連接AT24C02模塊


本節源碼位于如下目錄:

源碼如下所示:
int main(int argc, char **argv)unsigned char dev_addr = 0x50;unsigned char mem_addr = 0;unsigned char buf[32];int file;char filename[20];unsigned char *str;int ret;struct timespec req;if (argc != 3 && argc != 4){printf("Usage:\n");printf("write eeprom: %sw string\n" , argv[0]);printf("read eeprom: %sr\n" , argv[0]);return -1;}//打開指定的 I2C 設備文件file = open_i2c_dev(argv[1][0]-'0', filename, sizeof(filename), 0);if (file < 0){printf("can't open %s\n", filename);return -1;}//設置 I2C 設備的從設備地址if (set_slave_addr(file, dev_addr, 1)){printf("can't set_slave_addr\n");return -1;}//如果命令行參數是 “w”,則將字符串寫入 EEPROM。if (argv[2][0] == 'w'){// write str: argv[3]str = argv[3];req.tv_sec = 0;req.tv_nsec = 20000000; /* 20ms */while (*str)// 逐個字符寫入 EEPROM{// mem_addr, *str// mem_addr++, str++ret = i2c_smbus_write_byte_data(file, mem_addr, *str);if (ret){printf("i2c_smbus_write_byte_data err\n");return -1;}// wait tWR(10ms)?nanosleep(&req, NULL);// 每次寫入后等待 20 毫秒mem_addr++;str++;}ret = i2c_smbus_write_byte_data(file, mem_addr, 0); // string end charif (ret){printf("i2c_smbus_write_byte_data err\n");return -1;}}else //如果命令行參數是 “r”,則從 EEPROM 讀取數據。{// read 讀取 EEPROM 數據ret = i2c_smbus_read_i2c_block_data(file, mem_addr, sizeof(buf), buf);if (ret < 0){printf("i2c_smbus_read_i2c_block_data err\n");return -1;}buf[31] = '\0';printf("get data: %s\n", buf);}return 0;}
編譯:由于應用程序需要借助兩個庫i2cbusses.c和smbus.c,那么在編譯應用程序時需要包含這兩個程序:
source /opt/remi-sdk/environment-setup-aarch64-poky-linux$CC -I ./include -o at24c02_test at24c02_test.c i2cbusses.c smbus.c
假設設置開發板的IP為:192.168.5.9,上傳程序到開發板上。
scp ./input_read_fasync root@192.168.5.9:/mnt/測試:進入/mnt目錄運行程序:
root@myir-remi-1g:~root@myir-remi-1g:/mntat24c02_test
接上at24c02模塊,向模塊中寫入數據,再讀出來:
root@myir-remi-1g:/mnt# ./at24c02_test 3 w 123456789root@myir-remi-1g:/mnt# ./at24c02_test 3 rget data: 123456789
如您在使用瑞薩MCU/MPU產品中有任何問題,可識別下方二維碼或復制網址到瀏覽器中打開,進入瑞薩技術論壇尋找答案或獲取在線技術支持。
https://community-ja.renesas.com/zh/forums-groups/mcu-mpu/
未完待續
推薦閱讀
Linux串口應用編程?-?RZ?MPU工業控制教程連載(6)
贏瑞米派?|?瑞薩RZ/G通用MPU研討會火熱報名中
函數應用及數據讀取?-?RZ?MPU工業控制教程連載(5)