关于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_regs从I2C从机读一个字节(两个子函数源代码如下)
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_send和read_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驱动包中读操作中有错误的主要内容,如果未能解决你的问题,请参考以下文章
RT-Thrad|STM32F103+ESP8266 S01+RT-Thread联网之RT-Thread AT组件(3/4)
RT-Thrad|STM32F103+ESP8266 S01+RT-Thread联网之RT-Thread AT组件(3/4)