This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C129 and MPU6050 I2C

Other Parts Discussed in Thread: TM4C1230E6PM

Hi everyone!

I have been trying to read sensor data with my TM4C129 from an MPU6050 but I am having problems with I2C. I only have experience with Arduinos and this is the first time I try to use I2C and CCS so please bear with me if my question is silly. I am having problems with my code which starts looping forever at the first "while(!g_bMPU6050Done)" loop in the function "MPU6050Example"  , and this happens also if the I2C pins are not connected at all. I am using 10k pull up resistors, I took my code for the most part from the Tivaware sensor library user's guide, i think i am making a mistake somewhere where I initialize the I2C master instance. I tried to look online and on the forum but I couldnt find anything helpful, can somebody please help?

 

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include "sensorlib/i2cm_drv.h"
#include "sensorlib/hw_mpu6050.h"
#include "sensorlib/mpu6050.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_types.h"
#include "inc/hw_i2c.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "driverlib/i2c.h"
#include "driverlib/i2c.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"

tI2CMInstance g_sI2CMSimpleInst;

void InitI2C0(void)
{
    //enable I2C module 0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

    //reset module
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);

    //enable GPIO peripheral that contains I2C 0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    // Configure the pin muxing for I2C0 functions on port B2 and B3.
    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);

    // Select the I2C function for these pins.
    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);

    // Enable and initialize the I2C0 master module.  Use the system clock for
    // the I2C0 module. 
// I2C data transfer rate set to 400kbps. I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), true); //clear I2C FIFOs HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;

// Initialize the I2C master driver. I2CMInit(&g_sI2CMSimpleInst, I2C0_BASE, INT_I2C0, 0xff, 0xff, 120000000); } // // A boolean that is set when a MPU6050 command has completed. // volatile bool g_bMPU6050Done; // // The function that is provided by this example as a callback when MPU6050 // transactions have completed. // void MPU6050Callback(void *pvCallbackData, uint_fast8_t ui8Status) { // // See if an error occurred. // if(ui8Status != I2CM_STATUS_SUCCESS) { // // An error occurred, so handle it here if required. // } // // Indicate that the MPU6050 transaction has completed. // g_bMPU6050Done = true; } // // The MPU6050 example. // void MPU6050Example(void) { float fAccel[3], fGyro[3]; tI2CMInstance sI2CInst; tMPU6050 sMPU6050; // // Initialize the MPU6050. This code assumes that the I2C master instance // has already been initialized. // g_bMPU6050Done = false; MPU6050Init(&sMPU6050, &sI2CInst, 0x68, MPU6050Callback, 0); while(!g_bMPU6050Done) { } // // Configure the MPU6050 for +/- 4 g accelerometer range. // g_bMPU6050Done = false; MPU6050ReadModifyWrite(&sMPU6050, MPU6050_O_ACCEL_CONFIG, ~MPU6050_ACCEL_CONFIG_AFS_SEL_M, MPU6050_ACCEL_CONFIG_AFS_SEL_4G, MPU6050Callback,0); while(!g_bMPU6050Done) { } // // Loop forever reading data from the MPU6050. Typically, this process // would be done in the background, but for the purposes of this example, // it is shown in an infinite loop. // while(1) { // // Request another reading from the MPU6050. // g_bMPU6050Done = false; MPU6050DataRead(&sMPU6050, MPU6050Callback, 0); while(!g_bMPU6050Done) { } // // Get the new accelerometer and gyroscope readings. // MPU6050DataAccelGetFloat(&sMPU6050, &fAccel[0], &fAccel[1], &fAccel[2]); MPU6050DataGyroGetFloat(&sMPU6050, &fGyro[0], &fGyro[1], &fGyro[2]); // // Do something with the new accelerometer and gyroscope readings. // } } int main() { InitI2C0(); MPU6050Example(); return(0); }

  • I have used the I2C scanner code from this http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/381101.aspx and the microcontroller recognises the sensor at address 0x68 as it should, so I guess my wiring is correct and the I2C is initialized correctly, but the code in the previous post still gets stuck at the first "while(!g_bMPU6050Done)".

  • Hello Frederico,

    Can you please replace the line

            MPU6050Init(&sMPU6050, &sI2CInst, 0x68, MPU6050Callback, 0);

    with

            MPU6050Init(&sMPU6050, &g_sI2CMSimpleInst, 0x68, MPU6050Callback, 0);

    Regards

    Amit

  • Hi Amit,

    Thanks for your help. I have just done as you said, I have also deleted "tI2CMInstance sI2CInst" (since I was not using it), keeping the rest of the code exactly the same but the code still gets stuck at the first "while(!g_bMPU6050Done)". Since this code uses the I2C master driver library from the sensor library user's guide, is it possible that I am missing something from there?

  • Hello Federico,

    There are some gaps in the code that may be the cause.

    1. The function to set the System Clock has not been called. Thus the last parameter is not correct. It must be 16000000

    I2CMInit(&g_sI2CMSimpleInst, I2C0_BASE, INT_I2C0, 0xff, 0xff, 120000000);

    2. The SysCtlClockGet function is valid for TM4C123. This must be replaced by 16000000 unless you have the SysCtlClockFreqSet function called someplace else, in which case the function will return the value of the system clock

    I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), true);

    3. The MPU6050 functions have the last parameter as a pointer to the call back which has been replaced by the 0. Any reason why?

    Regards

    Amit

  • Hi Amit,

    I have substituted 16000000 in the two functions you mentioned in point 1 and 2 but the code is still not working. Regarding point 3 I have simply copied the code with the mpu6050 functions directly from the TI sensor library user's guide in the section called "programming example", where I did not change anything. According to the guide once the I2C master instance has been initialized this code should initialize the MPU6050, set the +/-4g range for the accelerometer, and read accelerometer and rotation data from it. This is the link to the guide http://www.ti.com/lit/ug/spmu371/spmu371.pdf , the code is on pages 114,115 and 116. 

  • I have been reading the libraries and done more research online and changed the code but it is still not working, getting stuck at the first "while (!g_bMPU6050Done)".  I made some changes to the code according to Amit's suggestions, I have also included a function that calls the I2C master interrupt handler and now the MPU6050 does not have a 0 instead of the callback function. This is the latest version of the code I have been trying to use without much success...
    #include <stdbool.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdbool.h>
    #include "sensorlib/i2cm_drv.h"
    #include "sensorlib/hw_mpu6050.h"
    #include "sensorlib/mpu6050.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_sysctl.h"
    #include "inc/hw_types.h"
    #include "inc/hw_i2c.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/debug.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/i2c.h"
    #include "driverlib/sysctl.h"
    
    
    //
    // A boolean that is set when a MPU6050 command has completed.
    //
    volatile bool g_bMPU6050Done;
    
    //
    // I2C master instance
    //
    tI2CMInstance g_sI2CMSimpleInst;
    
    //
    //Device frequency
    //
    int clockFreq;
    
    void InitI2C0(void)
    {
    	//enable I2C module 0
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    
    	//reset module
    	SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
    
    	//enable GPIO peripheral that contains I2C 0
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    
    	// Configure the pin muxing for I2C0 functions on port B2 and B3.
    	GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    	GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    
    	// Select the I2C function for these pins.
    	GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    	GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    
    	// Enable and initialize the I2C0 master module.  Use the system clock for
    	// the I2C0 module.    
    	// I2C data transfer rate set to 400kbps.
    	I2CMasterInitExpClk(I2C0_BASE, clockFreq, true);
    
    	//clear I2C FIFOs
    	HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;
    
    	// Initialize the I2C master driver.
    	I2CMInit(&g_sI2CMSimpleInst, I2C0_BASE, INT_I2C0, 0xff, 0xff, clockFreq);
    
    }
    
    //
    // The function that is provided by this example as a callback when MPU6050
    // transactions have completed.
    //
    void MPU6050Callback(void *pvCallbackData, uint_fast8_t ui8Status)
    {
    	//
    	// See if an error occurred.
    	//
    	if (ui8Status != I2CM_STATUS_SUCCESS)
    	{
    		//
    		// An error occurred, so handle it here if required.
    		//
    	}
    	//
    	// Indicate that the MPU6050 transaction has completed.
    	//
    	g_bMPU6050Done = true;
    }
    
    //
    // The interrupt handler for the I2C module.
    //
    void I2CMSimpleIntHandler(void)
    {
    	//
    	// Call the I2C master driver interrupt handler.
    	//
    	I2CMIntHandler(&g_sI2CMSimpleInst);
    }
    
    //
    // The MPU6050 example.
    //
    void MPU6050Example(void)
    {
    	float fAccel[3], fGyro[3];
    	tMPU6050 sMPU6050;
    	//
    	// Initialize the MPU6050. This code assumes that the I2C master instance
    	// has already been initialized.
    	//
    	g_bMPU6050Done = false;
    	MPU6050Init(&sMPU6050, &g_sI2CMSimpleInst, 0x68, MPU6050Callback, &sMPU6050);
    	while (!g_bMPU6050Done)
    	{
    	}
    	//
    	// Configure the MPU6050 for +/- 4 g accelerometer range.
    	//
    	g_bMPU6050Done = false;
    	MPU6050ReadModifyWrite(&sMPU6050, MPU6050_O_ACCEL_CONFIG,
    		~MPU6050_ACCEL_CONFIG_AFS_SEL_M,
    		MPU6050_ACCEL_CONFIG_AFS_SEL_4G, MPU6050Callback, &sMPU6050);
    	while (!g_bMPU6050Done)
    	{
    	}
    	//
    	// Loop forever reading data from the MPU6050. Typically, this process
    	// would be done in the background, but for the purposes of this example,
    	// it is shown in an infinite loop.
    	//
    	while (1)
    	{
    		//
    		// Request another reading from the MPU6050.
    		//
    		g_bMPU6050Done = false;
    		MPU6050DataRead(&sMPU6050, MPU6050Callback, &sMPU6050);
    		while (!g_bMPU6050Done)
    		{
    		}
    		//
    		// Get the new accelerometer and gyroscope readings.
    		//
    		MPU6050DataAccelGetFloat(&sMPU6050, &fAccel[0], &fAccel[1],
    			&fAccel[2]);
    		MPU6050DataGyroGetFloat(&sMPU6050, &fGyro[0], &fGyro[1], &fGyro[2]);
    		//
    		// Do something with the new accelerometer and gyroscope readings.
    		//
    	}
    }
    
    int main()
    {
    	clockFreq = SysCtlClockFreqSet(SYSCTL_OSC_INT | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480, 120000000);
    	InitI2C0();
    	MPU6050Example();
    	return(0);
    }

  • Hello Federico

    Give me a few days to test the final code post...Hopefully I should have answers for you next week.

    Regards

    Amit

  • Thank you very much Amit! I am really curious to know what is the problem.

  • Finally I have managed to solve the problem! I think my MPU6050 was faulty, I tested the I2C bus with an oscilloscope and i saw that the sensor was not responding properly so I ordered a new one and now its working perfectly!

  • Hello Frederico

    Thanks for posting it back and my apologies I could not get back to you with the SW program validity on time.

    But glad you figured it out to a faulty slave device.

    Regards

    Amit

  • Hello everyone,

    Sorry for re-open the old topic. I also use an Tiva TM4C1294

    However, I'm meeting a problem like that:

    "When I try to use the clock 120Mhz for all configuration, I could not receive the signal from MPU6050.

    SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);
    I2CMInit(&g_sI2CInst,I2C0_BASE,INT_I2C0, 0xff,0xff,120000000);

    It's is correct in 16Mhz.

    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    I2CMInit(&g_sI2CInst,I2C0_BASE,INT_I2C0, 0xff,0xff,16000000);

    Thus, the question is: How can I modify the input clock for I2C which is suitable for MPU6050?

    Or Can I do that:  

    Freq = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000
    I2CMInit(&g_sI2CInst,I2C0_BASE,INT_I2C0, 0xff,0xff, Freg / 6);  //120MHz / 6 = 20 MHz

    -Phu

  • Phu,


    The I2C should work with ~all valid CPU frequencies. Could you show the actual I2C code you use to access the MPU6050?

    If you use code without interrupts, then I suspect you might have the while(I2CMasterBusy()) delay problem - (because of the clock speed difference between the CPU and I2C?) the busy flag won't be immediately set. If this is the case, the fix is to first wait for the busy flag to become active [ while(!I2CMasterBusy()); ] and then do the "traditional" busy wait after that.

    Hope this helps,

    Veikko

  • Hello,

    excuse me.

    I am trying to read MPU-6050 with TM4C1230E6PM using I2C0.

    The keil uVision source code is the below.

    I succeed reading but all of sensing values are zero value.

    Would you tell me what I miss? or would you send me correctly operating source code?

    Thanks in advance.

    Below is my source code

    --------------------------- below --------------------------

    #include <stdbool.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdbool.h>
    #include "sensorlib/i2cm_drv.h"
    #include "sensorlib/hw_mpu6050.h"
    #include "sensorlib/mpu6050.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_sysctl.h"
    #include "inc/hw_types.h"
    #include "inc/hw_i2c.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/debug.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/i2c.h"
    #include "driverlib/sysctl.h"
    #include "utils/uartstdio.h"
    #include "driverlib/uart.h"

    //
    // A boolean that is set when a MPU6050 command has completed.
    //
    volatile bool g_bMPU6050Done = true;
    tI2CMInstance sI2CInst;
    tMPU6050 sMPU6050;

    void DelaySoft(volatile unsigned long ulDelay){
      ROM_SysCtlDelay((ROM_SysCtlClockGet() / 10000) * ulDelay);
    }

    //
    // The interrupt handler for the I2C module.
    //
    void I2CMSimpleIntHandler(void)
    {
      //
      // Call the I2C master driver interrupt handler.
      //
      I2CMIntHandler(&sI2CInst);
    }

    void InitI2C0(void)
    {
      //enable I2C module 0
      SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

      //enable GPIO peripheral that contains I2C 0
      SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

      // Configure the pin muxing for I2C0 functions on port B2 and B3.
      GPIOPinConfigure(GPIO_PB2_I2C0SCL);
      GPIOPinConfigure(GPIO_PB3_I2C0SDA);

      // Select the I2C function for these pins.
      GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
      GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);

      I2CIntRegister(I2C0_BASE, &I2CMSimpleIntHandler);
      ROM_IntMasterEnable();

      // Initialize the I2C master driver.
      I2CMInit(&sI2CInst, I2C0_BASE, INT_I2C0, 0xff, 0xff, ROM_SysCtlClockGet());
    }

    // The function that is provided by this example as a callback when I2C transactions have completed.
    void MPU6050Callback(void *pvData, uint_fast8_t ui8Status) {
      // See if an error occurred.
      if(ui8Status != I2CM_STATUS_SUCCESS) {
        // An error occurred, so handle it here if required.
        UARTprintf("mpu6050 callback error\n");
      }

      // Indicate that the I2C transaction has completed.
      g_bMPU6050Done = true;
    }

    //*****************************************************************************
    // UARTstdio 유틸리티를 사용하기 위한 UART 설정
    //*****************************************************************************
    void ConfigureUART(void)
    {
    // UART로 사용될 GPIO 포트 활성화
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    // UART0 Peripheral 활성화
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    // GPIO 핀들을 UART mode로 변경
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    // 16MHz 내부 오실레이터를 UART clock source로 사용
    ROM_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    // Colsole I/O를 위한 UART 초기화
    UARTStdioConfig(0, 115200, 16000000);
    }

    char buf[100];
    char* ftoa(float f)
    {
    int pos=0,ix,dp,num;
    if (f<0)
    {
    buf[pos++]='-';
    f = -f;
    }
    dp=0;
    while (f>=10.0)
    {
    f=f/10.0;
    dp++;
    }
    for (ix=1;ix<8;ix++)
    {
    num = (int)f;
    f=f-num;
    if (num>9)
    buf[pos++]='#';
    else
    buf[pos++]='0'+num;
    if (dp==0) buf[pos++]='.';
    f=f*10.0;
    dp--;
    }
    return buf;
    }

    void MPU6050Example(void) {
      float fAccel[3], fGyro[3];

      UARTprintf("MPU6050 initialization\n");
       // Write two bytes of data to the I2C device at address 0x3C.
      g_bMPU6050Done = false;
      uint_fast8_t result = MPU6050Init(&sMPU6050, &sI2CInst, 0x68, MPU6050Callback, 0);
      while(!g_bMPU6050Done) {
      }

      UARTprintf("Configure the MPU6050 for +/- 4 g accelerometer range\n");
      // Read four bytes of data from the I2C device at address 0x3C.
      g_bMPU6050Done = false;
      MPU6050ReadModifyWrite(&sMPU6050, MPU6050_O_ACCEL_CONFIG, ~MPU6050_ACCEL_CONFIG_AFS_SEL_M,
      MPU6050_ACCEL_CONFIG_AFS_SEL_4G, MPU6050Callback, 0);
      while(!g_bMPU6050Done) {
      }

      // loop forever reading data from the MPU6050
      while(1) {
        // Request another reading from the MPU6050
        g_bMPU6050Done = false;
        MPU6050DataRead(&sMPU6050, MPU6050Callback, 0);
        while(!g_bMPU6050Done) {
        }

        // Get the new accelerometer and gyroscope readings.
        MPU6050DataAccelGetFloat(&sMPU6050, &fAccel[0], &fAccel[1], &fAccel[2]);
        MPU6050DataGyroGetFloat(&sMPU6050, &fGyro[0], &fGyro[1], &fGyro[2]);

        UARTprintf("complete data receive from MPU6050\n");
        UARTprintf("Accel x = %s", ftoa(fAccel[0]));
        UARTprintf(", y = %s", ftoa(fAccel[1]));
        UARTprintf(", z = %s\n", ftoa(fAccel[2]));
        UARTprintf("Gyro x = %s", ftoa(fGyro[0]));
        UARTprintf(", y = %s", ftoa(fGyro[1]));
        UARTprintf(", z = %s\n", ftoa(fGyro[2]));

        DelaySoft(1000);
      }
    }

    int main()
    {
      //
      // Setup the system clock to run at 40 MHz from PLL with crystal reference
      //
      ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

      // UARTprintf()를 사용하기위한 Utility
      ConfigureUART();

      // Print start
      UARTprintf("\nConfigure UART\n");

      InitI2C0();

      MPU6050Example();

      return(0);
    }

  • Hi KYUNGSUBSEO,
    You have to check some following problems:

    1. The clock of UART should be the same with the system clock.

    2. It may be like that: MPU6050Init(&g_sMPU6050Inst, &g_sI2CInst, MPU6050_I2C_ADDRESS,MPU6050AppCallback, &g_sMPU6050Inst);

    3. You should understand clearly the I2C communication,

    Write the value into MPU6050_O_PWR_MGMT_1 register and MPU6050_O_SMPLRT_DIV register.

    MPU6050Write(&g_sMPU6050Inst, MPU6050_O_PWR_MGMT_1, MPU6050_PWR_MGMT_1_CLKSEL_INT, 1,
    MPU6050AppCallback, &g_sMPU6050Inst);
    
    MPU6050Write(&g_sMPU6050Inst, MPU6050_O_SMPLRT_DIV, MPU6050_SMPLRT_DIV_S, 1,
    MPU6050AppCallback, &g_sMPU6050Inst);

    Best regards,

    Mr Phu.

  • Hello please explain to me how you solve this problem and also can you explain how you connected wires between mpu6050 and your launchpad
  • Hi Amit, could you help me please?

    I'm doing the same code from TI sensor library user's guide like Federico, but the datas always returns zeros...

    Thank you.