接前一篇文章:ICM20948 DMP代码详解(45)
上一回讲到了inv_icm20948_setup_compass_akm函数中的以下代码片段:
/* Set compass in power down through I2C SLV for compass */
result = inv_icm20948_execute_write_secondary(s, COMPASS_I2C_SLV_WRITE, s->secondary_state.compass_chip_addr, s->secondary_state.mode_reg_addr, DATA_AKM_MODE_PD);
if (result)
return result;
本会就对于inv_icm20948_execute_write_secondary函数以及其中调用的inv_icm20948_write_secondary函数代码进行解析。
再次贴出inv_icm20948_execute_write_secondary函数代码,在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948AuxTransport.c中,如下:
int inv_icm20948_execute_write_secondary(struct inv_icm20948 *s, int index, unsigned char addr, int reg, uint8_t v)
{
int result = 0;
result |= inv_icm20948_write_secondary(s, index, addr, reg, v);
result |= inv_icm20948_secondary_enable_i2c(s);
inv_icm20948_sleep_us(SECONDARY_INIT_WAIT*1000);
result |= inv_icm20948_secondary_disable_i2c(s);
result |= inv_icm20948_secondary_stop_channel(s, index);
return result;
}
inv_icm20948_write_secondary函数在同文件中,就在inv_icm20948_execute_write_secondary函数的上边,代码如下:
/*
* inv_icm20948_write_secondary(): set secondary registers for writing?.
The chip must be set as bank 3 before calling.
* This is derived from inv_icm20948_write_secondary in linux...
* for now, uses a very simple data struct for the registers
*
* index gives the mapping to the particular SLVx registers
* addr is the physical address of the device to be accessed
* reg is the device register we wish to access
* len is the number of bytes to be read
*
*/
int inv_icm20948_write_secondary(struct inv_icm20948 *s, int index, unsigned char addr, unsigned char reg, char v)
{
int result = 0;
unsigned char data;
data = (unsigned char)addr;
result |= inv_icm20948_write_mems_reg(s, s->secondary_state.slv_reg[index].addr, 1, &data);
data = reg;
result |= inv_icm20948_write_mems_reg(s, s->secondary_state.slv_reg[index].reg, 1, &data);
data = v;
result |= inv_icm20948_write_mems_reg(s, s->secondary_state.slv_reg[index].d0, 1, &data);
data = INV_MPU_BIT_SLV_EN | 1;
result |= inv_icm20948_write_mems_reg(s, s->secondary_state.slv_reg[index].ctrl, 1, &data);
return result;
}
可以对比着前文书对于inv_icm20948_read_secondary函数的解析过程来看。
第1段代码如下:
data = (unsigned char)addr;
result |= inv_icm20948_write_mems_reg(s, s->secondary_state.slv_reg[index].addr, 1, &data);
data是addr,即AK09916芯片的地址0x0C。注意,此处由于是写,因此并没有INV_MPU_BIT_I2C_READ | addr。
第2行代码中的s->secondary_state.slv_reg[index].addr是在前文书解析的inv_icm20948_init_secondary函数中初始化的(参见https://phmatthaus.blog.csdn.net/article/details/142306413)。
注意,此处的index和inv_icm20948_read_secondary函数不同了,对应的实参是在inv_icm20948_setup_compass_akm函数中传入的,为COMPASS_I2C_SLV_WRITE,就是上一回所说的写通道。
/** @brief I2C from secondary device can stand on up to 4 channels. To perform automatic read and feed DMP :
- channel 0 is reserved for compass reading data
- channel 1 is reserved for compass writing one-shot acquisition register
- channel 2 is reserved for als reading data */
#define COMPASS_I2C_SLV_READ 0
#define COMPASS_I2C_SLV_WRITE 1
#define ALS_I2C_SLV 2
也就是此处的index为1,表示通道1,其用于设置指南针(磁力计芯片)的寄存器。
这样,s->secondary_state.slv_reg[index].addr就是s->secondary_state.slv_reg[1].addr,在inv_icm20948_init_secondary函数中赋的值是REG_I2C_SLV1_ADDR。REG_I2C_SLV1_ADDR宏在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Defs.h中,定义如下:
#define REG_I2C_SLV0_ADDR (BANK_3 | 0x03)
#define REG_I2C_SLV0_REG (BANK_3 | 0x04)
#define REG_I2C_SLV0_CTRL (BANK_3 | 0x05)
#define REG_I2C_SLV0_DO (BANK_3 | 0x06)
#define REG_I2C_SLV1_ADDR (BANK_3 | 0x07)
#define REG_I2C_SLV1_REG (BANK_3 | 0x08)
#define REG_I2C_SLV1_CTRL (BANK_3 | 0x09)
#define REG_I2C_SLV1_DO (BANK_3 | 0x0A)
#define REG_I2C_SLV2_ADDR (BANK_3 | 0x0B)
#define REG_I2C_SLV2_REG (BANK_3 | 0x0C)
#define REG_I2C_SLV2_CTRL (BANK_3 | 0x0D)
#define REG_I2C_SLV2_DO (BANK_3 | 0x0E)
#define REG_I2C_SLV3_ADDR (BANK_3 | 0x0F)
#define REG_I2C_SLV3_REG (BANK_3 | 0x10)
#define REG_I2C_SLV3_CTRL (BANK_3 | 0x11)
#define REG_I2C_SLV3_DO (BANK_3 | 0x12)
#define REG_I2C_SLV4_CTRL (BANK_3 | 0x15)
也就是BANK_3 | 0x07 = (3 << 7) | 0x07。
对应于ICM20948芯片手册中的以下内容:
综上,inv_icm20948_read_secondary函数第1段代码的意思是:向I2C _SLV1_ADDR寄存器写入1个字节数据,该字节内容为0x0C,由于I2C_SLV1_RN位(bit 7)为低,因此代表准备写入数据。实际上就是选通AK09916磁力计芯片,准备写入数据。
inv_icm20948_write_secondary函数余下代码的解析,请看下回。