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.

CCS/MSP432P401R: Issue with I2C communication with MPU6050 - How to ensure device's presence?

Part Number: MSP432P401R

Tool/software: Code Composer Studio

Hello

I am new to CCS and MSP432 as well. I'm trying to communicate with the MPU6050 using the EUSCI-B0 module. I have the following connections in hardware:

 *  ACLK = n/a, MCLK = HSMCLK = SMCLK = BRCLK = default DCO = ~3.0MHz
 *
 *                                /|\  /|\
 *                MPU6050         4.7k  4.7k      MSP432P401
 *                   slave         |    |         master
 *             -----------------   |    |   -----------------
 *            |              SDA|<-|----+->|P1.6/UCB3SDA     |
 *            |                 |  |       |                 |
 *            |                 |  |       |                 |
 *            |              SCL|<-+------>|P1.7/UCB3SCL     |
 *            |                 |          |                 |
 *
MPU6050 has AD0 pin connected to ground meaning that 7-bit SLAVE_ADDRESS = 0x68;
I have tried several configurations and several examples of the I2C code but still cannot get it to work, probably because of my lack of understanding on the following issues:
1. The MPU6050 has a default internal clock set to 8MHz at start up. Does this have something to do with the frequency I assign to my master I2C side (MSP432)? As I understand, I2C uses the SCL signal itself to clock the SDA so, this should not be a problem.
2. I am using UART0 (EUSCI-A0 port 1 pins 2,3) and UART2 (EUSCI_A2 port3 pins 2,3) as well. Somehow, even my interrupts for the UART0 do not work for typed in values from the keyboard even though I am able to write (using prinft) to UART0 module. Does this in any way effect the use of EUSCI_B0 module which is at the same port (port1, pins 6,7)?
Here is my code that is largely borrowed from the examples at the following links and other forums:
"forum.43oh.com/.../"
I am unable to read/write to I2C slave device. I have tried to analyze using a logic analyzer but it seems like the sent byte is never acknowledged. Also, it seems like the device does not send the data that I try to load into the TXData. The members at forum questions above say that their code is working with some problems but for me, it seems to not work at all. I appreciate any help debugging it. Please Note that currently, I am just trying to give a single address inTXData[0] = 0x3B and hoping to read from it into RXData[0].

/*******************************************************************************/
/* DriverLib Includes */
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

/* Standard Includes */
#include <stdint.h>

#include <stdbool.h>
#include <printf.h>
#include <time.h>

#define RED     255
#define GREEN   255
#define BLUE    255

#define MCLK_FREQUENCY 12000000
#define PWM_PERIOD (MCLK_FREQUENCY/5000)

#define SLAVE_ADDRESS             0x68
#define NUM_OF_REC_BYTES    14

/* UART Configuration Parameter. These are the configuration parameters to
 * make the eUSCI A UART module to operate with a 9600 baud rate. These
 * values were calculated using the online calculator that TI provides
 * at:
 *software-dl.ti.com/.../index.html
 */

/* Statics  for I2C working with the MPU6050 sensor*/
int i = 0;
uint8_t TXData[16] = {0x6B,0x00,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48};
static uint8_t RXData[NUM_OF_REC_BYTES];
static volatile bool stopSent;
static uint8_t TXByteCtr;
unsigned int iter=0;


void EUSCIA0_IRQHandler(void);

const uint8_t port_mapping[] =
{
    //Port P2:
    PM_TA0CCR1A, PM_TA0CCR2A, PM_TA0CCR3A, PM_NONE, PM_TA1CCR1A, PM_NONE, PM_NONE, PM_NONE
};

const eUSCI_UART_Config uartConfig =
{
        EUSCI_A_UART_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
        78,                                     // BRDIV = 78
        2,                                       // UCxBRF = 2
        0,                                       // UCxBRS = 0
        EUSCI_A_UART_NO_PARITY,                  // No Parity
        EUSCI_A_UART_LSB_FIRST,                  // MSB First
        EUSCI_A_UART_ONE_STOP_BIT,               // One stop bit
        EUSCI_A_UART_MODE,                       // UART mode
        EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION  // Oversampling
};


/* I2C Master Configuration Parameter */
const eUSCI_I2C_MasterConfig i2cConfig =
{
        EUSCI_B_I2C_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
        3000000,                                // SMCLK = 3MHz
        EUSCI_B_I2C_SET_DATA_RATE_100KBPS,      // Desired I2C Clock of 100khz
        0,                                      // No byte counter threshold
        EUSCI_B_I2C_NO_AUTO_STOP                // No Autostop
};



int main(void){

    /* Halting WDT and disabling master interrupts */
        MAP_WDT_A_holdTimer();
        //MAP_Interrupt_disableMaster();

   /* Setting DCO to 12MHz */
        //CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12);


   // Set P1.0 to output direction
        GPIO_setAsOutputPin(
            GPIO_PORT_P1,
            GPIO_PIN0
            );

        MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);


    /* Selecting P1.2 and P1.3 in UART mode and P1.0 as output (LED) */
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
            GPIO_PIN1 |GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);

    /* Selecting P3.2 and P3.3 in UART mode */
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3,
                    GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);

    /* Select Port 1 for I2C - Set Pin 6, 7 to Secondary Module Function,
             *   (UCB3SIMO/UCB3SDA, UCB3SOMI/UCB3SCL).
             */
       MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
                    GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);



    /* Initialize main clock to 12MHz */
        MAP_CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12);
        MAP_CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
        MAP_CS_initClockSignal(CS_HSMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
        MAP_CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );

    /* Configuring UART Module */
        MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig);

        MAP_UART_initModule(EUSCI_A2_BASE, &uartConfig);

    /* Initializing I2C Master to SMCLK at 400khz with no autostop */
       MAP_I2C_initMaster(EUSCI_B0_BASE, &i2cConfig);

   /* Specify slave address */
       MAP_I2C_setSlaveAddress(EUSCI_B0_BASE, SLAVE_ADDRESS);

   /* Set Master in transmit mode */
      MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

    /* Enable UART module */
        MAP_UART_enableModule(EUSCI_A0_BASE);

        MAP_UART_enableModule(EUSCI_A2_BASE);


        //UART_registerInterrupt(EUSCI_A0_BASE, EUSCIA0_IRQHandler);

    /* Enable I2C Module to start operations */
           MAP_I2C_enableModule(EUSCI_B0_BASE);

    /* GPIO Setup for Pins 2.0-2.2 */
        MAP_PMAP_configurePorts((const uint8_t *) port_mapping, PMAP_P2MAP, 1,
            PMAP_DISABLE_RECONFIGURATION);

        MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2,
            GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION);

        /* Confinguring P1.1 & P1.4 as an input and enabling interrupts */
        MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
        MAP_GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
        MAP_GPIO_interruptEdgeSelect(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);

        /* Configure TimerA0 without Driverlib (CMSIS style register access) */
        TIMER_A0->CCR[0] = PWM_PERIOD;
        TIMER_A0->CCTL[1] = TIMER_A_CCTLN_OUTMOD_7;                      // CCR1 reset/set
        TIMER_A0->CCR[1] = PWM_PERIOD * (RED/255);         // CCR1 PWM duty cycle
        TIMER_A0->CCTL[2] = TIMER_A_CCTLN_OUTMOD_7;                      // CCR2 reset/set
        TIMER_A0->CCR[2] = PWM_PERIOD * (0/255);           // CCR2 PWM duty cycle
        TIMER_A0->CCTL[3] = TIMER_A_CCTLN_OUTMOD_7;                      // CCR3 reset/set
        TIMER_A0->CCR[3] = PWM_PERIOD * (0/255);           // CCR3 PWM duty cycle
        TIMER_A0->CTL = TIMER_A_CTL_SSEL__SMCLK | TIMER_A_CTL_MC__UP | TIMER_A_CTL_CLR;  // SMCLK, up mode, clear TAR


        /* Configure and enable SysTick */
        MAP_SysTick_setPeriod(1500000);
        MAP_SysTick_enableModule();
        MAP_SysTick_enableInterrupt();

        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
        MAP_Interrupt_enableInterrupt(INT_PORT1);

        /* Enable and clear the interrupt flag */
           MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE,
               EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_NAK_INTERRUPT);

    /* Enabling interrupts */
    MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT | EUSCI_A_UART_RECEIVE_ERRONEOUSCHAR_INTERRUPT
                             | EUSCI_A_UART_BREAKCHAR_INTERRUPT);

    MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
    //MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_TRANSMIT_INTERRUPT);
    MAP_UART_enableInterrupt(EUSCI_A2_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);

    //enable interrupts for each module
    MAP_Interrupt_enableInterrupt(INT_EUSCIA0);
    MAP_Interrupt_enableInterrupt(INT_EUSCIA2);
    MAP_Interrupt_enableInterrupt(INT_EUSCIB0);

    //MAP_Interrupt_enableSleepOnIsrExit();
    MAP_Interrupt_enableMaster();

    TXData[0] = 0x3B;

    printf(EUSCI_A0_BASE, "Tx: %x\n\r", TXData[0]);
    //MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, TXData[0]);
    //MAP_I2C_masterSendMultiByteStopWithTimeout(EUSCI_B0_BASE, 1000); //Chosen arbitrary value for timeout

    MAP_I2C_masterSendSingleByte(EUSCI_B0_BASE, TXData[0]);
    //while (I2C_isBusBusy(EUSCI_B0_BASE)==EUSCI_B_I2C_BUS_BUSY);

    MAP_I2C_enableInterrupt(EUSCI_B0_BASE,EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    while (MAP_I2C_masterIsStopSent(EUSCI_B0_BASE) == EUSCI_B_I2C_SENDING_STOP);
    //while(!UCB0IFG);

    MAP_I2C_masterReceiveStart(EUSCI_B0_BASE);


    while(1)
    {
        printf(EUSCI_A0_BASE, "Main started \n\r");
        MAP_PCM_gotoLPM0InterruptSafe();
                //MAP_PCM_gotoLPM0();
    }
}


void EUSCIB0_IRQHandler(void)
{
    uint_fast16_t status;
    status = MAP_I2C_getEnabledInterruptStatus(EUSCI_B0_BASE);
    MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, status);
    //printf(EUSCI_A0_BASE, "I2C\n\r");
   if (status & EUSCI_B_I2C_TRANSMIT_INTERRUPT0)
    {
        printf(EUSCI_A0_BASE, "I2C_Sent!\n\r");
        //MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
        //MAP_I2C_disableModule(EUSCI_B0_BASE);
        //MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_MODE);
        //MAP_I2C_enableModule(EUSCI_B0_BASE);
        //MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
        //MAP_I2C_masterReceiveStart(EUSCI_B0_BASE);
    }


    if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
    {

        RXData[0] = MAP_I2C_masterReceiveMultiByteNext(
                    EUSCI_B0_BASE);

        printf(EUSCI_A0_BASE, "Finished receive: %x\n\r", RXData[0]);
          //int i=iter - 2;
          //printf(EUSCI_A0_BASE, "Iter: %i\r\n", iter);
          //if(iter < 15)
          {
              //RXData[i] = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
              //printf(EUSCI_A0_BASE, "Rec: %i\r\n", RXData[i]);
          }
          //else
          {
//              RXData[0] = MAP_I2C_masterReceiveSingleByte(EUSCI_B0_BASE);
              //MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
//              printf(EUSCI_A0_BASE, "Finished receive: %x\n\r", RXData[0]);
          }
          //MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
      //    stopSent = true;
    }
}


/* EUSCI A0 UART ISR - Echoes data back to PC host */
void EUSCIA0_IRQHandler(void)
{
    //char receiveByte = UCA0RXBUF;
    uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A0_BASE);

    MAP_UART_clearInterruptFlag(EUSCI_A0_BASE, status);

    if(EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)
    {
        MAP_UART_transmitData(EUSCI_A0_BASE, MAP_UART_receiveData(EUSCI_A0_BASE));
    }

}

/* EUSCI A2 UART ISR - Echoes data back to PC host */
void EUSCIA2_IRQHandler(void)
{
    uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A2_BASE);

    MAP_UART_clearInterruptFlag(EUSCI_A2_BASE, status);

    if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)
    {
        printf(EUSCI_A0_BASE, "Receive2\n\r");
    }

    if(status & EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG)
    {
            printf(EUSCI_A0_BASE, "Transmit2 \n\r");
    }

}

/*
* Port 1 interrupt handler. This handler is called whenever switches attached
* to P1.1 (S1) and P1.4 (S2) are pressed.
*/
void PORT1_IRQHandler(void)
{
        //newTick = MAP_SysTick_getValue();
        uint32_t status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P1);
        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P1, status);

        /* Handles S1 button press */
        if (status & GPIO_PIN1)
        {
            //MAP_Interrupt_disableInterrupt(INT_PORT1);
            printf(EUSCI_A0_BASE, "LED should light up \n\r");
            TIMER_A0->CCR[1] = PWM_PERIOD * (0/255);                // CCR1 PWM duty cycle
            TIMER_A0->CCR[2] = PWM_PERIOD * (GREEN/255);            // CCR2 PWM duty cycle
            TIMER_A0->CCR[3] = PWM_PERIOD * (0/255);                // CCR3 PWM duty cycle
            MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);
            printf(EUSCI_A0_BASE, "LED lit?");
        }
        /* Handles S2 button press */
        if (status & GPIO_PIN4)
        {

            /* Initialize values to display */
                char *s = "printf test";
                char c = '!';
                int i = -12345;
                unsigned u = 4321;
                long int l = -123456780;
                long unsigned n = 1098765432;
                unsigned x = 0xABCD;

            printf(EUSCI_A0_BASE, "String         %s\r\n", s);
            printf(EUSCI_A0_BASE, "Char           %c\r\n", c);
            printf(EUSCI_A0_BASE, "Integer        %i\r\n", i);
            printf(EUSCI_A0_BASE, "Unsigned       %u\r\n", u);
            printf(EUSCI_A0_BASE, "Long           %l\r\n", l);
            printf(EUSCI_A0_BASE, "uNsigned loNg  %n\r\n", n);
            printf(EUSCI_A0_BASE, "heX            %x\r\n", x);
        }

}

/*
 * SysTick interrupt handler. This handler toggles RGB LED on/off.
 */
void SysTick_Handler(void)
{
    if (!(TIMER_A0->CCTL[1] & TIMER_A_CCTLN_OUTMOD_0)){
            TIMER_A0->CCTL[1] = TIMER_A_CCTLN_OUTMOD_7;
            TIMER_A0->CCTL[2] = TIMER_A_CCTLN_OUTMOD_7;
            TIMER_A0->CCTL[3] = TIMER_A_CCTLN_OUTMOD_7;
        }

}



  • Update: I had a hardware problem in that I had not soldered my MPU6050. I figured that when I moved the sensor board a bit and found that I got receive interrupt for I2C data. Now, I have soldered the part in so that there are no connections issues as before. As of now, the transmit code still does NOT work. However, after every power-up, MPU-6050 starts reading data bytes and sending to MSP432. I receive interrupt at the EUSCI_B0 RECEIVE interrupt handler and the values that are being sent are printed. I verified that these are correct values because the MPU6050 register map document tells how all the registers at reset are zero except for some whose values match with the bytes that I receive at the I2C receiver interrupt handler.
  • Hello Farah,

    Did you ensure that both the I2C master and slave are running at the same I2C clock rate? In the comments you indicate configuring the I2C master to 400kHz, is this the rate at which the I2C slave is running?

    Also did you look at the example in the MSP432P4 SDK at ./examples/nortos/MSP_EXP432P401R/driverlib/i2c_master_rw_repeated_start-master_code". This could be a good starting point for your development.

    Thanks,
    Sai
  • Thanks for your response Sai. It seems like most of my problem regarding the I2C slave was not in the software/programming. Once I figured that the device was  not properly soldered, I was able to correct the code and have it working. I intend to post the corrected code after I have finished working with it and post an update about the problem I had earlier. 

    About your pointer towards the I2C maximum frequency, I did make sure about that. The slave device is capable of a maximum frequency of 400kHz. Even though I didn't correct my comments, the value that I was using corresponds to the 100kHz clock rate. I am still not sure, however, about how to relate the clocking rate of the slave device to the external clocking rate (if any) given from the MSP432 board (if possible). It seems to me that the slave device works at an internal oscillator clock of 8MHz but this has nothing to do with I2C communication (perhaps). The device can be given an external clock of some 19 or 32 MHz that would make the calculations faster or make sampling of the on-board sensors faster. However, I think that the clocking frequency has nothing to do with the I2C data rate which depends only on the SDA and, more importantly, SCL and SCL cannot be more than 400kHz. I would like if you could point out any errors in my understanding and enlighten me. Thanks!

  • Hello Farah,

    I am glad you are making progress.

    As you have rightly pointed out, the clock rate of the device (or system clock) is different from the peripheral clock rate. The peripheral's (in this case I2C) clock is typically derived from the system clock but the rate can be totally different. Also the clock source (you are calling it external clock) can be different from the system clock. If you look at the clock tree of a device, you will understand the relation between the different clocks.

    When using an I2C slave, the datasheet of the I2C slave device should mention the I2C clock rates or transmission speeds supported and how to configure those rates. Many I2C slaves have a default rate of 100Kbps but this is not always true and should not be taken for granted.

    Thanks,
    Sai
  • Thanks very much for giving me pointers towards looking at the "clock tree" of the device. I haven't read much about the internal clocking mechanism of the device and will do so.

    For now, I am coming across an issue that is reported on other forums too but without solution for now. It's not about MSP432 I think. With MPU6050, I am able to read (or burst read) the register after power up. Similarly, if writing a register, I do get a successful I2C TRANSMIT interrupt in MSP432 EUSCI_B0 module. However, I cannot read or write to the device a second time whether it is a single write or a burst read that I perform first after power up. Could you say how that could be resolved? Thanks!
  • Hello Farah,
    I am currently doing a similar project using the mpu-6050 with the msp432. I'd really appreciate it if you could help my figure it out!

**Attention** This is a public forum