关于RT—Thread at24cxx驱动包中读操作中有错误

Posted xqyjlj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于RT—Thread at24cxx驱动包中读操作中有错误相关的知识,希望对你有一定的参考价值。

关于at24cxx驱动包中读操作中有错误

问题说明

最近在研究RT—Thread studio(附上链接RT—Thread Studio),因为其包的管理很方便。

可在我使用官方收录的at24cxx的软件包时,却发现了以下问题:

首先让我们看下驱动包里读一个字节的源代码

uint8_t at24cxx_read_one_byte(struct rt_i2c_bus_device *bus, uint16_t readAddr)
{
    rt_uint8_t buf[2];
    rt_uint8_t temp;
#if        (EE_TYPE > AT24C16)  
    buf[0] = (uint8_t)(readAddr>>8);        
    buf[1] = (uint8_t)readAddr;
    if (rt_i2c_master_send(bus, AT24CXX_ADDR, 0, buf, 2) == 0)
#else
    buf[0] = readAddr;
    if (rt_i2c_master_send(bus, AT24CXX_ADDR, 0, buf, 1) == 0)
#endif        
    {
        return -RT_ERROR;
    }
    read_regs(bus, 1, &temp);
    return temp;
}

程序调用rt_i2c_master_send对I2C从机写寄存器地址,调用read_regsI2C从机读一个字节(两个子函数源代码如下)
rt_i2c_master_send源代码

rt_size_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
                             rt_uint16_t               addr,
                             rt_uint16_t               flags,
                             const rt_uint8_t         *buf,
                             rt_uint32_t               count)
{
    rt_err_t ret;
    struct rt_i2c_msg msg;

    msg.addr  = addr;
    msg.flags = flags & RT_I2C_ADDR_10BIT;
    msg.len   = count;
    msg.buf   = (rt_uint8_t *)buf;

    ret = rt_i2c_transfer(bus, &msg, 1);

    return (ret > 0) ? count : ret;
}

read_regs源代码

static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t len, rt_uint8_t *buf)
{
    struct rt_i2c_msg msgs;

    msgs.addr = AT24CXX_ADDR;
    msgs.flags = RT_I2C_RD;
    msgs.buf = buf;
    msgs.len = len;

    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

这里我们看到rt_i2c_master_sendread_regs最终都是调用rt_i2c_transfer这个函数进行的数据传输,我们在看下rt_i2c_transfer的源代码

static rt_size_t i2c_bit_xfer(struct rt_i2c_bus_device *bus,
                              struct rt_i2c_msg         msgs[],
                              rt_uint32_t               num)
{
    struct rt_i2c_msg *msg;
    struct rt_i2c_bit_ops *ops = bus->priv;
    rt_int32_t i, ret;
    rt_uint16_t ignore_nack;

    bit_dbg("send start condition
");
    i2c_start(ops);
    for (i = 0; i < num; i++)
    {
        msg = &msgs[i];
        ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
        if (!(msg->flags & RT_I2C_NO_START))
        {
            if (i)
            {
                i2c_restart(ops);
            }
            ret = i2c_bit_send_address(bus, msg);
            if ((ret != RT_EOK) && !ignore_nack)
            {
                bit_dbg("receive NACK from device addr 0x%02x msg %d
",
                        msgs[i].addr, i);
                goto out;
            }
        }
        if (msg->flags & RT_I2C_RD)
        {
            ret = i2c_recv_bytes(bus, msg);
            if (ret >= 1)
                bit_dbg("read %d byte%s
", ret, ret == 1 ? "" : "s");
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_EIO;
                goto out;
            }
        }
        else
        {
            ret = i2c_send_bytes(bus, msg);
            if (ret >= 1)
                bit_dbg("write %d byte%s
", ret, ret == 1 ? "" : "s");
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_ERROR;
                goto out;
            }
        }
    }
    ret = i;

out:
    bit_dbg("send stop condition
");
    i2c_stop(ops);

    return ret;
}

rt_i2c_transfer源代码的最后我们可以看到 该函数在最后对I2C总线发送了停止信号(i2c_stop(ops))那么问题来了 at24cxx的驱动包读一个字节调用了两次rt_i2c_transfer,相当于每次调用就发送一个停止信号,这明显与I2C通讯机制不一致。

我们都知道I2C读一个字节数据的的流程是(大概流程 没写ACK NACK):

起始信号--> 器件地址+写-->寄存器地址-->起始信号-->器件地址+读-->从机发送数据-->停止信号 

at24cxx的驱动包读一个字节的流程变成了

起始信号--> 器件地址+写-->寄存器地址-->停止信号-->起始信号-->器件地址+读-->从机发送数据-->停止信号 

这里就是问题的关键。


以上是关于关于RT—Thread at24cxx驱动包中读操作中有错误的主要内容,如果未能解决你的问题,请参考以下文章

linux设备驱动I2C驱动

RT-Thrad|STM32F103+ESP8266 S01+RT-Thread联网之RT-Thread AT组件(3/4)

RT-Thrad|STM32F103+ESP8266 S01+RT-Thread联网之RT-Thread AT组件(3/4)

rt-thread串口驱动

rt-thread 之网络组件

先楫HPM6750测评RT-Thread WiFi联网和SPI驱动