MyCollege1999 2025-05-21 11:11 采纳率: 59.2%
浏览 17
已结题

xilinx versal sysmon用i2c读温度寄存器时,得不到数据

参考了这个文档am006-versal-sysmon,这个fpga作为i2c的slave,master由单片机程序控制,时序是参考如下的图:
用i2c代码方式访问时,都有ACK,读到了4个字节,但是4个字节的值不对(不是自己期望的)。有用过的朋友,有什么建议吗

img

  • 写回答

5条回答 默认 最新

  • 一杯年华@编程空间 2025-05-21 11:15
    关注

    一杯年华@编程空间帮您解答,本答案结合 ChatGPT4.0和DeepSeek整理

    我曾经遇到过类似的问题。当使用I2C读取Xilinx Versal SysMon温度寄存器时无法获得预期数据,可能是时序配置、寄存器地址、数据解析或硬件连接等方面存在问题。以下是具体分析和解决方案:

    一、问题分析

    1. 时序匹配问题

      • SysMon作为I2C从设备时,可能对时钟频率、起始/停止条件间隔有严格要求。若主机(STM32)的时序与文档(如AM006)规定的不一致(如SCL频率过高、应答时间不足),可能导致数据读取错误。
      • 图中显示读取流程包含“重复起始”(SrM)操作,需确认STM32代码是否正确实现“发送起始信号→写从机地址(WM)→写寄存器地址→重复起始→读从机地址(RM)→读数据”的完整流程。
    2. 寄存器地址与数据解析错误

      • SysMon的温度寄存器可能需要特定的访问地址或操作模式(如先写入控制寄存器使能读取,再读取数据寄存器)。若代码中未正确设置寄存器地址或忽略了预处理步骤(如发送配置命令),会导致返回无效数据。
      • 读取的4字节数据可能包含温度值的高/低位、状态位等,需按文档规定的格式解析(如是否需要右移、补码转换等)。
    3. 硬件连接与电气特性

      • I2C总线需上拉电阻(通常4.7kΩ),若硬件未正确连接或总线电压与设备不匹配(如STM32的3.3V与FPGA的电压不一致),可能导致ACK失败或数据失真。
      • 总线长度过长或布线不合理可能引入噪声,影响信号完整性。

    二、解决方案

    方案1:校准I2C时序,确保与文档一致(最优方案)

    关键步骤:

    1. 降低SCL频率
      • 参考AM006文档,将STM32的I2C时钟频率设置为100kHz或更低(默认标准模式),避免因速度过快导致FPGA无法及时响应。
    2. 实现完整的重复起始流程
      • 在STM32代码中,发送从机写地址(WM)和寄存器地址后,需发送重复起始信号,再发送从机读地址(RM),而非先发送停止信号再重新起始。
    3. 添加适当的延迟
      • 在应答位后或数据传输间隔添加短延迟(如10μs),确保FPGA有足够时间处理数据。

    代码片段(STM32 HAL库示例):

    // 写寄存器地址(步骤:起始→从机地址(写)→寄存器地址)
    HAL_I2C_Mem_Write(&hi2c1, SLAVE_ADDR, REG_ADDR, I2C_MEMADD_SIZE_8BIT, NULL, 0, 1000);
    
    // 等待应答并发送重复起始
    HAL_I2C_Mem_Read(&hi2c1, SLAVE_ADDR, REG_ADDR, I2C_MEMADD_SIZE_8BIT, rx_buffer, 4, 1000); // 自动处理重复起始
    

    原理:
    通过严格遵循文档时序,确保FPGA从机正确识别操作命令。重复起始流程避免了总线释放带来的时序误差,降低了因多次启停导致的信号干扰风险。

    方案2:验证寄存器地址与数据解析逻辑

    关键步骤:

    1. 确认寄存器访问顺序
      • 部分SysMon寄存器需先写入控制字(如0x00用于选择温度寄存器),再读取数据寄存器(如0x01)。需检查代码是否遗漏了写控制寄存器的步骤。
    2. 按格式解析数据
      • 假设读取的4字节中,温度值位于第2、3字节(如16位补码),需进行如下转换:
        int16_t raw_temp = (rx_buffer[1] << 8) | rx_buffer[2];
        float temperature = raw_temp * 0.0625f; // 假设分辨率为0.0625

    代码片段:

    // 先写控制寄存器选择温度通道
    uint8_t control_cmd = 0x00; // 示例命令,需根据文档调整
    HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDR, &control_cmd, 1, 1000);
    
    // 读取数据寄存器
    HAL_I2C_Master_Receive(&hi2c1, SLAVE_ADDR, rx_buffer, 4, 1000);
    

    原理:
    确保访问路径正确,避免因寄存器地址错误导致读取“哑数据”。正确解析二进制数据可将原始值转换为实际物理量,避免因格式误解导致结果异常。

    方案3:排查硬件连接与电气兼容性

    关键步骤:

    1. 检查上拉电阻与电压匹配
      • 确认I2C总线SDA/SCL引脚已连接4.7kΩ上拉电阻至3.3V(与STM32和FPGA的IO电压一致)。
    2. 使用逻辑分析仪抓包
      • 捕获总线上的时序波形,对比AM006文档中的示例,检查起始/停止位、ACK信号、数据位是否正确,定位时序错误点(如SCL高电平时间不足)。
    3. 缩短总线长度或增加滤波
      • 若总线过长,可添加RC滤波(如100Ω电阻+100nF电容)降低噪声。

    三、最优方案总结

    推荐优先尝试方案1(校准I2C时序),原因如下:

    • 时序问题是I2C通信失败的最常见原因,尤其涉及FPGA这类对时序敏感的器件时,重复起始流程和时钟频率的准确性至关重要。
    • 通过HAL库的HAL_I2C_Mem_Read函数可自动处理重复起始,减少手动控制时序的复杂性,提高兼容性。

    若方案1无效,可结合方案2验证寄存器访问逻辑,或通过方案3排查硬件问题。建议在代码中添加错误处理(如检查ACK状态),并打印原始读取数据,便于后续调试。

    请楼主采纳。如有问题请继续留言。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 5月31日
  • 已采纳回答 5月23日
  • 创建了问题 5月21日