参阅的datasheet是LSM9DS1.pdf文档,来自模块供应商。
硬件连接方面和i2c地址确认
i2c地址:通过设置SDO_AG和SDO_M的高低电平来设置accel/gryo和mag I2C地址
SDO_AG脚:为加速计和陀螺仪的设备地址(SA0)的最小有效位,拉低时i2c地址为0x6a;拉高时i2c地址为0x6b(当前状态为;置高,所以i2c地址是6b)。
SDO_M脚:i2c磁强计的设备地址(SA0)的最小有效位,拉低时i2c地址为0x1c;拉高时i2c地址为0x1e。
CS_A/G脚:拉高时,gsensor和陀螺仪进入i2c模式;拉低时,gsensor和陀螺仪进入spi模式;
CS_M脚:拉高时,进入i2c模式,拉低时,进入spi模式;
DRDY_M脚:磁传感器数据准备好;
INT_M脚:磁传感器中断脚
硬件相关GPIO和总线连接说明:
I2C总线连接的是i2c3;
DEN-A/G:加速计和陀螺仪数据启用,目前硬件连接的是GPIO1_C6;//拉高表示启用
INT1_A/G:加速度计和陀螺仪中断1,目前硬件连接的是GPIO1_C2;
INT2_A/G:加速度计和陀螺仪中断1,目前硬件连接的是GPIO1_B5;
I2C总线连接的是i2c3;
INT_M:磁传感器中断,目前硬件连接的是GPIO1_B1;
DRDY_M:磁传感器数据准备好,目前硬件连接的是GPIO1_B2;
软件驱动方面资料:
参考以下代码资料:
SparkFunLSM9DS1.cpp
LSM9DS1_Registers.h
读取sensor设备ID值方面:
gsensor/陀螺仪:读取7.11 WHO_AM_I (0Fh)寄存器的值,也就是读取0x0f寄存器的值,根据文档LSM9DS1.pdf应该读到0x68才是对的id值
地磁: 读取8.4 WHO_AM_I_M (0Fh)寄存器的值,也就是读取0x0f寄存器的值,根据文档LSM9DS1.pdf应该读到0x3d才是对的id值
磁、加速度计、陀螺仪传感可分别在断电模式下开启或设置,实现智能电源管理
A/G【加速度器和陀螺仪】工作模式
在LSM9DS1中,加速度计和陀螺仪有两种可用的工作模式:只有加速度计处于工作状态而陀螺仪处于下电状态,或者加速度计和陀螺仪传感器在相同的ODR下处于工作状态。
从一种模式切换到另一种模式需要一个写入操作:写入到CTRL_REG6_XL (20h),加速度计在正常模式下工作,陀螺仪断电; 写入到CTRL_REG1_G (10h),加速度计和陀螺仪在相同的ODR下激活。
3.3 Accelerometer and gyroscope multiple reads (burst)【文档LSM9DS1.pdf中的第21页有介绍】
当只有加速度计被激活,陀螺仪处于断电状态时,从OUT_X_XL (28h - 29h)开始可以执行多次读取。读取OUT_Z_XL (2Ch - 2Dh)后,系统自动从OUT_X_XL (28h - 29h)重新启动。
当加速度计和陀螺仪传感器在相同的ODR下被激活时,从OUT_X_G (18h - 19h)开始可以执行多次读取。读取OUT_Z_XL (2Ch - 2Dh)后,系统自动从OUT_X_G (18h - 19h)重新启动。
i2c接口使用快速模式(400khz) i2c标准和标准模式实现
从文档LSM9DS1.pdf中查找:
陀螺仪控制寄存器:
CTRL_REG1_G:0x10 //参考文档LSM9DS1.pdf中设置为0x40
CTRL_REG2_G: 0x11 //参考文档LSM9DS1.pdf中设置为0x0f
CTRL_REG3_G: 0x12 //参考文档LSM9DS1.pdf中设置为0x00
ORIENT_CFG_G: 0x13 //参考文档LSM9DS1.pdf中设置为0x38
陀螺仪数据寄存器:
7.19 OUT_X_G (18h - 19h)角速率传感器俯仰轴(X)角速率输出寄存器。该值表示为两个s补码中的16位字节。
7.20 OUT_Y_G (1Ah - 1Bh)角速率传感器滚轴(Y)角速率输出寄存器。该值表示为两个s补码中的16位字节。
7.21 OUT_Z_G (1Ch - 1Dh)角速率传感器偏航轴(Z)角速率输出寄存器。该值表示为两个s补码中的16位字节。
重力加速度计控制寄存器:
初始化控制寄存器方面的寄存器地址:
7.22 CTRL_REG4 (1Eh) //线性加速度传感器控制寄存器4, 参考文档LSM9DS1.pdf中设置为0x38
7.23 CTRL_REG5_XL (1Fh) //线性加速度传感器控制寄存器5, 参考文档LSM9DS1.pdf中设置为0x78
7.24 CTRL_REG6_XL (20h) //ODR_XL[2:0]用于设置电源模式和ODR选择,000为下电。表68显示了仅激活加速计时可用的所有频率,设置0x40表示激活sensor,ODR选择(赫兹)为50hz,其他可对照文档LSM9DS1.pdf
7.25 CTRL_REG7_XL (21h) //线性加速度传感器控制寄存器7, 参考文档LSM9DS1.pdf中设置为0x00
重力加速度数据寄存器:
7.31 OUT_X_XL (28h - 29h)线性加速度传感器x轴输出寄存器。该值表示为两个s补码中的16位字节。
7.32 OUT_y_Xl (2Ah - 2Bh)线性加速度传感器y轴输出寄存器。该值表示为两个s补码中的16位字节。
7.33 OUT_Z_XL (2Ch - 2Dh)线性加速度传感器z轴输出寄存器。该值表示为两个s补码中的16位字节。
即
0x28
0x29
0x2a
0x2b
0x2c
0x2d
M【磁传感器】工作模式设置
磁性传感器有三种工作模式:断电模式(默认),连续转换模式和单次转换模式。从电源关闭模式切换到其他模式需要对 CTRL_REG3_M (22h)执行一次写操作,在
MD(1:0)位。对于由温度补偿的磁性数据的输出,则CTRL_REG1_M (20h)中的TEMP_COMP位必须设置为 ‘1’。
也就是如果要设置磁感器的工作模式,可以通过设置CTRL_REG3_M (22h)的值的MD(1:0)位,具体说明如下:
MD[1:0] :Operating mode selection. Default value: 11 //默认状态是11,也就是下电模式,要设置成00,才能一直更新转化sensor数据寄存器数据,也就是往0x22写入寄存器值设置磁感器的工作模式,这里写入0x00设置为连续工作模式。
MD1 MD0 Mode
0 0 Continuous-conversion mode
0 1 Single-conversion mode
1 0 Power-down mode
1 1 Power-down mode
参考LSM9DS1.pdf文档:Table 22. Magnetic sensor register address map —> 这里是磁传感器寄存器的说明
磁传感器 id:WHO_AM_I_M: 寄存器地址值:0x0f; 寄存器值:0x3d
磁控制寄存器【初始化值设置】:
CTRL_REG1_M 【0x20】,初始化设置值0x10
CTRL_REG2_M 【0x21】,初始化设置值0x00
CTRL_REG3_M 【0x22】,初始化设置值0x03
CTRL_REG4_M 【0x23】,初始化设置值0x00
CTRL_REG5_M 【0x24】,初始化设置值0x00
磁数据寄存器:
8.11 OUT_X_L_M (28h), OUT_X_H_M(29h) 磁强计x轴数据输出。磁场的值表示为2的补数。
8.12 OUT_Y_L_M (2Ah), OUT_Y_H_M(2Bh) 磁力仪y轴数据输出。磁场的值表示为2的补数。
8.13 OUT_Z_L_M (2Ch), OUT_Z_H_M(2Dh) 磁强计z轴数据输出。磁场的值表示为2的补数。
调试问题点:
1、如果需要调试sensor进入的工作模式,可以相应的设置对应控制寄存器的值即可,具体可参考LSM9DS1.pdf文档。
2、加速度计的选择(±2;±4;±16)等,带宽的选择,校准等;
3、陀螺仪全面的选择,带宽的选择,校准等;
驱动创建了节点:
重力加速度:
陀螺仪:
rk3399_all:/ #
rk3399_all:/ # cat sys/class/sensor_class/gyro_lsm9ds1 //未打开sensor读取数据
gyro: read error with SENSOR_OFF
rk3399_all:/ # echo 1 > sys/class/sensor_class/gyro_lsm9ds1 //打开sensor读取数据
rk3399_all:/ # cat sys/class/sensor_class/gyro_lsm9ds1 //读取对应节点数据
[gyro-x-]: 63
磁感器:
rk3399_all:/ # cat sys/class/sensor_class/compass_lsm9ds1
compass: read error with SENSOR_OFF
rk3399_all:/ #
rk3399_all:/ #
rk3399_all:/ # echo 1 > sys/class/sensor_class/compass_lsm9ds1
rk3399_all:/ # cat sys/class/sensor_class/compass_lsm9ds1
[compass-x-]: -779
HAL层代码跟踪(主要的操作代码在以下目录):
MmaSensor.cpp //gsensor
GyroSensor.cpp //gyro
AkmSensor.cpp //compass
==>init_nusensors
poll__activate ==>
调用int MmaSensor::enable,然后调用ioctl(dev_fd, GSENSOR_IOCTL_START)打开gsensor,然后调用 MmaSensor::readEvents来读取gsensor数据
apk打开gsensor:
03-23 21:05:38.444 2594 3359 I SensorsHal: set batch: handle = 0, period_ns = 20000000ns, timeout = 0ns
03-23 21:05:38.444 2594 3359 E SensorsHal: -czd-: int poll__batch(struct sensors_poll_device_1 *, int, int, int64_t, int64_t) line[355]
03-23 21:05:38.444 2594 3359 I SensorsHal: MmaSensor update delay: 20ms
03-23 21:05:38.444 2594 3359 E SensorsHal: -czd-: MmaSensor update delay: 20ms
03-23 21:05:38.444 2594 3359 D SensorsHal: update gsensor delay to 20 ms
03-23 21:05:38.444 2594 3359 I SensorsHal: set active: handle = 0, enable = 1
03-23 21:05:38.444 2594 3359 E SensorsHal: -czd-: MmaSensor virtual int MmaSensor::enable(int32_t, int), -line[73]-, enable
03-23 21:05:38.445 2594 3359 E SensorsHal: -czd-: MmaSensor virtual int MmaSensor::enable(int32_t, int), -line[87]-, newState->1
03-23 21:05:38.473 2594 2760 E SensorsHal: -czd-: MmaSensor virtual int MmaSensor::readEvents(sensors_event_t *, int), -line[143]-, type -> 3
apk打开gyro:
03-23 21:05:20.354 2594 2607 I SensorsHal: set batch: handle = 5, period_ns = 200000000ns, timeout = 0ns
03-23 21:05:20.354 2594 2607 E SensorsHal: -czd-: int poll__batch(struct sensors_poll_device_1 *, int, int, int64_t, int64_t) line[355]
03-23 21:05:20.354 2594 2607 D SensorsHal: Couldn’t open /dev/gyrosensor (No such file or directory)
03-23 21:05:20.354 2594 2607 I SensorsHal: Gyrosensor update delay: 200ms
03-23 21:05:20.354 2594 2607 E SensorsHal: -czd-: GyroSensor virtual int GyroSensor::setDelay(int32_t, int64_t) [102], 200ms
03-23 21:05:20.354 2594 2607 E SensorsHal: fail to perform L3G4200D_IOCTL_SET_DELAY, result = -1, error is ‘Bad file descriptor’
apk打开compass:
03-23 21:08:51.548 2594 3359 I ActivityManager: START u0 {cmp=com.rz.android.sensor.box/.MagneticField} from uid 10050 on display 0
03-23 21:08:51.589 2594 3359 I SensorsHal: set batch: handle = 1, period_ns = 200000000ns, timeout = 0ns
03-23 21:08:51.590 2594 3359 E SensorsHal: -czd-: int poll__batch(struct sensors_poll_device_1 *, int, int, int64_t, int64_t) line[355]
03-23 21:08:51.590 2594 3359 I SensorsHal: set active: handle = 1, enable = 1
问题点总结:
1、首先确保硬件上电,i2c正常(sdl和sda空闲状态上拉拉高);
2、没有读取到id或者读取到id值不对,注意你去读取的id寄存器是否设置对了,对照datasheet排查?
3、如果出现getevent无数据上报,有可能是sensor的使能没有打开,没有active,可以看下active函数是否有被执行,加log确认;
4、上层apk读取到的数值太小,几乎没什么变化,可以确认下hal下的sensor计算参数是否有问题,我这里sensor的时候试过gsensor的参数变化不明显,后面查看代码发现是
ACCELERATION_RATIO_ANDROID_TO_HW这个宏定义的参数搞的鬼,原来是(9.80665f / 1000000),改成(9.80665f / 16384)之后就正常了。
5、针对陀螺仪和gsensor共用一个驱动的情形(例如我这里是只有gsensor driver,而gyro是寄生在gsensor driver的,并且在ic中他们实际上是共用一个i2c地址的情形),
驱动部分需要单独注册一个输入子设备来上报gyro的数据,跟gsensor的输入设备分开,数据也是单独处理;
hal层部分需要做一些手脚骗过hal层框架,比如open_device打开操作设备和close_device关闭设备的时候要去open/close gsensor的dev节点,
ioctl的时候也要改成跟gsensor部分的一致,然后其他的设置直接返回执行成功的返回值即可。