NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Sensors, Actuators, and Robotics » i2c MPU6050 help

October 24, 2012
by unnamed0404
unnamed0404's Avatar

Hey guys,

I'm trying to get the ATMega168 to talk to a MPU6050 accelerometer/gyro via i2c. The micro controller connections are basically the same as nerdkits standard setup, and I have pins 27 and 28 (SCL and SDA) going to the MPU6050. The MPU6050 I have is this breakout module:

https://www.sparkfun.com/products/11028

I have my microcontroller running at 5V, while the MPU6050 runs at 3.3V, so I've implemented a level shifter as described here:

http://www.kip.uni-heidelberg.de/lhcb/Publications/external/AN97055.pdf

also with 3.3k pullup resistors for each side.

I'm using peter fleury's avr i2c library, and ive tried to model my code pretty closely to this nunchuck example here:

http://www.nerdkits.com/forum/thread/972/

I uploaded the code, and tried to just do a quick initial test, (just reading address from my MPU6050), but it fails. I did checked the voltages on my SCL and SDA lines, and noticed that SDA was stuck at high, while SCL was stuck at low.

Has anyone seen this problem before? Any idea what could be wrong? I will upload my code a little later

Thanks

October 24, 2012
by unnamed0404
unnamed0404's Avatar

And here is my code

First the main file (which currently doesn't do anything except initialize everything and do a setup of the i2c and MPU6050)

#define F_CPU 14745600
#define MPU6050_ADR 0x68

#include <stdio.h>
#include <math.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "i2cmaster.h"
#include "MPU6050.h"

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

// PIN DEFINITIONS:
//
// PC5 -- SCL (2 Wire Serial Bus Clock Line)
// PC4 -- SDA (2 Wire Serial Bus Data Input/Output Line)

int main() {
  // start up the LCD
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

  sei();  //interrupt handler

  // start up the i2c protocol
  i2c_init();  // for clk speed of 100000

  int error = 1;
  uint16_t attempt = 0;

  do
  {
    lcd_line_three();
    lcd_write_string(PSTR("Attempt #"));
    lcd_write_int16(attempt);
    Setup_MPU6050();     //see MPU6050.c
    MPU6050_Test_I2C();   //see MPU6050.c
    attempt++;

  }
  while(error ==1);

return 0;

}

And here is peter fleury's i2cmaster.h, which I kept the same except for adding a couple of new functions towards the end

#ifndef _I2CMASTER_H
#define _I2CMASTER_H   1
/************************************************************************* 
* Title:    C include file for the I2C master interface 
*           (i2cmaster.S or twimaster.c)
* Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
* File:     $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target:   any AVR device
* Usage:    see Doxygen manual
**************************************************************************/

#ifdef DOXYGEN
/**
 @defgroup pfleury_ic2master I2C Master library
 @code #include <i2cmaster.h> @endcode

 @brief I2C (TWI) Master Software Library

 Basic routines for communicating with I2C slave devices. This single master 
 implementation is limited to one bus master on the I2C bus.

 This I2c library is implemented as a compact assembler software implementation of the I2C protocol 
 which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
 Since the API for these two implementations is exactly the same, an application can be linked either against the
 software I2C implementation or the hardware I2C implementation.

 Use 4.7k pull-up resistor on the SDA and SCL pin.

 Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module 
 i2cmaster.S to your target when using the software I2C implementation !

 Adjust the  CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.

 @note 
    The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted 
    to GNU assembler and AVR-GCC C call interface.
    Replaced the incorrect quarter period delays found in AVR300 with 
    half period delays.

 @author Peter Fleury pfleury@gmx.ch  http://jump.to/fleury

 @par API Usage Example
  The following code shows typical usage of this library, see example test_i2cmaster.c

 @code

 #include <i2cmaster.h>

 #define Dev24C02  0xA2      // device address of EEPROM 24C02, see datasheet

 int main(void)
 {
     unsigned char ret;

     i2c_init();                             // initialize I2C library

     // write 0x75 to EEPROM address 5 (Byte Write) 
     i2c_start_wait(Dev24C02+I2C_WRITE);     // set device address and write mode
     i2c_write(0x05);                        // write address = 5
     i2c_write(0x75);                        // write value 0x75 to EEPROM
     i2c_stop();                             // set stop conditon = release bus

     // read previously written value back from EEPROM address 5 
     i2c_start_wait(Dev24C02+I2C_WRITE);     // set device address and write mode

     i2c_write(0x05);                        // write address = 5
     i2c_rep_start(Dev24C02+I2C_READ);       // set device address and read mode

     ret = i2c_readNak();                    // read one byte from EEPROM
     i2c_stop();

     for(;;);
 }
 @endcode

*/
#endif /* DOXYGEN */

/**@{*/

#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
#endif

#include <avr/io.h>

/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_READ    1

/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_WRITE   0

/**
 @brief initialize the I2C master interace. Need to be called only once 
 @param  void
 @return none
 */
extern void i2c_init(void);

/** 
 @brief Terminates the data transfer and releases the I2C bus 
 @param void
 @return none
 */
extern void i2c_stop(void);

/** 
 @brief Issues a start condition and sends address and transfer direction

 @param    addr address and transfer direction of I2C device
 @retval   0   device accessible 
 @retval   1   failed to access device 
 */
extern unsigned char i2c_start(unsigned char addr);

/**
 @brief Issues a repeated start condition and sends address and transfer direction

 @param   addr address and transfer direction of I2C device
 @retval  0 device accessible
 @retval  1 failed to access device
 */
extern unsigned char i2c_rep_start(unsigned char addr);

/**
 @brief Issues a start condition and sends address and transfer direction

 If device is busy, use ack polling to wait until device ready 
 @param    addr address and transfer direction of I2C device
 @return   none
 */
extern void i2c_start_wait(unsigned char addr);

/**
 @brief Send one byte to I2C device
 @param    data  byte to be transfered
 @retval   0 write successful
 @retval   1 write failed
 */
extern unsigned char i2c_write(unsigned char data);

/**
 @brief    read one byte from the I2C device, request more data from device 
 @return   byte read from I2C device
 */
extern unsigned char i2c_readAck(void);

/**
 @brief    read one byte from the I2C device, read is followed by a stop condition 
 @return   byte read from I2C device
 */
extern unsigned char i2c_readNak(void);

/** 
 @brief    read one byte from the I2C device

 Implemented as a macro, which calls either i2c_readAck or i2c_readNak

 @param    ack 1 send ack, request more data from device<br>
               0 send nak, read is followed by a stop condition 
 @return   byte read from I2C device
 */
extern unsigned char i2c_read(unsigned char ack);

extern unsigned char ByteWriteI2C(unsigned char ControlByte, unsigned char register_address, unsigned char data);

extern unsigned char ByteReadI2C(unsigned char ControlByte, unsigned char register_address, unsigned char data);

#define i2c_read(ack)  (ack) ? i2c_readAck() : i2c_readNak();

/**@}*/
#endif

And here is twimaster.c, once again pretty much the same as Peter Fleury's except for a couple of added functions at the end.

*************************************************************************
* Title:    I2C master library using hardware TWI interface
* Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
* File:     $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target:   any AVR device with hardware TWI 
* Usage:    API compatible with I2C Software Library i2cmaster.h
**************************************************************************/
#include <inttypes.h>
#include <compat/twi.h>
#include "i2cmaster.h"
//#include <i2cmaster.h>

/* define CPU frequency in Mhz here if not defined in Makefile */
#ifndef F_CPU
#define F_CPU 14745600UL

#endif

/* I2C clock in Hz */
#define SCL_CLOCK  100000L

/*************************************************************************
 Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */

  TWSR = 0;                         /* no prescaler */
  TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */
  //TWBR = 66; // for clk speed of 99638.51351

}/* i2c_init */

/*************************************************************************  
  Issues a start condition and sends address and transfer direction.
  return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{
    uint8_t   twst;

    // send START condition
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

    // wait until transmission completed
    while(!(TWCR & (1<<TWINT)));

    // check value of TWI Status Register. Mask prescaler bits.
    twst = TW_STATUS & 0xF8;
    if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

    // send device address
    TWDR = address;
    TWCR = (1<<TWINT) | (1<<TWEN);

    // wail until transmission completed and ACK/NACK has been received
    while(!(TWCR & (1<<TWINT)));

    // check value of TWI Status Register. Mask prescaler bits.
    twst = TW_STATUS & 0xF8;
    if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

    return 0;

}/* i2c_start */

/*************************************************************************
 Issues a start condition and sends address and transfer direction.
 If device is busy, use ack polling to wait until device is ready

 Input:   address and transfer direction of I2C device
*************************************************************************/
void i2c_start_wait(unsigned char address)
{
    uint8_t   twst;

    while ( 1 )
    {
        // send START condition
        TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

        // wait until transmission completed
        while(!(TWCR & (1<<TWINT)));

        // check value of TWI Status Register. Mask prescaler bits.
        twst = TW_STATUS & 0xF8;
        if ( (twst != TW_START) && (twst != TW_REP_START)) continue;

        // send device address
        TWDR = address;
        TWCR = (1<<TWINT) | (1<<TWEN);

        // wail until transmission completed
        while(!(TWCR & (1<<TWINT)));

        // check value of TWI Status Register. Mask prescaler bits.
        twst = TW_STATUS & 0xF8;
        if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) 
        {           
            /* device busy, send stop condition to terminate write operation */
            TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

            // wait until stop condition is executed and bus released
            while(TWCR & (1<<TWSTO));

            continue;
        }
        //if( twst != TW_MT_SLA_ACK) return 1;
        break;
     }

}/* i2c_start_wait */

/*************************************************************************
 Issues a repeated start condition and sends address and transfer direction

 Input:   address and transfer direction of I2C device

 Return:  0 device accessible
          1 failed to access device
*************************************************************************/
unsigned char i2c_rep_start(unsigned char address)
{
    return i2c_start( address );

}/* i2c_rep_start */

/*************************************************************************
 Terminates the data transfer and releases the I2C bus
*************************************************************************/
void i2c_stop(void)
{
    /* send stop condition */
    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

    // wait until stop condition is executed and bus released
    while(TWCR & (1<<TWSTO));

}/* i2c_stop */

/*************************************************************************
  Send one byte to I2C device

  Input:    byte to be transfered
  Return:   0 write successful 
            1 write failed
*************************************************************************/
unsigned char i2c_write( unsigned char data )
{   
    uint8_t   twst;

    // send data to the previously addressed device
    TWDR = data;
    TWCR = (1<<TWINT) | (1<<TWEN);

    // wait until transmission completed
    while(!(TWCR & (1<<TWINT)));

    // check value of TWI Status Register. Mask prescaler bits
    twst = TW_STATUS & 0xF8;
    if( twst != TW_MT_DATA_ACK) return 1;
    return 0;

}/* i2c_write */

/*************************************************************************
 Read one byte from the I2C device, request more data from device

 Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readAck(void)
{
    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
    while(!(TWCR & (1<<TWINT)));

    return TWDR;

}/* i2c_readAck */

/*************************************************************************
 Read one byte from the I2C device, read is followed by a stop condition

 Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readNak(void)
{
    TWCR = (1<<TWINT) | (1<<TWEN);
    while(!(TWCR & (1<<TWINT)));

    return TWDR;

}/* i2c_readNak */

/*************************************************************************
     Write one byte to i2c device, to device address ControlByte, register number register_address

     Return:  one if error, 0 if success
    *************************************************************************/
unsigned char ByteWriteI2C(unsigned char ControlByte, unsigned char register_address, unsigned char data)
{
    unsigned char error;

    error = i2c_start(ControlByte);
    if(error == 1)
        return 1;
    error = i2c_write(register_address);
    if(error ==1)
        return 1;
    error = i2c_write(data);
    if(error ==1)
        return 1;
    i2c_stop();

    return 0;
}

/*************************************************************************
         Read one byte from i2c device, from device address ControlByte, register number register_address

         Return:  one if error, 0 if success
        *************************************************************************/
unsigned char ByteReadI2C(unsigned char ControlByte, unsigned char register_address, unsigned char data)
{
    unsigned char error;

    error = i2c_start(ControlByte);
    if(error ==1)
        return 1;
    error = i2c_write(register_address);
    if(error ==1)
        return 1;
    error = i2c_rep_start(ControlByte | 0x01);
    if(error ==1)
        return 1;
    data = i2c_readNak();

}

Next is MPU6050.h, which I took from Jeff Rowberg. This header just defines all the register addresses for the MPU6050.

/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2011 Jeff Rowberg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/

//#define MPU6050_ADDRESS 0b11010010 // Address with end write bit
//#define MPU6050_ADDRESS 0b11010000 // Address with end write bit
//#define MPU6050_ADDRESS 0b11010000
#define MPU6050_ADDRESS 0xD0

#define MPU6050_RA_XG_OFFS_TC 0x00 //[7] PWR_MODE, [6:1] XG_OFFS_TC, [0] OTP_BNK_VLD
#define MPU6050_RA_YG_OFFS_TC 0x01 //[7] PWR_MODE, [6:1] YG_OFFS_TC, [0] OTP_BNK_VLD
#define MPU6050_RA_ZG_OFFS_TC 0x02 //[7] PWR_MODE, [6:1] ZG_OFFS_TC, [0] OTP_BNK_VLD
#define MPU6050_RA_X_FINE_GAIN 0x03 //[7:0] X_FINE_GAIN
#define MPU6050_RA_Y_FINE_GAIN 0x04 //[7:0] Y_FINE_GAIN
#define MPU6050_RA_Z_FINE_GAIN 0x05 //[7:0] Z_FINE_GAIN
#define MPU6050_RA_XA_OFFS_H 0x06 //[15:0] XA_OFFS
#define MPU6050_RA_XA_OFFS_L_TC 0x07
#define MPU6050_RA_YA_OFFS_H 0x08 //[15:0] YA_OFFS
#define MPU6050_RA_YA_OFFS_L_TC 0x09
#define MPU6050_RA_ZA_OFFS_H 0x0A //[15:0] ZA_OFFS
#define MPU6050_RA_ZA_OFFS_L_TC 0x0B
#define MPU6050_RA_XG_OFFS_USRH 0x13 //[15:0] XG_OFFS_USR
#define MPU6050_RA_XG_OFFS_USRL 0x14
#define MPU6050_RA_YG_OFFS_USRH 0x15 //[15:0] YG_OFFS_USR
#define MPU6050_RA_YG_OFFS_USRL 0x16
#define MPU6050_RA_ZG_OFFS_USRH 0x17 //[15:0] ZG_OFFS_USR
#define MPU6050_RA_ZG_OFFS_USRL 0x18
#define MPU6050_RA_SMPLRT_DIV 0x19
#define MPU6050_RA_CONFIG 0x1A
#define MPU6050_RA_GYRO_CONFIG 0x1B
#define MPU6050_RA_ACCEL_CONFIG 0x1C
#define MPU6050_RA_FF_THR 0x1D
#define MPU6050_RA_FF_DUR 0x1E
#define MPU6050_RA_MOT_THR 0x1F
#define MPU6050_RA_MOT_DUR 0x20
#define MPU6050_RA_ZRMOT_THR 0x21
#define MPU6050_RA_ZRMOT_DUR 0x22
#define MPU6050_RA_FIFO_EN 0x23
#define MPU6050_RA_I2C_MST_CTRL 0x24
#define MPU6050_RA_I2C_SLV0_ADDR 0x25
#define MPU6050_RA_I2C_SLV0_REG 0x26
#define MPU6050_RA_I2C_SLV0_CTRL 0x27
#define MPU6050_RA_I2C_SLV1_ADDR 0x28
#define MPU6050_RA_I2C_SLV1_REG 0x29
#define MPU6050_RA_I2C_SLV1_CTRL 0x2A
#define MPU6050_RA_I2C_SLV2_ADDR 0x2B
#define MPU6050_RA_I2C_SLV2_REG 0x2C
#define MPU6050_RA_I2C_SLV2_CTRL 0x2D
#define MPU6050_RA_I2C_SLV3_ADDR 0x2E
#define MPU6050_RA_I2C_SLV3_REG 0x2F
#define MPU6050_RA_I2C_SLV3_CTRL 0x30
#define MPU6050_RA_I2C_SLV4_ADDR 0x31
#define MPU6050_RA_I2C_SLV4_REG 0x32
#define MPU6050_RA_I2C_SLV4_DO 0x33
#define MPU6050_RA_I2C_SLV4_CTRL 0x34
#define MPU6050_RA_I2C_SLV4_DI 0x35
#define MPU6050_RA_I2C_MST_STATUS 0x36
#define MPU6050_RA_INT_PIN_CFG 0x37
#define MPU6050_RA_INT_ENABLE 0x38
#define MPU6050_RA_DMP_INT_STATUS 0x39
#define MPU6050_RA_INT_STATUS 0x3A
#define MPU6050_RA_ACCEL_XOUT_H 0x3B
#define MPU6050_RA_ACCEL_XOUT_L 0x3C
#define MPU6050_RA_ACCEL_YOUT_H 0x3D
#define MPU6050_RA_ACCEL_YOUT_L 0x3E
#define MPU6050_RA_ACCEL_ZOUT_H 0x3F
#define MPU6050_RA_ACCEL_ZOUT_L 0x40
#define MPU6050_RA_TEMP_OUT_H 0x41
#define MPU6050_RA_TEMP_OUT_L 0x42
#define MPU6050_RA_GYRO_XOUT_H 0x43
#define MPU6050_RA_GYRO_XOUT_L 0x44
#define MPU6050_RA_GYRO_YOUT_H 0x45
#define MPU6050_RA_GYRO_YOUT_L 0x46
#define MPU6050_RA_GYRO_ZOUT_H 0x47
#define MPU6050_RA_GYRO_ZOUT_L 0x48
#define MPU6050_RA_EXT_SENS_DATA_00 0x49
#define MPU6050_RA_EXT_SENS_DATA_01 0x4A
#define MPU6050_RA_EXT_SENS_DATA_02 0x4B
#define MPU6050_RA_EXT_SENS_DATA_03 0x4C
#define MPU6050_RA_EXT_SENS_DATA_04 0x4D
#define MPU6050_RA_EXT_SENS_DATA_05 0x4E
#define MPU6050_RA_EXT_SENS_DATA_06 0x4F
#define MPU6050_RA_EXT_SENS_DATA_07 0x50
#define MPU6050_RA_EXT_SENS_DATA_08 0x51
#define MPU6050_RA_EXT_SENS_DATA_09 0x52
#define MPU6050_RA_EXT_SENS_DATA_10 0x53
#define MPU6050_RA_EXT_SENS_DATA_11 0x54
#define MPU6050_RA_EXT_SENS_DATA_12 0x55
#define MPU6050_RA_EXT_SENS_DATA_13 0x56
#define MPU6050_RA_EXT_SENS_DATA_14 0x57
#define MPU6050_RA_EXT_SENS_DATA_15 0x58
#define MPU6050_RA_EXT_SENS_DATA_16 0x59
#define MPU6050_RA_EXT_SENS_DATA_17 0x5A
#define MPU6050_RA_EXT_SENS_DATA_18 0x5B
#define MPU6050_RA_EXT_SENS_DATA_19 0x5C
#define MPU6050_RA_EXT_SENS_DATA_20 0x5D
#define MPU6050_RA_EXT_SENS_DATA_21 0x5E
#define MPU6050_RA_EXT_SENS_DATA_22 0x5F
#define MPU6050_RA_EXT_SENS_DATA_23 0x60
#define MPU6050_RA_MOT_DETECT_STATUS 0x61
#define MPU6050_RA_I2C_SLV0_DO 0x63
#define MPU6050_RA_I2C_SLV1_DO 0x64
#define MPU6050_RA_I2C_SLV2_DO 0x65
#define MPU6050_RA_I2C_SLV3_DO 0x66
#define MPU6050_RA_I2C_MST_DELAY_CTRL 0x67
#define MPU6050_RA_SIGNAL_PATH_RESET 0x68
#define MPU6050_RA_MOT_DETECT_CTRL 0x69
#define MPU6050_RA_USER_CTRL 0x6A
#define MPU6050_RA_PWR_MGMT_1 0x6B
#define MPU6050_RA_PWR_MGMT_2 0x6C
#define MPU6050_RA_BANK_SEL 0x6D
#define MPU6050_RA_MEM_START_ADDR 0x6E
#define MPU6050_RA_MEM_R_W 0x6F
#define MPU6050_RA_DMP_CFG_1 0x70
#define MPU6050_RA_DMP_CFG_2 0x71
#define MPU6050_RA_FIFO_COUNTH 0x72
#define MPU6050_RA_FIFO_COUNTL 0x73
#define MPU6050_RA_FIFO_R_W 0x74
#define MPU6050_RA_WHO_AM_I 0x75

And finally, here is MPU6050.c, which currently only includes functions for the setup and test of the MPU6050

#include <stdio.h>
#include "MPU6050.h"
#include <math.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "../libnerdkits/lcd.h"
#include "i2cmaster.h"
/*
#define gyro_xsensitivity 66.5 //66.5 Dead on at last check
#define gyro_ysensitivity 66.5 //72.7 Dead on at last check
#define gyro_zsensitivity 65.5
#define a 0.01

*/

void Setup_MPU6050()
{
unsigned char error;
//Sets sample rate to 1000/1+1 = 500Hz
error = ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_SMPLRT_DIV, 0x01);
if(error ==1) {
    lcd_line_four();
    lcd_write_string(PSTR("ByteWrite Fail"));
    }
else if (error == 0) {
    lcd_line_four();
    lcd_write_string(PSTR("ByteWrite Pass"));
    }
lcd_line_four();
lcd_write_string(PSTR("ByteWrite"));
//Disable FSync, 48Hz DLPF
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_CONFIG, 0x03);
//Disable gyro self tests, scale of 500 degrees/s
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_GYRO_CONFIG, 0b00001000);
//Disable accel self tests, scale of +-4g, no DHPF
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_ACCEL_CONFIG, 0b00001000);
//Freefall threshold of <|0mg|
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_FF_THR, 0x00);
//Freefall duration limit of 0
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_FF_DUR, 0x00);
//Motion threshold of >0mg
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_MOT_THR, 0x00);
//Motion duration of >0s
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_MOT_DUR, 0x00);
//Zero motion threshold
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_ZRMOT_THR, 0x00);
//Zero motion duration threshold
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_ZRMOT_DUR, 0x00);
//Disable sensor output to FIFO buffer
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_FIFO_EN, 0x00);

//AUX I2C setup
//Sets AUX I2C to single master control, plus other config
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_MST_CTRL, 0x00);
//Setup AUX I2C slaves
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV0_ADDR, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV0_REG, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV0_CTRL, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV1_ADDR, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV1_REG, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV1_CTRL, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV2_ADDR, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV2_REG, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV2_CTRL, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV3_ADDR, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV3_REG, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV3_CTRL, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV4_ADDR, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV4_REG, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV4_DO, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV4_CTRL, 0x00);
  ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV4_DI, 0x00);

  //MPU6050_RA_I2C_MST_STATUS //Read-only
  //Setup INT pin and AUX I2C pass through
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_INT_PIN_CFG, 0x00);
//Enable data ready interrupt
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_INT_ENABLE, 0x00);

//MPU6050_RA_DMP_INT_STATUS //Read-only
//MPU6050_RA_INT_STATUS 3A //Read-only
    //MPU6050_RA_ACCEL_XOUT_H //Read-only
    //MPU6050_RA_ACCEL_XOUT_L //Read-only
    //MPU6050_RA_ACCEL_YOUT_H //Read-only
    //MPU6050_RA_ACCEL_YOUT_L //Read-only
    //MPU6050_RA_ACCEL_ZOUT_H //Read-only
    //MPU6050_RA_ACCEL_ZOUT_L //Read-only
    //MPU6050_RA_TEMP_OUT_H //Read-only
    //MPU6050_RA_TEMP_OUT_L //Read-only
    //MPU6050_RA_GYRO_XOUT_H //Read-only
    //MPU6050_RA_GYRO_XOUT_L //Read-only
    //MPU6050_RA_GYRO_YOUT_H //Read-only
    //MPU6050_RA_GYRO_YOUT_L //Read-only
    //MPU6050_RA_GYRO_ZOUT_H //Read-only
    //MPU6050_RA_GYRO_ZOUT_L //Read-only
    //MPU6050_RA_EXT_SENS_DATA_00 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_01 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_02 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_03 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_04 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_05 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_06 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_07 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_08 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_09 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_10 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_11 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_12 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_13 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_14 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_15 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_16 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_17 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_18 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_19 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_20 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_21 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_22 //Read-only
    //MPU6050_RA_EXT_SENS_DATA_23 //Read-only
    //MPU6050_RA_MOT_DETECT_STATUS //Read-only

//Slave out, dont care
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV0_DO, 0x00);
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV1_DO, 0x00);
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV2_DO, 0x00);
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_SLV3_DO, 0x00);
//More slave config
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_I2C_MST_DELAY_CTRL, 0x00);
//Reset sensor signal paths
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_SIGNAL_PATH_RESET, 0x00);
//Motion detection control
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_MOT_DETECT_CTRL, 0x00);
//Disables FIFO, AUX I2C, FIFO and I2C reset bits to 0
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_USER_CTRL, 0x00);
//Sets clock source to gyro reference w/ PLL
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_PWR_MGMT_1, 0b00000010);
//Controls frequency of wakeups in accel low power mode plus the sensor standby modes
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_PWR_MGMT_2, 0x00);
    //MPU6050_RA_BANK_SEL //Not in datasheet
    //MPU6050_RA_MEM_START_ADDR //Not in datasheet
    //MPU6050_RA_MEM_R_W //Not in datasheet
    //MPU6050_RA_DMP_CFG_1 //Not in datasheet
    //MPU6050_RA_DMP_CFG_2 //Not in datasheet
    //MPU6050_RA_FIFO_COUNTH //Read-only
    //MPU6050_RA_FIFO_COUNTL //Read-only
//Data transfer to and from the FIFO buffer
ByteWriteI2C(MPU6050_ADDRESS, MPU6050_RA_FIFO_R_W, 0x00);
    //MPU6050_RA_WHO_AM_I //Read-only, I2C address

lcd_home();
lcd_write_string(PSTR("MPU6050 Setup Done"));

//printf("\nMPU6050 Setup Complete");
}

int MPU6050_Test_I2C()
{
unsigned char Data = 0x00;
ByteReadI2C(MPU6050_ADDRESS, MPU6050_RA_WHO_AM_I, Data);

if(Data == 0x68)
{
lcd_line_two();
lcd_write_string(PSTR("Read Test Passed")); 
//printf("\nI2C Read Test Passed, MPU6050 Address: 0x%x", Data);
return 0;
}
else
{
lcd_line_two();
lcd_write_string(PSTR("Read Test Failed")); 
//printf("ERROR: I2C Read Test Failed, Stopping");
//while(1){}
return 1;
}
}

I can't seem to be able to write or read from the MPU6050, and when I check the voltages of the SCL and SDA lines, SCL seems to be stuck pulled low and SDA is stuck pulled high. Anyone see anything wrong w/ my code ?(sorry I know its long, but I only changed small sections of it)

October 24, 2012
by Noter
Noter's Avatar

There is a lot of discussion and at least a few working examples of I2c here in the forum. A simple master/slave example is in the library too. Have you tried to get any of the existing examples working before jumping into your MPU6050 application?

October 25, 2012
by Ralphxyz
Ralphxyz's Avatar

Also do you have a data analyzer available. I know you are using a multimeter and thinking you are seeing stuck highs and lows but the multimeter will not see a rapid changing voltage or at best will show you an average of what it thinks it is seeing.

If you are on the east end of Long Island I'll loan you my data analyzer, it helped me when I had problems with I2C.

Ralph

October 25, 2012
by esoderberg
esoderberg's Avatar

Unnamed,

I'm using the TWI Master/Slave code posted in the library in conjunction with the MPU6050. Some of the major elements in addition to the TWI code in the library that you might find helpful posted below (an init function, calibration function, and a register read function for accel).

Eric

///////////////////////////////////////////

//inits the MPU6000 gyro control registers      
void MPU6000Gyro_init() {//
 uint8_t gyro_init=1;

 while (gyro_init){

    TWI_buffer_out[0] = 0X6B;//power managment reg
    TWI_buffer_out[1] = 0X80;//resets registers to default values (all zeros) except for reg 107(this reg!) to 0x40 (sleep mode activated) and "who am I" reg at 0x68
    TWI_master_start_write(MPU6000gyro_ADR,2);//
    delay_ms(100);

    TWI_buffer_out[0] = 0X6B;//power managment reg
    TWI_buffer_out[1] = 0X02;//sleep mode defaults on - setting that bit to zero takes it out of sleep mode // clk select also set to use y gyro axis as DS recommends
    TWI_master_start_write(MPU6000gyro_ADR,2);//NOTE to SELF ---  Other registers can't be set until out of sleep mode!!! 
    delay_ms(100);

    TWI_buffer_out[0] = 0x1A;//Low Pass Filter setting
    TWI_buffer_out[1] = 0x06;//2 set 98 hz/2.8ms delay---4 is 20Hz--5 sets 10hz Bandwidth and 13 ms delay---6 set 5hz---3 sets 42 hz
    TWI_master_start_write(MPU6000gyro_ADR,2);
    delay_ms(100);

    TWI_buffer_out[0] = 0x6A;//FIFO enable reg
    TWI_buffer_out[1] = 0x40;//Enable FIFO 
    TWI_master_start_write(MPU6000gyro_ADR,2);
    delay_ms(100);

    TWI_buffer_out[0] = 0x23;//FIFO sensor enable reg
    TWI_buffer_out[1] = 0x40;//Enable FIFO for x axis gyro
    TWI_master_start_write(MPU6000gyro_ADR,2);
    delay_ms(120);

        //routine to see if reading "Who am I"
    TWI_buffer_out[0] = 0x75;   
    TWI_master_start_write_then_read(MPU6000gyro_ADR,1,1);
    while(TWI_busy);

                    if (TWI_buffer_in[0]==0x68) {gyro_init = 0;}//0X68 (or 104) for correct "who am I"

                    else {gyro_init=1;}

                    // end of configuration and gyro status check   
                    }

                    }
////////////////////////////////////////////////////////////////////////////////////////////////////////

void cal() {
    //calibrate and init gyro values
 //////// Read Gyro //////////////

           {            //read gyro x axis (vehicle tilt), y (pitch), z (yaw)
            TWI_buffer_out[0] = 0x43;//x axis-tilt

            for(i=0; i<50; i++){
            TWI_master_start_write_then_read(MPU6000gyro_ADR, 1,6);
            while(TWI_busy);//average over 50 readings                  
        dyawinit += (TWI_buffer_in[4]<<8) + TWI_buffer_in[5];
        dtiltinit += (TWI_buffer_in[0]<<8) + TWI_buffer_in[1];}

                }
        dyawinit/=50;
        dtiltinit /= 50;    
    }

int16_t accy_read(){

int16_t accy;
                //accel read y axis (lateral on vehicle)
            TWI_buffer_out[0] = 0x3D;//accel_y
            TWI_master_start_write_then_read(MPU6000gyro_ADR, 1,2);
            while(TWI_busy);

             //Put results from accel into program variables  data comes in "two's complement" form  if MSB is 1, data is negative

            accy = ((TWI_buffer_in[0]<<8) + TWI_buffer_in[1]);

            accy=-accy/287; // divide by 16384 to put into units of g-- div by 287 to put into units of g * 57 deg/radian

            if ((accy>56)) accy=56;
            if((accy<-56)) accy=-56;
            return (accy);
            }
October 26, 2012
by unnamed0404
unnamed0404's Avatar

hey ralph, unfortunately I live about as far away as I could be from long island (I'm in CA), but thanks for the offer. I did check the voltages w/ an oscilloscope however, so it does look stuck. There seems to be a slight oscillation at a freq of 100MHz with an amplitude of a few tens of millivolts on the SCL line, not sure what that means.

Eric, thanks for your suggestion. I remember seeing a post of yours regarding using the ATmega168 w/ MPU6050, which confirmed for me that it could be done. I will try implementing those functions and see if it helps.

October 29, 2012
by unnamed0404
unnamed0404's Avatar

Per noter's suggestion, I decided to get a wii nunchuck, and just used Rick's initial code in his i2c post here: http://www.nerdkits.com/forum/thread/972/

which is definitely supposed to work. Unfortunately, I get one of the error codes when I run: "2nd start bad." It looks like the first i2c start is good, but when it goes into the while loop, the 2nd start fails. Why would it do that?

One concern of mine is that in order to connect the nunchuck up to the breadboard, I had to cut off end of the cable to access the clock and data lines, and it turns out the wires are extremely thin and in a bundle. It was rather difficult to try to stuff them into the breadboard, but i think I managed to do it, albeit sloppily. If wiring or something with my level shifter was wrong though, I would expect the first start to fail too..but it seems its only failing the 2nd.

Did any of you guys see this problem when you were implementing the nunchuck? Or any suggestions on what could be wrong?

November 06, 2012
by Ralphxyz
Ralphxyz's Avatar

Did any of you guys see this problem when you were implementing the nunchuck?

Hi unnamed0404, yep I remember getting that error, but I tend to get every possible error.

I can not remember the solution, but just wanted to encourage you to press on, the code definitely works!

Ralph

November 20, 2012
by unnamed0404
unnamed0404's Avatar

Hi Ralph,

Do you remember if you had to make changes to the actual code to make it work? Or did it have something to do with your hardware connections? I'm assuming hardware since the code has been proven to work for multiple people.

Thanks, Chris

November 20, 2012
by Ralphxyz
Ralphxyz's Avatar

If I remember correctly, I "thought" it had to be the code, but eventually figured out it was something I was doing (as usual).

It probable was wiring but I really do not remember.

The code I am sure works as is (thanks Rick).

Ralph

December 01, 2012
by unnamed0404
unnamed0404's Avatar

Yes! I finally got Rick's code working. Turns out it was the wiring. Initially I had cut up the wire and tried to manually insert them into my breadboard, but it turns out the wires were made of up many tiny wires wrapped together, so cutting it open made it messy and difficult to deal with. I bought the adapter from sparkfun and after that it worked fine.

Is there a rule of thumb you guys use for where to add those delays? Or do we just add them randomly? I noticed in Rick's code here:

http://www.nerdkits.com/forum/thread/972/

he added a 500 us delay before reading from i2c.

December 01, 2012
by Ralphxyz
Ralphxyz's Avatar

If I remember correctly the 500 us delay before reading I2C was to allow everything to settle down. Definitely not a "random" kinda thing but in this spot essential. You could probable play with the timing (350 us etc.) but a delay here is required.

Ralph

December 01, 2012
by unnamed0404
unnamed0404's Avatar

Ah i see, thanks, ill keep that in mind. So since the wii example worked, confirming my level shifter and microcontroller were working, I switched back to the MPU-6050 and made some more tweaks to the code. I was able to get a good first start, writing to the MPU-6050 and getting acknowledgement. However, when I tried to read the address register, it did not seem to give me anything. Since I got an acknowledgement for the first "i2c_start," it means the MPU-6050 should be partially working at least right?

I'm a little worried that I might have a defective chip since reading the address from it is like the very first step.

January 24, 2013
by unnamed0404
unnamed0404's Avatar

Hey Guys,

I finally got it working, so now I am reading data from the accelerometer and displaying it on the LCD.

I was wondering however, is there a better way for me to debug? Currently, for every change in code I make, I'm uploading the code to the microcontroller (therefore doing an erase and write cycle in flash memory). This seems kind of wasteful considering the microcontroller has a specified number of max erase/write cycles.

Is there an environment I can use to simulate both the MCU and MPU-6050, so that i don't have to keep programming the flash for every little change i make?

Thanks, Chris

January 24, 2013
by pcbolt
pcbolt's Avatar

Chris -

The only debug environment I've seen that may help you is the AVR Studio and the AVR Dragon programmer. There is a You Tube Video Here that show how it's set up and there is a second video in the series that shows how to do some basic debugging. I'm sure there are other emulators/debuggers but I'm not familiar with them.

January 24, 2013
by Noter
Noter's Avatar

Isn't the flash good for about 100,000 uploads? You'll probably wear out your PC before that happens and even if you reach the limit a new chip is only a few bucks. Personally I don't worry about it because I usually fry my chip long before 100K uploads anyway.

January 24, 2013
by JimFrederickson
JimFrederickson's Avatar

The "Program Flash" is good for at least 10,000 write cycles.

The "EEPROM" is good for a at least 100,000 write cycles.]

So yes if you wrote your program to your Microcontroller everyday of the year about 28 times the flash may fail in that year.

As noted there are hardware options that get around that issue/problem. (Avoid...)

But maybe using up, killing, a few extra of the DIP style chips may extend the life of the DIP style chips a little longer! (In reality the slight increase probably wouldn't have any affect, and maybe we are only using OLD STOCK now?)

I, personally, don't concern myself with that issue/problem.

I haven't had any chips fail/wear out yet... (In over 10yrs+ of using the AVR's...)

Post a Reply

Please log in to post a reply.

Did you know that NerdKits has been featured in the MIT Undergraduate Research Journal? Learn more...