接前一篇文章:ICM20948 DMP代码详解(9)
上一回解析完了icm20948_sensor_setup函数第1段代码中的inv_icm20948_get_whoami函数,也把源码工程中I2C读取寄存器的流程梳理了一下。本回回到第1段代码中,把剩余的部分解析完。再次贴出源码:
/*
* Just get the whoami
*/
rc = inv_icm20948_get_whoami(&icm_device, &whoami);
if (interface_is_SPI() == 0) { // If we're using I2C
if (whoami == 0xff) { // if whoami fails try the other I2C Address
switch_I2C_to_revA();
rc = inv_icm20948_get_whoami(&icm_device, &whoami);
}
}
INV_MSG(INV_MSG_LEVEL_INFO, "ICM20948 WHOAMI value=0x%02x", whoami);
/*
* Check if WHOAMI value corresponds to any value from EXPECTED_WHOAMI array
*/
for(i = 0; i < sizeof(EXPECTED_WHOAMI)/sizeof(EXPECTED_WHOAMI[0]); ++i) {
if(whoami == EXPECTED_WHOAMI[i]) {
break;
}
}
if(i == sizeof(EXPECTED_WHOAMI)/sizeof(EXPECTED_WHOAMI[0])) {
INV_MSG(INV_MSG_LEVEL_ERROR, "Bad WHOAMI value. Got 0x%02x.", whoami);
return rc;
}
接下来调用interface_is_SPI()判断使用的是I2C方式还是SPI方式。interface_is_SPI函数前文书(https://phmatthaus.blog.youkuaiyun.com/article/details/141950357)也讲过:
如果使用的是SPI方式,则返回true;否则返回false。这里假设使用的是I2C方式,那么会进入判断体中。
if (interface_is_SPI() == 0) { // If we're using I2C
if (whoami == 0xff) { // if whoami fails try the other I2C Address
switch_I2C_to_revA();
rc = inv_icm20948_get_whoami(&icm_device, &whoami);
}
}
如果通过inv_icm20948_get_whoami函数得到的whoami的值为0xff,则说明没有读到内容,则 调用switch_I2C_to_revA(),之后再次调用inv_icm20948_get_whoami函数尝试读取。
switch_I2C_to_revA函数也在EMD-App\src\ICM20948\system.c中,代码如下:
void switch_I2C_to_revA(void){
#if SERIF_TYPE_I2C
I2C_Address = ICM_I2C_ADDR_REVA;
#endif
}
ICM_I2C_ADDR_REVA宏在EMD-App\src\ICM20948\system.h中,定义如下:
#define ICM_I2C_ADDR_REVA 0x68 /* I2C slave address for INV device on Rev A board */
#define ICM_I2C_ADDR_REVB 0x69 /* I2C slave address for INV device on Rev B board */
I2C_Address是一个全局变量,在同文件(EMD-App\src\ICM20948\system.c)中,定义如下:
#if SERIF_TYPE_I2C
/*
* Variable for storing I2C Address
*/
uint8_t I2C_Address = ICM_I2C_ADDR_REVB;
#endif
默认用的是Rev B板子,其中ICM20948的I2C地址为0x69。如果读不到,则可能是Rev A板子,I2C地址为0x68,再次尝试读取WHO_AM_I寄存器的内容。这里的0x68和0x69在ICM20948的芯片手册中有说明,如下:
接下来来到以下代码片段:
/*
* Check if WHOAMI value corresponds to any value from EXPECTED_WHOAMI array
*/
for(i = 0; i < sizeof(EXPECTED_WHOAMI)/sizeof(EXPECTED_WHOAMI[0]); ++i) {
if(whoami == EXPECTED_WHOAMI[i]) {
break;
}
}
if(i == sizeof(EXPECTED_WHOAMI)/sizeof(EXPECTED_WHOAMI[0])) {
INV_MSG(INV_MSG_LEVEL_ERROR, "Bad WHOAMI value. Got 0x%02x.", whoami);
return rc;
}
EXPECTED_WHOAMI在EMD-App\src\ICM20948\sensor.c中,代码如下:
static const uint8_t EXPECTED_WHOAMI[] = { 0xEA }; /* WHOAMI value for ICM20948 or derivative */
sizeof(EXPECTED_WHOAMI)/sizeof(EXPECTED_WHOAMI[0])的值为1,因此for循环也只执行1次。循环体中判断读取到的WHO_AM_I寄存器值,如果为0xEA则跳出,注意此时i的值为0;否则循环体结束后退出,注意此时i的值为1。
这个0xEA也是在ICM20948手册中的,如下所示:
接下来判断i的值,如果为1,则说明是走过了完整for循环,也就代表了没有读到0xEA这个值,则需要给出提示,并返回rc值(应该是错误值)。
至此,icm20948_sensor_setup函数第1段代码就解析完了。这一步骤符合一般流程,即先读取WHO_AM_I寄存器(id),看看能否通过I2C与ICM20948正常通信。
icm20948_sensor_setup函数其余代码的解析请看下回。