#申请原创#
使用MPU系列陀螺仪有很长时间了,偶尔也遇到过DMP初始化失败的情况,折腾了一段时间无果后来就莫名其妙的好了,就没再仔细研究过了。
最近又查了一下资料,大概原因有很多,主要是软件和硬件方面的。
硬件方面:有人是原理图画错(这个仔细对一下上面官方参考原理图就不会有问题,1和11脚的时钟输入和同步一般不用,即接地,9脚AD0用于设置IIC地址,也一般接地,地址:0x68,接VDD就是0x69),有人是电容焊接的参数不对(Pin10接的C1稳压滤波电容是104,即100nF、0.1uF。Pin20接的C3电荷泵电容是222,即2.2nF,需要50V耐压。Pin13接的C2电源旁路电容也是104,100nF。Pin8接的逻辑电源旁路电容为103,即10nF),有人是杜邦线质量过于垃圾(高质量的杜邦线长一点也没关系),一般情况下没有太大静电和十几分钟三四百度热风枪吹基本上陀螺仪不会损坏。还有可能是残次品或者拆机货等等质量问题的。最后有条件的话IIC接口尽量加上拉电阻,经典值:4.7K。
软件方面:如果你上述的问题都确定没有,那么基本上就是软件的问题了。相信大多数小伙伴都是用的非硬件IIC,好处是随意扯线就能连接使用,主要还是ST等的单片机不跟Nordic、Dialog、TI、CSR的芯片一样支持任意映射IO。
解决软件问题的第一步是检测通信是不是正常,主要方法是通过示波器查看IIC的电平和时序。一般规规矩矩的方波就是时钟线SCL,不规则的就是数据线SDA,这个没问题的话就不是通信问题了。通信问题的话主要是电平可能拉不高比如在1.5V左右。这时候可能就会通信失败,比如像这样。
对于电平拉不高的情况主要是由于控制器没有释放SDA线或者是总线负载过大等等,没有释放SDA线的话,就把数据或指令传送完后输出高电平,一般是开漏输出靠外部的上拉电阻来拉高电平。UP之前测试HDMI屏幕触摸就是数据线没有释放导致的屏幕ID读取不到。如果不是这个问题,比如单独IIC器件都可以使用,但是板子上一堆IIC放一起不能都不能通信了,那么这时候就是总线负载过大,如果仅依赖单片机IO内部的上拉电阻显然是不够的,所以还是那句话,尽量都加上拉电阻。另外,多器件挂载一起IIC通信速度就不能太高,按需进行通信降频。UP之前测试的全面屏开发板挂载的AT24C02、MPU9250、AHT10、AP3216C、WM8978就不得不降频才保证都能通信成功。全面屏开发板IIC总线
接着扯回陀螺仪,基本上你能保证硬件和通信都没问题的话,剩下的陀螺仪配置和原始数据读取基本上都是水到渠成。但是,可能你用DMP的时候还是会出问题。
首先DMP的初始化相当耗堆栈,因此如果你的工程加了DMP随便就死机、白屏、不运行、无法调试等等,排除你自己的代码问题,基本上就是堆栈设置小了。UP之前调ICM20608就遇到过上述情况。
当你确保自己堆栈也足够的时候,那么这时候就可能是你自己的程序干扰了IIC的运行,例如耗时处理的中断等等。因此一定程度上模拟IIC抗干扰程度相对较低。所以在保持运行稳定的情况下尽量加快IIC的速度。另外,防止IIC通信的重入、禁止不可预测的前后台的IIC通信串扰,也就是做好通信管理机制。
DMP使用FIFO,有可能就尽快读取FIFO数据即可。不然也会可能由于FIFO过载卡住,那时候你的delay(100)就可能和delay(2000)一个效果,半天出来一个姿态角。并不是你的系统时钟出问题了。
DMP初始化失败除了加载DMP库可能是通信或者堆栈导致加载失败外,最多的就是自检失败了。调用顺序是run_self_test→mpu_run_self_test→accel_self_test,在accel_self_test中会将自检时读取的加速度数据经过计算和绝对值取值操作和test.max_accel_var进行比较。默认设置的值是0.14,也就是14%的差值,总之放好不要有明显抖动即可,实际上不需要水平放置也通过自检。另外自检时会将当前姿态全部设置为0,即初始状态,不然的话你可能需要一个偏移量才能得到真实的姿态角。
const struct test_s test = {
.gyro_sens = 32768/250,
.accel_sens = 32768/16,
.reg_rate_div = 0, /* 1kHz. */
.reg_lpf = 1, /* 188Hz. */
.reg_gyro_fsr = 0, /* 250dps. */
.reg_accel_fsr = 0x18, /* 16g. */
.wait_ms = 50,
.packet_thresh = 5, /* 5% */
.min_dps = 10.f,
.max_dps = 105.f,
.max_gyro_var = 0.14f,
.min_g = 0.3f,
.max_g = 0.95f,
.max_accel_var = 0.14f
};
因此结合上述的情况,最好是开启各种中断前完成初始化,及时读取FIFO,管理好通信机制。实测配置的100HzDMP输出,实际读取约有60Hz,所以你想快速解算还是尽量不用DMP。后续会更具体的做出测试对比。
最后,有些器件的重新初始化不断电可能会不生效,因此最好每次测试都重新断电重新上电测试。
BUT,这些小妙招对UP遇到的MPU问题都不生效。最终找到问题是由于原版DMP源码中的inv_mpu_dmp_motion_driver和inv_mpu源文件都定义了MAX_PACKET_LENGTH这个宏,并且大小是不一样的,一个12,一个32。而get_st_biases函数也就是自检函数又使用了这个宏,因此读取的数据长度和计算处理都不对,32值只用了一次,dmp_read_fifo函数中调用的fifo_data缓存。所以这里UP直接写的32。
实际上原版的DMP库并没有问题,但是有不足之处。比如只能驱动一个陀螺仪,而UP改造后的DMP支持多路陀螺仪驱动且整合了程序后只有一个源文件和头文件,这样将非常方便我们控制关节装置例如机械臂。
|