原本是想要自己的模拟I2C库,来组合时选块,对接上DMP所需接口,可是一直卡在初始化,后面改成STM32F4的硬件I2C,也是很便捷的对接上接口了。此外在也参考了网上的移植资料与记录。本文也作为学习笔记,记录下过程。
使用到的:STM32F407VGT6+STM32CubeMX+MotionDriver6.1。末尾链接提供工程文件和DMP相关文件。
移植流程
简单概述流程
- 将DMP相关文件复制到项目文件下
- 在
inv_mpu.h
文件中定义两个宏定义 - 在两个文件,定义配置宏接口
- 根据需求,看是否需要替换器件默认的I2C地址
- 编译后,有两处报错,双击跳转报错行,通过注释或者更改替代即可。
- 导入DMP初始化库,
#include "MPU6050_DMP.h"
。
详细概述流程
-
将下述6个文件复制到项目文件下。库文件末尾链接会提供,或者去官网。(简略描述官网下载流程:打开Home | TDK InvenSense,注册账号,选择左上方选项卡”Developers -> Software Downloads -> SmartMotion®“点击跳转后,可页面搜索”MPU“或者下滑就可看到MPU选项卡,就可以看到
eMD 6.12
下载链接) -
在
inv_mpu.h
文件中定义两个宏定义。宏STM32_MPU6050
用于后续构建对接I2C的配置,宏MPU6050
用于选择器件。#define STM32_MPU6050 #define MPU6050
-
在
inv_mpu_dmp_motion_driver.c
和inv_mpu.c
基于宏配置。因为上述定义了STM32_MPU6050
所以可以看到下述是基于该宏下编写。其实要要是不定义新配置宏,在默认的旧宏如MSP430...
上做删改也行,不过麻烦些许。inv_mpu_dmp_motion_driver.c文件下
// 引入新的配置 #elif defined STM32_MPU6050 #include "stm32f4xx_hal.h" #include "MyI2C.h" #define delayC_ms HAL_Delay #define get_ms get_ms_null #define log_i(...) do {} while (0) #define log_e(...) do {} while (0)
inv_mpu.c文件下
// 引入新的配置 #elif defined STM32_MPU6050 #include "stm32f4xx_hal.h" #include "MyI2C.h" #define i2c_write MyI2C_SeriesSendByte #define i2c_read MyI2C_SeriesReceiveByte #define delay_ms HAL_Delay #define get_ms get_ms_null #define log_i(...) do {} while (0) #define log_e(...) do {} while (0) #define fabs fabsf #define min(a,b) ((a<b)?a:b)
必需要修改的宏函数有4个,
i2c_write
,i2c_read
,delay_ms
,get_ms
。其中除了delay_ms可以用HAL_Delay函数,直接代替外,另外三个函数都在MyI2C.h库,基于原型做转换了,然后因为get_ms暂时无光紧要,就暂时先实现空函数,下面是该库的部分代码:uint8_t MyI2C_SeriesSendByte(unsigned char slave_addr, unsigned char reg_addr,unsigned char length, unsigned char const *data) {HAL_I2C_Mem_Write(&hi2c1, slave_addr, reg_addr, I2C_MEMADD_SIZE_8BIT, (uint8_t *)data, length,100);return 0; } uint8_t MyI2C_SeriesReceiveByte(unsigned char slave_addr, unsigned char reg_addr,unsigned char length, unsigned char *data) {HAL_I2C_Mem_Read(&hi2c1,slave_addr,reg_addr,I2C_MEMADD_SIZE_8BIT, data,length, 100);return 0; } void get_ms_null(unsigned long *count) { }
-
根据需求,看是否需要替换器件默认的I2C地址
根据I2C时序函数,看I2C器件地址是要7位,还是8位,因为我使用的是HAL提供的硬件I2C函数,且在函数输入时没有,左移1位,所以要替换器件的7位地址为8位(位移后的)。在inv_mpu.c文件下可以找到,将
0x68
修改为0xD0
,有两个地方存在该定义,不清楚哪个被宏包含顶的,可以两个都修改:const struct hw_s hw = {.addr = 0xD0, ......
-
编译后,有两处报错,双击跳转报错行,通过注释或者更改替代即可。
// __no_operation();__NOP;
// if (int_param) // reg_int_cb(int_param);
-
导入DMP初始化库,
#include "MPU6050_DMP.h"
。这个忘记是参考哪里的了,所以库代码就不放出来了,介绍存在的函数。
int MPU6050_DMP_init(void); int MPU6050_DMP_Get_Date(float *pitch, float *roll, float *yaw);
主函数
下述是在main.c文件中,使用演示的关键代码块,非全部列出,已经省略无关的代码,请按作用添加到主函数中。
float x = 0;
float y = 0;
float z = 0;
int ret = 0;
// 初始化
do
{ret = MPU6050_DMP_init();printf("MPU6050 init, ret = %d\r\n", ret);HAL_Delay(100);
} while(ret);
// 获取数据
while (1)
{//MPU6050_DMP_Get_Date(&x,&y,&z);while(MPU6050_DMP_Get_Date(&x,&y,&z)!=0){}printf("%.2f,%.2f,%.2f\r\n",x,y,z);
}
以及工程演示图:
可以看到,初始化还是需要手动将模块放置水平,放平后自检才算完成后,整个初始化完成。
常见问题
下述问题来自自身遇见,和总结网上的解决办法。
-
编译报错
Gyro driver is missing the system layer implementations.
没有按流程定义好相关和定义配置宏,导致在编译时找不到任何1个符合的配置,就通过
#else
跳转#error
输出错误消息。 -
调用
MPU6050_DMP_init
初始化的时候,一直返回-1
。这里我遇到的是对接的时序接口
i2c_write
,i2c_read
可能时序哪里不够严谨,导致的初始化返回失败。还有1种情况就是,器件地址问题,这得看接入的I2C的读写函数是否会左移1位也就是addr << 1
,如果会,按照在DMP中默认预定义是7位地址0x68
,是没问题的,如果不会则要修改成0xD0
也就是预先位移了。 -
调用
MPU6050_DMP_init
初始化的时候,一直返回-9
。错误代码是表示自检失败,要将模块放置水平。不过,默认的水平比较苛刻,所以可以通过注释部分自检相关的代码了,放宽模块水平的条件。
inv_mpu.c文件,大概2747~2754行左右。
//#ifdef AK89xx_SECONDARY // compass_result = compass_self_test(); // if (!compass_result) // result |= 0x04; //#else // result |= 0x04; //#endif
-
获取到的数据溢出,可能是fifo溢出了,改成下述,加快获取。
//MPU6050_DMP_Get_Date(&x,&y,&z); while(MPU6050_DMP_Get_Date(&x,&y,&z)!=0){}
资料链接
CupCondition.zip为项目文件,可以在CupCondition\MDK-ARM\Library
下提取到上文所有库。
MotionDriver_6_1.zip为DMP的六个核心文件,也是上文提到的要复制到项目中的。
motion_driver_6.12.zip是官网下载的整体包,里面存在较多东西。
链接:https://pan.baidu.com/s/1zybNDBb3zCNYr2XTj1Wzfw 提取码:j95w