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: Interfacing with IMU 9250/9255/6500 - I2C

Part Number: MSP432P401R

Tool/software: Code Composer Studio

Hello everybody.

I'm trying to interface IMU-9250 and MSP432 (through I2C) and I got a source code from GitHub to serve as a start point.
I made some modifications because the code got some errors when the code was compiled.

Now, when I send the first byte,i2cdev.writeByte(0x68, 0x6B, 0);, it always stuck on while(isISRComplete) {} line:

/** Write multiple bytes to an 8-bit device register.
* @param devAddr I2C slave device address
* @param regAddr First register address to write to
* @param length Number of bytes to write
* @param data Buffer to copy new data from
* @return Status of operation (true = success)
*/
bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t* data) {

UCB0I2CSA = 0x68; //only for testing

setTxBuf(regAddr); //prep the data to be sent, will be sent when the start condition is met.

UCB0CTLW0 |= UCTR | UCTXSTT;

P6OUT |= BIT0;
P6OUT &= ~BIT0;

while(isISRComplete) {} //wait until interrupt returns that it is ok to send more data
isrComplete(false);

uint8_t i;
for (i = 0; i < length; i++) {

UCB0TXBUF = data[i];
//setTxBuf(data[i]);

while(isISRComplete) {}
isrComplete(false);
}

UCB0CTLW0 |= UCTXSTP;

return 1;
}

I'd like to know if somebody faced this error before and whether could solve it.
I guess that is something wrong with the interrupt setup.

Thank you so much guys!

GITHUB LINK

main code:

#include "msp.h"
#include "IMU/I2Cdev.h"
//#include "IMU/MPU6050_6Axis_MotionApps20.h"
#include "IMU/MPU6050.h"
#include <stdio.h>
#include "UART/UART_A0.h"
#include <stdint.h>


MPU6050 accelgyro;
I2Cdev i2cdev;
UART_A0 uartA0;

char debugOutput[50];
int16_t ax, ay, az;
int16_t gx, gy, gz;

void MPU9150_setupCompass();
void VCORE1();

//void eUSCIB0IsrHandler(void);

void i2c_enable_interrupt(void)
{
    UCB0IE |= UCBCNTIE; /* Byte counter interrupt enable */
    UCB0IE |= UCNACKIE; /* Not-acknowledge interrupt enable */
    UCB0IE |= UCTXIE0; /* Transmit interrupt enable 0 */
    UCB0IE |= UCRXIE0; /* Receive interrupt enable 0 */
    NVIC_EnableIRQ(EUSCIB0_IRQn);
}

void main(void)
{
    volatile uint32_t i;

    uint32_t currentPowerState;

    WDT_A->CTL = WDT_A_CTL_PW |
    WDT_A_CTL_HOLD;            // Stop WDT

    /* Step 1: Transition to VCORE Level 1: AM0_LDO --> AM1_LDO */

    /* Get current power state, if it's not AM0_LDO, error out */
    currentPowerState = PCM->CTL0 & PCM_CTL0_CPM_MASK;
    if (currentPowerState != PCM_CTL0_CPM_0)

        while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY))
            ;
    PCM->CTL0 = PCM_CTL0_KEY_VAL | PCM_CTL0_AMR_1;
    while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY))
        ;
    if (PCM->IFG & PCM_IFG_AM_INVALID_TR_IFG)

        if ((PCM->CTL0 & PCM_CTL0_CPM_MASK) != PCM_CTL0_CPM_1)

    /* Step 2: Configure Flash wait-state to 1 for both banks 0 & 1 */
    FLCTL->BANK0_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK0_RDCTL_WAIT_MASK)) |
    FLCTL_BANK0_RDCTL_WAIT_1;
    FLCTL->BANK1_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK1_RDCTL_WAIT_MASK)) |
    FLCTL_BANK1_RDCTL_WAIT_1;

    /* Step 3: Configure DCO to 48MHz, ensure MCLK uses DCO as source*/
    CS->KEY = CS_KEY_VAL;                // Unlock CS module for register access
    CS->CTL0 = 0;                           // Reset tuning parameters
    CS->CTL0 = CS_CTL0_DCORSEL_5;           // Set DCO to 48MHz
    /* Select MCLK = DCO, no divider */
    CS->CTL1 = (CS->CTL1 & ~(CS_CTL1_SELM_MASK | CS_CTL1_DIVM_MASK)) |
    CS_CTL1_SELM_3;
    CS->KEY = 0;                      // Lock CS module from unintended accesses

    __enable_interrupt();

    NVIC_EnableIRQ(EUSCIB0_IRQn);     // Enable eUSCIB0 interrupt in NVIC module

    //NVIC->ISER[0];
    //NVIC_ISER0 = 1 << ((INT_EUSCIB0 - 16) & 31); // Enable eUSCIB0 interrupt in NVIC module

    i2cdev.writeByte(0x68, 0x6B, 0);	//wake from sleep
    MPU9150_setupCompass();

    //accelgyro.initialize();
    //accelgyro.testConnection();
    //accelgyro.setIntDataReadyEnabled(1);

    while (1)
    {
        P6OUT |= BIT0;
        P6OUT &= ~BIT0;
        int i;
        for (i = 10000; i > 0; i--)
        {
            __no_operation();
        }
        //accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
        i2cdev.writeByte(0x68, 0x6B, 0);	//wake from sleep
        //accelgyro.getAccelerationX();

        int n = sprintf(
                debugOutput,
                "ax: %d\t ay: %d\t az: %d\t gx: %d\t gy: %d\t gz: %6d\t", ax,
                ay, az, gx, gy, gz);

        uartA0.sendString(debugOutput);
        //accelgyro.getIntStatus();

    }

}

void MPU9150_setupCompass()
{
    /*
     //UCB0CTLW0 |= UCSWRST;
     UCB0I2CSA = MAG_I2C_ADDRESS;      //change Adress to Compass
     //UCB0CTLW0 &= ~UCSWRST;

     i2cdev.writeByte(0x68, 0x0A, 0x00); //PowerDownMode
     i2cdev.writeByte(0x68, 0x0A, 0x0F); //SelfTest
     i2cdev.writeByte(0x68, 0x0A, 0x00); //PowerDownMode
     */

    //UCB0CTLW0 |= UCSWRST;
    UCB0I2CSA = ACCEL_GYRO_I2C_ADDRESS
    ;      //change Adress to Compass
    //UCB0CTLW0 &= ~UCSWRST;

    i2cdev.writeByte(0x68, 0x24, 0x40); //Wait for Data at Slave0
    i2cdev.writeByte(0x68, 0x25, 0x8C); //Set i2c address at slave0 at 0x0C
    i2cdev.writeByte(0x68, 0x26, 0x02); //Set where reading at slave 0 starts
    i2cdev.writeByte(0x68, 0x27, 0x88); //set offset at start reading and enable
    i2cdev.writeByte(0x68, 0x28, 0x0C); //set i2c address at slv1 at 0x0C
    i2cdev.writeByte(0x68, 0x29, 0x0A); //Set where reading at slave 1 starts
    i2cdev.writeByte(0x68, 0x2A, 0x81); //Enable at set length to 1
    i2cdev.writeByte(0x68, 0x64, 0x01); //overvride register
    i2cdev.writeByte(0x68, 0x67, 0x03); //set delay rate
    i2cdev.writeByte(0x68, 0x01, 0x80);

    i2cdev.writeByte(0x68, 0x34, 0x04); //set i2c slv4 delay
    i2cdev.writeByte(0x68, 0x64, 0x00); //override register
    i2cdev.writeByte(0x68, 0x6A, 0x00); //clear usr setting
    i2cdev.writeByte(0x68, 0x64, 0x01); //override register
    i2cdev.writeByte(0x68, 0x6A, 0x20); //enable master i2c mode
    i2cdev.writeByte(0x68, 0x34, 0x13); //disable slv4
}

  • > while(isISRComplete) {} //wait until interrupt returns that it is ok to send more data

    This test looks backwards, since the ISR sets isISRComplete =true. Did you mean:

    > while(!isISRComplete()) {} //wait until interrupt returns that it is ok to send more data

    [Edit: I think you need the parens as well. Maybe it's C# where they're optional?]

  • Hello Bruce,

    It makes sense. I changed the code and it doesn't stuck anymore. I put the parenthesis too but it didn't make any difference, probably it's optional.

    Unfortunately, I can't receive any data from IMU.

    Now I don't know what part is getting wrong, because apparently all code is ok.

  • What does "can't receive any data" mean? No bytes? Bytes of all-0s?

    You mentioned you started with working code. What did you change?

    I see that both the ISR and WriteBytes are storing into UCB0TXBUF, which doesn't look right. The former is apparently working off the "txbuf" global, which isn't being set. It seems as though the latter should be using setTxBuf().

    [Edit: Removed comment about bus speed, which probably won't be a problem.]

  • Hello Bruce, sorry about the late...

    Yes I'm receiving all-0s. FIGURE 1.

    I'm using the code from Malcolm Williams. When I tried to compile the code it didn't work (FIGURE 2.). Link of GitHub of Williams code. 

    I'm sorry, I didn't understand this part: '[Edit: Removed comment about bus speed, which probably won't be a problem.]'

    I have an update. I tried again putting a parenthesis on 'isISRComplete' and the didn't need to use the exclamation mark in the while part. Is that right?

    After: while(!isISRComplete) {} -> Before: while(isISRComplete()) {}

    I appreciate your help. 

    --------------------------------------------------------------------------------------------------------------------------------------------------------

    FIGURE 1

     

     

    FIGURE 2.

  • I don't see any code in main() which fills in any of ax/ay/az, since this:
    >//accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
    is commented out, so they will be =0 forever.

    I suppose you could try un-commenting it, but since it was commented in the original, I'm wondering if the code you started with is not-quite-finished.

    Also, it looks as though getMotion6 ends up calling readBytes, but that function is empty (no code at all).

    Getting this code to work may be more difficult than you perhaps intended. Did you find any other samples?
  • I ran the code, without the comment bars, and the result was the same.

    I thought the same thing. Probably the code wasn't finished yet, because the first time I tried to run the code I found some bugs.

    I found another sample (LINK), using Energia IDE, and it uses the same libraries of Williams's code. But it didn't work (FIGURE 1).

    Now I think that my I2C's pins may have a problem. I have an MSP430 and I'll try to establish a connection with MSP430 and MSP432 via I2C, to discard this possibility.

    FIGURE 1:

  • Does your IMU board have the I2C pullups on it? Launchpads normally don't.
  • There are a number of things that bug me about that I2C code that tell me it doesn't work. One is that the ISR always pulls data from a single byte buffer and stores it into the transmit data register in response to a transmit data register empty interrupt. Yet the code to transmit several bytes also stores to that register.

    When I wrote some code for a MSP430 to talk to a MPU9150 over I2C I remember the I2C code being trouble. The ISR was a pain although it eventually did work. The peripherals on theMSP432 may or may not be similar enough so that code would help you

    I see code to configure the MPU9250 I2C master so that it will read the magnetometer data into its registers (which is what I did) but I don't see where that gets read. The code you referenced appears to access the magnetometer directly. Doing both is bound to cause trouble.
  • The peripheral eUSCIB is the same for the MSP430 and MSP432 families. (this is the i2c communications peripheral)

    Regards,
    Chris

  • David, do you still have the code ?

  • Of course. It isn't pretty as that project was overtaken by events so I never bothered to clean it up.

    I will make it available temporarily here:

**Attention** This is a public forum