alexforencich i2c_master 读写 TEA5767 时事务卡住
结论
从这段代码看,先检查 valid/ready 是否在同一个时钟周期完成握手。cmd_ready 或 m_axis_data_tvalid 单独拉高,都不表示命令或数据已传输;通常只有 valid 和 ready 同时为高时,握手才算完成。当前片段读取数据时只检查 m_axis_data_tvalid,而 m_axis_tready 要到同一个时序块中才置高,因此状态机可能会消费尚未握手的数据。
仅凭这段代码,无法判断 TEA5767 是否没有对后续字节返回 ACK,也无法确认该版本 i2c_master.v 如何定义一次 cmd_read。还需结合完整的信号赋值、控制器接口约定和波形检查。
先检查读取数据握手
假设 m_axis_tready 初始值为 0,那么在 ST_READ_CAPTURE 中安排的非阻塞赋值要到时钟沿之后才生效。如果这时 m_axis_data_tvalid 已经为高,状态机仍会立即更新计数器并离开捕获状态,但当前周期并未发生 valid && ready 握手。
应使用握手条件判断何时接收数据,并确保在进入捕获状态前已将 m_axis_tready 置高,或由其他时序逻辑持续拉高它。例如:
// 在进入 ST_READ_CAPTURE 前,或由独立时序逻辑控制
m_axis_tready <= 1'b1;
// 只有握手完成时才消费数据
if (m_axis_data_tvalid && m_axis_tready) begin
read_data_reg <= {read_data_reg[31:0], m_axis_data_tdata};
if (read_cnt == 3'd4) begin
state <= ST_READ_WAIT;
end else begin
read_cnt <= read_cnt + 3'd1;
state <= ST_READ_ISSUE;
end
end
如果这些信号由同一个 always 块中的非阻塞赋值驱动,判断握手时要看时序逻辑当前读到的旧值。不能把本周期刚安排的 m_axis_tready <= 1'b1 当成本周期已经拉高。
再核对命令握手
在 ST_READ_ISSUE 中,状态机根据 cmd_ready 决定何时设置 cmd_valid 并离开当前状态。若 cmd_valid 此前为 0,那么执行 cmd_valid <= 1'b1 后,通常要等到后续某个时钟沿 cmd_valid && cmd_ready 同时为高时才完成握手。请确认在握手完成前,状态机和其他逻辑会保持命令字段稳定,并在握手后撤销 cmd_valid。
一般的 ready/valid 发送逻辑如下,具体信号仍以模块接口定义为准:
if (cmd_valid && cmd_ready) begin
cmd_valid <= 1'b0;
// 命令已被接收,再进入后续状态
end
如果只在 cmd_ready 拉高时短暂产生 cmd_valid,或者在握手前修改命令字段,控制器可能收不到预期命令。写数据通道的 data_tvalid 和 data_tready 也要按同样的原则检查:只有两者同时为高时才能推进到下一字节;发生背压时,当前字节和 data_tlast 应保持稳定。
核对多字节读序列
代码为每个字节发起一次 cmd_read,只在首字节设置 cmd_start,并在最后一个字节设置 cmd_stop。这是否符合 master 的接口约定,需要查看所用版本中 cmd_read、cmd_start、cmd_stop 和 cmd_valid 的定义及状态机处理逻辑。不能只凭 cmd_write_multiple 这个名称判断它也控制多字节读取。
还要确认读命令是在前一个字节完成数据握手后才发出,并检查 master 是否正确处理最后一个字节的结束条件。如果接口要求在读事务结束时用 cmd_stop 终止,该字段就必须随对应命令一起完成握手,不能只在本地 FSM 中根据计数器更新。
用波形定位卡住位置
逐周期查看以下信号:
- 命令通道:
cmd_valid、cmd_ready、cmd_start、cmd_read、cmd_stop。 - 写数据通道:
data_tvalid、data_tready、data_tdata、data_tlast。 - 读数据通道:
m_axis_data_tvalid、m_axis_tready、m_axis_data_tdata。 - I²C 状态:
i2c_busy、i2c_missed_ack,以及 SDA、SCL。
先统计每次传输中 valid && ready 实际发生的次数,再对照 SDA 上每个字节后的 ACK/NACK。如果读数据的 valid 持续为高,而 ready 没有同时为高,问题就在数据通道握手;如果命令没有完成握手,应先修正命令发起逻辑;如果握手和时钟都正常,但从设备在某个字节后返回 NACK,再检查器件地址、读事务时序和 TEA5767 的状态读取要求。
目前没有波形,无法确认停顿实际发生在命令通道、数据通道还是 I²C 总线上。
备注:内容仅供参考。
