作者:mobiledu2502912677 | 来源:互联网 | 2023-09-03 15:24
在上篇文章中,实现了GPIO模拟I2C从机的初步设计,但在实际的使用过程中,发现了一些问题,为了解决实际传输过程中发生的数据传输错误问题,在本篇文章中,会根据实际测试情况对上篇的代码做一些修改。
在上篇文章中,实现了GPIO模拟I2C从机的初步设计,但在实际的使用过程中,发现了一些问题,为了解决实际传输过程中发生的数据传输错误问题,在本篇文章中,会根据实际测试情况对上篇的代码做一些修改。
问题描述
主从机传输主要发生在从机接收数据部分,下图1是使用示波器(500MHz 2.5GS/s)抓取的主机发送的时钟和数据信号关系。可以在图中看出:
①时钟占空比并不是50%
②数据变化并不是在时钟的高电平或者低电平的中间部位发生变化,而是在时钟刚发生跳变之后就发生了变化。(图中测试发现时钟变化150ns之后数据信号就发生了变化)
图1
根据上篇文章的代码(见下)
while(!recFinish)
{
for(bitcount = 0
{
while(GET_SCL_DAT)
SDA_IN
while(!GET_SCL_DAT)
r0 = GET_SDA_DAT
while(GET_SCL_DAT)
{
r1 = GET_SDA_DAT
if((r0 == 0) && (r1 == 1))
{
recFinish = 1
return 1
}
}
rxbyte <<= 1
if(r1)
rxbyte |= 0x01
else
rxbyte |= 0x00
}
buf[(*len)++] = rxbyte
IIC_SLAVE_SEND_ACK
}
return 0
在r1位置的极限情况下,r1会采样到SCL刚变为低的值,这样就会发生错误的采样,在实际测试中发生了下列错误的采样(主机将数据写入从机,并从从机中读取以验证)
图2 读写测试
可以看到一些规律,每一个Byte只会发生一次错误,所有的错误都是高位没有采样到。原因就发生才r1采样的时候采样错误。
为了改正这种错误,就需要重新确定采样值。
if(r1)
rxbyte |= 0x01;
else
rxbyte |= 0x00;
有两种修改方法:一种是在取采样值的时候,取r0,这样避免在取r1的时候出现数据跳变,即上面的代码修改为:
if(r0)
rxbyte |= 0x01;
else
rxbyte |= 0x00;
但这种修改方法还是有不完善的地方,因为r0也有可能发生跳变,也有可能是一个不稳定的采样点,那么最理想的状态是采样图1中r2的值,r1可能在SCL发生跳变的瞬间也发生数据的跳变,但是r2一定是在SCL为高的时候的采样点,是不会发生数据的跳变的。
代码可修改如下:
while(!recFinish)
{
for(bitcount = 0
{
while(GET_SCL_DAT)
SDA_IN
while(!GET_SCL_DAT)
r0 = GET_SDA_DAT
r1 = r0
while(GET_SCL_DAT)
{
r2 = r1
r1 = GET_SDA_DAT
if((r0 == 0) && (r2 == 1))
{
recFinish = 1
return 1
}
}
rxbyte <<= 1
if(r2)
rxbyte |= 0x01
else
rxbyte |= 0x00
}
buf[(*len)++] = rxbyte
IIC_SLAVE_SEND_ACK
}
return 0
由此修改后,可以保证采样值正确,接收数据也正常,不会发生数据错误。
在此,GPIO模拟I2C从机的设计告一段落。