天天看點

I2C/SMBus 調試

Linux I2C 故障注入

可以将基于GPIO的I2C總線master驅動程式配置為提供故障注入功能。然後,它被連接配接到另一個I2C總線,該總線由測試中的I2C總線master驅動程式驅動。GPIO故障注入驅動程式可以在總線上建立特殊的狀态,其他I2C總線master驅動程式應該優雅地處理這些狀态。

一旦Kconfig選項I2C_GPIO_FAULT_INJECTOR被啟用,Kernel debugfs檔案系統中就會有一個' i2c-fault-injector '子目錄,通常挂載在/sys/ Kernel /debug。每個GPIO驅動的I2C總線将有一個單獨的子目錄。每個子目錄将包含觸發錯誤注入的檔案。現在将描述它們及其預期的用例。

通過讀取該檔案,您可以獲得SCL的目前狀态。通過書寫,你可以改變它的狀态,迫使它降低或再次釋放它。是以,通過使用“echo 0 > scl”,強制拉低scl,是以,沒有通信将是可能的,因為在測試中的總線主機将沒有時鐘。它應該檢測SCL沒有響應的情況,并向上層報告錯誤。

通過讀取該檔案,您可以獲得SDA的目前狀态。通過書寫,你可以改變它的狀态,迫使它降低或再次釋放它。是以,通過使用“echo 0 > sda”,您将迫使sda降低,是以,資料無法傳輸。被測試的總線主機應該使用Linux I2C核心的助手(參見' struct bus_recovery_info ')檢測這個條件并觸發總線恢複(參見I2C規範版本4,第3.1.16節)。但是,總線恢複不會成功,因為在您使用“echo 1 > SDA”再次手動釋放它之前,SDA仍然處于低位。使用“不完全傳輸”類故障注入器可以進行自動釋放測試。

以下故障注入器建立的情況是SDA将被裝置保持在較低的水準。總線恢複應該能夠修複這些情況。但是請注意:有一些I2C用戶端裝置可以檢測到在他們這邊卡住的SDA,并在幾毫秒後釋放它。此外,可能有一個外部裝置故障并監視I2C總線。它還可以檢測被卡住的SDA,并自己初始化總線恢複。如果您想在總線主驅動程式中實作總線恢複,請確定之前檢查了此類裝置的硬體設定。并始終使用範圍或邏輯分析儀進行驗證!

該檔案是隻寫的,您需要将現有I2C用戶端裝置的位址寫入該檔案。然後,将啟動對該裝置的讀傳輸,但它将在傳輸用戶端位址後的ACK階段停止。因為裝置将ACK它的存在,這導緻SDA被裝置拉低,而SCL是高的。是以,類似于上面的“sda”檔案,被測試的總線主機應該檢測這個條件并嘗試總線恢複。然而,這一次,它應該成功,裝置應該在切換SCL後釋放SDA。

與上面類似,此檔案是隻寫的,您需要将現有I2C用戶端裝置的位址寫入該檔案。

注入器将再次在一個ACK階段停止,是以裝置将保持低SDA,因為它承認資料。然而,與' incomplete_address_phase '相比,有兩個差別:

發送出去的消息将是寫消息

在位址位元組之後,一個0x00位元組将被傳輸。然後,在ACK停下。

這是一種非常微妙的狀态,當SCL上進一步發生時鐘脈沖時,裝置被設定為将任何資料寫入寄存器0x00(如果它有寄存器)。這就是為什麼總線恢複(多達9個時鐘脈沖)必須檢查SDA或發送額外的停止條件,以確定總線已被釋放。否則随機資料将被寫入裝置!

這裡,我們想模拟在多主機設定中被測試的主機與另一個主機失去總線仲裁的情況。

這個檔案是隻寫的,你需要寫仲裁幹擾的持續時間(以µs為機關,最大100ms)。然後調用程序将休眠并等待下一個總線時鐘。不過,這個過程是可中斷的。

仲裁損失是通過等待SCL下降,然後将SDA拉低一段時間來實作的。是以,發送出去的I2C位址應該被損壞,并且應該被正确地檢測到。這意味着發送的位址應該有很多“1”位,以便能夠檢測損壞。這個位址不需要裝置,因為仲裁失敗應該提前檢測到。還要注意,SCL的下降是通過中斷來監視的,是以中斷延遲可能會導緻第一個比特沒有損壞。在空閑總線上使用這個故障注入器的一個好的起點是:

這個錯誤注入器會在master啟動傳輸時造成核心恐慌。這通常意味着總線master驅動程式的狀态機将不正常地中斷,總線可能會以一種不正常的狀态結束。使用這個來檢查您的shutdown/reboot/boot代碼是否可以處理這個場景。

這個檔案是隻寫的,您需要在檢測到的傳輸開始和引發的核心恐慌之間寫入延遲(以µs為機關,最大為100ms)。然後調用程序将休眠并等待下一個總線時鐘。不過,這個過程是可中斷的。通過等待SCL下降,被測試的主機檢測到傳輸的開始。使用這個故障注入器的一個好的起點是:

注意,不需要有一個裝置監聽您正在使用的位址。不過,結果可能會因這一點而有所不同。

i2c-stub

這個子產品是一個非常簡單的假I2C/SMBus驅動程式。它實作了六種類型的SMBus指令:寫快速、(r/w)位元組、(r/w)位元組資料、(r/w)字資料、(r/w) I2C塊資料和(r/w) SMBus塊資料。

在加載該驅動程式時,您需要提供晶片位址作為子產品參數,該驅動程式将僅對針對這些位址的SMBus指令作出反應。

不需要硬體,也不與此子產品相關聯。它将接受寫到指定位址的快速指令;它将通過從記憶體中讀取或寫入數組來響應其他指令(也響應指定的位址)。它還将發送它處理的每個指令的核心日志。

為所有位元組操作實作了一個具有自增功能的指針寄存器。這允許像eeprom所支援的那樣連續讀取位元組。

SMBus塊指令支援預設是禁用的,必須通過在功能子產品參數中設定相應的位(0x03000000)來顯式啟用。

為了配置SMBus塊操作的SMBus指令,必須編寫SMBus塊指令。寫可以是局部的。塊讀指令總是傳回到目前為止用最大寫選擇的位元組數。

典型的用例如下:

加載這個子產品

使用i2cset(來自i2c-tools項目)預加載一些資料

加載目标晶片驅動子產品

在核心日志中觀察其行為

在i2c-tools包中有一個名為i2c-stub-from-dump的腳本,它可以從晶片轉儲自動加載寄存器值。

int chip_addr [10]:

晶片的SMBus位址

unsigned long functionality:

功能覆寫,以禁用一些指令。有關合适的值,請參閱<linux/i2c.h>中的I2C_FUNC_*常量。例如,值0x1f0000隻會啟用 quick、byte和byte data指令。

u8 bank_reg[10], u8 bank_mask[10], u8 bank_start[10], u8 bank_end[10]:

可選bank設定。它們告訴哪個寄存器中的哪個位選擇了活躍的bank,以及bank寄存器的範圍。

如果你的目标驅動輪詢一些位元組或字等待它改變,stub可能會鎖定它。使用i2cset解鎖。

如果您發送的垃圾資訊足夠多,printk可能是有損的。這個子產品确實需要像relayfs這樣的東西。

繼續閱讀