Interface MPU6050 (GY-521) with STM32

I have already covered How to get acceleration values in ADXL345. MPU6050 is also an accelerometer cum Gyroscope device and today in this tutorial we are going to interface it with the STM32 microcontroller.

I will use LCD 20×4 to display the respective values. What’s interesting here is that the LCD and GY521, both will be connected to the same I2C peripheral. SO we are only using 2 wires from microcontroller to interface both the devices and that’s what the true purpose of I2C is.

MPU6050 Have a lot of functions and its not possible to cover all of them in just one tutorial. So in part 1, we will only cover the following:-

  • How to Initialize the device
  • How to read RAW values
  • How to convert acceleration values in ‘g’
  • and Gyroscope values in dps (°/s)

Some Insight into the CODE


Let’s start with the initialization of the MPU6050. In order to initialize the sensor, we need to perform the following actions:-

We need to check if the sensor is responding by reading the “WHO_AM_I (0x75)” Register. If the sensor responds with 0x68, this means it’s available and good to go.

I am using HAL_I2C_Mem_Read function to directly read from the given memory register

HAL_I2C_Mem_Read (&hi2c1, MPU6050_ADDR,WHO_AM_I_REG,1, &check, 1, 1000);

Next we will wake the sensor up and in order to do that we will write to the “PWR_MGMT_1 (0x6B)” Register. See below the register content

On writing (0x00) to the PWR_MGMT_1 Register, sensor wakes up and the Clock sets up to 8 MHz

// power management register 0X6B we should write all 0's to wake the sensor up
Data = 0;
HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, PWR_MGMT_1_REG, 1,&Data, 1, 1000);

Now we have to set the Data output Rate or Sample Rate. This can be done by writing into “SMPLRT_DIV (0x19)” Register. This register specifies the divider from the gyroscope output rate used to generate the Sample Rate for the MPU6050.

As the formula says Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV). Where Gyroscope Output Rate is 8KHz, To get the sample rate of 1KHz, we need to use the SMPLRT_DIV as ‘7’.

// Set DATA RATE of 1KHz by writing SMPLRT_DIV register
Data = 0x07;
HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, SMPLRT_DIV_REG, 1, &Data, 1, 1000);

Now configure the Accelerometer and Gyroscope registers and to do so, we need to modify “GYRO_CONFIG (0x1B)” and “ACCEL_CONFIG (0x1C)”Registers.


Writing (0x00) to both of these registers would set the Full scale range of ± 2g in ACCEL_CONFIG Register and a Full scale range of ± 250 °/s in GYRO_CONFIG Register along with Self-test disabled.

This completes the initialization of the MPU6050 and Now we will see How to Read the Data from the sensor and how to convert it in the respective formats. Let us start with the Acceleration values first.

Read Value from MPU6050

We can read 1 BYTE from each Register separately or we can just read 6 BYTES all together starting from ACCEL_XOUT_H Register.

As shown above, The ACCEL_XOUT_H (0x3B) Register stores the higher Byte for the acceleration data along X-Axis and Lower Byte is stored in ACCEL_XOUT_L Register. So we need to combine these 2 BYTES into a 16 bit integer value. Below is the process to do that:-


we are shifting the higher 8 bits to the left and than ‘OR’ it with the lower 8 bits.

 For Example,  if ACCEL_XOUT_H = 11101110 and ACCEL_XOUT_L = 10101010, we will get the resultant 16 bit value as 1110111010101010

Similarly we can do the same for the ACCEL_YOUT and ACCEL_ZOUT Registers. These values will still be the RAW values and we still need to convert them into proper ‘g’ format.

You can see in the picture above that for the Full-Scale range of ± 2g, the sensitivity is 16384 LSB/g. So to get the ‘g‘ value, we need to divide the RAW from 16384. Look at the code below

// Read 6 BYTES of data starting from ACCEL_XOUT_H register

HAL_I2C_Mem_Read (&hi2c1, MPU6050_ADDR, ACCEL_XOUT_H_REG, 1, Rec_Data, 6, 1000);

Accel_X_RAW = (int16_t)(Rec_Data[0] << 8 | Rec_Data [1]);
Accel_Y_RAW = (int16_t)(Rec_Data[2] << 8 | Rec_Data [3]);
Accel_Z_RAW = (int16_t)(Rec_Data[4] << 8 | Rec_Data [5]);

/*** convert the RAW values into acceleration in 'g'
     we have to divide according to the Full scale value set in FS_SEL
     I have configured FS_SEL = 0. So I am dividing by 16384.0
     for more details check ACCEL_CONFIG Register              ****/

Ax = Accel_X_RAW/16384.0;  // get the float g
Ay = Accel_Y_RAW/16384.0;
Az = Accel_Z_RAW/16384.0;

Reading Gyro Data is similar to the Acceleration case. We will start reading 6 BYTES of data from the GYRO_XOUT_H Register, Combine the 2 Bytes to get 16 bit integer RAW values. As we have selected the Full-Scale range of ± 250 °/s, for which the sensitivity is 131 LSB /°/s, we have to divide the RAW values by 131.0 to get the values in dps ( °/s ). Check below

// Read 6 BYTES of data starting from GYRO_XOUT_H register

HAL_I2C_Mem_Read (&hi2c1, MPU6050_ADDR, GYRO_XOUT_H_REG, 1, Rec_Data, 6, 1000);

Gyro_X_RAW = (int16_t)(Rec_Data[0] << 8 | Rec_Data [1]);
Gyro_Y_RAW = (int16_t)(Rec_Data[2] << 8 | Rec_Data [3]);
Gyro_Z_RAW = (int16_t)(Rec_Data[4] << 8 | Rec_Data [5]);

/*** convert the RAW values into dps (°/s)
     we have to divide according to the Full scale value set in FS_SEL
     I have configured FS_SEL = 0. So I am dividing by 131.0
     for more details check GYRO_CONFIG Register              ****/

Gx = Gyro_X_RAW/131.0;
Gy = Gyro_Y_RAW/131.0;
Gz = Gyro_Z_RAW/131.0;

To print the values on the LCD, use the function below

sprintf (buf, "%.2f", Ax);

If the LCD don’t show anything, do the following.
Goto project->setting->c/c++ build->setting->tool setting->c linker and type -u _printf_float inside the command.


Check out the Video Below


You can help with the development by DONATING
To download the code, click DOWNLOAD button and view the Ad. The project will download after the Ad is finished.

21 Comments. Leave new

  • Hello sir
    I have a little difficulty using I2C with DMA to
    read values from MPU6050. When using DMA (HAL_I2C_Mem_Read_DMA circular mode), the read value is correct only once and crashes. However, when using I2C in polling mode, the reading value returns to normal.

  • I2C_Read (Address+0x01, buffer, size);

    why Address add by 0x01? Please help me

    • The slave address is 7 bit in size, and the lsb is R/W bit. For the write operation, the R/W bit is a 0, and for read operation this bit is a 1.
      For example, assume that the 7 bit slave address is 0x27. For write operation, the slave address will be (0x27<<1)+0 and for read operation the address will be (0x27<<1)+1. The HAL library do this addition automatically.

  • at rest it should probably show a naught acceleration or at least near to that. I get 1.01g in Az. Isn’t it weird?

  • is it a mandatory to use a very high frequency in HCLK? I’m using 32MHz and it doesn’t even read back the WHO_AM_I_REG address. I’m using stm32wb55

  • Hello, I’ve been wondering about this line

    #define MPU9250_ADDR 0XD0

    Can you explain what is 0xD0 and where it comes from? I’ve read the article and watch the video but I can’t find any explanation about it.

    • LSB using for read/write first byte of packece in I2C protocol. 1byte -> a6 a5 a4 a3 a2 a1 a0 r/w. So xD0 =11010000 in binary equal, if you slide right one bit this value be 1101000 in binary and equal x68 in hex.

    • Hi,

      The address of the device is 0x68.

      But this is needed to be shifted to the left by 1 to allow bit 0 to be set as 0/1 for R/W when communicating with device.


      (0x68 << 1) = 0x0D

      01101000 << 1

      Hopefully this helps

    • This is the base address of the mpu6050

  • Hi Controllers Tech unable to get the Gx, Gy and Gz value using STM32 NUCLEO F446RE Board and 2004A LCD Display Do I need to change the registers value as I am using MPU6050 GY-87 IMU

  • Megantara_Azhar(PENS)
    November 6, 2020 3:49 PM

    hi thanks a lot..abaout your tutorial i hope you can share more tutuorial related with stm32f4 and also sensor thatallow it to be connected.

  • can u share circuit diagrams ?

  • please make gps tutorial

  • Hello Controllers tech team
    Your content was very helpfully and thanks for explain it simple and complete.
    I buy this devices STM32F103C8T6 & MPU6050 & LCD 4020 with PCF8574.
    I program your HEX code into the micro with ST link Utility.
    But i have a problem for the first run, the output of IMU not show on LCD and values are 0.

    and i check signal SCL & SDA with logic analyzer.

    Second question i need get Acceleration & Gyroscope data on MATLAB and which one function must be use for USART ?

    thanks for helping.


Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.


Adblocker detected! Please consider reading this notice.

We've detected that you are using AdBlock Plus or some other adblocking software which is preventing the page from fully loading.

We don't have any banner, Flash, animation, obnoxious sound, or popup ad. We do not implement these annoying types of ads!

We need money to operate the site, and almost all of it comes from our online advertising.

Please add to your ad blocking whitelist or disable your adblocking software.