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: BMI160 Power Mode - SPI 3 wire Communication

Part Number: MSP432P401R


Tool/software: Code Composer Studio

Hello everybody,

This is my first post, so if there are any problems please excuse me. 

I am attempting to communicate with the BMI160 IMU using SPI 3 wire communication. I feel relatively confident in having set everything up correctly, but cannot seem to power on the sensor. 

The sensor starts in I2C mode, so to make sure it switches to SPI it is recommended to perform a single read access to the register 0x7F. After having done this I attempt to access the CMD register and write 0x11 to power on the accelerometer in normal mode. I then perform single read accesses first to the PMU Status register (0x03), which indicates what power mode the sensor is in, and then the Error register (0x02) to check if there are any errors. For each of these reads I receive back 0xFF. To my understanding this means that I have not powered on the accelerometer and thus the PMU status is off, and there are errors because of this.

I then go on to perform multiple reads from the data registers (0x12-0x17) and the only value i receive for all of those registers is 0xFF. At this point I am not sure what the problem could be, but I was hoping someone could point me in the right direction. I have attached my code below. 

Thanks in advance!

/* ======= Header Includes ============================ */

#include "msp.h"
#include "driverlib.h"
#include "stdint.h"
#include "stdio.h"

/* ======= Macro Definitions ============================ */

// GPIO
#define LED1Red     GPIO_PORT_P1,GPIO_PIN0      // Output first LED Red P1.0
#define LED2Red     GPIO_PORT_P2,GPIO_PIN0      // Output second LED Red P2.0
#define LED2Green   GPIO_PORT_P2,GPIO_PIN1      // Output second LED Green P2.1
#define LED2Blue    GPIO_PORT_P2,GPIO_PIN2      // Output second LED Blue P2.2
#define PowerPin    GPIO_PORT_P2,GPIO_PIN5      // Output P2.5 for 3.3V to power BMI160 VDD (PIN 1) (PIN 2 goes to 3V3 for VDDIO)
#define S1          GPIO_PORT_P1,GPIO_PIN1      // Switch 1 (S1) P1.1
#define S2          GPIO_PORT_P1,GPIO_PIN4      // Switch 2 (S2) P1.4
#define TA01        GPIO_PORT_P2,GPIO_PIN4      // TA0.1 Timer A Module 0, capture-compare output 1
#define SCK         GPIO_PORT_P1,GPIO_PIN5      // EUSCI_B0 CLK (SCK) pin for BMI160 sensor with SPI (PIN 6)
#define MOSI        GPIO_PORT_P1,GPIO_PIN6      // EUSCI_B0 MOSI pin for BMI160 sensor with SPI (PIN 5)
#define MISO        GPIO_PORT_P1,GPIO_PIN7      // EUSCI_B0 MOSI pin for BMI160 sensor with SPI (PIN 4)
#define SS          GPIO_PORT_P4,GPIO_PIN3      // Slave Select (CS) pin for BMI160 sensor

// BMI160
#define CMD_REG_ADDR 0x7E                   // CMD Register triggers operations like softreset
#define CMD_ACCEL_NORMAL_POWER 0x11         // Command to set PMU mode of accelerometer to normal power
#define PMU_STATUS 0x03                     // PMU status address to check power mode of sensor
#define ACCEL_REG_ADDR 0x12                 // Accelerometer data first register address, ends at 0x17
#define ERR_REG 0x02                        // Error register to report sensor error flags
#define SINGLE_READ 0x7F                    // Register to perform single read access before actual communication to use SPI interface

/* Byte swap of 16-bit register value */
// These macros swap the high and low bytes of 16-bit argument v
#define HI_UINT16(a) (((a) >> 8) & 0xFF)
#define LO_UINT16(a) ((a) & 0xFF)
#define SWAP(v) ( (LO_UINT16(v) << 8) | HI_UINT16(v) )

/* ======= Variable Definitions ======================== */

uint8_t xAccMSB;                            // Most significant bit of x from Accel
uint8_t xAccLSB;                            // Least significant bit of x from Accel
uint8_t yAccMSB;                            // Most significant bit of y from Accel
uint8_t yAccLSB;                            // Least significant bit of y from Accel
uint8_t zAccMSB;                            // Most significant bit of z from Accel
uint8_t zAccLSB;                            // Least significant bit of z from Accel
int x;
int y;
int z;
float xexp;
float yexp;
float zexp;
uint8_t mode;                               // Used to check power mode of sensor
int i = 0;                                  // For delays

/* ======= SPI Master Configuration Parameter ========== */

const eUSCI_SPI_MasterConfig spiMasterConfig =
{
    EUSCI_B_SPI_CLOCKSOURCE_SMCLK,              // SMCLK Clock Source
    3000000,                                    // SMCLK = DCO = 3 MHz
    200000,                                     // SPICLK = 200kHz
    EUSCI_B_SPI_MSB_FIRST,                      // MSB First
    EUSCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT,    // Phase
    EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH,  // High polarity
    EUSCI_B_SPI_3PIN                            // 3Wire SPI Mode - this means we will set/clear the CS line manually via GPIO
};

/* ======= Timer A1 Configuration Parameter ============ */

const Timer_A_UpModeConfig upConfig_1 =     // Configure counter in Up mode
{
    TIMER_A_CLOCKSOURCE_SMCLK,            // Tie Timer A to SMCLK
    TIMER_A_CLOCKSOURCE_DIVIDER_64,       // Increment counter every 64 clock cycles
    11719,                                // Period of Timer A to read every 0.25 seconds
    TIMER_A_TAIE_INTERRUPT_DISABLE,       // Disable Timer A rollover interrupt
    TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE,   // Enable Capture Compare interrupt
    TIMER_A_DO_CLEAR                      // Clear counter upon initialization
};

/* ======= Main Loop ==================================== */

int main(void)
{
    // Stop watchdog timer
    WDT_A_holdTimer();

    // Enable Floating point module
    FPU_enableModule();

    // Set DCO to 3 MHz
    CS_setDCOFrequency(3E+6);
    CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);

    // Disable master interrupt
    Interrupt_disableMaster();

/* ======= GPIO Setup ===================================== */

    // LED Setup
    // Set up LED 1 Red
    GPIO_setAsOutputPin(LED1Red);
    // Set up LED 2 Red
    GPIO_setAsOutputPin(LED2Red);
    // Set up LED 2 Green
    GPIO_setAsOutputPin(LED2Green);
    // Set up LED 2 Blue
    GPIO_setAsOutputPin(LED2Blue);

    // Turn off all LED's
    GPIO_setOutputLowOnPin(LED1Red);
    GPIO_setOutputLowOnPin(LED2Red);
    GPIO_setOutputLowOnPin(LED2Green);
    GPIO_setOutputLowOnPin(LED2Blue);

    // Set up P2.5 Output 3.3V
    GPIO_setAsOutputPin(PowerPin);
    GPIO_setOutputHighOnPin(PowerPin);

/* ======= Timer A1 Settings ================================ */

    Timer_A_configureUpMode(TIMER_A1_BASE, &upConfig_1);                    // Configure Timer A using above structure
    Timer_A_enableInterrupt(TIMER_A1_BASE);
    Interrupt_enableInterrupt(INT_TA1_0);                                   // Enable Timer A interrupt
    Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_UP_MODE);                   // Start Timer A

/* ======= Initialize BMI160 ================================== */

    // Initialize SPI
    initializeSPI();

    // Configure BMI160 sensor
    mode = configSensor(SINGLE_READ, CMD_REG_ADDR, CMD_ACCEL_NORMAL_POWER);
    printf("%02X\n", mode);       // Print the output from the SINGLE_READ address to the console

    // Delay
    for(i=0; i < 5000; i++){};

    // Check Sensor Power Mode
    mode = check(PMU_STATUS);
    printf("%02X\n", mode);       // Print the power mode to the console

    // Check Error Register
    mode = check(ERR_REG);
    printf("%02X\n", mode);       // Print the error output to the console


    // Enable timer interrupt
    Interrupt_enableMaster();                                               // Enable all interrupts

    while(1)
    {
        PCM_gotoLPM0();
    }
}
// End of main function instance

/* ======= Timer ISR ======================================== */

void TA1_0_IRQHandler()
{
    Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_0);

    readSPI(ACCEL_REG_ADDR);
    printf("x = %d\n", x);
    //printf("y = %f\n", yexp);
    //printf("z = %f\n\n", zexp);
}

/* ======= Configure BMI160 Accelerometer in Normal Power Mode ===================== */

uint8_t configSensor(uint8_t readReg, uint8_t reg, uint8_t value)
{
    uint8_t RXData = 0;

    // Set high bit to read from this register
    readReg = 0x80 | readReg;

    // Set Slave Select (CS) line low to begin transmission
    GPIO_setOutputLowOnPin(SS);

    // Make sure transmit buffer is clear
    while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT)));

    // Transmit register address
    SPI_transmitData(EUSCI_B0_BASE, readReg);

    // Make sure receive interrupt flag is set
    while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_B_SPI_RECEIVE_INTERRUPT)));

    // Pick up received byte in SPI receive data register
    RXData = SPI_receiveData(EUSCI_B0_BASE);

    // Set Slave Select (CS) line high to end transmission
    GPIO_setOutputHighOnPin(SS);

    reg = reg & ~0x80;      // Clear high bit to write to this register

    // Set Slave Select (CS) line low to begin transmission
    GPIO_setOutputLowOnPin(SS);

    // Transmit slave register address
    SPI_transmitData(EUSCI_B0_BASE, reg);

    // Transmit write value
    SPI_transmitData(EUSCI_B0_BASE, value);

    // Set Slave Select (CS) line high to end transmission
    GPIO_setOutputHighOnPin(SS);

    return(RXData);
}

/* ======= Read from Accelerometer Data Registers ========================= */

void readSPI (uint8_t reg)
{
    GPIO_toggleOutputOnPin(LED1Red);   // toggle LED1 red

    // Set high bit to read from this register
    reg = 0x80 | reg;

    // Set Slave Select (CS) line low to begin transmission
    GPIO_setOutputLowOnPin(SS);

    // Make sure transmit buffer is clear
    while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT)));

    // Transmit register address
    SPI_transmitData(EUSCI_B0_BASE, reg);

    // Make sure receive interrupt flag is set
    while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_B_SPI_RECEIVE_INTERRUPT)));

    // Pick up received byte in SPI receive data register
    xAccLSB = SPI_receiveData(EUSCI_B0_BASE);
    xAccMSB = SPI_receiveData(EUSCI_B0_BASE);
    yAccLSB = SPI_receiveData(EUSCI_B0_BASE);
    yAccMSB = SPI_receiveData(EUSCI_B0_BASE);
    zAccLSB = SPI_receiveData(EUSCI_B0_BASE);
    zAccMSB = SPI_receiveData(EUSCI_B0_BASE);

    // Set Slave Select (CS) line high to end transmission
    GPIO_setOutputHighOnPin(SS);

    GPIO_toggleOutputOnPin(LED1Red);   // toggle LED1 red

    // Parse the sensor's data.
    x = (int) (xAccLSB << 8 | xAccMSB);
    y = (int) (xAccLSB << 8 | xAccMSB);
    z = (int) (xAccLSB << 8 | xAccMSB);

    xexp = (float) x;
    yexp = (float) y;
    zexp = (float) z;

    xexp = xexp / 16384;
    yexp = yexp / 16384;
    zexp = zexp / 16384;
}

/* ======= Initialize SPI =============================================== */

void initializeSPI(void)
{
    // Selecting P1.5, P1.6, P1.7 in SPI mode
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);

    // Use P4.3 as the Slave Select (CS) pin (Active Low)
    GPIO_setAsOutputPin(SS);
    GPIO_setOutputHighOnPin(SS);

    // Configuring SPI in 3-wire master mode
    SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig);

    // Enable SPI module
    SPI_enableModule(EUSCI_B0_BASE);
}

/* ======= Check Register Value =============================================== */

uint8_t check(uint8_t reg)
{
    uint8_t RXData = 0;

    // Set high bit to read from this register
    reg = 0x80 | reg;

    // Set Slave Select (CS) line low to begin transmission
    GPIO_setOutputLowOnPin(SS);

    // Make sure transmit buffer is clear
    while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT)));

    // Transmit register address
    SPI_transmitData(EUSCI_B0_BASE, reg);

    // Make sure receive interrupt flag is set
    while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_B_SPI_RECEIVE_INTERRUPT)));

    // Pick up received byte in SPI receive data register
    RXData = SPI_receiveData(EUSCI_B0_BASE);

    // Set Slave Select (CS) line high to end transmission
    GPIO_setOutputHighOnPin(SS);

    return(RXData);
}

**Attention** This is a public forum