接前一篇文章:ICM-20948 Wake on Motion功能开发全过程(1)
准备工作
上一回解析到ICM-20948基础功能代码中的icm20948_configure函数,解析了前两个函数icm20948_create和icm20948_reset。本回继续往下解析。为了便于理解和回顾,再次贴出icm20948_configure函数代码,如下:
static esp_err_t icm20948_configure(icm20948_acce_fs_t acce_fs, icm20948_gyro_fs_t gyro_fs)
{
esp_err_t ret;
/*
* One might need to change ICM20948_I2C_ADDRESS to ICM20948_I2C_ADDRESS_1
* if address pin pulled low (to GND)
*/
icm20948 = icm20948_create(I2C_NUM_0, ICM20948_I2C_ADDRESS);
if (!icm20948)
{
ESP_LOGE(TAG, "icm20948_create returned NULL");
return ESP_FAIL;
}
ESP_LOGI(TAG, "icm20948_create successfully");
ret = icm20948_reset(icm20948);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "icm20948_reset failed");
return ret;
}
ESP_LOGI(TAG, "icm20948_reset successfully");
vTaskDelay(10 / portTICK_PERIOD_MS);
ret = icm20948_wakeup(icm20948);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "icm20948_wakeup failed");
return ret;
}
ESP_LOGI(TAG, "icm20948_wakeup successfully");
ret = icm20948_set_bank(icm20948, 0);
if (ret != ESP_OK)
return ret;
uint8_t device_id;
ret = icm20948_get_deviceid(icm20948, &device_id);
if (ret != ESP_OK)
return ret;
ESP_LOGI(TAG, "0x%02X", device_id);
if (device_id != ICM20948_WHO_AM_I_VAL)
return ESP_FAIL;
ret = icm20948_set_gyro_fs(icm20948, gyro_fs);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "icm20948_set_gyro_fs failed");
return ESP_FAIL;
}
ESP_LOGI(TAG, "icm20948_set_gyro_fs successfully");
ret = icm20948_set_accel_fs(icm20948, accel_fs);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "icm20948_set_accel_fs failed");
return ESP_FAIL;
}
ESP_LOGI(TAG, "icm20948_set_accel_fs successfully");
return ret;
}
(3)icm20948_wakeup函数
对应代码片段如下:
ret = icm20948_wakeup(icm20948);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "icm20948_wakeup failed");
return ret;
}
ESP_LOGI(TAG, "icm20948_wakeup successfully");
icm20948_wakeup函数代码如下:
esp_err_t icm20948_wakeup(icm20948_handle_t sensor)
{
esp_err_t ret;
uint8_t tmp;
ret = icm20948_read(sensor, ICM20948_PWR_MGMT_1, &tmp, 1);
if (ESP_OK != ret)
{
ESP_LOGE(TAG, "icm20948_read failed");
return ret;
}
tmp &= (~BIT6);
ret = icm20948_write(sensor, ICM20948_PWR_MGMT_1, &tmp, 1);
if (ESP_OK != ret)
{
ESP_LOGE(TAG, "icm20948_write failed");
return ret;
}
return ESP_OK;
}
icm20948_wakeup函数中,先通过icm20948_read函数读取ICM-20948的PWR_MGMT_1寄存器的内容;之后将bit6清零;再写回到ICM-20948的PWR_MGMT_1寄存器中。
PWR_MGMT_1寄存器对应芯片手册中的以下内容:
(4)icm20948_set_bank函数
对应代码片段如下:
ret = icm20948_set_bank(icm20948, 0);
if (ret != ESP_OK)
return ret;
icm20948_set_bank函数代码如下:
esp_err_t icm20948_set_bank(icm20948_handle_t sensor, uint8_t bank)
{
esp_err_t ret;
if (bank > 3)
return ESP_FAIL;
bank = (bank << 4) & 0x30;
ret = icm20948_write(sensor, ICM20948_REG_BANK_SEL, &bank, 1);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "icm20948_write failed");
return ret;
}
return ESP_OK;
}
icm20948_set_bank函数中,直接通过icm20948_write函数向ICM-20948的REG_BANK_SEL寄存器写入bank值,此处bank值为0。
REG_BANK_SEL寄存器对应芯片手册中的以下内容:
ICM-20948一共有4个BANK(BANK0~3),每个BANK中都有REG_BANK_SEL寄存器,值都是0x7F。这样就可以自由地在BANK间进行切换。实际上,icm20948_configure代码是有问题的。因为PWR_MGMT_1是BANK0中的寄存器,应该先选择BANK,后选择寄存器,而不是到这一步才选择BANK。当然,由于芯片复位后默认是选择BANK0,因此虽然并未显式选择BANK0,PWR_MGMT_1寄存器也是能够正常设置的。
(5)icm20948_get_deviceid函数
对应代码片段如下:
uint8_t device_id;
ret = icm20948_get_deviceid(icm20948, &device_id);
if (ret != ESP_OK)
return ret;
ESP_LOGI(TAG, "0x%02X", device_id);
if (device_id != ICM20948_WHO_AM_I_VAL)
return ESP_FAIL;
icm20948_get_deviceid函数代码如下:
esp_err_t icm20948_get_deviceid(icm20948_handle_t sensor, uint8_t *const deviceid)
{
return icm20948_read(sensor, ICM20948_WHO_AM_I, deviceid, 1);
}
icm20948_get_deviceid函数通过icm20948_read函数读取ICM-20948的WHO_AM_I寄存器的内容,并作判断。
WHO_AM_I寄存器对应芯片手册中的以下内容:
由手册可知,ICM-20948的device id为0xEA。上边代码中会检测这个值,如果不是0xEA,则返回错误。
icm20948_configure函数中的其余内容,下一回继续解析。