Linux I2C 從裝置測試單元后端¶
作者:Wolfram Sang <wsa@sang-engineering.com>,2020 年
此後端可用於觸發 I2C 匯流排主裝置的測試用例,這些用例需要具有特定功能的遠端裝置(且這些裝置通常不易獲得)。示例包括多主裝置測試和 SMBus 主機通知測試。對於某些測試,I2C 從裝置控制器必須能夠在主模式和從模式之間切換,因為它也需要傳送資料。
請注意,此裝置用於測試和除錯。它不應在生產版本中啟用。儘管存在一些版本控制並且我們努力保持向後相容性,但無法保證穩定的 ABI!
例項化裝置是常規操作。例如,對於匯流排 0,地址 0x30
# echo "slave-testunit 0x1030" > /sys/bus/i2c/devices/i2c-0/new_device
或者使用韌體節點。這是一個裝置樹示例(請注意,這只是一個除錯裝置,因此沒有官方的 DT 繫結)
&i2c0 {
...
testunit@30 {
compatible = "slave-testunit";
reg = <(0x30 | I2C_OWN_SLAVE_ADDRESS)>;
};
};
之後,裝置將開始監聽。讀取將返回一個位元組。如果測試單元空閒,其值為 0,否則為當前執行命令的命令號。
寫入時,裝置由 4 個 8 位暫存器組成,除了一些“部分”命令外,所有暫存器都必須寫入才能啟動測試用例,即通常向裝置寫入 4 位元組資料。這些暫存器是
偏移 |
名稱 |
描述 |
|---|---|---|
0x00 |
CMD |
觸發哪個測試 |
0x01 |
DATAL |
測試的配置位元組 1 |
0x02 |
DATAH |
測試的配置位元組 2 |
0x03 |
DELAY |
測試啟動前延遲 n * 10 毫秒 |
使用 i2c-tools 包中的 ‘i2cset’ 命令,通用命令格式如下
# i2cset -y <bus_num> <testunit_address> <CMD> <DATAL> <DATAH> <DELAY> i
DELAY 是一個通用引數,它將延遲 CMD 中測試的執行。當一個命令正在執行(包括延遲)時,新命令將不會被確認。您需要等待舊命令完成。
命令將在以下部分中描述。無效命令將導致傳輸不被確認。
命令¶
0x00 NOOP¶
保留供將來使用。
0x01 READ_BYTES¶
CMD |
DATAL |
DATAH |
DELAY |
|---|---|---|---|
0x01 |
要讀取資料的地址(低 7 位,最高位目前未使用) |
要讀取的位元組數 |
n * 10 毫秒 |
也需要主模式。這對於測試您的匯流排主驅動程式是否正確處理多主模式很有用。您可以觸發測試單元從總線上的另一個裝置讀取位元組。如果正在測試的匯流排主裝置也想同時訪問匯流排,則匯流排將處於忙碌狀態。示例:延遲 50 毫秒後從裝置 0x50 讀取 128 位元組
# i2cset -y 0 0x30 1 0x50 0x80 5 i
0x02 SMBUS_HOST_NOTIFY¶
CMD |
DATAL |
DATAH |
DELAY |
|---|---|---|---|
0x02 |
要傳送的狀態字的低位元組 |
要傳送的狀態字的高位元組 |
n * 10 毫秒 |
也需要主模式。此測試將向主機發送一個 SMBUS_HOST_NOTIFY 訊息。請注意,目前 Linux 核心中會忽略狀態字。示例:延遲 10 毫秒後傳送狀態字為 0x6442 的通知
# i2cset -y 0 0x30 2 0x42 0x64 1 i
如果主機控制器支援 HostNotify,則應出現此除錯級別的訊息(Linux 6.11 及更高版本)
Detected HostNotify from address 0x30
0x03 SMBUS_BLOCK_PROC_CALL¶
CMD |
DATAL |
DATAH |
DELAY |
|---|---|---|---|
0x03 |
0x01(即會寫入一個額外位元組) |
要傳送回的位元組數 |
省略,部分命令! |
部分命令。此測試將響應 SMBus 規範中定義的塊程序呼叫。寫入的一個數據位元組指定在隨後的讀取傳輸中將返回多少位元組。請注意,在此讀取傳輸中,測試單元將預置後續位元組的長度。因此,如果您的主機匯流排驅動程式像大多數驅動程式一樣模擬 SMBus 呼叫,它需要支援 i2c_msg 的 I2C_M_RECV_LEN 標誌。這是一個很好的測試用例。返回的資料首先包含長度,然後是一個從 length-1 到 0 的位元組陣列。以下是使用 i2ctransfer 模擬 i2c_smbus_block_process_call() 的示例(您需要 i2c-tools v4.2 或更高版本)
# i2ctransfer -y 0 w3@0x30 3 1 0x10 r?
0x10 0x0f 0x0e 0x0d 0x0c 0x0b 0x0a 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00
0x04 GET_VERSION_WITH_REP_START¶
CMD |
DATAL |
DATAH |
DELAY |
|---|---|---|---|
0x04 |
目前未使用 |
目前未使用 |
省略,部分命令! |
部分命令。傳送此命令後,測試單元將回復一個讀取訊息,該訊息包含一個基於 UTS_RELEASE 的以 NUL 結尾的版本字串。第一個字元始終是 'v',版本字串的最大長度為 128 位元組。但是,它只會在讀取訊息透過重複啟動與寫入訊息連線時才響應。如果您的控制器驅動程式正確處理重複啟動,這將起作用
# i2ctransfer -y 0 w3@0x30 4 0 0 r128
0x76 0x36 0x2e 0x31 0x31 0x2e 0x30 0x2d 0x72 0x63 0x31 0x2d 0x30 0x30 0x30 0x30 ...
如果您有 i2c-tools 4.4 或更高版本,您可以立即打印出資料
# i2ctransfer -y -b 0 w3@0x30 4 0 0 r128
v6.11.0-rc1-00009-gd37a1b4d3fd0
兩條訊息之間的 STOP/START 組合將不起作用,因為它們不等同於重複啟動(REPEATED START)。例如,這隻會返回預設響應
# i2cset -y 0 0x30 4 0 0 i; i2cget -y 0 0x30
0x00
0x05 SMBUS_ALERT_REQUEST¶
CMD |
DATAL |
DATAH |
DELAY |
|---|---|---|---|
0x05 |
響應值(7 個最高有效位被解釋為 I2C 地址) |
目前未使用 |
n * 10 毫秒 |
此測試透過 SMBAlert 引腳觸發中斷,主機控制器必須處理該中斷。該引腳必須作為 GPIO 連線到測試單元。GPIO 訪問不允許休眠。目前,這隻能使用韌體節點來描述。因此,對於裝置樹,您可以在測試單元節點中新增類似如下的內容
gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
以下命令將在延遲 1 秒後觸發警報,響應值為 0xc9
# i2cset -y 0 0x30 5 0xc9 0x00 100 i
如果主機控制器支援 SMBusAlert,則應出現此除錯級別的訊息
smbus_alert 0-000c: SMBALERT# from dev 0x64, flag 1
此訊息可能會出現多次,因為測試單元是軟體而非硬體,因此可能無法足夠快地響應主機的應答。但是,中斷計數應只增加一次
# cat /proc/interrupts | grep smbus_alert
93: 1 gpio-rcar 26 Edge smbus_alert
如果主機在 1 秒內未響應警報,則測試將中止,測試單元將報告錯誤。
對於此測試,測試單元將暫時放棄其分配的地址,並在 SMBus 警報響應地址 (0x0c) 上監聽。之後它將重新分配其原始地址。