1. AP3216在STM32IGT6的PH4、PH5上,地址为0x1E,AP3216为标准IIC器件。
2. 写操作,
根据读写时序,传输的struct rt_i2c_msg的addr设置为0x1E,flags设置为RT_I2C_WR,数据长度len为2,buf指向长度为2的数组,第一个数据为AP3216寄存器地址,第二个为要写入寄存器的值,然后使用rt_i2c_transfer()函数就可以了。
3. 读操作
根据时序图,读操作与写操作开始基本相同,先发送AP3216地址与读信号,发送结束后再发送要读的寄存器地址,不同的是读取要先发送一个起始start信号,然后发送AP3216地址,然后读取返回的数据。在两次发送地址之间有一个重发的start信号,但是没有stop信号,如果使用两次rt_i2c_transfe()函数,会产生一个stop,操作可能失败,方法是定义一个struct rt_i2c_msg数组,这样声明赋值:
struct rt_i2c_msg msgs[2];
msgs[0].addr = AP3216C_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®
msgs[0].len = 1;
msgs[1].addr = AP3216C_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = buf;
msgs[1].len = len;
rt_i2c_transfer(bus, msgs, 2);
中间的其实信号,在RT-Thread系统的i2c-bit-ops中定义了i2c_bit_xfer()函数,此函数定义如下:
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 = (struct rt_i2c_bit_ops *)bus->priv;
rt_int32_t i, ret;
rt_uint16_t ignore_nack;
LOG_D("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)
{
LOG_D("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)
LOG_D("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)
LOG_D("write %d byte%s", ret, ret == 1 ? "" : "s");
if (ret < msg->len)
{
if (ret >= 0)
ret = -RT_ERROR;
goto out;
}
}
}
ret = i;
out:
LOG_D("send stop condition");
i2c_stop(ops);
return ret;
}
可以看出此函数首先通过i2c_start(ops) 发送起始信号,i=0,不执行i2c_stop(ops),当i>0时便执行此代码,调用i2c_restart(ops),实现重新发送一次start信号,然后发送地址,通过flag值判断读或者写,结束后发送stop信号。如果分两次调用rt_i2c_transfer()函数,就会发送两次i2c_stop(ops)即两次stop;
4. 最后附上一个简单代码事例
#include
#include
//0x3c = 0011 1100 >> 1 --> 0001 1110
#define AP3216_ADD 0x1E
#ifndef AP3216_I2CBUS_NAME
#define AP3216_I2CBUS_NAME "i2c2" /* 连接的I2C总线设备名称 */
#endif
static struct rt_i2c_bus_device *ap3216_i2c_bus=RT_NULL;
static rt_err_t ap_write(rt_uint8_t addr, rt_uint8_t cmd)
{
rt_uint8_t buf[2];
struct rt_i2c_msg msgs;
buf[0] = addr;
buf[1] = cmd;
msgs.addr = AP3216_ADD;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
msgs.len = 2;
if(rt_i2c_transfer(ap3216_i2c_bus, &msgs, 1) != 1)
{
rt_kprintf("error when send %d %d", addr, cmd);
return -RT_ERROR;
}else{
return RT_EOK;
}
}
static rt_err_t ap_read(rt_uint8_t addr, rt_uint8_t *rtnum)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = msgs[1].addr \
= AP3216_ADD;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = &addr;
msgs[0].len = 1;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = rtnum;
msgs[1].len = 1;
if(rt_i2c_transfer(ap3216_i2c_bus, msgs, 2) != 2)
{
rt_kprintf("read failed regesiter %d", addr);
return -RT_ERROR;
}else{
return RT_EOK;
}
}
static rt_err_t ap3216_init(void)
{
rt_uint8_t tmp;
if(ap_write(0x00, 0x03) != RT_EOK)
{
rt_kprintf("init first failed\n");
return -RT_ERROR;
}else
{
rt_thread_mdelay(50);
ap_read(0x00, &tmp);
}
if(tmp == 0x03)
return RT_EOK;
else{
rt_kprintf("init second failed\n");
return -RT_ERROR;
}
}
static void i2c_ap3216_app(int argc, char *argv[])
{
char name[RT_NAME_MAX];
rt_uint8_t cnt;
rt_uint8_t buf[6];
rt_uint16_t ir, als, ps;
if (argc == 2)
{
rt_strncpy(name, argv[1], RT_NAME_MAX);
}
else
{
rt_strncpy(name, AP3216_I2CBUS_NAME, RT_NAME_MAX);
}
/* 查找I2C总线设备,获取I2C总线设备句柄 */
ap3216_i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);
if(ap3216_i2c_bus == RT_NULL)
{
rt_kprintf("can't find %s device!\n", name);
}else{
rt_kprintf("find i2c2\n");
}
ap3216_init();
while(1){
for(cnt = 0; cnt < 6; cnt++){
ap_read(0x0A+cnt, buf+cnt);
}
if(buf[0]&0X80)ir=0; //IR_OF位为1,则数据无效
else ir=((rt_uint16_t)buf[1]<<2)|(buf[0]&0X03); //读取IR传感器的数据
als=((rt_uint16_t)buf[3]<<8)|buf[2]; //读取ALS传感器的数据
if(buf[4]&0x40)ps=0; //IR_OF位为1,则数据无效
else ps=((rt_uint16_t)(buf[5]&0X3F)<<4)|(buf[4]&0X0F); //读取PS传感器的数据
rt_kprintf("%d\t",ir);
rt_kprintf("%d\t",als);
rt_kprintf("%d\t\n",ps);
rt_thread_mdelay(500);
}
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(i2c_ap3216_app, i2c ap3216 app);