接前一篇文章:ICM20948 DMP代码详解(27)
上一回解析完了dmp_icm20948_reset_control_registers函数,回到inv_icm20948_initialize_lower_driver函数中,继续往下进行解析。为了便于理解和回顾,再次贴出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 variable
s->sAllowLpEn = 1;
s->s_compass_available = 0;
// ICM20948 do not support the proximity sensor for the moment.
// s_proximity_available variable is nerver changes
s->s_proximity_available = 0;
// Set varialbes to default values
memset(&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 mode
result |= 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;
else
s->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;
else
s->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 size
result |= 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 Interrupt
data = 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 fix
inv_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 B2S
dmp_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;
}
当前来到以下代码片段:
// set FIFO watermark to 80% of actual FIFO size
result |= dmp_icm20948_set_FIFO_watermark(s, 800);
dmp_icm20948_set_FIFO_watermark函数在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Dmp3Driver.c中,代码如下:
/**
* Sets FIFO watermark. DMP will send FIFO interrupt if FIFO count > FIFO watermark
* @param[in] fifo_wm FIFO watermark set to 80% of actual FIFO size by default
*/
int dmp_icm20948_set_FIFO_watermark(struct inv_icm20948 *s, unsigned short fifo_wm)
{
int result;
unsigned char big8[2]={0};
result = inv_icm20948_write_mems(s, FIFO_WATERMARK, 2, inv_icm20948_convert_int16_to_big8(fifo_wm,big8));
if (result)
return result;
return 0;
}
根据注释,函数的功能是:设置FIFO水线。如果FIFO计数>FIFO水线,DMP将发送FIFO中断。
FIFO_WATERMARK宏在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Dmp3Driver.c中,定义如下:
#define FIFO_WATERMARK (31 * 16 + 14)
FIFO_WATERMARK的值为31 * 16 + 14 = 510。又是一个“两本账”寄存器。
inv_icm20948_convert_int16_to_big8函数在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948DataConverter.c中,代码如下:
uint8_t *inv_icm20948_convert_int16_to_big8(int16_t x, uint8_t *big8)
{
big8[0] = (uint8_t)((x >> 8) & 0xff);
big8[1] = (uint8_t)(x & 0xff);
return big8;
}
由于传入的值并不是单字节、而是双字节的(比如此处传入的值为800),因此需要转换一下大小端模式。就以这里的800为例,十六进制数为0x0336,小端模式下低字节是0x36,高字节是0x03,因此在此转换为大端模式时要调换一下,低字节(big8[0])为0x03,高字节(big8[1])为0x36。
这样,dmp_icm20948_set_FIFO_watermark函数的功能就一目了然了,设置DMP FIFO的水线为800。当FIFO超过800个字节时,DMP将会发送FIFO中断。
这里再详细说一下这个水线值的设置。根据dmp_icm20948_set_FIFO_watermark函数参数说明,此水线值默认设置为FIFO大小的80%,这里设置成了800,那么可想而知,后边肯定会又代码将FIFO设置为1000。
至此,dmp_icm20948_set_FIFO_watermark函数就解析完了。回到inv_icm20948_initialize_lower_driver函数中,下一回继续解析inv_icm20948_initialize_lower_driver函数中的后续代码。