Linux 的 I2C 指令
在 Linux 中,常使用的 i2c 工具指令有:
i2cdetect, i2cget, i2cset, i2cdump, i2ctransfer
以下將一一說明指令的功能。
又如果在 Driver 執行成功的情況下,會無法使用上述指令取得暫存器的值,因為此時該 I2C 裝置已被 Driver 佔用。
不過在 Driver 有實作 regmap 的情況下,可以利用 cat 指令,直接從系統資料夾 - /sys/kernel/debug/regmap/ 的 I2C bus - I2C slave Address 資料夾內的 registers 檔案來查看暫存器值。
例如 I2C bus 為 7,I2C slave Address 為 0x11,則透過 cat 讀取暫存器值的指令為:
# cat /sys/kernel/debug/regmap/7-0011/registers
registers 的個數是在 Driver - kernel/sound/soc/codecs/es8388.c 設定的,參數為 max_register,如下:
static const struct regmap_config es8388_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = ES8388_REG_MAX, .cache_type = REGCACHE_RBTREE, };
i2cdetect
i2cdetect 指令是用來列出在 Linux 中,所有已知及可用的 I2C buses。
要列出全部的 I2CBUS,可以使用 -l 參數:
# i2cdetect -l
i2c-10 i2c ddc I2C adapter
i2c-6 i2c rk3x-i2c I2C adapter
i2c-4 i2c rk3x-i2c I2C adapter
i2c-11 i2c ddc I2C adapter
i2c-2 i2c rk3x-i2c I2C adapter
i2c-0 i2c rk3x-i2c I2C adapter
i2c-9 i2c fde50000.dp I2C adapter
i2c-7 i2c rk3x-i2c I2C adapter
要偵測特定的 I2C BUS 的所有 slave address 是否有裝置,可以使用 -a + bus_no 參數。
例如偵測在 I2C BUS 2 中,是否有裝置 :
# i2cdetect -y -a 2
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- --
30: 30 -- -- -- -- -- 36 -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
執行結果有以下 3 種情況:
--: 表示經尋問該位址後,沒有得到回應。
UU: 表示該位址被 driver 所使用,所以沒有尋問該位址,同時該位址很可能存在 I2C 裝置。
address: 表示經尋問該位址後,有 I2C 裝置回應。
也可以直接指定特定的 I2C BUS 及特定的 slave address 來做偵測。
例如偵測 I2C BUS 2 中 slave address 60 (= 0x3c) 是否有裝置:
# i2cdetect -y 2 60 60
# i2cdetect -y 2 0x3c 0x3c
0 1 2 3 4 5 6 7 8 9 a b c d e f
00:
10:
20:
30: --
40:
50:
60:
70:
但也不是每個 I2C 裝置一定會被 i2cdetect 偵測到,例如有些裝置是需要 init sequence 來啟動裝置的。
以 Camera OV5640 舉例來說,如果 init sequence 不正確,則 Camera OV5640 無法正常啟動,就不會對 i2cdetect 指令作回應,因為此時裝置還沒啟動。
init sequence 通常會由該裝置的 driver 負責執行,也就是說,如果 driver 有問題,會導致 Camera OV5640 無法順利啟動,也就無法被 i2cdetect 偵測到。
另外在執行 i2cdetect 時,如果遇到 timeout error,則可能是因為缺少 pull-up 電阻導致的,需要請 HW 確認。
i2cget
i2cget 指令可以用來讀取 I2C 裝置的特定暫存器位址的值。
例如要讀取 I2C BUS 2 中,slave address 為 0x22 的裝置,其暫儲器位址為 0x00 的值:
# i2cget -y 2 0x22 0x00
0x23
i2cset
和 i2cget 相反,i2cset 指令可以用來寫入 I2C 裝置的特定暫存器位址的值。
例如要把 0x12 寫入 I2C BUS 2 中,slave address 為 0x22 的裝置,其暫儲器位址為 0x00 的值:
# i2cset -y 2 0x22 0x00 0x12
i2cdump
和 i2cget 類似,i2cdump 指令可以用來讀取 I2C 裝置的大範圍暫存器位址的值。
例如要讀取 I2C BUS 2 中,slave address 為 0x22 的裝置,其全部暫儲器位址的值:
# i2cdump -y 2 0x22
如果要指定暫儲器位址,只讀取前 16 bytes,可以使用 -r + first-last 參數:
# i2cdump -y -r 0x0-0xf 2 0x22
i2ctransfer
i2ctransfer 指令可以用來寫入或讀取 I2C 裝置的大範圍暫存器位址的值。
但是不管是要執行寫入還是讀取,都需要先進行寫入,也就是要先寫入位址(offset)。
例如要讀取 I2C BUS 2 中,slave address 為 0x22 的裝置,暫儲器位址從 0x02 開始,讀取 14 bytes:
# i2ctransfer -y 2 w1@0x22 0x02 r14
例如要寫入 I2C BUS 2 中,slave address 為 0x22 的裝置,暫儲器位址從 0x01 開始,寫入 2 bytes 的值,分別為 0x10, 0x16:
# i2ctransfer -y 2 w3@0x22 0x01 0x10 0x16
讀寫 16-bit address 的暫存器
例如要讀取 I2C BUS 2 中,slave address 為 0x22 的裝置,暫儲器位址從 0x300a 開始,讀取 2 bytes:
# i2ctransfer -y 2 w2@0x22 0x30 0x0a r2
例如要寫入 I2C BUS 2 中,slave address 為 0x22 的裝置,暫儲器位址從 0x300a 開始,寫入 2 bytes 的值,分別為 0x10, 0x16:
# i2ctransfer -y 2 w4@0x22 0x30 0x0a 0x10 0x16
Reference
[RK3399][Android7.1] 调试笔记 --- I2C读取错误unexpected irq in STOP: 0x10
文字內容 或 影像內容 部份參考、引用自網路,如有侵權,請告知。
留言列表