Saturday, December 19, 2015

Mailbag !! MPU6050 Module I2C Driver, Init and config




   As been requested by many people that have difficulties to use the MPU6050 Modules, I've done a more detailed ESP8266 Video Tutorial related with the MPU6050 GY-521 Module initialisation and basic usage.

   It is a detailed, step-by-step tutorial, showing all the needed init stages and tests for a proper and smooth usage of the MPU6050 GY-521 module.

https://www.youtube.com/watch?v=DDzIQ_6IQBY






  This is how are looking the received modules:

MPU6050 - GY-521 Module - top

MPU6050 - GY-521 Module - bottom


  These ones seems to  work OK connected directly to the 3.3V power on the ESP8266 nEXT  EVO board Bus and looks to have some very low dropout voltage regulator. This are the good news about.
Now some bad news: it seems to be sold different types/flavours of modules (maybe old/new batches with various BOM) under the same name code so your experience may vary and might be necessary to use 5V power input for the GY-521. Or just bypass the Voltage Regulator to avoid any wiring around :).



MPU-60X0 Overview

      The MPU-60X0 is the world’s first integrated 6-axis MotionTracking device that combines a 3-axis gyroscope, 3-axis accelerometer, and a Digital Motion Processor™ (DMP) all in a small 4x4x0.9mm package.
     With its dedicated I2C sensor bus, it directly accepts inputs from an external 3-axis compass to provide a complete 9-axis MotionFusion™ output. It is also designed to interface with multiple non-inertial digital sensors, such as pressure sensors, on its auxiliary I2C port.

  So, it can act as a I2C master for other I2C devices.  That's cool!

   For power supply flexibility, the MPU-60X0 operates from VDD power supply voltage range of 2.375V-3.46V. Additionally, the MPU-6050 provides a VLOGIC reference pin (in addition to its analog supply pin: VDD), which sets the logic levels of its I2C interface. The VLOGIC voltage may be 1.8V±5% or VDD.

   The MPU-6000 and MPU-6050 are identical, except that the MPU-6050 supports the I2C serial interface only, and has a separate VLOGIC reference pin. The MPU-6000 supports both I2C and SPI interfaces and has a single supply pin, VDD, which is both the device’s logic reference supply and the analog supply for the part.



MPU-60X0 Features


1. Gyroscope Features
  • The triple-axis MEMS gyroscope in the MPU-60X0 includes a wide range of features:
  •  Digital-output X-, Y-, and Z-Axis angular rate sensors (gyroscopes) with a user-programmable full-scale range of ±250, ±500, ±1000, and ±2000°/sec
  •  External sync signal connected to the FSYNC pin supports image, video and GPS synchronization
  •  Integrated 16-bit ADCs enable simultaneous sampling of gyros
  •  Enhanced bias and sensitivity temperature stability reduces the need for user calibration
  •  Improved low-frequency noise performance
  •  Digitally-programmable low-pass filter
  •  Gyroscope operating current: 3.6mA
  •  Standby current: 5μA
  •  Factory calibrated sensitivity scale factor
  •  User self-test 


2. Accelerometer Features
  • The triple-axis MEMS accelerometer in MPU-60X0 includes a wide range of features:
  •  Digital-output triple-axis accelerometer with a programmable full scale range of ±2g, ±4g, ±8g and ±16g
  •  Integrated 16-bit ADCs enable simultaneous sampling of accelerometers while requiring no external multiplexer
  •  Accelerometer normal operating current: 500μA
  •  Low power accelerometer mode current: 10μA at 1.25Hz, 20μA at 5Hz, 60μA at 20Hz, 110μA at 40Hz
  •  Orientation detection and signaling
  •  Tap detection
  •  User-programmable interrupts
  •  High-G interrupt
  •  User self-test



3. Additional Features
  • The MPU-60X0 includes the following additional features:
  •  9-Axis MotionFusion by the on-chip Digital Motion Processor (DMP)
  •  Auxiliary master I2C bus for reading data from external sensors (e.g., magnetometer)
  •  3.9mA operating current when all 6 motion sensing axes and the DMP are enabled
  •  VDD supply voltage range of 2.375V-3.46V
  •  Flexible VLOGIC reference voltage supports multiple I2C interface voltages (MPU-6050 only)
  •  Smallest and thinnest QFN package for portable devices: 4x4x0.9mm
  •  Minimal cross-axis sensitivity between the accelerometer and gyroscope axes
  •  1024 byte FIFO buffer reduces power consumption by allowing host processor to read the data in bursts and then go into a low-power mode as the MPU collects more data
  •  Digital-output temperature sensor
  •  User-programmable digital filters for gyroscope, accelerometer, and temp sensor
  •  10,000 g shock tolerant
  •  400kHz Fast Mode I2C for communicating with all registers
  •  1MHz SPI serial interface for communicating with all registers (MPU-6000 only)
  •  20MHz SPI serial interface for reading sensor and interrupt registers (MPU-6000 only)
  •  MEMS structure hermetically sealed and bonded at wafer level
  •  RoHS and Green compliant


4. MotionProcessing
  •  Internal Digital Motion Processing™ (DMP™) engine supports 3D MotionProcessing and gesture recognition algorithms
  •  The MPU-60X0 collects gyroscope and accelerometer data while synchronizing data sampling at a user defined rate. The total dataset obtained by the MPU-60X0 includes 3-Axis gyroscope data, 3-Axis accelerometer data, and temperature data. The MPU’s calculated output to the system processor can also include heading data from a digital 3-axis third party magnetometer.
  •  The FIFO buffers the complete data set, reducing timing requirements on the system processor by allowing the processor burst read the FIFO data. After burst reading the FIFO data, the system processor can save power by entering a low-power sleep mode while the MPU collects more data.
  •  Programmable interrupt supports features such as gesture recognition, panning, zooming, scrolling, tap detection, and shake detection
  •  Digitally-programmable low-pass filters
  •  Low-power pedometer functionality allows the host processor to sleep while the DMP maintains the step count.
  • 5.5 Clocking
  •  On-chip timing generator ±1% frequency variation over full temperature range
  •  Optional external clock inputs of 32.768kHz or 19.2MHz


It is quite a beast in a tiny package, with Gyroscope, Accelerometer, DMP and all the other goodies inside. For more details please take a look at the MPU60x0 Datasheet




What we will need:





    Connection with the ESP8266 nEXT EVO Board is very easy, as MPU6050 GY-521 Module connector is fully compatible with the nEXT Bus connector. Depending on how to you choose you socket type, you can install it on TOP or Bottom of the ESP8266 nEXT EVO Board :

MPU6050 GY-521 Module on top of the ESP8266 nEXT Evo Board




Driver implementation


1. Init I2C bus/interface

 Standard I2C Bus Initialisation function:
function init_I2C()
    i2c.setup(bus, sda, scl, i2c.SLOW)
end


 2. READ MPU6050 Register

Before reading data from MPU6050, you must tell it which of its internal addresses you want to read
A read starts off by writing to the MPU6050






Procedure:
  •  Send a start sequence.
  •  Send I2C address of the device with the R/W bit low (i2c.TRANSMITTER)
  •  Send the Internal register address
  •  Stop sequence
  • Send a start sequence again (repeated start)
  • Send the I2C address of the device with the R/W bit high (i2c.RECEIVER) 
  • Read data byte from the register
  • Send the stop sequence. 


function read_reg_MPU(reg)
  i2c.start(bus)
  i2c.address(bus, dev_addr, i2c.TRANSMITTER)
  i2c.write(bus, reg)
  i2c.stop(bus)
  i2c.start(bus)
  i2c.address(bus, dev_addr, i2c.RECEIVER)
  c=i2c.read(bus, 1)
  i2c.stop(bus)
  --print(string.byte(c, 1))
  return c
end



3. WRITE MPU6050 Register






Procedure:
  • Send a start sequence
  • Send the I2C address of the MPU6050 with the R/W bit low (i2c.TRANSMITTER)
  • Send the internal register number you want to write to
  • Send the data byte
  • IF you want more data to be sent can be done here. MPU6050 will automatically increment the internal register address after each byte
  • Send the stop sequence.

function write_reg_MPU(reg,val)
  i2c.start(bus)
  i2c.address(bus, dev_addr, i2c.TRANSMITTER)
  i2c.write(bus, reg)
  i2c.write(bus, val)
  i2c.stop(bus)
end


4. INIT MPU6050

When power up, MPU6050 will start in SLEEP mode. To be able to use it you need to START the device.

Procedure: 
  • Set SLEEP bit = 0 in the Power Management Register (107) OR Clear the Register

function init_MPU(reg,val)  --(107) 0x6B / 0
   write_reg_MPU(reg,val)
end


5. MPU6050 connectivity
 
MPU6050 connectivity status only!
Be sure that you have properly initialised I2C Bus before!

function status_MPU(dev_addr)
     i2c.start(bus)
     c=i2c.address(bus, dev_addr ,i2c.TRANSMITTER)
     i2c.stop(bus)
     if c==true then
        print(" Device found at address : "..string.format("0x%X",dev_addr))
     else print("Device not found !!")
     end
end


6. Check MPU6050 Status

Using the status_MPU() function and the Who Am I register to check if the MPU6050 is available and alive before doing anything else.

function check_MPU(dev_addr)
   print("")
   status_MPU(0x68)
   read_reg_MPU(117) --Register 117 – Who Am I - 0x75
   if string.byte(c, 1)==104 then print(" MPU6050 Device answered OK!")
   else print("  Check Device - MPU6050 NOT available!")
        return
   end
   read_reg_MPU(107) --Register 107 – Power Management 1-0x6b
   if string.byte(c, 1)==64 then print(" MPU6050 in SLEEP Mode !")
   else print(" MPU6050 in ACTIVE Mode !")
   end
end



 7. READ MPU6050 RAW DATA

Reading RAW data from the MPU6050. No conversion or transformation si done.
Received Data is in 2 complement format.

Procedure:
  •  Send a start sequence.
  •  Send I2C address of the device with the R/W bit low (i2c.TRANSMITTER)
  •  Send the Internal register address
  •  Stop sequence
  • Send a start sequence again (repeated start)
  • Send the I2C address of the device with the R/W bit high (i2c.RECEIVER) 
  • Read the number of the requested data bytes from the registers
  • Send the stop sequence.

function read_MPU_raw()
  i2c.start(bus)
  i2c.address(bus, dev_addr, i2c.TRANSMITTER)
  i2c.write(bus, 59)
  i2c.stop(bus)
  i2c.start(bus)
  i2c.address(bus, dev_addr, i2c.RECEIVER)
  c=i2c.read(bus, 14)
  i2c.stop(bus)
 
  Ax=bit.lshift(string.byte(c, 1), 8) + string.byte(c, 2)
  Ay=bit.lshift(string.byte(c, 3), 8) + string.byte(c, 4)
  Az=bit.lshift(string.byte(c, 5), 8) + string.byte(c, 6)
  Gx=bit.lshift(string.byte(c, 9), 8) + string.byte(c, 10)
  Gy=bit.lshift(string.byte(c, 11), 8) + string.byte(c, 12)
  Gz=bit.lshift(string.byte(c, 13), 8) + string.byte(c, 14)

  print("Ax:"..Ax.."     Ay:"..Ay.."      Az:"..Az)
  print("Gx:"..Gx.."   Gy:"..Gy.."   Gz:"..Gz)
  print("\nTempH: "..string.byte(c, 7).." TempL: "..string.byte(c, 8).."\n")

  return c, Ax, Ay, Az, Gx, Gy, Gz
end



8. Main program

 Procedure: 
  • Initialise I2C Bus
  • Initialise MPU6050 and START device
  • Check device connectivity and status
  • Read data from device (RAW)

---test program
dev_addr = 0x68 --104
bus = 0
sda, scl = 2, 1
init_I2C()
init_MPU(0x6B,0)

check_MPU(0x68)
read_MPU_raw()  -- one shot
-- read data from MPU6050 every 1s
tmr.alarm(0, 1000, 1, function() read_MPU_raw() end)

--stop tmr when done
tmr.stop(0)


Related resources available on Github:

1. MPU6050 Driver Code :  MPU6050_driver_test_v2.lua
2. MPU6050 Datasheet
3. MPU6050 Register map and descriptions




12 comments:

Unknown said...

Hi
i have use your code and is perfect except one part of it.
The MPU6050 generate and negative value. You have not write code for this.

Anonymous said...

I'm sure the NodeMCU community would be happy to accept a pull-request for this as a Lua module. Have you considered this?

Unknown said...

I also realized that the values ​​generated by MPU6050 are half esquisistos. The accelerometer is stopped but the values ​​do not stabilize. But it was very good post, great job

Vítor said...

I am trying to use this code, but my program returns "Device not found !!" on the status_MPU function, because 'c' is false. I run a similar program with Arduino with the same address (0x68) and it worked well. Can you elucidate me?

Unknown said...

what you gave to do if you are getting "Device not found" error is connecting MPUs AD0 pin to GND. i think you can also connect it to 3.3V but you will need to change the adress to 0x69 if

Unknown said...

Hi there, I've got the same problem : device not found on a wemos D1 R2 board. I tried 0x68 address, 0x69 address without success.

AD0 to ground (LOW) -> address 0x68, AD0 to HIGH -> 0x69 from https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf

Any idea?

Unknown said...

Hi there, got my answer. I figured out that on my wemos firmwared with latest https://github.com/nodemcu/nodemcu-firmware, the i2c bus seems not to work on D1 (SCL) and D2 (SDA) pins. I changed code to sda, scl = 3,4 and everything is now ok. I don't know really why!!! that bothers me.

a useful lua program to know what is on you i2c bus http://www.esp8266.com/viewtopic.php?f=19&t=1049

I did not use INT or ADO pins. Only SDA, SCL, VCC (+5V or +3,3V) and GND.

Unknown said...

I tested severals good configurations :

Device found at address 0x68
Device is wired: SDA to GPIO5 - IO index 1
Device is wired: SCL to GPIO0 - IO index 3

Scanning all pins for I2C Bus device
Device found at address 0x68
Device is wired: SDA to GPIO5 - IO index 1
Device is wired: SCL to GPIO2 - IO index 4

Scanning all pins for I2C Bus device
Device found at address 0x68
Device is wired: SDA to GPIO5 - IO index 1
Device is wired: SCL to GPIO12 - IO index 6

Scanning all pins for I2C Bus device
Device found at address 0x68
Device is wired: SDA to GPIO5 - IO index 1
Device is wired: SCL to GPIO13 - IO index 7

Scanning all pins for I2C Bus device
Device found at address 0x68
Device is wired: SDA to GPIO4 - IO index 2
Device is wired: SCL to GPIO0 - IO index 3

Scanning all pins for I2C Bus device
Device found at address 0x68
Device is wired: SDA to GPIO4 - IO index 2
Device is wired: SCL to GPIO0 - IO index 3

Scanning all pins for I2C Bus device
Device found at address 0x68
Device is wired: SDA to GPIO4 - IO index 2
Device is wired: SCL to GPIO12 - IO index 6

etc...

Unknown said...

when running in a loop, its taking a very long time to show the changed value. May i know the reason? Im powering it by 3V3.

Unknown said...

I'm trying to control a servo with the angl outputted by nodeMCU. This way, there is a delay caused.

Unknown said...

Olá Amigos...

The problem is very simple solution... modify a part like see above:

Ax=bit.lshift(string.byte(c, 1), 8) + string.byte(c, 2)
--Ay=bit.lshift(string.byte(c, 3), 8) + string.byte(c, 4)
--Az=bit.lshift(string.byte(c, 5), 8) + string.byte(c, 6)
--Gx=bit.lshift(string.byte(c, 9), 8) + string.byte(c, 10)
--Gy=bit.lshift(string.byte(c, 11), 8) + string.byte(c, 12)
--Gz=bit.lshift(string.byte(c, 13), 8) + string.byte(c, 14)

--print("Ax:"..Ax.." Ay:"..Ay.." Az:"..Az)
--print("Gx:"..Gx.." Gy:"..Gy.." Gz:"..Gz)
--print("\nTempH: "..string.byte(c, 7).." TempL: "..string.byte(c, 8).."\n")

if (Ax > 0x7FFF) then
Ax = Ax - 0x10000;
end

Ax=Ax/182.5

Ax=string.format("%.3f", Ax)
print("Ang_x: "..Ax)
--print("Ace_x: "..Gx)

return c, Ax --, Ay, Az, Gx, Gy, Gz
end

Now run the program and before do change where need.

good luck

VERTEXMARINE said...

Hi
please could help about sending
MPU6050 data to Wifi based on UDP protocole
thanks

Post a Comment