9轴传感器MPU9250调试
MPU9250实际上是mpu6500+ak8963的贴合芯片,内部的AK8963是负责三轴磁力传感器采样的芯片 ,它通过I2C总线与MPU6500连接在一起。ak8963的寄存器读取可以通过特定的i2c直通模式:
驱动代码,也是用mpu6500和ak8963对应的驱动即可。 gsensor、陀螺仪、地磁传感器对应驱动如下:
drivers/input/sensors/accel/mpu6500_acc.c
drivers/input/sensors/gyro/mpu6500_gyro.c
drivers/input/sensors/compass/ak8963.c.c
调试步骤:
1.开启支持地磁传感器和编译AK8963的hardware:
device/rockchip/rk356x diff --git a/BoardConfig.mk b/BoardConfig.mk index 4601141..46b500f 100644 --- a/BoardConfig.mk +++ b/BoardConfig.mk @@ -54,6 +54,7 @@ endif BOARD_SENSOR_ST := true BOARD_SENSOR_MPU_VR := false BOARD_SENSOR_MPU_PAD := false +BOARD_SENSOR_COMPASS_AK8963-64 := true BOARD_USES_GENERIC_INVENSENSE := false @@ -68,7 +69,7 @@ BOARD_NFC_SUPPORT := false BOARD_HAS_GPS := true BOARD_GRAVITY_SENSOR_SUPPORT := true -BOARD_COMPASS_SENSOR_SUPPORT := false +BOARD_COMPASS_SENSOR_SUPPORT := true BOARD_GYROSCOPE_SENSOR_SUPPORT := true BOARD_PROXIMITY_SENSOR_SUPPORT := false BOARD_LIGHT_SENSOR_SUPPORT := false
BOARD_SENSOR_COMPASS_AK8963-64这个宏对应的编译代码为:
hardware/rockchip/sensor/st/Android.mk
######### AKM daemon ################################################# ifeq ($(strip $(BOARD_SENSOR_COMPASS_AK8963)), true) include $(LOCAL_PATH)/akm8963/Android.mk else ifeq ($(strip $(BOARD_SENSOR_COMPASS_AK09911)), true) include $(LOCAL_PATH)/akm09911/Android.mk else ifeq ($(strip $(BOARD_SENSOR_COMPASS_AK8975)), true) include $(LOCAL_PATH)/akm8975/Android.mk else ifeq ($(strip $(BOARD_SENSOR_COMPASS_AK8963-64)), true) include $(LOCAL_PATH)/akm8963-64/Android.mk endif
2.dts设备添加:
@@ -306,6 +306,36 @@ type = <SENSOR_TYPE_GYROSCOPE>; //layout = <5>; }; + + mpu6500_acc: mpu_acc@68 { + compatible = "mpu6500_acc"; + status = "okay"; + reg = <0x68>; + irq-gpio = <&gpio3 RK_PA3 IRQ_TYPE_EDGE_RISING>; + irq_enable = <0>; + poll_delay_ms = <30>; + type = <SENSOR_TYPE_ACCEL>; + layout = <9>; + }; + + mpu6500_gyro: mpu_gyro@68 { + compatible = "mpu6500_gyro"; + status = "okay"; + reg = <0x68>; + irq_enable = <0>; + poll_delay_ms = <30>; + type = <SENSOR_TYPE_GYROSCOPE>; + layout = <9>; + }; + + akm8963_mag: akm_mag@c { + status = "okay"; + compatible = "ak8963"; + reg = <0x0c>; + type = <SENSOR_TYPE_COMPASS>; + poll_delay_ms = <30>; + layout = <3>; + };
3.驱动修改:
直通模式需要MPU6500初始化的时候设置一下0x37这个寄存器Bit1写1即可开启,然后就会有0x0c的地址出来,这个就是ak8963的地址,相当于一条总线挂2个单独的设备。
#define MPU6500_INT_PIN_CFG 0x37 /*------------------------------ MPU6500_INT_PIN_CFG --------------------------------*/ #define BIT_BYPASS_EN 0x2
diff --git a/drivers/input/sensors/accel/mpu6500_acc.c b/drivers/input/sensors/accel/mpu6500_acc.c index 6fc2058e0f9f..3dee84f6b44e 100644 --- a/drivers/input/sensors/accel/mpu6500_acc.c +++ b/drivers/input/sensors/accel/mpu6500_acc.c @@ -86,7 +86,7 @@ static int sensor_active(struct i2c_client *client, int enable, int rate) int result = 0; int status = 0; u8 pwrm1 = 0; - + sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg); pwrm1 = sensor_read_reg(client, MPU6500_PWR_MGMT_1); @@ -175,6 +175,11 @@ static int sensor_init(struct i2c_client *client) } msleep(10); + res = sensor_write_reg(client, MPU6500_INT_PIN_CFG, BIT_BYPASS_EN); + if (res) + pr_err("%s:wmc---wmc---t-pass1 mode\n", __func__); + read_data = sensor_read_reg(client, MPU6500_INT_PIN_CFG); + res = sensor->ops->active(client, 0, sensor->pdata->poll_delay_ms);
设置完0x37寄存器的时候,发现差不多开机起来才有对应的0x0c地址出来(i2ctool工具检测),这个时候如果正常加载ak8963,会失败(原因是0x0c的地址还没有出来)。试过把ak8963编译成模块的方式,开机完成后在脚本里启动.ko驱动,驱动可以加载成功,但是没有数据上报。原因应该是驱动一定要在HAL层启动之前初始化,要不然可能没有生成/dev/compass这个文件节点,HAL层会出错。
仔细看开机log:
[ 19.676846] gsensor_mpu6500 5-0068: set sensor poll time to 66ms [ 19.677119] sensor_active-------hfksdhfkskg.......enable:1 [ 19.761173] gsensor_mpu6500 5-0068: sensor on: starting poll sensor data 62ms
发现有一个hal对底层ioclt的动作,追踪代码流程:
drivers/input/sensors/sensor-dev.c gsensor_dev_ioctl -->GSENSOR_IOCTL_APP_SET_RATE -->sensor_reset_rate static int sensor_reset_rate(struct i2c_client *client, int rate) { ....... if (sensor->status_cur == SENSOR_ON) { if (!sensor->pdata->irq_enable) { sensor->stop_work = 1; cancel_delayed_work_sync(&sensor->delaywork); } sensor->ops->active(client, SENSOR_OFF, rate); result = sensor->ops->active(client, SENSOR_ON, rate); if (!sensor->pdata->irq_enable) { sensor->stop_work = 0; schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms)); } } ....... }
sensor->ops->active实际调用了
static int sensor_active(struct i2c_client *client, int enable, int rate) { 。。。。 if (!enable) { status = BIT_ACCEL_STBY; sensor->ops->ctrl_data |= status; if ((sensor->ops->ctrl_data & BIT_GYRO_STBY) == BIT_GYRO_STBY) { pwrm1 |= MPU6500_PWRM1_SLEEP; } } else { status = ~BIT_ACCEL_STBY; sensor->ops->ctrl_data &= status; pwrm1 &= ~MPU6500_PWRM1_SLEEP; mpu6500_set_rate(client, rate); } 。。。。 }
传入的enable参数要为1的时候,6500设置的寄存器的功能才有效。正常开机完成的时候,ioctl对底层会设置1。这也是为什么开机初阶段为什么命明设置了0x37的寄存器,
但是要等开机才有0x0c地址出来的原因。
于是要想办法不等开机起来,直接在开机初始化的时候就设置enble为1即可解决该问题。
在sensor_init里面,刚好有对sensor_active的设置:
diff --git a/drivers/input/sensors/accel/mpu6500_acc.c b/drivers/input/sensors/accel/mpu6500_acc.c index 6fc2058e0f9f..8dea829f49cc 100644 --- a/drivers/input/sensors/accel/mpu6500_acc.c +++ b/drivers/input/sensors/accel/mpu6500_acc.c @@ -175,7 +175,12 @@ static int sensor_init(struct i2c_client *client) }- res = sensor->ops->active(client, 0, sensor->pdata->poll_delay_ms); + res = sensor->ops->active(client, 1, sensor->pdata->poll_delay_ms); if (res) { dev_err(&client->dev, "%s:line=%d,error\n", __func__, __LINE__);
4.apk测试
9轴对应的数据都有了。