https://blog.csdn.net/yang1111111112/article/details/83276512
这篇文章有详细的简介,
问题是,关于RT-Thread中IIC地址的设置,在Apollo中,原理图如图,A0、A1、A2是接地,则IIC读地址是0xA0,写地址是0xA1,但是这样读取是错误的
在RT-Thread的IIC底层驱动中,
rt_i2c_master_send函数调用了rt_i2c_transfer函数,rt_i2c_transfer函数take了对应IIC设备对应的互斥量,此例是i2c2的,随后调用了i2c的 ops->master_xfer函数,在master_xfer函数中调用i2c_bit_send_address函数,问题是在i2c_bit_send_address函数中,代码如下
static rt_err_t i2c_bit_send_address(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg *msg)
{
rt_uint16_t flags = msg->flags;
rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
rt_uint8_t addr1, addr2;
rt_int32_t retries;
rt_err_t ret;
retries = ignore_nack ? 0 : bus->retries;
if (flags & RT_I2C_ADDR_10BIT)
{
addr1 = 0xf0 | ((msg->addr >> 7) & 0x06);
addr2 = msg->addr & 0xff;
LOG_D("addr1: %d, addr2: %d", addr1, addr2);
ret = i2c_send_address(bus, addr1, retries);
if ((ret != 1) && !ignore_nack)
{
LOG_W("NACK: sending first addr");
return -RT_EIO;
}
ret = i2c_writeb(bus, addr2);
if ((ret != 1) && !ignore_nack)
{
LOG_W("NACK: sending second addr");
return -RT_EIO;
}
if (flags & RT_I2C_RD)
{
LOG_D("send repeated start condition");
i2c_restart(ops);
addr1 |= 0x01;
ret = i2c_send_address(bus, addr1, retries);
if ((ret != 1) && !ignore_nack)
{
LOG_E("NACK: sending repeated addr");
return -RT_EIO;
}
}
}
else
{
/* 7-bit addr */
addr1 = msg->addr << 1;
if (flags & RT_I2C_RD)
addr1 |= 1;
ret = i2c_send_address(bus, addr1, retries);
if ((ret != 1) && !ignore_nack)
return -RT_EIO;
}
return RT_EOK;
}
在RT-Thread中,对IIC设备的地址设置一共有两种设置模式,分别是十位和七位,在七位地址发送的代码这种,对地址进行了一位左移,addr1 = msg->addr<<1;所以,AT24C02原先是0xA0和0xA1,那么在代码中1010 0000(0xA0)应该是0101 0000(0x50),其实根据这行代码:
if (flags & RT_I2C_RD)
addr1 |= 1;
可以看出,对于读信号,RT-Thread会自动在对地位置1,操作是addr1 = msg->addr<<1; addr1 |= 1;所以对AT24C02的读操作给的地址依然是0x50。