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.

RTOS/TM4C123GH6PM: I2C Protocol with TI-RTOS

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: EK-TM4C123GXL

Tool/software: TI-RTOS

Hi,

I'm trying to getting data from MPU-6050 using TI-RTOS. I tried with different work arounds and debugged. Unfortunately "I2C_transfer(i2c, &i2cTransaction)" is always returning false. 

I 've found code using non-RTOS. But I want to implement with RTOS.

Please help me in this issue. 

Many Thanks in advance,

Yashwanth.

  • Please find attached code of my trail.
    Please correct me . where i'm going wrong

    /*
     * Copyright (c) 2015, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /*
     *    ======== i2crf430cl330_load.c ========
     */
    
    /* XDCtools Header files */
    #include <xdc/std.h>
    #include <xdc/runtime/Error.h>
    #include <xdc/runtime/System.h>
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/utils/Load.h>
    
    /* TI-RTOS Header files */
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/I2C.h>
    
    #include <inc/hw_memmap.h>
    #include <driverlib/gpio.h>
    #include <driverlib/i2c.h>
    #include "driverlib/sysctl.h"
    
    
    /* Example/Board Header files */
    #include "Board.h"
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #define PWMR_MGMT           0x6B
    #define MPU6050_I2C_ADDRESS 0x68
    #define MPU6050_I2C_BASE I2C3_BASE
    
    #define TASKSTACKSIZE       768
    
    
    Task_Struct task0Struct;
    Char task0Stack[TASKSTACKSIZE];
    
    
    
    struct MPU6050
    {
        uint8_t AccelXH;
        uint8_t AccelXL;
        uint8_t AccelYH;
        uint8_t AccelYL;
        uint8_t AccelZH;
        uint8_t AccelZL;
        uint8_t TempH;
        uint8_t TempL;
        uint8_t GyroXH;
        uint8_t GyroXL;
        uint8_t GyroYH;
        uint8_t GyroYL;
        uint8_t GyroZH;
        uint8_t GyroZL;
    } mpu6050;
    
    void writeRegister(I2C_Handle handle, uint16_t regAddr, uint16_t value)
    {
        uint8_t             txBuffer[4];
        I2C_Transaction     i2cTransaction;
    
        i2cTransaction.slaveAddress = MPU6050_I2C_ADDRESS;
    
        /* Write to a 16-bit status register */
        i2cTransaction.writeBuf = txBuffer;
        i2cTransaction.writeCount = 4;
        i2cTransaction.readCount = 0;
    
        txBuffer[0] = regAddr >> 8;   //HB Addr
        txBuffer[1] = regAddr & 0xFF; //LB Addr
        txBuffer[2] = value   & 0xFF;
        txBuffer[3] = value   >> 8;
    
        if (!I2C_transfer(handle, &i2cTransaction)) {
            GPIO_write(Board_LED2, Board_LED_ON);
            System_abort("Bad I2C transfer!");
        }
    }
    
    void readRegister(I2C_Handle handle,
                      uint16_t regAddr,
                      uint8_t *data,
                      size_t   length)
    {
        uint8_t             txBuffer[2];
        I2C_Transaction     i2cTransaction;
    
        i2cTransaction.slaveAddress = MPU6050_I2C_ADDRESS;
    
        /* Write to a 16-bit status register */
        i2cTransaction.writeBuf = txBuffer;
        i2cTransaction.readBuf = data;
        i2cTransaction.writeCount = 2;
        i2cTransaction.readCount = length;
    
        txBuffer[0] = regAddr >> 8;   //HB Addr
        txBuffer[1] = regAddr & 0xFF; //LB Addr
    
        if (!I2C_transfer(handle, &i2cTransaction)) {
            GPIO_write(Board_LED2, Board_LED_ON);
            System_abort("Bad I2C transfer!");
        }
    }
    
    /*
     *  ======== taskFxn ========
     *  Task for this function is created statically. See the project's .cfg file.
     */
    Void imuTask(UArg arg0, UArg arg1)
    {
        I2C_Handle i2c;
        I2C_Params i2cParams;
        unsigned int i;
    
        /* Create I2C for usage */
        I2C_Params_init(&i2cParams);
        i2cParams.bitRate = I2C_100kHz;
        i2c = I2C_open(Board_I2C_NFC, &i2cParams);
        if (i2c == NULL)
        {
            System_abort("Error Initializing I2C\n");
        }
        else
        {
            System_printf("I2C Initialized!\n");
        }
        // Initialize the MPU6050
        writeRegister(i2c,0x6B, 0x80);
        // Use PLL with X axis gyroscope reference
        writeRegister(i2c,0x6B, 0x01);
        // Enable I2C Master mode
        writeRegister(i2c,0x6A, 0x20);
        // Set sample rate divider
        writeRegister(i2c,0x19, 0x13);
        writeRegister(i2c,0x67, 0x11);
    
        GPIO_write(Board_LED0, Board_LED_OFF);
    
        for (i = 0; i < 20; i++)
        {
            while (GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_2) == GPIO_PIN_2);
            //readRegister(i2c, 0x3B, (uint8_t *)&mpu6050, 14);
            readRegister(i2c, 0x3B, (uint8_t *) &mpu6050, 14);
        }
    
        /* Deinitialized I2C */
        I2C_close(i2c);
        System_printf("I2C closed!\n");
        System_flush();
    
    }
    
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        Task_Params taskParams;
    
        /* Call board init functions */
        Board_initGeneral();
        Board_initGPIO();
        Board_initI2C();
    
        SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|
                        SYSCTL_OSC_MAIN);
    
        /* Construct nfcLoad Task thread */
        Task_Params_init(&taskParams);
        taskParams.stackSize = TASKSTACKSIZE;
        taskParams.stack = &task0Stack;
        taskParams.instance->name = "imusensor";
        taskParams.priority = 1;
        Task_construct(&task0Struct, (Task_FuncPtr)imuTask, &taskParams, NULL);
    
        GPIO_write(Board_LED0, Board_LED_ON);
    
        System_printf("Starting the I2C example\nSystem provider is set to SysMin."
                      " Halt the target to view any SysMin contents in ROV.\n");
        /* SysMin will only print to the console when you call flush or exit */
        System_flush();
    
        srand(0xBEA5);
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }
    

  • Yashwanth,

    Your usage of the I2C APIs are correct. I suspect that the MPU6050 is not acknowledging the slave address.

    You should inspect your I2C bus using a logic analyzer to further debug.

    Regards,
    Derrick
  • After you reset the MPU6050 with a write of 0x80 to register 0x6B, you need to let the device finish its reset sequence before you disable sleep mode and set the clock with the write of 0x01 to 0x6B. One way of doing this is to read register 0x6B until you read that the sleep bit is set (0x40). Then write 0x01.

    (Corrected 0x68 to 0x6B on Nov 9, 2018)

  • As you suggested : After writing 0x80 to register 0x68. I tried with do- while loop to get the register value of register 0x68. I read the register 0x68 as 0x7f . It means that sleep bit is set 1 is it?
    Even after that, If it try to read the register 14 registers from 0x3B I'm getting 7F 02 CF E3 14 EC B4 F6 AD...values continuosly even by changing the position of the sensor.

    Regards,
    Yashwanth Kumar Gandeti
  • I am sorry. The slave address is 0x68, but the address of the Power Management register is 0x6B. (To my old eyes they looked the same.) Write 0x80 to register 0x6B. Then read register 0x6B. You should get 0x00 a few times then 0x40. After you read 0x40, write 0x01 to that register. Here is a non-RTOS example that works:

    /cfs-file/__key/communityserver-discussions-components-files/908/6646.MPU6050_2D00_2.zip

  • i2cmpu6050.zipHi Bob Crosby,

    First of all thanks for your patience and replying to my queries

    The registers were correct.

    Please find my attached RTOS  code and help me.

    Note: most of the times I2C_Transfer() is false.

    Thanks and Regards,

    Yashwanth

  • OK, I think I see the problem. The MPU-6050 register addresses and commands are 8 bit, not 16 bit. Here is what your code wrote:

    It actually wrote 0x6B to register 0 and 0x80 to register 1 and 0x00 to register 2. It should look like this:

    Now you see it read 0x40 from register 0x6B. Here are some simple modifications to your writeRegister and readRegister routines.

    void writeRegister(I2C_Handle handle, uint16_t regAddr, uint16_t value)
    {
        uint8_t             txBuffer[4];
        I2C_Transaction     i2cTransaction;
    
        i2cTransaction.slaveAddress = MPU6050_I2C_ADDRESS;
    
        /* Write to a 16-bit status register */
        i2cTransaction.writeBuf = txBuffer;
        i2cTransaction.writeCount = 2;
        i2cTransaction.readCount = 0;
    
        txBuffer[0] = regAddr & 0xFF; //LB Addr
        txBuffer[1] = value   & 0xFF;
    
        if (!I2C_transfer(handle, &i2cTransaction)) {
            GPIO_write(Board_LED2, Board_LED_ON);
            System_abort("Bad I2C transfer!");
        }
    }
    
    void readRegister(I2C_Handle handle,
                      uint16_t regAddr,
                      uint8_t *data,
                      size_t   length)
    {
        uint8_t             txBuffer[2];
        I2C_Transaction     i2cTransaction;
    
        i2cTransaction.slaveAddress = MPU6050_I2C_ADDRESS;
    
        /* Write to a 16-bit status register */
        i2cTransaction.writeBuf = txBuffer;
        i2cTransaction.readBuf = data;
        i2cTransaction.writeCount = 1;
        i2cTransaction.readCount = length;
    
        txBuffer[0] = regAddr & 0xFF; //LB Addr
    
        if (!I2C_transfer(handle, &i2cTransaction)) {
            GPIO_write(Board_LED2, Board_LED_ON);
            System_abort("Bad I2C transfer!");
        }
    }
    

  • Dear Bob Crosby,

    Thanks a lot for your debugging and sharing a code. It really helped me.

    I have encountered one problem. If i run the code in normal run and tap the i2c lines using Oscilloscope I'm able to see the data on the SDA line. When I try to debug the code to get values in Expressions window most of the times I2C_Transfer() called in first writeRegister() itself returning false and data in oscilloscope is always zero. Do you have any idea why its behaving like this?

    This zero values were continuous even after reset button press. If I unplug the board and connect then its working fine.

    Note:To check if any I2C_Transfer() is failed, i'm turning on the LED. so that the LED is turning on just after the first call of I2C_Transfer.

    Hope your explanation will give me clear idea on this issue and how it works.

    Once again Thanks a lot for your help.

    Regards,
    Yashwanth.
  • It sounds like the MPU-6050 is confused. When you unplug the board, does it power down the MPU-6050 too? The problem may be that the MPU-6050 does not handle the I2C commands being suspended when you have breakpoints in the code.
  • Yeah. When i unplug mpu 6050 is powering down. But when I reset mpu 6050 is not resetting ( I mean led on mpu 6050 is not blinking)

  • When ever i press the reset button on Launchpad . I2C Communication is going to "I2C Bad Transfer". This will continue until i unplug and plug in the launch pad. After powering up it will work normallly.
    Bob Crosby,Can you please help me on this issue?

    Regards,
    Yashwanth Kumar Gandeti
  • I can reproduce your problem. Since you are doing continuous reads, when you press reset on the EK-TM4C123GXL, the I2C communication is halted in the middle of an operation. It looks like the MPU6050 is responding by holding SDA low. This prevents further I2C communication.

    First, let me remind you that the MPU6050 is not a TI part and I am not an expert on that part.

    To minimize the impact, I suggest that you not do continuous reads. By configuring the INT pin as an output and sampling it, (or using it as an interrupt) you can minimize the number of reads to only when a new reading is computed. That minimizes the issue, but does not solve it. I will play with it a bit and see if I can force the I2C interface by bit-banging the I2C SCL if SDA is held low when coming out of reset.
  • Thanks a lot Bob Crosby,
    I have completely satisfied with your clear explanations on topics.

    Regards,
    Yashwanth Kumar Gandeti
  • Here is the code (lines added between "Board_initGPIO()" and "Board_initI2C()") that I added to resolve when the MPU6050 is holding SDA low.

    int main(void)
    {
        Task_Params taskParams;
    
        /* Call board init functions */
        Board_initGeneral();
        Board_initGPIO();
        // Check that I2C SDA is not being held low
        // If so, toggle I2C SCL until it is released
        GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_1);
        GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_0);
        while(GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_1) != GPIO_PIN_1)
        {
            GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0);
            GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, GPIO_PIN_0);
        }
        Board_initI2C();
    
        SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|
                        SYSCTL_OSC_MAIN);
    
        /* Construct nfcLoad Task thread */
        Task_Params_init(&taskParams);
        taskParams.stackSize = TASKSTACKSIZE;
        taskParams.stack = &task0Stack;
        taskParams.instance->name = "imusensor";
        taskParams.priority = 1;
        Task_construct(&task0Struct, (Task_FuncPtr)imuTask, &taskParams, NULL);
    
        GPIO_write(Board_LED0, Board_LED_ON);
    
        System_printf("Starting the I2C example\nSystem provider is set to SysMin."
                      " Halt the target to view any SysMin contents in ROV.\n");
        /* SysMin will only print to the console when you call flush or exit */
        System_flush();
    
        srand(0xBEA5);
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }
    

    The pulse in SCL is so short that it is basically hidden by the trigger line but you can see that it causes the MPU6050 to let SDA go high.

  • I'm very much thankful to you Bob Crosby. You cleared all the issues regarding this problem. your code snippets helped me a lot.
    Your continuous support and follow up to the issue is marvelous.
    Thanks TI.

    Regards,
    Yashwanth Kumar Gandeti.