vhdl 中的 i2c 通信,从 master ack 到第一位读取 vhdl 时的 X 位
i2c communication in vhdl, an X bit when going form master ack to first bit read vhdl
我在 i2c 主机确认从机发送的数据正常时遇到问题。在我的测试台上,我在 SDA 总线上给出了一个 Z,这样主机就可以进行确认,但是在主机确认后(它是 0),我对数据的另一部分进行了处理,当我从 SDA 总线上的主机确认 0 到' 1' 作为从从机发送的第一位,我得到第一位的 X 状态。这就像如果公共汽车是 Z 它就不会出现。是模拟问题还是我只是做错了我得到了那个结果?它会出现在现实中还是从机会在 SDA 总线上给出一个 Z 更长的时间?下面我给出了仿真代码和波形。
sda <='Z',
'0' after 3200 ps,
'Z' after 3400 ps,
'0' after 5800 ps,
'Z' after 6000 ps,
'0' after 8600 ps,
'Z' after 8800 ps,
'0' after 11600 ps,
'1' after 11850 ps,------ start first byte
'1' after 12150 ps,
'0' after 13050 ps,
'1' after 13350 ps,
'0' after 13650 ps, ----- end first byte
'Z' after 14250 ps,------ Z for master ack
'1' after 14550 ps,------ start second byte
'0' after 14850 ps,
'1' after 16650 ps,------ end second byte
'Z' after 16950 ps,------ Z for master ack
'1' after 17250 ps,------ start third byte
'1' after 17550 ps,
'0' after 18150 ps,
'1' after 18750 ps,
'0' after 19350 ps,------ end third byte
'Z' after 19650 ps;------ Z for master ack
3 位模式末尾的红色和绿色小部分是由于在该增量时间内有两个地方驱动相同的信号。当模拟器无法解析线上的两个驱动器时会发生这种情况。
为了不发生这种情况,您应该编写测试平台,使其使用与主 i2c 模块使用的时钟相同的时钟。现在,您的测试台正在使用固定的模拟器时间。模拟器看到主 i2c 和测试平台都在驱动线路时可能有 1 皮秒的时间。
另一种选择是让您在时钟边沿之后等待一小段时间来实际查看数据,例如,可以使用主机的负边沿和从机的正边沿。
不管怎样,综合后这应该不是问题,所以第三种选择就是忽略它。
该测试台没有正确模拟 I2C 信号。
I2C 使用集电极开路驱动器,它永远不能将总线驱动为高电平,并且有一个弱上拉电阻。要模拟你可以这样做:
sda <= 'H'; -- weak pullup always in effect
sda <='Z',
'0' after 3200 ps,
'Z' after 3400 ps,
'0' after 5800 ps,
'Z' after 6000 ps,
'0' after 8600 ps,
'Z' after 8800 ps,
'0' after 11600 ps,
'Z' after 11850 ps,------ want to send '1', but open-collector cannot drive high!
'Z' after 12150 ps,
从信号读取时,您可以使用例如
IF TO_X01(sda) = '1'
解决多个集电极开路驱动器的线与性质。
您仍然需要解决 Russell 提到的设置和保持时序问题。
正如其他人所指出的,您的问题是由于多个冲突的驱动程序在同一个增量周期内暂时处于活动状态造成的。这会在您的逻辑中产生级联效应,开始传播 'X' 源于冲突的值。
即使这是一个不会发生驱动程序争用的 open-collector/drain 系统,您也不应该忽视这样的缺陷。此外,您不应该通过使测试台的行为与真正的 I2C 从设备不同来掩盖问题。
在模拟集电极开路驱动程序时,您永远不应使用“1”驱动共享总线信号。相反,当你想要一个'1'时,你应该通过将SDA/SCL驱动到'Z'来模拟上拉电阻的效果,第三个专用驱动器在信号上放置一个常数'H'(或者,不太准确,直接从主机或从机驱动 'H')。这会创建一个弱驱动程序,可以在没有冲突的情况下被强“0”覆盖。您可以在输入端口信号上使用 to_X01() 函数,以防止 'H' 值通过主控或从属内部的逻辑传播。它会在内部将 'H' 转换为“1”,因此您只会在总线信号上看到逻辑“1”或“0”。
我在 i2c 主机确认从机发送的数据正常时遇到问题。在我的测试台上,我在 SDA 总线上给出了一个 Z,这样主机就可以进行确认,但是在主机确认后(它是 0),我对数据的另一部分进行了处理,当我从 SDA 总线上的主机确认 0 到' 1' 作为从从机发送的第一位,我得到第一位的 X 状态。这就像如果公共汽车是 Z 它就不会出现。是模拟问题还是我只是做错了我得到了那个结果?它会出现在现实中还是从机会在 SDA 总线上给出一个 Z 更长的时间?下面我给出了仿真代码和波形。
sda <='Z',
'0' after 3200 ps,
'Z' after 3400 ps,
'0' after 5800 ps,
'Z' after 6000 ps,
'0' after 8600 ps,
'Z' after 8800 ps,
'0' after 11600 ps,
'1' after 11850 ps,------ start first byte
'1' after 12150 ps,
'0' after 13050 ps,
'1' after 13350 ps,
'0' after 13650 ps, ----- end first byte
'Z' after 14250 ps,------ Z for master ack
'1' after 14550 ps,------ start second byte
'0' after 14850 ps,
'1' after 16650 ps,------ end second byte
'Z' after 16950 ps,------ Z for master ack
'1' after 17250 ps,------ start third byte
'1' after 17550 ps,
'0' after 18150 ps,
'1' after 18750 ps,
'0' after 19350 ps,------ end third byte
'Z' after 19650 ps;------ Z for master ack
3 位模式末尾的红色和绿色小部分是由于在该增量时间内有两个地方驱动相同的信号。当模拟器无法解析线上的两个驱动器时会发生这种情况。
为了不发生这种情况,您应该编写测试平台,使其使用与主 i2c 模块使用的时钟相同的时钟。现在,您的测试台正在使用固定的模拟器时间。模拟器看到主 i2c 和测试平台都在驱动线路时可能有 1 皮秒的时间。
另一种选择是让您在时钟边沿之后等待一小段时间来实际查看数据,例如,可以使用主机的负边沿和从机的正边沿。
不管怎样,综合后这应该不是问题,所以第三种选择就是忽略它。
该测试台没有正确模拟 I2C 信号。
I2C 使用集电极开路驱动器,它永远不能将总线驱动为高电平,并且有一个弱上拉电阻。要模拟你可以这样做:
sda <= 'H'; -- weak pullup always in effect
sda <='Z',
'0' after 3200 ps,
'Z' after 3400 ps,
'0' after 5800 ps,
'Z' after 6000 ps,
'0' after 8600 ps,
'Z' after 8800 ps,
'0' after 11600 ps,
'Z' after 11850 ps,------ want to send '1', but open-collector cannot drive high!
'Z' after 12150 ps,
从信号读取时,您可以使用例如
IF TO_X01(sda) = '1'
解决多个集电极开路驱动器的线与性质。
您仍然需要解决 Russell 提到的设置和保持时序问题。
正如其他人所指出的,您的问题是由于多个冲突的驱动程序在同一个增量周期内暂时处于活动状态造成的。这会在您的逻辑中产生级联效应,开始传播 'X' 源于冲突的值。
即使这是一个不会发生驱动程序争用的 open-collector/drain 系统,您也不应该忽视这样的缺陷。此外,您不应该通过使测试台的行为与真正的 I2C 从设备不同来掩盖问题。
在模拟集电极开路驱动程序时,您永远不应使用“1”驱动共享总线信号。相反,当你想要一个'1'时,你应该通过将SDA/SCL驱动到'Z'来模拟上拉电阻的效果,第三个专用驱动器在信号上放置一个常数'H'(或者,不太准确,直接从主机或从机驱动 'H')。这会创建一个弱驱动程序,可以在没有冲突的情况下被强“0”覆盖。您可以在输入端口信号上使用 to_X01() 函数,以防止 'H' 值通过主控或从属内部的逻辑传播。它会在内部将 'H' 转换为“1”,因此您只会在总线信号上看到逻辑“1”或“0”。