关于调用rt-thread的i2c驱动(i2c_bit_ops.c)毛刺问题解决

在调用Rt-thread的i2c驱动(i2c_bit_ops.c)去实现gpio模拟i2c的过程,在读过程出现了毛刺现象,该毛刺出现在数据位的第8bit后,现通过修改i2c_bit_ops.c源码解决毛刺问题。
写操作:
将i2c_bit_ops.c中i2c_waitack的API进行如下修改,即可消除写操作过程中的毛刺,原因很简单,这里就不在叙述。
原版API代码:

rt_inline rt_bool_t i2c_waitack(struct rt_i2c_bit_ops *ops)
{
    rt_bool_t ack;

    SDA_H(ops);
    i2c_delay(ops);

    if (SCL_H(ops) < 0)
    {
        bit_dbg("wait ack timeout\n");
        return -RT_ETIMEOUT;
    }
    
    ack = !GET_SDA(ops);    /* ACK : SDA pin is pulled low */
    bit_dbg("%s\n", ack ? "ACK" : "NACK");
    SCL_L(ops);
    return ack;
}

修改后:

rt_inline rt_bool_t i2c_waitack(struct rt_i2c_bit_ops *ops)
{
    rt_bool_t ack;

    //SDA_H(ops);      /*修改处*/
    i2c_delay(ops);

    if (SCL_H(ops) < 0)
    {
        bit_dbg("wait ack timeout\n");
        return -RT_ETIMEOUT;
    }
    
    ack = !GET_SDA(ops);    /* ACK : SDA pin is pulled low */
    bit_dbg("%s\n", ack ? "ACK" : "NACK");
    SDA_L(ops);     /*修改处*/
    SCL_L(ops);
    return ack;
}

读操作时:
会在第8bit后出现毛刺现象,因为该过程,主机在等待从机发送ACK或者NACK(最后一个byte),此时,总线处于无人控制阶段,当第8bit为0时,总线将自动去拉高,从而产生毛刺。针对此现象采取操作如下:
读第8bit时若获取SDA数据为0,则直接拉低SDA总线,如果数据为1,则不进行操作,但是这样操作会造成,在下一次写时,出现写失败现象,SDA总线不听使唤,从而导致通信失败,原因如下:
最后一个byte回复NACK时并未对SDA进行拉高,因为原先Rt-thread i2c驱动认为一个byte时,不对SDA进行操作,SDA将自动拉高,但是由于我们提前去拉低了SDA总线,这将导致SDA不会自动去拉高,所以必须手动去拉高,主要修改i2c_readb 与i2c_send_ack_or_nack这两个API,修改如下:
原版代码如下:

static rt_int32_t i2c_readb(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t i;
    rt_uint8_t data = 0;
    struct rt_i2c_bit_ops *ops = bus->priv;

    SDA_H(ops);
    i2c_delay(ops);
    for (i = 0; i < 8; i++)
    {
        data <<= 1;

        if (SCL_H(ops) < 0)
        {
            bit_dbg("i2c_readb: wait scl pin high "
                    "timeout at bit %d\n", 7 - i);

            return -RT_ETIMEOUT;
        }
        
        if (GET_SDA(ops))
            data |= 1;
        SCL_L(ops);
        i2c_delay2(ops);
    }

    return data;
}

static rt_err_t i2c_send_ack_or_nack(struct rt_i2c_bus_device *bus, int ack)
{
    struct rt_i2c_bit_ops *ops = bus->priv;

    if (ack)
        SET_SDA(ops, 0);
    i2c_delay(ops);
    if (SCL_H(ops) < 0)
    {
        bit_dbg("ACK or NACK timeout\n");

        return -RT_ETIMEOUT;
    }
    SCL_L(ops);

    return RT_EOK;
}

修改后如下:

static rt_int32_t i2c_readb(struct rt_i2c_bus_device *bus)
{
    rt_uint8_t i;
    rt_uint8_t data = 0;
    struct rt_i2c_bit_ops *ops = bus->priv;

    SDA_H(ops);
    i2c_delay(ops);
    for (i = 0; i < 8; i++)
    {
        data <<= 1;

        if (SCL_H(ops) < 0)
        {
            bit_dbg("i2c_readb: wait scl pin high "
                    "timeout at bit %d\n", 7 - i);

            return -RT_ETIMEOUT;
        }
        if(i != 7)
        {
	        if (GET_SDA(ops))
	            data |= 1;
        }
        else
        {
	        if (GET_SDA(ops))
	            data |= 1;
	         else
	         	SDA_L(ops);
	    }
        
        SCL_L(ops);
        i2c_delay2(ops);
    }

    return data;
}

static rt_err_t i2c_send_ack_or_nack(struct rt_i2c_bus_device *bus, int ack)
{
    struct rt_i2c_bit_ops *ops = bus->priv;

    if (ack)
        SET_SDA(ops, 0);
    else
    	SDA_H(ops);
    i2c_delay(ops);
    if (SCL_H(ops) < 0)
    {
        bit_dbg("ACK or NACK timeout\n");

        return -RT_ETIMEOUT;
    }
    SCL_L(ops);

    return RT_EOK;
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值