本文已参与 [新人创作礼] 活动,一起开启掘金创作之路。
inv_mpu.c中,int mpu_init(void)中:
//配置陀螺仪满量程范围,FSR: ±2000°/s,LSB: 16.4 LSB/°/s
if (mpu_set_gyro_fsr(2000))
return -1;
inv_mpu.c中:
/**
* @brief Set the gyro full-scale range.
* @param[in] fsr Desired full-scale range.
* @return 0 if successful.
*/
int mpu_set_gyro_fsr(unsigned short fsr)
{
unsigned char data;
if (!(st.chip_cfg.sensors))
return -1;
switch (fsr) {
case 250:
data = INV_FSR_250DPS << 3; //enum gyro_fsr_e INV_FSR_250DPS=0
break;
case 500:
data = INV_FSR_500DPS << 3; //enum gyro_fsr_e INV_FSR_500DPS=1
break;
case 1000:
data = INV_FSR_1000DPS << 3; //enum gyro_fsr_e INV_FSR_1000DPS=2
break;
case 2000:
data = INV_FSR_2000DPS << 3; //enum gyro_fsr_e INV_FSR_2000DPS=3
break;
default:
return -1;
}
if (st.chip_cfg.gyro_fsr == (data >> 3))
return 0;
if (i2c_write(st.hw->addr, st.reg->gyro_cfg, 1, &data)) //.gyro_cfg = 0x1B,
return -1;
st.chip_cfg.gyro_fsr = data >> 3;
return 0;
}
对应手册中的寄存器为:
inv_mpu.c中,int mpu_init(void)中:
//配置加速度计满量程范围,FSR: ±2g,LSB: 16384 LSB/g
if (mpu_set_accel_fsr(2))
return -1;
inv_mpu.c中:
/**
* @brief Set the accel full-scale range.
* @param[in] fsr Desired full-scale range.
* @return 0 if successful.
*/
int mpu_set_accel_fsr(unsigned char fsr)
{
unsigned char data;
if (!(st.chip_cfg.sensors))
return -1;
switch (fsr) {
case 2:
data = INV_FSR_2G << 3; //enum accel_fsr_e INV_FSR_2G=0
break;
case 4:
data = INV_FSR_4G << 3; //enum accel_fsr_e INV_FSR_4G=1
break;
case 8:
data = INV_FSR_8G << 3; //enum accel_fsr_e INV_FSR_8G=2
break;
case 16:
data = INV_FSR_16G << 3; //enum accel_fsr_e INV_FSR_16G=3
break;
default:
return -1;
}
if (st.chip_cfg.accel_fsr == (data >> 3))
return 0;
if (i2c_write(st.hw->addr, st.reg->accel_cfg, 1, &data)) //.accel_cfg = 0x1C,
return -1;
st.chip_cfg.accel_fsr = data >> 3;
return 0;
}
对应手册中的寄存器为:
inv_mpu.c中,int mpu_init(void)中:
//配置数字低通滤波器,42Hz
if (mpu_set_lpf(42))
return -1;
inv_mpu.c中:
/**
* @brief Set digital low pass filter.
* The following LPF settings are supported: 188, 98, 42, 20, 10, 5.
* @param[in] lpf Desired LPF setting.
* @return 0 if successful.
*/
int mpu_set_lpf(unsigned short lpf)
{
unsigned char data;
if (!(st.chip_cfg.sensors))
return -1;
if (lpf >= 188)
data = INV_FILTER_188HZ; //enum lpf_e INV_FILTER_188HZ=1
else if (lpf >= 98)
data = INV_FILTER_98HZ; //enum lpf_e INV_FILTER_98HZ=2
else if (lpf >= 42)
data = INV_FILTER_42HZ; //enum lpf_e INV_FILTER_42HZ=3
else if (lpf >= 20)
data = INV_FILTER_20HZ; //enum lpf_e INV_FILTER_20HZ=4
else if (lpf >= 10)
data = INV_FILTER_10HZ; //enum lpf_e INV_FILTER_10HZ=5
else
data = INV_FILTER_5HZ; //enum lpf_e INV_FILTER_5HZ=6
if (st.chip_cfg.lpf == data)
return 0;
if (i2c_write(st.hw->addr, st.reg->lpf, 1, &data)) //.lpf = 0x1A,
return -1;
st.chip_cfg.lpf = data;
return 0;
}
对应手册中的寄存器为:
inv_mpu.c中,int mpu_init(void)中:
//配置采样频率分频寄存器,50Hz
if (mpu_set_sample_rate(50))
return -1;
inv_mpu.c中:
/**
* @brief Set sampling rate.
* Sampling rate must be between 4Hz and 1kHz.
* @param[in] rate Desired sampling rate (Hz).
* @return 0 if successful.
*/
int mpu_set_sample_rate(unsigned short rate)
{
unsigned char data;
if (!(st.chip_cfg.sensors))
return -1;
if (st.chip_cfg.dmp_on)
return -1;
else {
if (st.chip_cfg.lp_accel_mode) {
if (rate && (rate <= 40)) {
/* Just stay in low-power accel mode. */
mpu_lp_accel_mode(rate);
return 0;
}
/* Requested rate exceeds the allowed frequencies in LP accel mode,
* switch back to full-power mode.
*/
mpu_lp_accel_mode(0);
}
if (rate < 4)
rate = 4;
else if (rate > 1000)
rate = 1000;
data = 1000 / rate - 1;
if (i2c_write(st.hw->addr, st.reg->rate_div, 1, &data)) //.rate_div = 0x19,
return -1;
st.chip_cfg.sample_rate = 1000 / (1 + data);
#ifdef AK89xx_SECONDARY
mpu_set_compass_sample_rate(min(st.chip_cfg.compass_sample_rate, MAX_COMPASS_SAMPLE_RATE));
#endif
/* Automatically set LPF to 1/2 sampling rate. */
mpu_set_lpf(st.chip_cfg.sample_rate >> 1);
return 0;
}
}
对应手册中的寄存器为:
mpu_set_sample_rate函数中调用了mpu_lp_accel_mode函数。该函数也在inv_mpu.c中,源码如下:
/**
* @brief Enter low-power accel-only mode.
* In low-power accel mode, the chip goes to sleep and only wakes up to sample
* the accelerometer at one of the following frequencies:
* \n MPU6050: 1.25Hz, 5Hz, 20Hz, 40Hz
* \n MPU6500: 1.25Hz, 2.5Hz, 5Hz, 10Hz, 20Hz, 40Hz, 80Hz, 160Hz, 320Hz, 640Hz
* \n If the requested rate is not one listed above, the device will be set to
* the next highest rate. Requesting a rate above the maximum supported
* frequency will result in an error.
* \n To select a fractional wake-up frequency, round down the value passed to
* @e rate.
* @param[in] rate Minimum sampling rate, or zero to disable LP
* accel mode.
* @return 0 if successful.
*/
int mpu_lp_accel_mode(unsigned char rate)
{
unsigned char tmp[2];
if (rate > 40)
return -1;
if (!rate) {
mpu_set_int_latched(0);
tmp[0] = 0;
tmp[1] = BIT_STBY_XYZG; //#define BIT_STBY_XYZG (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)
if (i2c_write(st.hw->addr, st.reg->pwr_mgmt_1, 2, tmp)) //.pwr_mgmt_1 = 0x6B,
return -1;
st.chip_cfg.lp_accel_mode = 0;
return 0;
}
/* For LP accel, we automatically configure the hardware to produce latched
* interrupts. In LP accel mode, the hardware cycles into sleep mode before
* it gets a chance to deassert the interrupt pin; therefore, we shift this
* responsibility over to the MCU.
*
* Any register read will clear the interrupt.
*/
mpu_set_int_latched(1);
#if defined MPU6050
tmp[0] = BIT_LPA_CYCLE; //#define BIT_LPA_CYCLE (0x20)
if (rate == 1) {
tmp[1] = INV_LPA_1_25HZ; //enum lp_accel_rate_e INV_LPA_1_25HZ=0
mpu_set_lpf(5);
} else if (rate <= 5) {
tmp[1] = INV_LPA_5HZ; //enum lp_accel_rate_e INV_LPA_5HZ=1
mpu_set_lpf(5);
} else if (rate <= 20) {
tmp[1] = INV_LPA_20HZ; //enum lp_accel_rate_e INV_LPA_20HZ=2
mpu_set_lpf(10);
} else {
tmp[1] = INV_LPA_40HZ; //enum lp_accel_rate_e INV_LPA_40HZ=3
mpu_set_lpf(20);
}
tmp[1] = (tmp[1] << 6) | BIT_STBY_XYZG;
if (i2c_write(st.hw->addr, st.reg->pwr_mgmt_1, 2, tmp)) //.pwr_mgmt_1 = 0x6B,
return -1;
#elif defined MPU6500
/* Set wake frequency. */
if (rate == 1)
tmp[0] = INV_LPA_1_25HZ;
else if (rate == 2)
tmp[0] = INV_LPA_2_5HZ;
else if (rate <= 5)
tmp[0] = INV_LPA_5HZ;
else if (rate <= 10)
tmp[0] = INV_LPA_10HZ;
else if (rate <= 20)
tmp[0] = INV_LPA_20HZ;
else if (rate <= 40)
tmp[0] = INV_LPA_40HZ;
else if (rate <= 80)
tmp[0] = INV_LPA_80HZ;
else if (rate <= 160)
tmp[0] = INV_LPA_160HZ;
else if (rate <= 320)
tmp[0] = INV_LPA_320HZ;
else
tmp[0] = INV_LPA_640HZ;
if (i2c_write(st.hw->addr, st.reg->lp_accel_odr, 1, tmp))
return -1;
tmp[0] = BIT_LPA_CYCLE;
if (i2c_write(st.hw->addr, st.reg->pwr_mgmt_1, 1, tmp))
return -1;
#endif
st.chip_cfg.sensors = INV_XYZ_ACCEL;
st.chip_cfg.clk_src = 0;
st.chip_cfg.lp_accel_mode = 1;
mpu_configure_fifo(0);
return 0;
}
对应手册中的寄存器为:
mpu_lp_accel_mode函数中又调用了mpu_set_int_latched函数,该函数同样在inv_mpu.c中,源码如下:
/**
* @brief Enable latched interrupts.
* Any MPU register will clear the interrupt.
* @param[in] enable 1 to enable, 0 to disable.
* @return 0 if successful.
*/
int mpu_set_int_latched(unsigned char enable)
{
unsigned char tmp;
if (st.chip_cfg.latched_int == enable)
return 0;
if (enable)
tmp = BIT_LATCH_EN | BIT_ANY_RD_CLR; //#define BIT_LATCH_EN (0x20), #define BIT_ANY_RD_CLR (0x10)
else
tmp = 0;
if (st.chip_cfg.bypass_mode)
tmp |= BIT_BYPASS_EN; //#define BIT_BYPASS_EN (0x02)
if (st.chip_cfg.active_low_int)
tmp |= BIT_ACTL; //#define BIT_ACTL (0x80)
if (i2c_write(st.hw->addr, st.reg->int_pin_cfg, 1, &tmp)) //.int_pin_cfg = 0x37,
return -1;
st.chip_cfg.latched_int = enable;
return 0;
}
对应手册中的寄存器为:
inv_mpu.c中,int mpu_init(void)中:
//选择FIFO
if (mpu_configure_fifo(0))
return -1;
inv_mpu.c中:
/**
* @brief Select which sensors are pushed to FIFO.
* @e sensors can contain a combination of the following flags:
* \n INV_X_GYRO, INV_Y_GYRO, INV_Z_GYRO
* \n INV_XYZ_GYRO
* \n INV_XYZ_ACCEL
* @param[in] sensors Mask of sensors to push to FIFO.
* @return 0 if successful.
*/
int mpu_configure_fifo(unsigned char sensors)
{
unsigned char prev;
int result = 0;
/* Compass data isn't going into the FIFO. Stop trying. */
sensors &= ~INV_XYZ_COMPASS; //#define INV_XYZ_COMPASS (0x01)
if (st.chip_cfg.dmp_on)
return 0;
else {
if (!(st.chip_cfg.sensors))
return -1;
prev = st.chip_cfg.fifo_enable;
st.chip_cfg.fifo_enable = sensors & st.chip_cfg.sensors;
if (st.chip_cfg.fifo_enable != sensors)
/* You're not getting what you asked for. Some sensors are
* asleep.
*/
result = -1;
else
result = 0;
if (sensors || st.chip_cfg.lp_accel_mode)
set_int_enable(1);
else
set_int_enable(0);
if (sensors) {
if (mpu_reset_fifo()) {
st.chip_cfg.fifo_enable = prev;
return -1;
}
}
}
return result;
}
mpu_configure_fifo函数中调用了set_int_enable函数。该函数也在inv_mpu.c中,源码如下:
/**
* @brief Enable/disable data ready interrupt.
* If the DMP is on, the DMP interrupt is enabled. Otherwise, the data ready
* interrupt is used.
* @param[in] enable 1 to enable interrupt.
* @return 0 if successful.
*/
static int set_int_enable(unsigned char enable)
{
unsigned char tmp;
if (st.chip_cfg.dmp_on) {
if (enable)
tmp = BIT_DMP_INT_EN; //#define BIT_DMP_INT_EN (0x02)
else
tmp = 0x00;
if (i2c_write(st.hw->addr, st.reg->int_enable, 1, &tmp)) //.int_enable = 0x38,
return -1;
st.chip_cfg.int_enable = tmp;
} else {
if (!st.chip_cfg.sensors)
return -1;
if (enable && st.chip_cfg.int_enable)
return 0;
if (enable)
tmp = BIT_DATA_RDY_EN; //#define BIT_DATA_RDY_EN (0x01)
else
tmp = 0x00;
if (i2c_write(st.hw->addr, st.reg->int_enable, 1, &tmp)) //.int_enable = 0x38,
return -1;
st.chip_cfg.int_enable = tmp;
}
return 0;
}
对应手册中的寄存器为:
mpu_configure_fifo函数中还调用了mpu_reset_fifo函数。该函数也在inv_mpu.c中,源码如下:
/**
* @brief Reset FIFO read/write pointers.
* @return 0 if successful.
*/
int mpu_reset_fifo(void)
{
unsigned char data;
if (!(st.chip_cfg.sensors))
return -1;
data = 0;
if (i2c_write(st.hw->addr, st.reg->int_enable, 1, &data)) //.int_enable = 0x38,
return -1;
if (i2c_write(st.hw->addr, st.reg->fifo_en, 1, &data)) //.fifo_en = 0x23,
return -1;
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
if (st.chip_cfg.dmp_on) {
data = BIT_FIFO_RST | BIT_DMP_RST; //#define BIT_FIFO_RST (0x04), #define BIT_DMP_RST (0x08)
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
delay_ms(50);
data = BIT_DMP_EN | BIT_FIFO_EN; //#define BIT_DMP_EN (0x80), #define BIT_FIFO_EN (0x40)
if (st.chip_cfg.sensors & INV_XYZ_COMPASS) //#define INV_XYZ_COMPASS (0x01)
data |= BIT_AUX_IF_EN; //#define BIT_AUX_IF_EN (0x20)
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
if (st.chip_cfg.int_enable)
data = BIT_DMP_INT_EN; //#define BIT_DMP_INT_EN (0x02)
else
data = 0;
if (i2c_write(st.hw->addr, st.reg->int_enable, 1, &data)) //.int_enable = 0x38,
return -1;
data = 0;
if (i2c_write(st.hw->addr, st.reg->fifo_en, 1, &data)) //.fifo_en = 0x23,
return -1;
} else {
data = BIT_FIFO_RST; //#define BIT_FIFO_RST (0x04)
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
if (st.chip_cfg.bypass_mode || !(st.chip_cfg.sensors & INV_XYZ_COMPASS)) //#define INV_XYZ_COMPASS (0x01)
data = BIT_FIFO_EN; //#define BIT_FIFO_EN (0x40)
else
data = BIT_FIFO_EN | BIT_AUX_IF_EN; //#define BIT_FIFO_EN (0x40), #define BIT_AUX_IF_EN (0x20)
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
delay_ms(50);
if (st.chip_cfg.int_enable)
data = BIT_DATA_RDY_EN; //#define BIT_DATA_RDY_EN (0x01)
else
data = 0;
if (i2c_write(st.hw->addr, st.reg->int_enable, 1, &data)) //.int_enable = 0x38,
return -1;
if (i2c_write(st.hw->addr, st.reg->fifo_en, 1, &st.chip_cfg.fifo_enable)) //.fifo_en = 0x23,
return -1;
}
return 0;
}
mpu_reset_fifo这个函数很长,一段一段来分析。
data = 0;
if (i2c_write(st.hw->addr, st.reg->int_enable, 1, &data)) //.int_enable = 0x38,
return -1;
if (i2c_write(st.hw->addr, st.reg->fifo_en, 1, &data)) //.fifo_en = 0x23,
return -1;
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
INT_ENABLE(0x38)这个寄存器上边已经介绍过了,此处写0代表不使能MOT_EN、FIFO_OFLOW_EN、I2C_MST_INT_EN、DATA_RDY_EN。
FIFO_ENABLE(0x23)寄存器如下图所示:
USER_CTRL(0x6A)寄存器如下图所示:
编辑
mpu_reset_fifo函数接下来的代码分为了两种情况:使用DMP和不使用DMP。
使用DMP时,
data = BIT_FIFO_RST | BIT_DMP_RST; //#define BIT_FIFO_RST (0x04), #define BIT_DMP_RST (0x08)
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
不使用DMP时,
data = BIT_FIFO_RST; //#define BIT_FIFO_RST (0x04)
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
可以看到无论是否使用DMP,BIT_FIFO_RST(0x04)位(Bit2)都是要设置的,参考上面的USER_CTRL(0x6A)寄存器说明,是将FIFO_RESET位置1,也就是说复位FIFO缓冲区,复位后该位自动清零。当然,此时由于还没有设置FIFO_EN位,因此暂时还不能起作用,只是先设置上而已。
如果使用了DMP功能,则需要多设置一个BIT_DMP_RST(0x08)。同样参考上边的USER_CTRL(0x6A)寄存器说明,Bit3并没有意义,因此这里应该是手册中的寄存器说明不够详细,实际上是有意义的。
继续往下看,
使用DMP时,
data = BIT_DMP_EN | BIT_FIFO_EN; //#define BIT_DMP_EN (0x80), #define BIT_FIFO_EN (0x40)
if (st.chip_cfg.sensors & INV_XYZ_COMPASS) //#define INV_XYZ_COMPASS (0x01)
data |= BIT_AUX_IF_EN; //#define BIT_AUX_IF_EN (0x20)
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
不使用DMP时,
if (st.chip_cfg.bypass_mode || !(st.chip_cfg.sensors & INV_XYZ_COMPASS)) //#define INV_XYZ_COMPASS (0x01)
data = BIT_FIFO_EN; //#define BIT_FIFO_EN (0x40)
else
data = BIT_FIFO_EN | BIT_AUX_IF_EN; //#define BIT_FIFO_EN (0x40), #define BIT_AUX_IF_EN (0x20)
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &data)) //.user_ctrl = 0x6A,
return -1;
不论是否使用DMP,BIT_FIFO_EN(0x40)位(Bit6)都要设置。这一位就是上边提到过的FIFO_EN位,这位连同上边的FIFO_RESET位同时置1,就复位了FIFO缓冲区,复位后该位自动清零。
使用DMP功能的时候还需要设置BIT_DMP_EN(0x80),对应USER_CTRL(0x6A)寄存器中的Bit7,这位同样没有给出意义,应该也是这个手册不够详细所致。但是我们可以猜测出大概的意思,BIT_DMP_EN连同BIT_DMP_RST一起设置,作用是复位DMP模式下的FIFO(只是猜测而已)。
BIT_AUX_IF_EN(0x20)位(Bit5)代表USER_CTRL(0x6A)寄存器中的I2C_MST_EN,该位置1,使能I2C主机模式;该位清0,辅助I2C总线逻辑上由主I2C总线驱动。
其实这段代码很好理解,只要是外接地磁传感器的场景,就需要使能I2C主机模式,否则就禁止该模式。
继续往下看,
使用DMP时,
if (st.chip_cfg.int_enable)
data = BIT_DMP_INT_EN; //#define BIT_DMP_INT_EN (0x02)
else
data = 0;
if (i2c_write(st.hw->addr, st.reg->int_enable, 1, &data)) //.int_enable = 0x38,
return -1;
不使用DMP时,
if (st.chip_cfg.int_enable)
data = BIT_DATA_RDY_EN; //#define BIT_DATA_RDY_EN (0x01)
else
data = 0;
if (i2c_write(st.hw->addr, st.reg->int_enable, 1, &data)) //.int_enable = 0x38,
return -1;
这段代码差别最为明显,使用DMP功能时用的是BIT_DMP_INT_EN(0x02)位(Bit1),不使用DMP功能时用的是BIT_DATA_RDY_EN(0x01)位(Bit0),参见上边INT_ENABLE(0x38)寄存器的内容,DATA_RDY_EN位置1,使能数据就绪中断,所有的传感器寄存器写操作完成时都会产生。Bit1同样没有列出具体意义,猜测应该是使能DMP模式下的数据就绪中断。当然,这一切的前提是配置了中断使能,如果不需要使能中断,则data直接置为0。
继续往下看,来到mpu_reset_fifo函数的最后一部分了。
使用DMP时,
data = 0;
if (i2c_write(st.hw->addr, st.reg->fifo_en, 1, &data)) //.fifo_en = 0x23,
return -1;
不使用DMP时,
if (i2c_write(st.hw->addr, st.reg->fifo_en, 1, &st.chip_cfg.fifo_enable)) //.fifo_en = 0x23,
return -1;
这段差别也很明显,使用DMP功能时,完全不需要开启FIFO ENABLE(0x23)寄存器中的任何位,也就是说加速度、陀螺仪、地磁和温度的FIFO都不啊用开启;而不使用DMP功能时,则需要根据之前的设定对FIFO ENABLE(0x23)寄存器进行设置。
到这里,mpu_reset_fifo函数就全部分析完了,而这也意味着mpu_configure_fifo函数分析完了。
inv_mpu.c中,int mpu_init(void)中:
/* Already disabled by setup_compass. */
if (mpu_set_bypass(0))
return -1;
inv_mpu.c中:
/**
* @brief Set device to bypass mode.
* @param[in] bypass_on 1 to enable bypass mode.
* @return 0 if successful.
*/
int mpu_set_bypass(unsigned char bypass_on)
{
unsigned char tmp;
if (st.chip_cfg.bypass_mode == bypass_on)
return 0;
if (bypass_on) {
if (i2c_read(st.hw->addr, st.reg->user_ctrl, 1, &tmp)) //.user_ctrl = 0x6A,
return -1;
tmp &= ~BIT_AUX_IF_EN; //#define BIT_AUX_IF_EN (0x20)
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &tmp))
return -1;
delay_ms(3);
tmp = BIT_BYPASS_EN; //#define BIT_BYPASS_EN (0x02)
if (st.chip_cfg.active_low_int)
tmp |= BIT_ACTL; //#define BIT_ACTL (0x80)
if (st.chip_cfg.latched_int)
tmp |= BIT_LATCH_EN | BIT_ANY_RD_CLR; //#define BIT_LATCH_EN (0x20), #define BIT_ANY_RD_CLR (0x10)
if (i2c_write(st.hw->addr, st.reg->int_pin_cfg, 1, &tmp)) //.int_pin_cfg = 0x37,
return -1;
} else {
/* Enable I2C master mode if compass is being used. */
if (i2c_read(st.hw->addr, st.reg->user_ctrl, 1, &tmp)) // //.user_ctrl = 0x6A,
return -1;
if (st.chip_cfg.sensors & INV_XYZ_COMPASS) //#define INV_XYZ_COMPASS (0x01)
tmp |= BIT_AUX_IF_EN; //#define BIT_AUX_IF_EN (0x20)
else
tmp &= ~BIT_AUX_IF_EN;
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &tmp))
return -1;
delay_ms(3);
if (st.chip_cfg.active_low_int)
tmp = BIT_ACTL; //#define BIT_ACTL (0x80)
else
tmp = 0;
if (st.chip_cfg.latched_int)
tmp |= BIT_LATCH_EN | BIT_ANY_RD_CLR; //#define BIT_LATCH_EN (0x20), #define BIT_ANY_RD_CLR (0x10)
if (i2c_write(st.hw->addr, st.reg->int_pin_cfg, 1, &tmp)) //.int_pin_cfg = 0x37,
return -1;
}
st.chip_cfg.bypass_mode = bypass_on;
return 0;
}
mpu_set_bypass函数中分为两种情况:配置为旁路和配置为非旁路。
先来看旁路的情况。首先读取USER_CTRL(0x6A)寄存器,重点关注BIT_AUX_IF_EN(0x20)位(Bit5)。上边已经介绍过,这位实际上对应的是I2C_MST_EN。代码中将该位清零,之后写回USER_CTRL(0x6A)寄存器。实际上是辅助I2C总线(AUX_DA和AUX_CL)逻辑上由主I2C总线(SDA和SCL)驱动。之后延时3毫秒。然后对于INT引脚/旁路有效使能配置(0x37)寄存器进行赋值,I2C_BYPASS_EN位置1,根据配置依次对于INT_LEVEL、LATCH_INT_EN、INT_RD_CLR进行赋值。
再来看非旁路的情况。同样是首先读取USER_CTRL(0x6A)寄存器的内容,然后根据是否连接了地磁芯片进行配置,连接了地磁传感器,BIT_AUX_IF_EN(0x20)位(Bit5)置1,即使能 I2C 主机模式;未连接地磁传感器,该位清零,即辅助I2C总线(AUX_DA和AUX_CL)逻辑上由主I2C总线(SDA和SCL)驱动。之后也同样是延时3毫秒。然后也是对于INT引脚/旁路有效使能配置(0x37)寄存器进行赋值,根据配置依次对于INT_LEVEL、LATCH_INT_EN、INT_RD_CLR进行赋值。注意,I2C_BYPASS_EN位此时是置0的。
inv_mpu.c中,int mpu_init(void)中:
mpu_set_sensors(0);
inv_mpu.c中:
/**
* @brief Turn specific sensors on/off.
* @e sensors can contain a combination of the following flags:
* \n INV_X_GYRO, INV_Y_GYRO, INV_Z_GYRO
* \n INV_XYZ_GYRO
* \n INV_XYZ_ACCEL
* \n INV_XYZ_COMPASS
* @param[in] sensors Mask of sensors to wake.
* @return 0 if successful.
*/
int mpu_set_sensors(unsigned char sensors)
{
unsigned char data;
#ifdef AK89xx_SECONDARY
unsigned char user_ctrl;
#endif
if (sensors & INV_XYZ_GYRO) //#define INV_XYZ_GYRO (INV_X_GYRO | INV_Y_GYRO | INV_Z_GYRO)
data = INV_CLK_PLL; //enum clock_sel_e INV_CLK_PLL=1
else if (sensors)
data = 0;
else
data = BIT_SLEEP; //#define BIT_SLEEP (0x40)
if (i2c_write(st.hw->addr, st.reg->pwr_mgmt_1, 1, &data)) { //.pwr_mgmt_1 = 0x6B,
st.chip_cfg.sensors = 0;
return -1;
}
st.chip_cfg.clk_src = data & ~BIT_SLEEP;
data = 0;
if (!(sensors & INV_X_GYRO)) //#define INV_X_GYRO (0x40)
data |= BIT_STBY_XG; //#define BIT_STBY_XG (0x04)
if (!(sensors & INV_Y_GYRO)) //#define INV_Y_GYRO (0x20)
data |= BIT_STBY_YG; //#define BIT_STBY_YG (0x02)
if (!(sensors & INV_Z_GYRO)) //#define INV_Z_GYRO (0x10)
data |= BIT_STBY_ZG; //#define BIT_STBY_ZG (0x01)
if (!(sensors & INV_XYZ_ACCEL)) //#define INV_XYZ_ACCEL (0x08)
data |= BIT_STBY_XYZA; //#define BIT_STBY_XYZA (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA)
if (i2c_write(st.hw->addr, st.reg->pwr_mgmt_2, 1, &data)) { //.pwr_mgmt_2 = 0x6C,
st.chip_cfg.sensors = 0;
return -1;
}
if (sensors && (sensors != INV_XYZ_ACCEL))
/* Latched interrupts only used in LP accel mode. */
mpu_set_int_latched(0);
#ifdef AK89xx_SECONDARY
#ifdef AK89xx_BYPASS
if (sensors & INV_XYZ_COMPASS)
mpu_set_bypass(1);
else
mpu_set_bypass(0);
#else
if (i2c_read(st.hw->addr, st.reg->user_ctrl, 1, &user_ctrl))
return -1;
/* Handle AKM power management. */
if (sensors & INV_XYZ_COMPASS) {
data = AKM_SINGLE_MEASUREMENT;
user_ctrl |= BIT_AUX_IF_EN;
} else {
data = AKM_POWER_DOWN;
user_ctrl &= ~BIT_AUX_IF_EN;
}
if (st.chip_cfg.dmp_on)
user_ctrl |= BIT_DMP_EN;
else
user_ctrl &= ~BIT_DMP_EN;
if (i2c_write(st.hw->addr, st.reg->s1_do, 1, &data))
return -1;
/* Enable/disable I2C master mode. */
if (i2c_write(st.hw->addr, st.reg->user_ctrl, 1, &user_ctrl))
return -1;
#endif
#endif
st.chip_cfg.sensors = sensors;
st.chip_cfg.lp_accel_mode = 0;
delay_ms(50);
return 0;
}
至此,int mpu_init(void)就全部解析完毕了。