点击此处查看详细分析解答
您好,根据您提供的问题描述和上下文信息,我来分析如何正确使用设备树方法进行I2C通信,并解释当前通信失败的可能原因。
问题原因分析
您遇到的通信失败,主要源于协议栈与底层通信接口不匹配。
- 协议帧格式不匹配:景嘉微JY1032 GPU的通信协议是自定义的Block Write/Read协议。其请求帧结构为
[Command Code] [Byte Count] [Request Data Structure...],其中Request Data Structure内部包含了 LUN, arg, opcode, offset, length, data 等特定字段。您直接调用 bmc.kepler.Chip.BlockIO 的 Write 方法,该方法通常期望发送的数据格式是 [offset] [data...](偏移量+数据),这与您GPU要求的复杂请求帧结构不一致。
- 底层通信方法选择错误:您使用的
busctl call ... Write 和 Read 是独立的读写操作,适合简单的寄存器访问。对于需要先写入完整请求帧再读取完整响应帧的复合操作,应使用 ComboWriteRead 方法,该方法在一个事务中完成写和读,能更好地处理您这种自定义协议。
- Chip对象配置可能不准确:您配置的
Chip_McuChip 中,Address 为 102(0x66),AddrWidth 和 OffsetWidth 均为 1。但您的协议要求发送 Command Code、Byte Count 等,这超过了简单的1字节偏移量寻址,可能需要底层驱动支持SMBus Block协议。
- 底层Hisport驱动错误:错误日志
ioctl(HISPORT_CMD_READ) failed: Unknown error 320 表明,在最后尝试通过Hisport硬件驱动读取数据时失败。这可能是由上述的协议帧格式错误、总线堵塞、或该Hisport总线/设备本身存在问题导致的。
正确使用设备树方法进行I2C通信的步骤
1. 检查并修正Chip对象配置
您的CSR配置需要根据实际协议进行调整。考虑到协议需要发送 Command Code 和 Byte Count,强烈建议 将 AddrWidth 和 OffsetWidth 设置为支持Block协议的值。
根据OpenUBMC的常见实践和I2C/SMBus配置说明,正确的配置方式应为:
Address:设备的7位I2C地址。根据您提供的信息,地址是0x66(十进制102)。
AddrWidth 和 OffsetWidth:对于需要发送自定义命令码的Block协议,OffsetWidth 应设置为适合发送整个请求帧的大小,或使用更高级的接口。在您的场景中,建议改为如下配置,以使底层能够正确处理Block Write/Read:
"Chip_McuChip": {
"Address": 102,
"AddrWidth": 1,
"OffsetWidth": 1, // 注意:对于复杂协议,OffsetWidth=1可能不足以描述所有场景,可能需要调整或使用特定方法
"WriteTmout": 100,
"ReadTmout": 100,
"HealthStatus": 0
}
重要说明:仅仅将 OffsetWidth 设为 1 并无法自动实现您所需的 [Command Code] [Byte Count] [Data...] 协议格式。底层 bmc.kepler.Chip.BlockIO 的 Write/Read 方法主要负责发送一个偏移量(offset)和一段数据,而不是复杂的自定义协议帧。
2. 使用正确的D-Bus接口和方法
对于景嘉微JY1032这种自定义的Block Write/Read协议,您应该使用 ComboWriteRead 方法。
ComboWriteRead 方法允许您在一个调用中构造完整的发送数据并接收完整的回复帧,是处理自定义I2C协议的正确方式。
接口说明:
- Service:
bmc.kepler.hwproxy
- Object Path:
/bmc/kepler/Chip/Complex/Chip_McuChip_0101010902
- Interface:
bmc.kepler.Chip.BlockIO
- Method:
ComboWriteRead
- Method Signature (D-Bus类型): 通常为
(ayay),即两个字节数组:发送数据数组 和 接收缓冲区长度。
- 返回值:通常是一个字节数组
ay,即 接收数据数组。
使用 busctl 命令的调用示例:
根据您的协议,一个Block Write请求的原始字节流应为:
[Command Code=0x20] [Byte Count=13] [Request Data Structure (13 bytes)]
那么,您需要将整个请求帧(包括Command Code)作为 ComboWriteRead 的写入数据参数传入。ComboWriteRead 方法会将这些数据原封不动地通过I2C总线发送出去,然后接收指定长度的回复。
构造发送数据(一个完整的Block Write帧):
Command Code: 0x20
Byte Count: 0x0D (十进制13, 表示后面有13个字节的数据帧)
Request Data Structure:
- Byte 1 (LUN):
0x01 (第一帧)
- Byte 2 (arg):
0x00 (示例)
- Byte 3-4 (opcode):
0x00 0x03 (示例: 假设opcode为3)
- Byte 5-8 (offset):
0x00 0x00 0x00 0x00 (示例: 从0开始)
- Byte 9-12 (length):
0x00 0x00 0x00 0x20 (示例: 读取32字节)
- Byte 13 (data):
0x00 (示例)
完整的发送数据(ay):
[0x20, 0x0D, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00]
命令示例:
busctl --user call bmc.kepler.hwproxy /bmc/kepler/Chip/Complex/Chip_McuChip_0101010902 bmc.kepler.Chip.BlockIO ComboWriteRead ayay 15 0x20 0x0D 0x01 0x00 0x00 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x00 32
命令参数解释:
15:发送的字节数组的长度。
0x20 0x0D ... 0x00:完整的发送数据帧。
32:期望接收的缓冲区长度(这里设为32,与M值一致)。
如果调用成功,您将收到一个字节数组 (ay),其内容即为GPU返回的 Read Response 帧,您可以按照协议解析其中的 error_code, opcode, total_length, length, data 等字段。
3. 检查Hisport驱动和总线状态
底层Hisport驱动返回错误320,表明在硬件层面通信已经失败。
- 检查Hisport状态:确认Hisport总线
Hisport_12是否正常工作,是否被其他任务占用。
- 验证I2C地址:确认您的GPU设备的7位I2C地址确实是0x66。根据OpenUBMC的I2C地址配置规则,如果硬件使用7位地址,但在CSR中配置时,需要将7位地址左移一位(配置8位地址)。例如,设备7位地址为0x33,则应配置为0x66。您当前配置的
Address: 102即0x66,已经正确执行了左移操作,因此地址配置没问题。
- 硬件连接:确认Hisport总线与GPU设备之间的物理连接和电气特性是正常的。
总结建议
- 放弃
Write 和 Read 方法:对于景嘉微JY1032这类需要发送完整协议帧的复杂设备,必须使用 ComboWriteRead 方法。
- 正确构造发送数据:将
Block Write 协议的整个帧(Command Code + Byte Count + Request Data)作为 ComboWriteRead 的写入参数。
- 确保Chip对象配置正确:
Address 配置已正确(左移后为0x66),但 AddrWidth 和 OffsetWidth 应设为1以适配底层协议处理。
- 排查底层Hisport驱动错误:错误码
320表明Hisport驱动层面出现问题,需要进一步检查Hisport总线状态和相关日志。