GPIO实现I2C从机的设计[2]

来源:互联网 发布:有没有人能告诉你 知乎 编辑:程序博客网 时间:2024/05/21 16:57

在上篇文章中,实现了GPIO模拟I2C从机的初步设计,但在实际的使用过程中,发现了一些问题,为了解决实际传输过程中发生的数据传输错误问题,在本篇文章中,会根据实际测试情况对上篇的代码做一些修改。

问题描述
主从机传输主要发生在从机接收数据部分,下图1是使用示波器(500MHz 2.5GS/s)抓取的主机发送的时钟和数据信号关系。可以在图中看出:
①时钟占空比并不是50%
②数据变化并不是在时钟的高电平或者低电平的中间部位发生变化,而是在时钟刚发生跳变之后就发生了变化。(图中测试发现时钟变化150ns之后数据信号就发生了变化)
图1
图1

根据上篇文章的代码(见下)

while(!recFinish){    for(bitcount = 0; bitcount < 8; bitcount ++)    {        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
图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; bitcount < 8; bitcount ++)    {        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从机的设计告一段落。

1 0
原创粉丝点击