搜索
bottom↓
回复: 8

求助!MPU9250 SPI 读取磁力计数据疑惑

[复制链接]
(32098684)

出0入0汤圆

发表于 2020-4-5 20:27:48 | 显示全部楼层 |阅读模式
目前使用STM32G431作主控,MPU9250的SPI驱动程序是参考坛友的(没有了搜索功能,找不到原贴了),目前就差磁力计的读取有问题。
程序用MPU9250内部的IIC slv0来读取磁力计数据到MPU6500_EXT_SENS_DATA_xx寄存器,然后实现和加速度计和陀螺仪一样,直接使用SPI读取MPU6500_EXT_SENS_DATA_xx寄存器就得到了9轴原始数据,现在读到的陀螺仪和加速度计数据都没问题,但是磁力计数据只有在上电时读取了一次,然后值就一直不变了。
至此还有个疑问,当磁力计数据更新时,是如何通知MPU9250内部的IIC slv0去读取数据的?
程序如下:
uint8 SPI_RW(uint8 TxData);
uint8 MPU9250_ReadReg( uint8 ReadAddr);
void MPU9250_WriteReg( uint8 WriteAddr, uint8 WriteData );
void MPU9250_ReadRegs( uint8 ReadAddr, uint8 *ReadBuf, uint8 Bytes );
void MPU9250_MAG_I2C_Write(uint8 reg,uint8 value);
uint8 MPU9250_MAG_I2C_Read(uint8 reg);
void READ_MPU9250_MAG(uint32 *Mag);
void Init_MPU9250();

void Init_MPU9250(void)
{
        IMU_DISABLE();
        LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_7);//必须禁止MS5611,否则同时与两个传感器通讯
       
        MPU9250_WriteReg(MPU6500_PWR_MGMT_1, 0x80); //解除休眠状态
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_PWR_MGMT_1, 0x01); //时钟选择
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_USER_CTRL ,0x30); //I2C_MST _EN , I2C_IF_DIS
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_PWR_MGMT_2 ,0x00);//Enable Acc & Gyro
        WaitSysTimeBlock(1,UINT_MS);
       
        //陀螺仪采样率和量程
        MPU9250_WriteReg(MPU6500_CONFIG ,0x07); // DLPF_CFG[2:0] = 111;
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_GYRO_CONFIG ,0x18); // +-2000dps
        WaitSysTimeBlock(1,UINT_MS);
       
        //加速度计采样率和量程
        MPU9250_WriteReg(MPU6500_ACCEL_CONFIG ,0x08); // +-4G
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_ACCEL_CONFIG_2 ,0x48); // Set Acc Data Rates
        WaitSysTimeBlock(1,UINT_MS);
        //如果读操作完成,则清除中断状态
        MPU9250_WriteReg(MPU6500_INT_PIN_CFG ,0x10); // Set INT_ANYRD_2CLEAR
        WaitSysTimeBlock(10,UINT_MS);
       
        //使能 fifo 溢出中断
        MPU9250_WriteReg(MPU6500_INT_ENABLE ,0x10);
        WaitSysTimeBlock(1,UINT_MS);
       
        //选择Master iic时钟,4:iic延时,D:400KHZ,分频后的iic时钟频率
        MPU9250_WriteReg(MPU6500_I2C_MST_CTRL ,0x4D);
        WaitSysTimeBlock(10,UINT_MS);


        MPU9250_MAG_I2C_Write(AK8963_CNTL2,0x01); // Reset AK8963
        WaitSysTimeBlock(10,UINT_MS);
        //bit4:0输出14位,1输出16位,bit0~3:模式选择,0x06:连续测量模式2
        //MPU9250_MAG_I2C_Write(AK8963_CNTL1,0x06); // use i2c to set AK8963 working on Continuous measurement mode1 & 16-bit output
        MPU9250_MAG_I2C_Write(AK8963_CNTL1,0x16); // use i2c to set AK8963 working on Continuous measurement mode1 & 16-bit output
        WaitSysTimeBlock(10,UINT_MS);

        //IIC Master 要去读的从机寄存器起始地址
        MPU9250_WriteReg(MPU6500_I2C_SLV0_REG, AK8963_HXL);
        WaitSysTimeBlock(100,UINT_MS);
        //IIC Master 要去读的实际从机地址
        MPU9250_WriteReg(MPU6500_I2C_SLV0_ADDR, AK8963_I2C_ADDR | 0x80);
        WaitSysTimeBlock(100,UINT_MS);
       
        //IIC Master 要去读的从机寄存器个数(由起始地址按顺序读)
        //bit7:Enable slv0,bit0~3:读取的数据长度
        MPU9250_WriteReg(MPU6500_I2C_SLV0_CTRL, 0x80 | 6);
        WaitSysTimeBlock(100,UINT_MS);
}

uint8 SPI_RW(uint8 TxData)
{  
        uint8 temp=0;

        while(!LL_SPI_IsActiveFlag_TXE(SPIx))
        {
                //当发送寄存器非空时,一直循环       
        }
       
        LL_SPI_TransmitData8(SPIx,TxData);
        while(!LL_SPI_IsActiveFlag_RXNE(SPIx))
        {
                //当接收FIFO小于1/4*32时,一直循环
        }

        return LL_SPI_ReceiveData8(SPIx);//读取一个8位数据
}

uint8 MPU9250_ReadReg( uint8 ReadAddr)
{
        uint8 readResult;
        IMU_ENABLE();
        SPI_RW(0x80 | ReadAddr);
        readResult = SPI_RW(0xFF);
        IMU_DISABLE();
        return readResult;
}

void MPU9250_WriteReg( uint8 WriteAddr, uint8 WriteData )
{
        IMU_ENABLE();
        SPI_RW(WriteAddr);
        SPI_RW(WriteData);
        IMU_DISABLE();
}

void MPU9250_ReadRegs( uint8 ReadAddr, uint8 *ReadBuf, uint8 Bytes )
{
        uint8 i = 0;

        IMU_ENABLE();
        SPI_RW(0x80 | ReadAddr);
        for(i=0; i<Bytes; i++)
        {
                ReadBuf[i] = SPI_RW(0xFF);
        }
        IMU_DISABLE();
}

void MPU9250_MAG_I2C_Write(uint8 WriteAddr,uint8 WriteData)
{
        uint8_t timeout = 0;
        uint8_t status = 0;

        MPU9250_WriteReg(MPU6500_I2C_SLV4_REG, WriteAddr);
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_I2C_SLV4_ADDR, AK8963_I2C_ADDR);
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_I2C_SLV4_DO, WriteData);
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_I2C_SLV4_CTRL, 0x80);
        WaitSysTimeBlock(1,UINT_MS);

        do {
                status=MPU9250_ReadReg(MPU6500_I2C_MST_STATUS);
                //timeout++;
        } while(((status & 0x40) == 0));
        //WaitSysTimeBlock(1,UINT_MS);
}

uint8 MPU9250_MAG_I2C_Read(uint8 reg)
{
        uint8 readResult;
        uint8 status = 0;
        uint8 timeout = 0;
       
        MPU9250_WriteReg(MPU6500_I2C_SLV4_REG ,reg);// set reg addr
        WaitSysTimeBlock(10,UINT_MS);
        MPU9250_WriteReg(MPU6500_I2C_SLV4_ADDR ,AK8963_I2C_ADDR|0x80); //设置磁力计地址,mode:read
        WaitSysTimeBlock(10,UINT_MS);
        MPU9250_WriteReg(MPU6500_I2C_SLV4_CTRL, 0x80);
        WaitSysTimeBlock(10,UINT_MS);
       
        do {
                //WaitSysTimeBlock(1,UINT_MS);
                status=MPU9250_ReadReg(MPU6500_I2C_MST_STATUS);
                //timeout++;
               
        } while(((status & 0x40) == 0));
        //WaitSysTimeBlock(1,UINT_MS);
        readResult=MPU9250_ReadReg(MPU6500_I2C_SLV4_DI);
        //WaitSysTimeBlock(0,UINT_MS);
        return readResult;
}

uint8 MPU9250_Check_MPU6500_ID( void )
{
        uint8 DeviceID;

        /* MPU6500 */
        DeviceID=MPU9250_ReadReg(MPU6500_WHO_AM_I);

        return DeviceID;
}

uint8 MPU9250_Check_AK8963_ID()
{
        uint8 DeviceID;

        DeviceID = 0x00;
        DeviceID=MPU9250_MAG_I2C_Read(AK8963_WIA);

        return DeviceID;
}

void MPU9250_Read( uint8 *ReadBuf )
{
       
        MPU9250_ReadRegs(MPU6500_ACCEL_XOUT_H, ReadBuf, 20);       
}

输出:
[20:11:01.443]收←◆ax:-3968,ay:1588,az:6324,temperature:784,gx:44,gy:-109,gz:-47,mx:228,my:560,mz:-342
[20:11:01.643]收←◆ax:-3960,ay:1572,az:6392,temperature:800,gx:68,gy:-157,gz:9,mx:228,my:560,mz:-342
[20:11:01.842]收←◆ax:-3988,ay:1632,az:6324,temperature:832,gx:49,gy:-97,gz:17,mx:228,my:560,mz:-342
[20:11:02.043]收←◆ax:-3948,ay:1608,az:6408,temperature:800,gx:37,gy:-32,gz:-9,mx:228,my:560,mz:-342
[20:11:02.243]收←◆ax:-3920,ay:1644,az:6392,temperature:848,gx:57,gy:-140,gz:-24,mx:228,my:560,mz:-342
[20:11:02.442]收←◆ax:-3984,ay:1584,az:6448,temperature:800,gx:32,gy:-179,gz:-35,mx:228,my:560,mz:-342
[20:11:02.642]收←◆ax:-3924,ay:1636,az:6400,temperature:800,gx:38,gy:-25,gz:-42,mx:228,my:560,mz:-342
[20:11:02.842]收←◆ax:-4012,ay:1592,az:6356,temperature:880,gx:51,gy:-88,gz:-13,mx:228,my:560,mz:-342
[20:11:03.043]收←◆ax:-3912,ay:1596,az:6316,temperature:832,gx:66,gy:-130,gz:-30,mx:228,my:560,mz:-342
[20:11:03.242]收←◆ax:-3968,ay:1580,az:6384,temperature:800,gx:44,gy:-156,gz:12,mx:228,my:560,mz:-342
(32043408)

出0入0汤圆

 楼主| 发表于 2020-4-6 11:49:04 | 显示全部楼层
经过昨晚通宵,把官方两篇文档完完整整读了3遍,今早终于找到原因了:
(32043287)

出0入0汤圆

 楼主| 发表于 2020-4-6 11:51:05 | 显示全部楼层
        通过正常SPI控制内部IIC方式读取磁力计的内部寄存器,发现有一个寄存器存在异常,
        mpu9250MagBuffer[3]=MPU9250_MAG_I2C_Read(AK8963_ST1);
        它的值在一开始上电时为0x03,之后就一直0x02。
        bit0:0代表正常,1代表数据准备完毕。
        bit1:0代表正常,1代表数据溢出。
        就是说在采样一次后数据溢出位一直没被清除,从而磁力计不再采样,看了一下清除改位方法:
        DOR bit turns to “1” when data has been skipped in continuous measurement mode or external trigger measurement mode. It returns to “0” when any one of ST2 register or measurement data register(HXL~HZH) is read.
        随后我加了一条语句每次都读一下AK8963_HXL寄存器,发现DOR位并没有清零,然后我再试着读AK8963_ST2(ST2),发现该位清空了,并且磁力计数据也正常更新了。然后我又试着把HXL~HZH读完,发现该位还是未能清除,所以,结果出来了,清空DOR位必须读ST2寄存器。
        所以当时设置了SLV0为什么不能把ST2的寄存器也读了呢,这是因为SLV0一次读取最大长度只有7(bit0~3)所以从AK8963_ST1寄存器开始读是刚好读不到ST2寄存器的,必须从AK8963_HXL读起。
        修改为从AK8963_HXL读,长度为7,此时,磁力计的连续读取终于成功了。


简单点说就是被官方手册坑了:It returns to “0” when any one of ST2 register or measurement data register(HXL~HZH) is read.,而实际只有读ST2才会清理ST1的DOR位
(32042243)

出0入0汤圆

 楼主| 发表于 2020-4-6 12:08:29 | 显示全部楼层
贴出完整代码,不必要延时已经注释,延时函数是SYSTick计时器中断计算的,比较准确,SPI的速度是21.25MBits/s
(32041998)

出0入0汤圆

 楼主| 发表于 2020-4-6 12:12:34 | 显示全部楼层
原贴参考:https://www.amobbs.com/thread-5627630-1-1.html

#ifndef _BBA_DRI_MPU9250_H__
#define _BBA_DRI_MPU9250_H__

#include "main.h"
#include "BBA_Typedef.h"
#include "BBA_Dri_Timer.h"

/*====================================================================================================*/
/*====================================================================================================*/
/*
|     |      ACCELEROMETER      |        GYROSCOPE        |
| LPF | BandW | Delay  | Sample | BandW | Delay  | Sample |
+-----+-------+--------+--------+-------+--------+--------+
|  0  | 260Hz |    0ms |  1kHz  | 256Hz | 0.98ms |  8kHz  |
|  1  | 184Hz |  2.0ms |  1kHz  | 188Hz |  1.9ms |  1kHz  |
|  2  |  94Hz |  3.0ms |  1kHz  |  98Hz |  2.8ms |  1kHz  |
|  3  |  44Hz |  4.9ms |  1kHz  |  42Hz |  4.8ms |  1kHz  |
|  4  |  21Hz |  8.5ms |  1kHz  |  20Hz |  8.3ms |  1kHz  |
|  5  |  10Hz | 13.8ms |  1kHz  |  10Hz | 13.4ms |  1kHz  |
|  6  |   5Hz | 19.0ms |  1kHz  |   5Hz | 18.6ms |  1kHz  |
|  7  | -- Reserved -- |  1kHz  | -- Reserved -- |  8kHz  |
*/
//typedef enum {
//  MPU_LPS_256Hz   = 0x00,
//  MPU_LPS_188Hz   = 0x01,
//  MPU_LPS_98Hz    = 0x02,
//  MPU_LPS_42Hz    = 0x03,
//  MPU_LPS_20Hz    = 0x04,
//  MPU_LPS_10Hz    = 0x05,
//  MPU_LPS_5Hz     = 0x06,
//  MPU_LPS_Disable = 0x07,
//} MPU_LPF_TypeDef;
//typedef enum {
//  MPU_GyrFS_250dps  = 0x00,
//  MPU_GyrFS_500dps  = 0x08,
//  MPU_GyrFS_1000dps = 0x10,
//  MPU_GyrFS_2000dps = 0x18
//} MPU_GyrFS_TypeDef;
//typedef enum {
//  MPU_AccFS_2g  = 0x00,
//  MPU_AccFS_4g  = 0x08,
//  MPU_AccFS_8g  = 0x10,
//  MPU_AccFS_16g = 0x18
//} MPU_AccFS_TypeDef;

//typedef struct {
//  MPU_LPF_TypeDef MPU_LowPassFilter;
//  MPU_GyrFS_TypeDef MPU_Gyr_FullScale;
//  MPU_AccFS_TypeDef MPU_Acc_FullScale;
//} MPU_InitTypeDef;

/* ---- Sensitivity --------------------------------------------------------- */

#define MPU9250A_2g       ((fp32)0.000061035156f) // 0.000061035156 g/LSB
#define MPU9250A_4g       ((fp32)0.000122070312f) // 0.000122070312 g/LSB
#define MPU9250A_8g       ((fp32)0.000244140625f) // 0.000244140625 g/LSB
#define MPU9250A_16g      ((fp32)0.000488281250f) // 0.000488281250 g/LSB

#define MPU9250G_250dps   ((fp32)0.007633587786f) // 0.007633587786 dps/LSB
#define MPU9250G_500dps   ((fp32)0.015267175572f) // 0.015267175572 dps/LSB
#define MPU9250G_1000dps  ((fp32)0.030487804878f) // 0.030487804878 dps/LSB
#define MPU9250G_2000dps  ((fp32)0.060975609756f) // 0.060975609756 dps/LSB

#define MPU9250M_4800uT   ((fp32)0.6f)            // 0.6 uT/LSB

#define MPU9250T_85degC   ((fp32)0.002995177763f) // 0.002995177763 degC/LSB

/* ---- MPU6500 Reg In MPU9250 ---------------------------------------------- */

#define MPU6500_I2C_ADDR            ((uint8)0xD0)
#define MPU6500_Device_ID           ((uint8)0x71)  //BBA_Check

#define MPU6500_SELF_TEST_XG        ((uint8)0x00)
#define MPU6500_SELF_TEST_YG        ((uint8)0x01)
#define MPU6500_SELF_TEST_ZG        ((uint8)0x02)
#define MPU6500_SELF_TEST_XA        ((uint8)0x0D)
#define MPU6500_SELF_TEST_YA        ((uint8)0x0E)
#define MPU6500_SELF_TEST_ZA        ((uint8)0x0F)
#define MPU6500_XG_OFFSET_H         ((uint8)0x13)
#define MPU6500_XG_OFFSET_L         ((uint8)0x14)
#define MPU6500_YG_OFFSET_H         ((uint8)0x15)
#define MPU6500_YG_OFFSET_L         ((uint8)0x16)
#define MPU6500_ZG_OFFSET_H         ((uint8)0x17)
#define MPU6500_ZG_OFFSET_L         ((uint8)0x18)
#define MPU6500_SMPLRT_DIV          ((uint8)0x19)
#define MPU6500_CONFIG              ((uint8)0x1A)
#define MPU6500_GYRO_CONFIG         ((uint8)0x1B)
#define MPU6500_ACCEL_CONFIG        ((uint8)0x1C)
#define MPU6500_ACCEL_CONFIG_2      ((uint8)0x1D)
#define MPU6500_LP_ACCEL_ODR        ((uint8)0x1E)
#define MPU6500_MOT_THR             ((uint8)0x1F)
#define MPU6500_FIFO_EN             ((uint8)0x23)
#define MPU6500_I2C_MST_CTRL        ((uint8)0x24)
#define MPU6500_I2C_SLV0_ADDR       ((uint8)0x25)
#define MPU6500_I2C_SLV0_REG        ((uint8)0x26)
#define MPU6500_I2C_SLV0_CTRL       ((uint8)0x27)
#define MPU6500_I2C_SLV1_ADDR       ((uint8)0x28)
#define MPU6500_I2C_SLV1_REG        ((uint8)0x29)
#define MPU6500_I2C_SLV1_CTRL       ((uint8)0x2A)
#define MPU6500_I2C_SLV2_ADDR       ((uint8)0x2B)
#define MPU6500_I2C_SLV2_REG        ((uint8)0x2C)
#define MPU6500_I2C_SLV2_CTRL       ((uint8)0x2D)
#define MPU6500_I2C_SLV3_ADDR       ((uint8)0x2E)
#define MPU6500_I2C_SLV3_REG        ((uint8)0x2F)
#define MPU6500_I2C_SLV3_CTRL       ((uint8)0x30)
#define MPU6500_I2C_SLV4_ADDR       ((uint8)0x31)
#define MPU6500_I2C_SLV4_REG        ((uint8)0x32)
#define MPU6500_I2C_SLV4_DO         ((uint8)0x33)
#define MPU6500_I2C_SLV4_CTRL       ((uint8)0x34)
#define MPU6500_I2C_SLV4_DI         ((uint8)0x35)
#define MPU6500_I2C_MST_STATUS      ((uint8)0x36)
#define MPU6500_INT_PIN_CFG         ((uint8)0x37)
#define MPU6500_INT_ENABLE          ((uint8)0x38)
#define MPU6500_INT_STATUS          ((uint8)0x3A)
#define MPU6500_ACCEL_XOUT_H        ((uint8)0x3B)
#define MPU6500_ACCEL_XOUT_L        ((uint8)0x3C)
#define MPU6500_ACCEL_YOUT_H        ((uint8)0x3D)
#define MPU6500_ACCEL_YOUT_L        ((uint8)0x3E)
#define MPU6500_ACCEL_ZOUT_H        ((uint8)0x3F)
#define MPU6500_ACCEL_ZOUT_L        ((uint8)0x40)
#define MPU6500_TEMP_OUT_H          ((uint8)0x41)
#define MPU6500_TEMP_OUT_L          ((uint8)0x42)
#define MPU6500_GYRO_XOUT_H         ((uint8)0x43)
#define MPU6500_GYRO_XOUT_L         ((uint8)0x44)
#define MPU6500_GYRO_YOUT_H         ((uint8)0x45)
#define MPU6500_GYRO_YOUT_L         ((uint8)0x46)
#define MPU6500_GYRO_ZOUT_H         ((uint8)0x47)
#define MPU6500_GYRO_ZOUT_L         ((uint8)0x48)
#define MPU6500_EXT_SENS_DATA_00    ((uint8)0x49)
#define MPU6500_EXT_SENS_DATA_01    ((uint8)0x4A)
#define MPU6500_EXT_SENS_DATA_02    ((uint8)0x4B)
#define MPU6500_EXT_SENS_DATA_03    ((uint8)0x4C)
#define MPU6500_EXT_SENS_DATA_04    ((uint8)0x4D)
#define MPU6500_EXT_SENS_DATA_05    ((uint8)0x4E)
#define MPU6500_EXT_SENS_DATA_06    ((uint8)0x4F)
#define MPU6500_EXT_SENS_DATA_07    ((uint8)0x50)
#define MPU6500_EXT_SENS_DATA_08    ((uint8)0x51)
#define MPU6500_EXT_SENS_DATA_09    ((uint8)0x52)
#define MPU6500_EXT_SENS_DATA_10    ((uint8)0x53)
#define MPU6500_EXT_SENS_DATA_11    ((uint8)0x54)
#define MPU6500_EXT_SENS_DATA_12    ((uint8)0x55)
#define MPU6500_EXT_SENS_DATA_13    ((uint8)0x56)
#define MPU6500_EXT_SENS_DATA_14    ((uint8)0x57)
#define MPU6500_EXT_SENS_DATA_15    ((uint8)0x58)
#define MPU6500_EXT_SENS_DATA_16    ((uint8)0x59)
#define MPU6500_EXT_SENS_DATA_17    ((uint8)0x5A)
#define MPU6500_EXT_SENS_DATA_18    ((uint8)0x5B)
#define MPU6500_EXT_SENS_DATA_19    ((uint8)0x5C)
#define MPU6500_EXT_SENS_DATA_20    ((uint8)0x5D)
#define MPU6500_EXT_SENS_DATA_21    ((uint8)0x5E)
#define MPU6500_EXT_SENS_DATA_22    ((uint8)0x5F)
#define MPU6500_EXT_SENS_DATA_23    ((uint8)0x60)
#define MPU6500_I2C_SLV0_DO         ((uint8)0x63)
#define MPU6500_I2C_SLV1_DO         ((uint8)0x64)
#define MPU6500_I2C_SLV2_DO         ((uint8)0x65)
#define MPU6500_I2C_SLV3_DO         ((uint8)0x66)
#define MPU6500_I2C_MST_DELAY_CTRL  ((uint8)0x67)
#define MPU6500_SIGNAL_PATH_RESET   ((uint8)0x68)
#define MPU6500_MOT_DETECT_CTRL     ((uint8)0x69)
#define MPU6500_USER_CTRL           ((uint8)0x6A)
#define MPU6500_PWR_MGMT_1          ((uint8)0x6B)
#define MPU6500_PWR_MGMT_2          ((uint8)0x6C)
#define MPU6500_FIFO_COUNTH         ((uint8)0x72)
#define MPU6500_FIFO_COUNTL         ((uint8)0x73)
#define MPU6500_FIFO_R_W            ((uint8)0x74)
#define MPU6500_WHO_AM_I            ((uint8)0x75)        // ID = 0x71 In MPU9250
#define MPU6500_XA_OFFSET_H         ((uint8)0x77)
#define MPU6500_XA_OFFSET_L         ((uint8)0x78)
#define MPU6500_YA_OFFSET_H         ((uint8)0x7A)
#define MPU6500_YA_OFFSET_L         ((uint8)0x7B)
#define MPU6500_ZA_OFFSET_H         ((uint8)0x7D)
#define MPU6500_ZA_OFFSET_L         ((uint8)0x7E)

/* ---- AK8963 Reg In MPU9250 ----------------------------------------------- */

#define AK8963_I2C_ADDR             ((uint8)0x0C)//BBA原来0x18 有0x0C的
#define AK8963_Device_ID            ((uint8)0x48)//BBA_Check

// Read-only Reg
#define AK8963_WIA                  ((uint8)0x00)
#define AK8963_INFO                 ((uint8)0x01)
#define AK8963_ST1                  ((uint8)0x02)
#define AK8963_ST1_DOR                                ((uint8)0x02)
#define AK8963_HXL                  ((uint8)0x03)
#define AK8963_HXH                  ((uint8)0x04)
#define AK8963_HYL                  ((uint8)0x05)
#define AK8963_HYH                  ((uint8)0x06)
#define AK8963_HZL                  ((uint8)0x07)
#define AK8963_HZH                  ((uint8)0x08)
#define AK8963_ST2                  ((uint8)0x09)
#define AK8963_ST2_HOFL                                ((uint8)0x08)
// Write/Read Reg
#define AK8963_CNTL1                ((uint8)0x0A)
#define AK8963_CNTL2                ((uint8)0x0B)
#define AK8963_CNTL2_SRST                        ((uint8)0x01)
#define AK8963_ASTC                 ((uint8)0x0C)
#define AK8963_TS1                  ((uint8)0x0D)
#define AK8963_TS2                  ((uint8)0x0E)
#define AK8963_I2CDIS               ((uint8)0x0F)
// Read-only Reg ( ROM )
#define AK8963_ASAX                 ((uint8)0x10)
#define AK8963_ASAY                 ((uint8)0x11)
#define AK8963_ASAZ                 ((uint8)0x12)
/*====================================================================================================*/
/*====================================================================================================*/

uint8 SPI_RW(uint8 TxData);
uint8 MPU9250_ReadReg( uint8 ReadAddr);
void MPU9250_WriteReg( uint8 WriteAddr, uint8 WriteData );
void MPU9250_ReadRegs( uint8 ReadAddr, uint8 *ReadBuf, uint8 Bytes );
void MPU9250_MAG_I2C_Write(uint8 reg,uint8 value);
uint8 MPU9250_MAG_I2C_Read(uint8 reg);
void MPU9250_AK8963_Read();
void Init_MPU9250();

uint8 MPU9250_Check_MPU6500_ID();
uint8 MPU9250_Check_AK8963_ID();
#endif

#include "BBA_Dri_MPU9250.h"
#include "BBA_Dri_Debug.h"
#include "main.h"
#include <string.h>

#define SPIx SPI3
#define IMU_ENABLE()        LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_6);
#define IMU_DISABLE()        LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_6);
#define MPU9250_InitRegNum 10

uint8 SPI_RW(uint8 TxData);
uint8 MPU9250_ReadReg( uint8 ReadAddr);
void MPU9250_WriteReg( uint8 WriteAddr, uint8 WriteData );
void MPU9250_ReadRegs( uint8 ReadAddr, uint8 *ReadBuf, uint8 Bytes );
void MPU9250_MAG_I2C_Write(uint8 reg,uint8 value);
uint8 MPU9250_MAG_I2C_Read(uint8 reg);
void READ_MPU9250_MAG(uint32 *Mag);
void Init_MPU9250();

void Init_MPU9250(void)
{
        IMU_DISABLE();
        LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_7);//必须禁止MS5611,否则同时与两个传感器通讯
       
        MPU9250_WriteReg(MPU6500_PWR_MGMT_1, 0x80); //解除休眠状态
        WaitSysTimeBlock(1,UINT_MS);
        //MPU9250_WriteReg(MPU6500_PWR_MGMT_1, 0x01); //时钟选择
        //WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_USER_CTRL ,0x30); //I2C_MST _EN , I2C_IF_DIS
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_PWR_MGMT_2 ,0x00);//Enable Acc & Gyro
        //WaitSysTimeBlock(1,UINT_MS);
       
//        //将MPU9250的内部时钟分频,用来作为fifo和IIC Master自动搬运外部iic(包括AK8963)数据到EXT_SENS_DATA_xx的频率
//        MPU9250_WriteReg(MPU6500_SMPLRT_DIV ,0x0f);//
//        WaitSysTimeBlock(1,UINT_MS);
//       
//        //bit0:When enabled, slave 0 will only be accessed 1+I2C_MST_DLY) samples as determined by SMPLRT_DIV and DLPF_CFG
//        MPU9250_WriteReg(MPU6500_I2C_MST_DELAY_CTRL ,0x00);//
//        WaitSysTimeBlock(1,UINT_MS);
       
        //陀螺仪采样率和量程
        MPU9250_WriteReg(MPU6500_CONFIG ,0x07); // DLPF_CFG[2:0] = 111(低通滤波);
        //WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_GYRO_CONFIG ,0x18); // +-2000dps
        //WaitSysTimeBlock(1,UINT_MS);
       
        //加速度计采样率和量程
        MPU9250_WriteReg(MPU6500_ACCEL_CONFIG ,0x08); // +-4G
        //WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_ACCEL_CONFIG_2 ,0x48); // Set Acc Data Rates
        //WaitSysTimeBlock(1,UINT_MS);
        //如果读操作完成,则清除中断状态
        MPU9250_WriteReg(MPU6500_INT_PIN_CFG ,0x10); // Set INT_ANYRD_2CLEAR
        //WaitSysTimeBlock(1,UINT_MS);
       
        //使能 fifo 溢出中断
        MPU9250_WriteReg(MPU6500_INT_ENABLE ,0x10);
        WaitSysTimeBlock(1,UINT_MS);
       
        //选择Master iic时钟,4:iic延时,D:400KHZ,分频后的iic时钟频率
        MPU9250_WriteReg(MPU6500_I2C_MST_CTRL ,0x0D);
        WaitSysTimeBlock(1,UINT_MS);


        MPU9250_MAG_I2C_Write(AK8963_CNTL2,0x01); // Reset AK8963
        WaitSysTimeBlock(1,UINT_MS);
        //bit4:0输出14位,1输出16位,bit0~3:模式选择,0x06:连续测量模式2
        //bit0~3:0x02的话是连续模式1,与模式2的区别是模式1采样率为8HZ,模式2是200HZ
        MPU9250_MAG_I2C_Write(AK8963_CNTL1,0x16); // use i2c to set AK8963 working on Continuous measurement mode1 & 16-bit output
        WaitSysTimeBlock(1,UINT_MS);

        //IIC Master 要去读的从机寄存器起始地址
        MPU9250_WriteReg(MPU6500_I2C_SLV0_REG, AK8963_HXL);
        WaitSysTimeBlock(1,UINT_MS);
        //IIC Master 要去读的实际从机地址
        MPU9250_WriteReg(MPU6500_I2C_SLV0_ADDR, AK8963_I2C_ADDR | 0x80);
        WaitSysTimeBlock(1,UINT_MS);
       
        //IIC Master 要去读的从机寄存器个数(由起始地址按顺序读)
        //bit7:Enable slv0,bit0~3:读取的数据长度
        MPU9250_WriteReg(MPU6500_I2C_SLV0_CTRL, 0x80 | 7);
        WaitSysTimeBlock(1,UINT_MS);
}

uint8 SPI_RW(uint8 TxData)
{  
        uint8 temp=0;

        while(!LL_SPI_IsActiveFlag_TXE(SPIx))
        {
                //当发送寄存器非空时,一直循环       
        }
       
        LL_SPI_TransmitData8(SPIx,TxData);
        while(!LL_SPI_IsActiveFlag_RXNE(SPIx))
        {
                //当接收FIFO小于1/4*32时,一直循环
        }

        return LL_SPI_ReceiveData8(SPIx);//读取一个8位数据
}

uint8 MPU9250_ReadReg( uint8 ReadAddr)
{
        uint8 readResult;
        IMU_ENABLE();
        SPI_RW(0x80 | ReadAddr);
        readResult = SPI_RW(0xFF);
        IMU_DISABLE();
        return readResult;
}

void MPU9250_WriteReg( uint8 WriteAddr, uint8 WriteData )
{
        IMU_ENABLE();
        SPI_RW(WriteAddr);
        SPI_RW(WriteData);
        IMU_DISABLE();
}

void MPU9250_ReadRegs( uint8 ReadAddr, uint8 *ReadBuf, uint8 Bytes )
{
        uint8 i = 0;

        IMU_ENABLE();
        SPI_RW(0x80 | ReadAddr);
        for(i=0; i<Bytes; i++)
        {
                ReadBuf = SPI_RW(0xFF);
        }
        IMU_DISABLE();
}

void MPU9250_MAG_I2C_Write(uint8 WriteAddr,uint8 WriteData)
{
        uint8_t timeout = 0;
        uint8_t status = 0;

        MPU9250_WriteReg(MPU6500_I2C_SLV4_REG, WriteAddr);
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_I2C_SLV4_ADDR, AK8963_I2C_ADDR);
        WaitSysTimeBlock(1,UINT_MS);
        //当写数据到iic设备寄存器时,DO寄存器就用来存储要写的数据
        MPU9250_WriteReg(MPU6500_I2C_SLV4_DO, WriteData);
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_I2C_SLV4_CTRL, 0x80);
        WaitSysTimeBlock(1,UINT_MS);

//        do {
//                status=MPU9250_ReadReg(MPU6500_I2C_MST_STATUS);
//                //timeout++;
//        } while(((status & 0x40) == 0));
        //WaitSysTimeBlock(1,UINT_MS);
}

uint8 MPU9250_MAG_I2C_Read(uint8 reg)
{
        uint8 readResult;
        uint8 status = 0;
        uint8 timeout = 0;
       
        MPU9250_WriteReg(MPU6500_I2C_SLV4_REG ,reg);// set reg addr
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_I2C_SLV4_ADDR ,AK8963_I2C_ADDR|0x80); //设置磁力计地址,mode:read
        WaitSysTimeBlock(1,UINT_MS);
        MPU9250_WriteReg(MPU6500_I2C_SLV4_CTRL, 0x80);
        WaitSysTimeBlock(1,UINT_MS);
       
//        do {
//                //WaitSysTimeBlock(1,UINT_MS);
//                status=MPU9250_ReadReg(MPU6500_I2C_MST_STATUS);
//                //timeout++;
//               
//        } while(((status & 0x40) == 0));
        //WaitSysTimeBlock(1,UINT_MS);
        //当读取iic设备数据时,,DI寄存器就用来存储设备发回来的数据(注意:slv0~3的回传数据寄存器是EXT_SENS_DATA_xx)
        readResult=MPU9250_ReadReg(MPU6500_I2C_SLV4_DI);
        WaitSysTimeBlock(1,UINT_MS);
        return readResult;
}

uint8 MPU9250_Check_MPU6500_ID( void )
{
        uint8 DeviceID;

        /* MPU6500 */
        DeviceID=MPU9250_ReadReg(MPU6500_WHO_AM_I);

        return DeviceID;
}

uint8 MPU9250_Check_AK8963_ID()
{
        uint8 DeviceID=0x00;
        DeviceID=MPU9250_MAG_I2C_Read(AK8963_WIA);
       
        return DeviceID;
}

void MPU9250_AK8963_Read()
{
        extern uint8 mpu9250MagBuffer[];
        memset(mpu9250MagBuffer,0x00,12);
        mpu9250MagBuffer[0]=MPU9250_MAG_I2C_Read(AK8963_ASAX);// X轴灵敏度调整值
        mpu9250MagBuffer[1]=MPU9250_MAG_I2C_Read(AK8963_ASAY);
        mpu9250MagBuffer[2]=MPU9250_MAG_I2C_Read(AK8963_ASAZ);
       
        mpu9250MagBuffer[3]=MPU9250_MAG_I2C_Read(AK8963_ST1);
        //if((mpu9250MagBuffer[3]&0x01)==1)//data ready
        {
                //mpu9250MagBuffer[5]=MPU9250_MAG_I2C_Read(AK8963_HXL);
                //mpu9250MagBuffer[4]=MPU9250_MAG_I2C_Read(AK8963_ST2);
                //if(
                mpu9250MagBuffer[5]=MPU9250_MAG_I2C_Read(AK8963_HXL);
                mpu9250MagBuffer[6]=MPU9250_MAG_I2C_Read(AK8963_HXH);
                mpu9250MagBuffer[7]=MPU9250_MAG_I2C_Read(AK8963_HYL);
                mpu9250MagBuffer[8]=MPU9250_MAG_I2C_Read(AK8963_HYH);
                mpu9250MagBuffer[9]=MPU9250_MAG_I2C_Read(AK8963_HZL);
                mpu9250MagBuffer[10]=MPU9250_MAG_I2C_Read(AK8963_HZH);
                //mpu9250MagBuffer[11]=MPU9250_MAG_I2C_Read(AK8963_HXL);
                //mpu9250MagBuffer[5]=MPU9250_MAG_I2C_Read(AK8963_HXL);
               
               
                //mpu9250MagBuffer[5]=MPU9250_MAG_I2C_Read(AK8963_WIA);
                //mpu9250MagBuffer[6]=MPU9250_MAG_I2C_Read(AK8963_CNTL1)<<8;
        }
        //mpu9250MagBuffer[11]=MPU9250_MAG_I2C_Read(AK8963_ST2);
}
void MPU9250_Read( uint8 *ReadBuf )
{
        MPU9250_ReadRegs(MPU6500_ACCEL_XOUT_H, ReadBuf, 20);       
}

调用:
Init_MPU9250();
MPU9250_Read(mpu9250Buffer);
sprintf((char *)sendBuffer,"ax:%d,ay:%d,az:%d,\
temperature:%d,\
gx:%d,gy:%d,gz:%d,\
AK8963_ID:0x%02X,mx:%d,my:%d,mz:%d",
                        (int16)(mpu9250Buffer[0]<<8|mpu9250Buffer[1]),
                        (int16)(mpu9250Buffer[2]<<8|mpu9250Buffer[3]),
                        (int16)(mpu9250Buffer[4]<<8|mpu9250Buffer[5]),
                        (int16)(mpu9250Buffer[6]<<8|mpu9250Buffer[7]),
                        (int16)(mpu9250Buffer[8]<<8|mpu9250Buffer[9]),
                        (int16)(mpu9250Buffer[10]<<8|mpu9250Buffer[11]),
                        (int16)(mpu9250Buffer[12]<<8|mpu9250Buffer[13]),
                        (uint8) AK8963_ID,
                        (int16)(mpu9250Buffer[15]<<8|mpu9250Buffer[14]),
                        (int16)(mpu9250Buffer[17]<<8|mpu9250Buffer[16]),
                        (int16)(mpu9250Buffer[19]<<8|mpu9250Buffer[18]));
               
                BBA_DEBUG_TX(sendBuffer,strlen(sendBuffer));

输出:
[12:12:20.996]收←◆ax:12060,ay:-884,az:10284,temperature:2208,gx:138,gy:64,gz:148,AK8963_ID:0x00,mx:403,my:-63,mz:-225
[12:12:21.196]收←◆ax:12148,ay:-980,az:10356,temperature:2240,gx:159,gy:73,gz:133,AK8963_ID:0x00,mx:412,my:-64,mz:-224
[12:12:21.396]收←◆ax:12112,ay:-896,az:10340,temperature:2144,gx:173,gy:102,gz:166,AK8963_ID:0x00,mx:408,my:-70,mz:-228
[12:12:21.595]收←◆ax:12096,ay:-840,az:10284,temperature:2192,gx:191,gy:90,gz:161,AK8963_ID:0x00,mx:404,my:-72,mz:-224
[12:12:21.795]收←◆ax:12052,ay:-848,az:10252,temperature:2192,gx:160,gy:88,gz:160,AK8963_ID:0x00,mx:410,my:-68,mz:-228
[12:12:21.995]收←◆ax:12068,ay:-888,az:10380,temperature:2208,gx:155,gy:102,gz:138,AK8963_ID:0x00,mx:404,my:-68,mz:-230
[12:12:22.195]收←◆ax:11972,ay:-824,az:10416,temperature:2176,gx:151,gy:137,gz:143,AK8963_ID:0x00,mx:404,my:-70,mz:-220
[12:12:22.394]收←◆ax:12084,ay:-892,az:10432,temperature:2208,gx:146,gy:74,gz:123,AK8963_ID:0x00,mx:417,my:-63,mz:-225
[12:12:22.594]收←◆ax:12084,ay:-900,az:10316,temperature:2208,gx:168,gy:90,gz:179,AK8963_ID:0x00,mx:401,my:-75,mz:-217
[12:12:22.794]收←◆ax:12068,ay:-908,az:10396,temperature:2240,gx:201,gy:91,gz:172,AK8963_ID:0x00,mx:404,my:-62,mz:-222
[12:12:22.994]收←◆ax:12124,ay:-904,az:10364,temperature:2192,gx:160,gy:121,gz:173,AK8963_ID:0x00,mx:404,my:-74,mz:-228
[12:12:23.193]收←◆ax:12036,ay:-896,az:10392,temperature:2208,gx:150,gy:76,gz:123,AK8963_ID:0x00,mx:412,my:-64,mz:-234
(31966144)

出0入0汤圆

发表于 2020-4-7 09:16:48 | 显示全部楼层
本帖最后由 lcw_swust 于 2020-4-7 13:02 编辑

这货就是有点坑,AK8963连续模式必须读取ST2,数据才会更新.
手册中还有一些位是反相的,要注意看注释.
(31943074)

出0入0汤圆

 楼主| 发表于 2020-4-7 15:41:18 | 显示全部楼层
忘了还有一个问题,顺手贴上
External sensor data is written to these registers at the Sample Rate as defined in Register 25. This access rate can be reduced by using the Slave Delay Enable registers (Register 103).
当采样发生时,外部iic的数据会被传送到MPU6500_EXT_SENS_DATA_xx寄存器。
(31943009)

出0入0汤圆

 楼主| 发表于 2020-4-7 15:42:23 | 显示全部楼层
lcw_swust 发表于 2020-4-7 09:16
这货就是有点坑,AK8963连续模式必须读取ST2,数据才会更新.
手册中还有一些位是反相的,要注意看注释. ...

手册有点随便,read/write 的寄存器到了详细说明页时又变成read only
(1690729)

出0入0汤圆

发表于 2021-3-23 19:07:03 | 显示全部楼层
MPU9250 spi学习下
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子论坛 ( 公安交互式论坛备案:44190002001997 粤ICP备09047143号 )

GMT+8, 2021-4-12 08:45

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表