接前一篇文章:ICM20948 DMP代码详解(18)
上一回完成了对inv_icm20948_set_chip_power_state函数的完全解析。本回回到调用它的inv_icm20948_read_mems_reg函数中,继续往下解析。为了便于理解和回顾,再次贴出inv_icm20948_read_mems_reg函数源码,在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Transport.c中,如下:
/**
* @brief Read data from a register on MEMs.
* @param[in] Register address
* @param[in] Length of data
* @param[in] Data to be written
* @return 0 if successful.
*/
int inv_icm20948_read_mems_reg(struct inv_icm20948 * s, uint16_t reg, unsigned int length, unsigned char *data)
{
int result = 0;
unsigned int bytesRead = 0;
unsigned char regOnly = (unsigned char)(reg & 0x7F);
unsigned char i, dat[INV_MAX_SERIAL_READ];
unsigned char power_state = inv_icm20948_get_chip_power_state(s);
if((power_state & CHIP_AWAKE) == 0) // Wake up chip since it is asleep
result = inv_icm20948_set_chip_power_state(s, CHIP_AWAKE, 1);
if(check_reg_access_lp_disable(s, reg)) // Check if register needs LP_EN to be disabled
result |= inv_icm20948_set_chip_power_state(s, CHIP_LP_ENABLE, 0); //Disable LP_EN
result |= inv_set_bank(s, reg >> 7);
while (bytesRead<length)
{
int thisLen = min(INV_MAX_SERIAL_READ, length-bytesRead);
if(s->base_state.serial_interface == SERIAL_INTERFACE_SPI) {
result |= inv_icm20948_read_reg(s, regOnly+bytesRead, &dat[bytesRead], thisLen);
} else {
result |= inv_icm20948_read_reg(s, regOnly+bytesRead, &data[bytesRead],thisLen);
}
if (result)
return result;
bytesRead += thisLen;
}
if(s->base_state.serial_interface == SERIAL_INTERFACE_SPI) {
for (i=0; i< length; i++) {
*data= dat[i];
data++;
}
}
if(check_reg_access_lp_disable(s, reg)) // Check if register needs LP_EN to be enabled
result |= inv_icm20948_set_chip_power_state(s, CHIP_LP_ENABLE, 1); //Enable LP_EN
return result;
}
check_reg_access_lp_disable函数在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Transport.c中,代码如下:
static uint8_t check_reg_access_lp_disable(struct inv_icm20948 *s, unsigned short reg)
{
switch(reg){
case REG_LP_CONFIG: /** (BANK_0 | 0x05) */
case REG_PWR_MGMT_1: /** (BANK_0 | 0x06) */
case REG_PWR_MGMT_2: /** (BANK_0 | 0x07) */
case REG_INT_PIN_CFG: /** (BANK_0 | 0x0F) */
case REG_INT_ENABLE: /** (BANK_0 | 0x10) */
case REG_FIFO_COUNT_H: /** (BANK_0 | 0x70) */
case REG_FIFO_COUNT_L: /** (BANK_0 | 0x71) */
case REG_FIFO_R_W: /** (BANK_0 | 0x72) */
return inv_icm20948_ctrl_get_batch_mode_status(s);
case REG_FIFO_CFG: /** (BANK_0 | 0x76) */
case REG_MEM_BANK_SEL: /** (BANK_0 | 0x7E) */
case REG_BANK_SEL: /** 0x7F */
case REG_INT_STATUS: /** (BANK_0 | 0x19) */
case REG_DMP_INT_STATUS: /** (BANK_0 | 0x18) */
return 0;
break;
default:
break;
}
return 1;
}
此处在inv_icm20948_read_mems_reg函数中传给check_reg_access_lp_disable函数的实参是reg,而这个reg又是inv_icm20948_initialize_lower_driver函数传给inv_icm20948_read_mems_reg函数的,实际的寄存器是REG_USER_CTRL。
REG_USER_CTRL宏在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Defs.h中定义,如下:
#define REG_USER_CTRL (BANK_0 | 0x03)
对应于ICM20948芯片手册中的USER_CTRL寄存器,如下所示:
由于REG_USER_CTRL不属于switch中的case,或者说属于default,因此函数check_reg_access_lp_disable直接返回1。
这样,inv_icm20948_read_mems_reg函数的以下代码片段的完整功能就明晰了。
unsigned char power_state = inv_icm20948_get_chip_power_state(s);
if((power_state & CHIP_AWAKE) == 0) // Wake up chip since it is asleep
result = inv_icm20948_set_chip_power_state(s, CHIP_AWAKE, 1);
if(check_reg_access_lp_disable(s, reg)) // Check if register needs LP_EN to be disabled
result |= inv_icm20948_set_chip_power_state(s, CHIP_LP_ENABLE, 0); //Disable LP_EN
1)首先通过inv_icm20948_get_chip_power_state函数得到power_state即s->base_state.wake_state;
2)如果power_state中的CHIP_AWAKE没有置位、即ICM20948芯片处于休眠状态,则调用inv_icm20948_set_chip_power_state函数将其唤醒;
3)之后检查USER_CTRL寄存器是否需要将LP_EN禁止;
4)如果需要,则再次通过inv_icm20948_set_chip_power_state函数禁止低功耗模式(注意是暂时性的,下边还会恢复低功耗模式)。
回到inv_icm20948_read_mems_reg函数中。接下来调用inv_set_bank函数设置bank。inv_set_bank函数前文书中已经解析过(参见https://phmatthaus.blog.csdn.net/article/details/142096690),在此不再赘述。
接下来就要开始实际的数据读取了,对于这部分的解析,放在下一回中。