欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 产业 > ICM20948 DMP代码详解(14)

ICM20948 DMP代码详解(14)

2024/10/25 0:35:10 来源:https://blog.csdn.net/phmatthaus/article/details/142064432  浏览:    关键词:ICM20948 DMP代码详解(14)

接前一篇文章:ICM20948 DMP代码详解(13)

上一回完成了对icm20948_sensor_setup函数中第2段代码的解析,本回继续往下进行解析。为了便于理解和回顾,再次贴出icm20948_sensor_setup函数代码,在EMD-App\src\ICM20948\sensor.c中,如下:

int icm20948_sensor_setup(void){int rc;uint8_t i, whoami = 0xff;/** Just get the whoami*/rc = inv_icm20948_get_whoami(&icm_device, &whoami);if (interface_is_SPI() == 0)	{		// If we're using I2Cif (whoami == 0xff) {				// if whoami fails try the other I2C Addressswitch_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;}/* Setup accel and gyro mounting matrix and associated angle for current board */inv_icm20948_init_matrix(&icm_device);/* set default power mode */INV_MSG(INV_MSG_LEVEL_VERBOSE, "Putting Icm20948 in sleep mode...");rc = inv_icm20948_initialize(&icm_device, dmp3_image, sizeof(dmp3_image));if (rc != 0) {INV_MSG(INV_MSG_LEVEL_ERROR, "Initialization failed. Error loading DMP3...");return rc;}/** Configure and initialize the ICM20948 for normal use*/INV_MSG(INV_MSG_LEVEL_INFO, "Booting up icm20948...");/* Initialize auxiliary sensors */inv_icm20948_register_aux_compass( &icm_device, INV_ICM20948_COMPASS_ID_AK09916, AK0991x_DEFAULT_I2C_ADDR);rc = inv_icm20948_initialize_auxiliary(&icm_device);if (rc == -1) {INV_MSG(INV_MSG_LEVEL_ERROR, "Compass not detected...");}icm20948_apply_mounting_matrix();icm20948_set_fsr();/* re-initialize base state structure */inv_icm20948_init_structure(&icm_device);/* we should be good to go ! */INV_MSG(INV_MSG_LEVEL_VERBOSE, "We're good to go !");return 0;
}

当前来到以下代码片段:

	/* set default power mode */INV_MSG(INV_MSG_LEVEL_VERBOSE, "Putting Icm20948 in sleep mode...");rc = inv_icm20948_initialize(&icm_device, dmp3_image, sizeof(dmp3_image));if (rc != 0) {INV_MSG(INV_MSG_LEVEL_ERROR, "Initialization failed. Error loading DMP3...");return rc;}

inv_icm20948_initialize函数在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Setup.c中,代码如下:

int inv_icm20948_initialize(struct inv_icm20948 * s, const uint8_t *dmp3_image, uint32_t dmp3_image_size)
{if(s->serif.is_spi) {/* Hardware initialization */// No image to be loaded from flash, no pointer to pass.if (inv_icm20948_initialize_lower_driver(s, SERIAL_INTERFACE_SPI, dmp3_image, dmp3_image_size)) {return -1;}}else {/* Hardware initialization */// No image to be loaded from flash, no pointer to pass.if (inv_icm20948_initialize_lower_driver(s, SERIAL_INTERFACE_I2C, dmp3_image, dmp3_image_size)) {return -1;}}return 0;
}

inv_icm20948_initialize函数分为两个分支,一个是SPI,另一个是I2C。这里只看I2C的分支。

甭管是SPI还是I2C,最终调用的都是inv_icm20948_initialize_lower_driver函数,只是靠函数的第2个参数来区别的。inv_icm20948_initialize_lower_driver函数在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948DataBaseDriver.c中,代码如下:

/** Should be called once on power up. Loads DMP3, initializes internal variables needed 
*   for other lower driver functions.
*/
int inv_icm20948_initialize_lower_driver(struct inv_icm20948 *s, enum SMARTSENSOR_SERIAL_INTERFACE type, const uint8_t *dmp3_image, uint32_t dmp3_image_size)
{int result = 0;static unsigned char data;// set static variables->sAllowLpEn = 1;s->s_compass_available = 0;// ICM20948 do not support the proximity sensor for the moment.// s_proximity_available variable is nerver changess->s_proximity_available = 0;// Set varialbes to default valuesmemset(&s->base_state, 0, sizeof(s->base_state));s->base_state.pwr_mgmt_1 = BIT_CLK_PLL;s->base_state.pwr_mgmt_2 = BIT_PWR_ACCEL_STBY | BIT_PWR_GYRO_STBY | BIT_PWR_PRESSURE_STBY;s->base_state.serial_interface = type;result |= inv_icm20948_read_mems_reg(s, REG_USER_CTRL, 1, &s->base_state.user_ctrl);result |= inv_icm20948_wakeup_mems(s);result |= inv_icm20948_read_mems_reg(s, REG_WHO_AM_I, 1, &data);/* secondary cycle mode should be set all the time */data = BIT_I2C_MST_CYCLE|BIT_ACCEL_CYCLE|BIT_GYRO_CYCLE;// Set default mode to low power moderesult |= inv_icm20948_set_lowpower_or_highperformance(s, 0);// Disable Ivory DMP.if(s->base_state.serial_interface == SERIAL_INTERFACE_SPI)   s->base_state.user_ctrl = BIT_I2C_IF_DIS;elses->base_state.user_ctrl = 0;result |= inv_icm20948_write_single_mems_reg(s, REG_USER_CTRL, s->base_state.user_ctrl);//Setup Ivory DMP.result |= inv_icm20948_load_firmware(s, dmp3_image, dmp3_image_size);if(result)return result;elses->base_state.firmware_loaded = 1;result |= inv_icm20948_set_dmp_address(s);// Turn off all sensors on DMP by default.//result |= dmp_set_data_output_control1(0);   // FIXME in DMP, these should be off by default.result |= dmp_icm20948_reset_control_registers(s);// set FIFO watermark to 80% of actual FIFO sizeresult |= dmp_icm20948_set_FIFO_watermark(s, 800);// Enable Interrupts.data = 0x2;result |= inv_icm20948_write_mems_reg(s, REG_INT_ENABLE, 1, &data); // Enable DMP Interruptdata = 0x1;result |= inv_icm20948_write_mems_reg(s, REG_INT_ENABLE_2, 1, &data); // Enable FIFO Overflow Interrupt// TRACKING : To have accelerometers datas and the interrupt without gyro enables.data = 0XE4;result |= inv_icm20948_write_mems_reg(s, REG_SINGLE_FIFO_PRIORITY_SEL, 1, &data);// Disable HW temp fixinv_icm20948_read_mems_reg(s, REG_HW_FIX_DISABLE,1,&data);data |= 0x08;inv_icm20948_write_mems_reg(s, REG_HW_FIX_DISABLE,1,&data);// Setup MEMs properties.s->base_state.accel_averaging = 1; //Change this value if higher sensor sample avergaing is required.s->base_state.gyro_averaging = 1;  //Change this value if higher sensor sample avergaing is required.inv_icm20948_set_gyro_divider(s, FIFO_DIVIDER);       //Initial sampling rate 1125Hz/19+1 = 56Hz.inv_icm20948_set_accel_divider(s, FIFO_DIVIDER);      //Initial sampling rate 1125Hz/19+1 = 56Hz.// Init the sample rate to 56 Hz for BAC,STEPC and B2Sdmp_icm20948_set_bac_rate(s, DMP_ALGO_FREQ_56);dmp_icm20948_set_b2s_rate(s, DMP_ALGO_FREQ_56);// FIFO Setup.result |= inv_icm20948_write_single_mems_reg(s, REG_FIFO_CFG, BIT_SINGLE_FIFO_CFG); // FIFO Config. fixme do once? burst write?result |= inv_icm20948_write_single_mems_reg(s, REG_FIFO_RST, 0x1f); // Reset all FIFOs.result |= inv_icm20948_write_single_mems_reg(s, REG_FIFO_RST, 0x1e); // Keep all but Gyro FIFO in reset.result |= inv_icm20948_write_single_mems_reg(s, REG_FIFO_EN, 0x0); // Slave FIFO turned off.result |= inv_icm20948_write_single_mems_reg(s, REG_FIFO_EN_2, 0x0); // Hardware FIFO turned off.s->base_state.lp_en_support = 1;if(s->base_state.lp_en_support == 1)inv_icm20948_set_chip_power_state(s, CHIP_LP_ENABLE, 1);result |= inv_icm20948_sleep_mems(s);   return result;
}

一上来先看几个struct inv_icm20948的成员:

	// set static variables->sAllowLpEn = 1;s->s_compass_available = 0;// ICM20948 do not support the proximity sensor for the moment.// s_proximity_available variable is nerver changess->s_proximity_available = 0;
typedef struct inv_icm20948 {struct inv_icm20948_serif serif;……/* base driver */uint8_t sAllowLpEn;uint8_t s_compass_available;uint8_t s_proximity_available;……
} inv_icm20948_t;

这一段根据变量字面意思,分别是:允许低功耗;指南针不可用;接近传感器不可用。

接下来的及段代码都是围绕struct inv_icm20948的另一成员base_state进行读取和设置的。

typedef struct inv_icm20948 {struct inv_icm20948_serif serif;/** @brief struct for the base_driver : this contains the Mems information */struct base_driver_t{unsigned char wake_state;chip_lp_ln_mode_icm20948_t chip_lp_ln_mode;unsigned char pwr_mgmt_1;unsigned char pwr_mgmt_2;unsigned char user_ctrl;unsigned char gyro_div;unsigned short secondary_div;short accel_div;unsigned char gyro_averaging;unsigned char accel_averaging;uint8_t gyro_fullscale; uint8_t accel_fullscale;uint8_t lp_en_support:1;uint8_t firmware_loaded:1;uint8_t serial_interface;uint8_t timebase_correction_pll;} base_state;……
} inv_icm20948_t;

一段一段来看。先来看第1段:

	// Set varialbes to default valuesmemset(&s->base_state, 0, sizeof(s->base_state));s->base_state.pwr_mgmt_1 = BIT_CLK_PLL;s->base_state.pwr_mgmt_2 = BIT_PWR_ACCEL_STBY | BIT_PWR_GYRO_STBY | BIT_PWR_PRESSURE_STBY;s->base_state.serial_interface = type;

一上来先把s->base_state成员清零。

接下来将base_state的pwr_mgmt_1赋值为BIT_CLK_PLL(0x01,EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Defs.h中定义);pwr_mgmt_2赋值为BIT_PWR_ACCEL_STBY | BIT_PWR_GYRO_STBY | BIT_PWR_PRESSURE_STBY(0x38 | 0x07 | 0x40,同样在Icm20948Defs.h中定义)。这两个成员从名字上就能看出来一定与电源管理寄存器相关。

接下来将base_state的serial_interface成员设置为type,这个type就是上边提到的inv_icm20948_initialize函数中走SPI分支还是I2C分支,即传入的是SERIAL_INTERFACE_SPI还是SERIAL_INTERFACE_I2C。这里是SERIAL_INTERFACE_I2C。这两个值为枚举类型,也在Icm20948Defs.h中定义,如下:

enum SMARTSENSOR_SERIAL_INTERFACE {SERIAL_INTERFACE_I2C = 1,SERIAL_INTERFACE_SPI,SERIAL_INTERFACE_INVALID
};

再往下就该通过I2C与具体的寄存器打交道了,下一回开始进行详细解析。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com