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总线将有一个单独的子目录。每个子目录将包含触发错误注入的文件。现在将描述它们及其预期的用例。

Wire states

“scl”

通过读取该文件,您可以获得SCL的当前状态。通过书写,你可以改变它的状态,迫使它降低或再次释放它。因此,通过使用“echo 0 > scl”,强制拉低scl,因此,没有通信将是可能的,因为在测试中的总线主机将没有时钟。它应该检测SCL没有响应的情况,并向上层报告错误。

“sda”

通过读取该文件,您可以获得SDA的当前状态。通过书写,你可以改变它的状态,迫使它降低或再次释放它。因此,通过使用“echo 0 > sda”,您将迫使sda降低,因此,数据无法传输。被测试的总线主机应该使用Linux I2C核心的助手(参见' struct bus_recovery_info ')检测这个条件并触发总线恢复(参见I2C规范版本4,第3.1.16节)。但是,总线恢复不会成功,因为在您使用“echo 1 > SDA”再次手动释放它之前,SDA仍然处于低位。使用“不完全传输”类故障注入器可以进行自动释放测试。

不完整的传输(Incomplete transfers)

以下故障注入器创建的情况是SDA将被设备保持在较低的水平。总线恢复应该能够修复这些情况。但是请注意:有一些I2C客户端设备可以检测到在他们这边卡住的SDA,并在几毫秒后释放它。此外,可能有一个外部设备故障并监视I2C总线。它还可以检测被卡住的SDA,并自己初始化总线恢复。如果您想在总线主驱动程序中实现总线恢复,请确保之前检查了此类设备的硬件设置。并始终使用范围或逻辑分析仪进行验证!

“incomplete_address_phase”

该文件是只写的,您需要将现有I2C客户端设备的地址写入该文件。然后,将启动对该设备的读传输,但它将在传输客户端地址后的ACK阶段停止。因为设备将ACK它的存在,这导致SDA被设备拉低,而SCL是高的。因此,类似于上面的“sda”文件,被测试的总线主机应该检测这个条件并尝试总线恢复。然而,这一次,它应该成功,设备应该在切换SCL后释放SDA。

“incomplete_write_byte”

与上面类似,此文件是只写的,您需要将现有I2C客户端设备的地址写入该文件。

注入器将再次在一个ACK阶段停止,因此设备将保持低SDA,因为它承认数据。然而,与' incomplete_address_phase '相比,有两个区别:

  1. 发送出去的消息将是写消息
  2. 在地址字节之后,一个0x00字节将被传输。然后,在ACK停下。

这是一种非常微妙的状态,当SCL上进一步发生时钟脉冲时,设备被设置为将任何数据写入寄存器0x00(如果它有寄存器)。这就是为什么总线恢复(多达9个时钟脉冲)必须检查SDA或发送额外的停止条件,以确保总线已被释放。否则随机数据将被写入设备!

失去仲裁(Lost arbitration)

这里,我们想模拟在多主机设置中被测试的主机与另一个主机失去总线仲裁的情况。

“lose_arbitration”

这个文件是只写的,你需要写仲裁干扰的持续时间(以µs为单位,最大100ms)。然后调用进程将休眠并等待下一个总线时钟。不过,这个过程是可中断的。

仲裁损失是通过等待SCL下降,然后将SDA拉低一段时间来实现的。因此,发送出去的I2C地址应该被损坏,并且应该被正确地检测到。这意味着发送的地址应该有很多“1”位,以便能够检测损坏。这个地址不需要设备,因为仲裁失败应该提前检测到。还要注意,SCL的下降是通过中断来监视的,因此中断延迟可能会导致第一个比特没有损坏。在空闲总线上使用这个故障注入器的一个好的起点是:

# echo 200 > lose_arbitration &
# i2cget -y <bus_to_test> 0x3f

传输过程中Panic

这个错误注入器会在master启动传输时造成内核恐慌。这通常意味着总线master驱动程序的状态机将不正常地中断,总线可能会以一种不正常的状态结束。使用这个来检查您的shutdown/reboot/boot代码是否可以处理这个场景。

“inject_panic”

这个文件是只写的,您需要在检测到的传输开始和引发的内核恐慌之间写入延迟(以µs为单位,最大为100ms)。然后调用进程将休眠并等待下一个总线时钟。不过,这个过程是可中断的。通过等待SCL下降,被测试的主机检测到传输的开始。使用这个故障注入器的一个好的起点是:

# echo 0 > inject_panic &
# i2cget -y <bus_to_test> <some_address>

注意,不需要有一个设备监听您正在使用的地址。不过,结果可能会因这一点而有所不同。

i2c-stub

描述

这个模块是一个非常简单的假I2C/SMBus驱动程序。它实现了六种类型的SMBus命令:写快速、(r/w)字节、(r/w)字节数据、(r/w)字数据、(r/w) I2C块数据和(r/w) SMBus块数据。

在加载该驱动程序时,您需要提供芯片地址作为模块参数,该驱动程序将仅对针对这些地址的SMBus命令作出反应。

不需要硬件,也不与此模块相关联。它将接受写到指定地址的快速命令;它将通过从内存中读取或写入数组来响应其他命令(也响应指定的地址)。它还将发送它处理的每个命令的内核日志。

为所有字节操作实现了一个具有自增功能的指针寄存器。这允许像eeprom所支持的那样连续读取字节。

SMBus块命令支持默认是禁用的,必须通过在功能模块参数中设置相应的位(0x03000000)来显式启用。

为了配置SMBus块操作的SMBus命令,必须编写SMBus块命令。写可以是局部的。块读命令总是返回到目前为止用最大写选择的字节数。

典型的用例如下:

  1. 加载这个模块
  2. 使用i2cset(来自i2c-tools项目)预加载一些数据
  3. 加载目标芯片驱动模块
  4. 在内核日志中观察其行为

在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这样的东西。

 

上一篇:msp432搭建平衡小车(二)


下一篇:IIC详解,包括原理、过程,最后一步步教你实现IIC(转)