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); }