stm32i2cstm32f4mpu6050

How to read data from MPU6050 using STM32F4


I need to monitorate the acelleration of a object. I'm using the MPU6050(accelerometer and gyroscope) and the controller STM32F401RBT6. The code below is the solution that i'm using for this.

#define MPU6050_ADDR 0xD0
#define SMPLRT_DIV_REG 0x19
#define GYRO_CONFIG_REG 0x1B
#define ACCEL_CONFIG_REG 0x1C
#define ACCEL_XOUT_H_REG 0x3B
#define TEMP_OUT_H_REG 0x41
#define GYRO_XOUT_H_REG 0x43
#define PWR_MGMT_1_REG 0x6B
#define WHO_AM_I_REG 0X75

uint16_t Accel_X_RAW,Accel_Y_RAW,Accel_Z_RAW;
uint16_t Ax,Ay,Az;
char buffer[10];

void MPU6050_Init(void)
{
    uint8_t check, data;
    HAL_I2C_Mem_Read(&hi2c3,MPU6050_ADDR,WHO_AM_I_REG,1,&check,1,100);
    if(check == 104)
    {
        data = 0x07;
        HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,SMPLRT_DIV_REG,1,&data,1,50);
        HAL_Delay(50);
        data = 0x00;
        HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,ACCEL_CONFIG_REG,1,&data,1,50);
        HAL_Delay(50);
        data = 0x00;
        HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,GYRO_CONFIG_REG,1,&data,1,50);
        HAL_Delay(50);
        data = 0;
        HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,PWR_MGMT_1_REG,1,&data,1,50);
        HAL_Delay(50);
    }
}

void MPU6050_Read_Accel(void)
{
    uint8_t recData[6];
    for(int i=0;i<6;i++) recData[i] = 0;

    HAL_I2C_Mem_Read(&hi2c3,MPU6050_ADDR,ACCEL_XOUT_H_REG,I2C_MEMADD_SIZE_8BIT,recData,6,100);
    HAL_Delay(50);
    uint16_t dataConvert1,dataConvert2;
    dataConvert1 = (uint16_t)(0x0000 | recData[0]) << 8;
    dataConvert2 = (uint16_t)(0x0000 | recData[1]);
    Accel_X_RAW = dataConvert1 | dataConvert2;
    dataConvert1 = (uint16_t)(0x0000 | recData[2]) << 8;
    dataConvert2 = (uint16_t)(0x0000 | recData[3]);
    Accel_Y_RAW = dataConvert1 | dataConvert2;
    dataConvert1 = (uint16_t)(0x0000 | recData[4]) << 8;
    dataConvert2 = (uint16_t)(0x0000 | recData[5]);
    Accel_Z_RAW = dataConvert1 | dataConvert2;

    Ax = (uint16_t)(Accel_X_RAW / 16384);
    Ay = (uint16_t)(Accel_Y_RAW / 16384);
    Az = (uint16_t)(Accel_Z_RAW / 16384);
}

int main(void)
{
    HAL_Init();

    SystemClock_Config();

    MX_I2C3_Init();
    MX_GPIO_Init();
    MX_USB_DEVICE_Init();

    MPU6050_Init();

    while (1)
    {
      MPU6050_Read_Accel();
      sprintf(buffer, "%d / ", Accel_X_RAW);
      CDC_Transmit_FS((char*)buffer,10);
    }
}

I already did it on ATMEL Controler (Arduino) and it worked, but not on STM32. I am trying to read the value of X Axis and show it using the USB CDC. This code sets a value for the `` `Accel_X_RAW```` variable between 0 and 65535. In Arduino, the reference value was 32768 when the object was stopped, but reading with STM32 remains at the maximum value (65535) if don't have movement. I don't know what's wrong with this code, I tried many options, but it still doesn't work. Can you help me please.


Solution

  • According to the MPU6050 datasheet, the 16-bit values for acceleration and gyroscope are returned in the signed 2's complement form (it detects acceleration values in the range +-g). As you are receiving signed data in the unsigned variables, the result is not what you expect. Therefore, replace all uint16_t datatypes with int16_t.

    The reason why you are getting 65535 value; the hex value of -1 in signed int16_t form is 0xFFFF. However, if you store it in the uint16_t variable, it will be read as 65535. I am assuming that the default acceleration value at rest is -1g.

    #include <stdlib.h> /* For using memset */
    
    #define MPU6050_ADDR 0xD0
    #define SMPLRT_DIV_REG 0x19
    #define GYRO_CONFIG_REG 0x1B
    #define ACCEL_CONFIG_REG 0x1C
    #define ACCEL_XOUT_H_REG 0x3B
    #define TEMP_OUT_H_REG 0x41
    #define GYRO_XOUT_H_REG 0x43
    #define PWR_MGMT_1_REG 0x6B
    #define WHO_AM_I_REG 0X75
    
    int16_t Accel_X_RAW,Accel_Y_RAW,Accel_Z_RAW;
    int16_t Ax,Ay,Az;
    char buffer[10];
    
    void MPU6050_Init(void)
    {
        uint8_t check, data;
        HAL_I2C_Mem_Read(&hi2c3,MPU6050_ADDR,WHO_AM_I_REG,1,&check,1,100);
        if(check == 104)
        {
            data = 0x07;
            HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,SMPLRT_DIV_REG,1,&data,1,50);
            HAL_Delay(50);
            data = 0x00;
            HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,ACCEL_CONFIG_REG,1,&data,1,50);
            HAL_Delay(50);
            data = 0x00;
            HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,GYRO_CONFIG_REG,1,&data,1,50);
            HAL_Delay(50);
            data = 0;
            HAL_I2C_Mem_Write(&hi2c3,MPU6050_ADDR,PWR_MGMT_1_REG,1,&data,1,50);
            HAL_Delay(50);
        }
    }
    
    void MPU6050_Read_Accel(void)
    {
        uint8_t recData[6];
        //for(int i=0;i<6;i++) recData[i] = 0;
        memset(recData, 0, sizeof(recData));
    
        HAL_I2C_Mem_Read(&hi2c3,MPU6050_ADDR,ACCEL_XOUT_H_REG,I2C_MEMADD_SIZE_8BIT,recData,6,100);
        HAL_Delay(50);
    
        Accel_X_RAW = (int16_t)(recData[0] << 8 | recData[1]);
        Accel_Y_RAW = (int16_t)(recData[2] << 8 | recData[3]);
        Accel_Z_RAW = (int16_t)(recData[4] << 8 | recData[5]);
    
        Ax = (int16_t)(Accel_X_RAW / 16384);
        Ay = (int16_t)(Accel_Y_RAW / 16384);
        Az = (int16_t)(Accel_Z_RAW / 16384);
    }
    
    int main(void)
    {
        HAL_Init();
    
        SystemClock_Config();
    
        MX_I2C3_Init();
        MX_GPIO_Init();
        MX_USB_DEVICE_Init();
    
        MPU6050_Init();
    
        while (1)
        {
          MPU6050_Read_Accel();
          sprintf(buffer, "%d / ", Accel_X_RAW);
          CDC_Transmit_FS((char*)buffer,10);
        }
    }