Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 

    BMI160 Sensor data conversion

    BMI160 Sensor data conversion

    sensor512
    New Poster

    Hello,

    I am uisng BMI160. I am trying to convert the raw data to "g m/s2" value. I am uinsg the  +-8g range in the 0x41 register.

    The outout value is printed in serial terminal:

    Reading samples
    Sent acc: 8664
    Sent acc: 8778
    Sent acc: 8678
    Sent acc: 8623
    Sent acc: 8695
    Sent acc: 8680
    Sent acc: 8741
    Sent acc: 8636
    Sent acc: 8692
    Sent acc: 8688
    Sent acc: 8760
    Sent acc: 8816
    Sent acc: 8731
    Sent acc: 8718
    Sent acc: 8724

    How would I convert it into readable acceleration value?

    Thanks.

    Here is my code:

    #define GLOBAL_Q 15
    #include "QmathLib.h"
    #include <msp430.h>
    #include "driverlib.h"
    #include "DSPLib.h"
    #include <gpio.h>
    #include <intrinsics.h>
    #include <msp430fr5xx_6xxgeneric.h>
    #include <stdint.h>
    #include <stdio.h>
    
    
    //#define GLOBAL_Q 15
    //#include "QmathLib.h"
    _q15 q15FFT;
    _q15 q15Amp; // Q variables using Q15 type
    volatile float qFFT_out;
    volatile float qAmp_out;
    
    //new
    //#include "myClocks.h"
    //new
    
    //******************************************************************************
    // Defines *********************************************************************
    //******************************************************************************
    //Address if the BMI160
    #define SLAVE_ADDR 0x69
    //Maximum I2C buffer size
    #define MAX_BUFFER_SIZE 20
    
    //Number of FFT samples
    #define SAMPLES 1024
    #define TimeStampSample 10
    /* Declare as persistent to move variable from RAM to FRAM */
    #pragma PERSISTENT(input)
    int16_t input[SAMPLES] = {0}; //Store samples
    
    #pragma PERSISTENT(max)
    int16_t max[SAMPLES] = {0}; //Store frequencies with maximum amplitudes
    
    
    #pragma PERSISTENT(amp)
    int16_t amp[SAMPLES] = {0}; //Store the maximum amplitudes
    
    
    /* Temporary data array for processing */
    DSPLIB_DATA(temp,4)
    /* Declare as persistent to move variable to FRAM */
    #pragma PERSISTENT(temp)
    int16_t temp[3*SAMPLES/2] = {0};
    
    //Global flags for sensor interrupts to avoid interrupt nesting
    volatile int motion_trigger = 0;
    
    /* Benchmark cycle counts */
    volatile uint32_t cycleCount;
    
    //#pragma PERSISTENT(SENSORTIME)
    //volatile int32_t SENSORTIME[SAMPLES] = {0}; //Store samples
    
    
    //new
    
    #define UP 0x0010 // Timer_A Up mode
    #define CONTINUOUS 0x0020 // Timer_A Continuous mode
    #define ACLK 0x0100 // Timer_A SMCLK source
    #define DEVELOPMENT 0x5A80 // Stop the watchdog timer
    #define BOUNCE_DELAY 0xA000 // Delay for Button Bounce
    #define MS_10 400 // Approximate value to count for 10ms
    #define SMCLK 0x0200 // Timer_A SMCLK source
    
    //new
    
    
    
    //******************************************************************************
    // Frequency Functions *********************************************************
    //******************************************************************************
    
    void bubbleSort(int amp[], int max[], int n)
    {
    int i, j, temp;
    for (i = 0; i < n-1; i++)
    {
    // Last i elements are already in place
    for (j = 0; j < n-i-1; j++)
    {
    if (amp[j] < amp[j+1])
    {
    temp = max[j];
    max[j] = max[j+1];
    max[j+1] = temp;
    
    temp = amp[j];
    amp[j] = amp[j+1];
    amp[j+1] = temp;
    }
    }
    }
    }
    
    void getMaximums(int16_t input[], int samples, int16_t max[], int16_t amp[])
    {
    int i,j = 0;
    for(i=1; i<samples-1; i++)
    {
    if((input[i-1] < input[i]) && (input[i] > input[i+1]))
    {
    amp[j] = input[i];
    max[j++] = i;
    }
    }
    bubbleSort(amp, max, samples);
    }
    
    //******************************************************************************
    // Timer Functions *************************************************************
    //******************************************************************************
    
    int delay(int count)
    {
    if(TA1CTL & TAIFG) // If Timer_1 is done counting
    {
    count = count-1; // Decrement count
    TA1CTL = TA1CTL & (~TAIFG); // Reset Timer_1
    }
    return count; // Return the value of count
    } // end delay
    //******************************************************************************
    // UART Functions **************************************************************
    //******************************************************************************
    void UART_transmitString( char *pStr ) //Transmits a string over UART0
    {
    while( *pStr )
    {
    while(!(UCA0IFG&UCTXIFG));
    UCA0TXBUF = *pStr;
    pStr++;
    }
    }
    
    //******************************************************************************
    // I2C Functions ***************************************************************
    //******************************************************************************
    typedef enum I2C_ModeEnum{
    IDLE_MODE,
    NACK_MODE,
    TX_REG_ADDRESS_MODE,
    RX_REG_ADDRESS_MODE,
    TX_DATA_MODE,
    RX_DATA_MODE,
    SWITCH_TO_RX_MODE,
    SWITHC_TO_TX_MODE,
    TIMEOUT_MODE
    } I2C_Mode;
    
    /* Used to track the state of the software state machine*/
    I2C_Mode MasterMode = IDLE_MODE;
    
    uint8_t TransmitRegAddr = 0; //Register address for transmission
    uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for received values
    uint8_t RXByteCtr = 0; //Count received bytes
    uint8_t ReceiveIndex = 0; //Index of received data
    uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for transmitted values
    uint8_t TXByteCtr = 0; //Count transmitted bytes
    uint8_t TransmitIndex = 0; //Index of transmitted data
    
    void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
    {
    uint8_t copyIndex = 0;
    for (copyIndex = 0; copyIndex < count; copyIndex++)
    {
    dest[copyIndex] = source[copyIndex];
    }
    }
    
    I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count)
    {
    //printf("R\n");
    /* Initialize state machine */
    MasterMode = TX_REG_ADDRESS_MODE;
    TransmitRegAddr = reg_addr;
    RXByteCtr = count;
    TXByteCtr = 0;
    ReceiveIndex = 0;
    TransmitIndex = 0;
    
    /* Initialize slave address and interrupts */
    UCB1I2CSA = dev_addr;
    UCB1IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts
    UCB1IE &= ~UCRXIE; // Disable RX interrupt
    UCB1IE |= UCTXIE; // Enable TX interrupt
    
    UCB1CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition
    __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
    // UCB1IE &= ~UCRXIE; // Disable RX interrupt
    
    
    return MasterMode;
    
    }
    
    I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
    {
    /* Initialize state machine */
    MasterMode = TX_REG_ADDRESS_MODE;
    TransmitRegAddr = reg_addr;
    
    //Copy register data to TransmitBuffer
    CopyArray(reg_data, TransmitBuffer, count);
    
    TXByteCtr = count;
    RXByteCtr = 0;
    ReceiveIndex = 0;
    TransmitIndex = 0;
    
    /* Initialize slave address and interrupts */
    UCB1I2CSA = dev_addr;
    UCB1IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts
    UCB1IE &= ~UCRXIE; // Disable RX interrupt
    UCB1IE |= UCTXIE; // Enable TX interrupt
    
    UCB1CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition
    __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
    //printf("W\n");
    return MasterMode;
    }
    
    //******************************************************************************
    // BMI160 Functions ************************************************************
    //******************************************************************************
    void bmi160_init(char FOC_axis)
    {
    uint8_t writeData[1];
    //Read Chip ID, which is D1
    I2C_Master_ReadReg(SLAVE_ADDR, 0x00, 1);
    if(ReceiveBuffer[0] != 0xD1)
    {
    UART_transmitString(" Incorrect sensor chip ID ");
    printf("Incorrect sensor chip ID\n");
    }
    
    
    
    
    //Configure the accelerometer
    writeData[0]=0b00101100; //Set acc_us to 0 for off, and acc_bwp must then be 010. Set acc_odr to 1011(800Hz),1100(1600Hz),1000(100Hz),0001(25/32Hz)
    I2C_Master_WriteReg(SLAVE_ADDR, 0x40, writeData, 1);
    //Check if configuration worked
    I2C_Master_ReadReg(SLAVE_ADDR, 0x40, 1);
    if(ReceiveBuffer[0] != writeData[0])
    {
    UART_transmitString(" Accelerometer config failed ");
    printf("Accelerometer config failed\n");
    }
    //Set the range of the accelerometer
    writeData[0]=0b0011; //0b0011 for 2g, 0b0101 for 4g, 0b1000 for 8g
    I2C_Master_WriteReg(SLAVE_ADDR, 0x41, writeData, 1);
    //Check if range is set
    I2C_Master_ReadReg(SLAVE_ADDR, 0x41, 1);
    if(ReceiveBuffer[0] != writeData[0])
    {
    UART_transmitString(" Accelerometer range set failed ");
    printf("Accelerometer range set failed\n");
    }
    
    
    //Set the Accelerometer to normal power mode
    writeData[0] = 0x11;
    I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1);
    //Read power mode status of sensors
    I2C_Master_ReadReg(SLAVE_ADDR, 0x03, 1);
    if(ReceiveBuffer[0] != 0x10)
    {
    UART_transmitString(" Accelerometer not on ");
    printf("Accelerometer not on\n");
    }
    
    //Fast Offset Compensation (FOC) setup
    
    //0 for reserved, 0 for gyroscope, 00 for x, 00 for y, 0 for z (10 = -1g, 00 = 0g, 01 = 1g)
    switch(FOC_axis)
    {
    case 'X':
    writeData[0] = 0b00100000;
    break;
    case 'Y':
    writeData[0] = 0b00001000;
    break;
    case 'Z':
    writeData[0] = 0b00000010;
    break;
    default:
    writeData[0] = 0b00000000; //Default of all 0g
    break;
    }
    I2C_Master_WriteReg(SLAVE_ADDR, 0x69, writeData, 1);
    //Check FOC
    I2C_Master_ReadReg(SLAVE_ADDR, 0x69, 1);
    if(ReceiveBuffer[0] != writeData[0])
    {
    UART_transmitString(" FOC not set ");
    printf("Incorrect sensor chip ID\n");
    }
    //Start FOC
    writeData[0] = 0x03;
    I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1);
    //Wait until FOC is finished
    int finish = 0;
    while(finish==0)
    {
    I2C_Master_ReadReg(SLAVE_ADDR, 0x1B, 1);
    if((ReceiveBuffer[0] & 0b00001000) == 0b00001000)
    {
    finish = 1;
    }
    }
    //Enable offset compensation
    writeData[0] = 0b01000000; //Enable accelerometer offset compensation
    I2C_Master_WriteReg(SLAVE_ADDR, 0x77, writeData, 1);
    //Check offset compensation
    I2C_Master_ReadReg(SLAVE_ADDR, 0x77, 1);
    if(ReceiveBuffer[0] != writeData[0])
    {
    UART_transmitString(" Offset not enabled ");
    printf("Incorrect sensor chip ID\n");
    }
    //UART_transmitString(" BMI160 Initialized \n");
    }
    
    
    
    //******************************************************************************
    // Device Initialization *******************************************************
    //******************************************************************************
    void initGPIO()
    {
    /* Terminate all GPIO pins to Output LOW to minimize power consumption */
    GPIO_setAsOutputPin(GPIO_PORT_PA, GPIO_PIN_ALL16);
    GPIO_setAsOutputPin(GPIO_PORT_PB, GPIO_PIN_ALL16);
    GPIO_setAsOutputPin(GPIO_PORT_PC, GPIO_PIN_ALL16);
    GPIO_setAsOutputPin(GPIO_PORT_PD, GPIO_PIN_ALL16);
    GPIO_setAsOutputPin(GPIO_PORT_PE, GPIO_PIN_ALL16);
    GPIO_setAsOutputPin(GPIO_PORT_PF, GPIO_PIN_ALL16);
    GPIO_setOutputLowOnPin(GPIO_PORT_PA, GPIO_PIN_ALL16);
    GPIO_setOutputLowOnPin(GPIO_PORT_PB, GPIO_PIN_ALL16);
    GPIO_setOutputLowOnPin(GPIO_PORT_PC, GPIO_PIN_ALL16);
    GPIO_setOutputLowOnPin(GPIO_PORT_PD, GPIO_PIN_ALL16);
    GPIO_setOutputLowOnPin(GPIO_PORT_PE, GPIO_PIN_ALL16);
    GPIO_setOutputLowOnPin(GPIO_PORT_PF, GPIO_PIN_ALL16);
    
    // I2C pins (P4.0 is SDA, P4.1 is SCL)
    P4SEL1 |= BIT0 | BIT1;
    P4SEL0 &= ~(BIT0 | BIT1);
    
    // Configure P3.4 and P3.5 to UART (Primary, TX and RX respectively) for NeoCortec
    P3SEL0 |= BIT4 | BIT5; // USCI_A1 UART operation
    P3SEL1 &= ~(BIT4 | BIT5); // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary
    
    // Configure P2.0 and P2.1 to UART (Primary, TX and RX respectively) for PC
    P2SEL0 |= BIT0 | BIT1; // USCI_A0 UART operation
    P2SEL1 &= ~(BIT0 | BIT1); // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary
    
    // Configure button S1 (P1.1) interrupt
    GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);
    GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN1);
    GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1);
    
    // Configure button S2 (P1.2) interrupt
    GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN2);
    GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN2);
    GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN2);
    
    // Configure CTS active (P1.3) interrupt
    GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN3, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN3);
    GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN3);
    GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN3);
    
    // Configure Nwu (P1.4) interrupt
    GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4);
    GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN4);
    GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN4);
    
    // Configure INT1 (P3.2) interrupt
    GPIO_selectInterruptEdge(GPIO_PORT_P3, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P3, GPIO_PIN2);
    GPIO_clearInterrupt(GPIO_PORT_P3, GPIO_PIN2);
    GPIO_enableInterrupt(GPIO_PORT_P3, GPIO_PIN2);
    
    // Configure INT2 (P2.5) interrupt
    GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN5, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN5);
    GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN5);
    GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN5);
    
    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;
    __bis_SR_register(GIE);
    }
    
    void initClockTo16MHz()
    {
    // Configure one FRAM waitstate as required by the device datasheet for MCLK
    // operation beyond 8MHz _before_ configuring the clock system.
    FRCTL0 = FRCTLPW | NWAITS_1;
    
    // Clock System Setup
    CSCTL0_H = CSKEY_H; // Unlock CS registers
    CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz
    
    // Set SMCLK = MCLK = DCO, ACLK = VLOCLK (9.4kHz)
    CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    
    // Per Device Errata set divider to 4 before changing frequency to
    // prevent out of spec operation from overshoot transient
    CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4; // Set all corresponding clk sources to divide by 4 for errata
    CSCTL1 = DCOFSEL_4 | DCORSEL; // Set DCO to 16MHz
    
    // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz))
    __delay_cycles(60);
    CSCTL3 = DIVA__32 | DIVS__1 | DIVM__1; // Set ACLK to 239.75Hz, SMCLK to 16MHz, and MCLK to 16MHz
    CSCTL0_H = 0; // Lock CS registers
    }
    
    void initI2C()
    {
    UCB1CTLW0 = UCSWRST; // Enable SW reset
    UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC; // I2C master mode, SMCLK
    UCB1BRW = 160; // fSCL = ACLK/160 = ~100kHz
    UCB1I2CSA = SLAVE_ADDR; // Slave Address
    UCB1CTLW0 &= ~UCSWRST; // Clear SW reset, resume operation
    UCB1IE |= UCNACKIE;
    }
    
    void UART_init(void)
    {
    // Configure USCI_A1 for UART mode
    UCA1CTLW0 = UCSWRST; // Put eUSCI in reset
    UCA1CTLW0 |= UCSSEL__SMCLK; // CLK = SMCLK
    UCA1BR0 = 8; // Clock prescaler set to 8
    UCA1BR1 = 0x00; // High byte empty, low byte is 8
    UCA1MCTLW |= UCOS16 | UCBRF_10 | 0xF700; // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte
    UCA1CTLW0 &= ~UCSWRST; // Initialize eUSCI
    UCA1IE |= UCRXIE; // Enable USCI_A1 RX interrupt
    
    // Configure USCI_A0 for UART mode
    UCA0CTLW0 = UCSWRST; // Put eUSCI in reset
    UCA0CTLW0 |= UCSSEL__SMCLK; // CLK = SMCLK
    UCA0BR0 = 8; // Clock prescaler set to 8
    UCA0BR1 = 0x00; // High byte empty, low byte is 8
    UCA0MCTLW |= UCOS16 | UCBRF_10 | 0xF700; // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte
    UCA0CTLW0 &= ~UCSWRST; // Initialize eUSCI
    UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
    }
    
    
    
    //******************************************************************************
    // Main ************************************************************************
    //******************************************************************************
    
    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
    //Initialize all peripherals
    initClockTo16MHz();
    initGPIO();
    UART_init();
    initI2C();
    
    bmi160_init('Z');
    
    // Initialize the FFT parameters
    msp_status status;
    msp_fft_q15_params fftParams;
    
    /* Initialize the fft parameter structure. */
    fftParams.length = SAMPLES;
    fftParams.bitReverse = true;
    fftParams.twiddleTable = msp_cmplx_twiddle_table_4096_q15; //Twiddle table for 4096 values
    
    
    int i = 0;
    
    //new
    TA0CTL = TA0CTL | (SMCLK + CONTINUOUS); // SMCLK: Counts faster than ACLK
    // CONTINUOUS: Count 0 to 0xFFFF
    TA0CCTL0 = CCIE; // Timer_0 interrupt
    
    TA1CTL = TA1CTL | (ACLK + UP ); // Count up from 0 with ACLK
    TA1CCR0 = MS_10; // Duration approximatley 10ms
    
    _BIS_SR(GIE); // Activate all interrupts
    
    //new
    
    while(1)
    {
    printf("Reading samples\n");
    //Read SAMPLES amount of data from the BMI160
    for(i=0;i<SAMPLES;i++)
    {
    I2C_Master_ReadReg(SLAVE_ADDR, 0x16, 2); //Read the acceleration value from the BMI160 registers
    input[i]= ReceiveBuffer[0] | (ReceiveBuffer[1] << 8); //Store the value in an array
    //I2C_Master_ReadReg(SLAVE_ADDR, 0x18, 3); //Read the acceleration value from the BMI160 registers
    //SENSORTIME[i] = ((uint32_t)ReceiveBuffer[2] << 16) | ((uint32_t)ReceiveBuffer[1] << 😎 | ((uint32_t)ReceiveBuffer[0] << 0);
    //delay_ms(1); //Determines sampling frequency, up to 10kHz
    //__delay_cycles(4500);
    printf("Sent acc: %u\n",(unsigned)input[i]);
    }
    }
    }
    
    
    //******************************************************************************
    // Interrupts ******************************************************************
    //******************************************************************************
    
    //I2C Interrupt
    #pragma vector = USCI_B1_VECTOR
    __interrupt void USCI_B1_ISR(void)
    {
    //Must read from UCB1RXBUF
    uint8_t rx_val = 0;
    switch(__even_in_range(UCB1IV, USCI_I2C_UCBIT9IFG))
    {
    case USCI_NONE: break; // Vector 0: No interrupts
    case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG
    case USCI_I2C_UCNACKIFG: // Vector 4: NACKIFG
    UCB1CTLW0 |= UCTXSTT; // Re-send start if NACK
    break;
    case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG
    case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG
    case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3
    case USCI_I2C_UCTXIFG3: break; // Vector 12: TXIFG3
    case USCI_I2C_UCRXIFG2: break; // Vector 14: RXIFG2
    case USCI_I2C_UCTXIFG2: break; // Vector 16: TXIFG2
    case USCI_I2C_UCRXIFG1: break; // Vector 18: RXIFG1
    case USCI_I2C_UCTXIFG1: break; // Vector 20: TXIFG1
    case USCI_I2C_UCRXIFG0: // Vector 22: RXIFG0
    rx_val = UCB1RXBUF;
    if (RXByteCtr)
    {
    ReceiveBuffer[ReceiveIndex++] = rx_val;
    RXByteCtr--;
    }
    
    if (RXByteCtr == 1)
    {
    UCB1CTLW0 |= UCTXSTP;
    }
    else if (RXByteCtr == 0)
    {
    UCB1IE &= ~UCRXIE;
    MasterMode = IDLE_MODE;
    __bic_SR_register_on_exit(CPUOFF); // Exit LPM0
    }
    break;
    case USCI_I2C_UCTXIFG0: // Vector 24: TXIFG0
    switch (MasterMode)
    {
    case TX_REG_ADDRESS_MODE:
    UCB1TXBUF = TransmitRegAddr;
    if (RXByteCtr)
    MasterMode = SWITCH_TO_RX_MODE; // Need to start receiving now
    else
    MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer
    break;
    
    case SWITCH_TO_RX_MODE:
    UCB1IE |= UCRXIE; // Enable RX interrupt
    UCB1IE &= ~UCTXIE; // Disable TX interrupt
    UCB1CTLW0 &= ~UCTR; // Switch to receiver
    MasterMode = RX_DATA_MODE; // State state is to receive data
    UCB1CTLW0 |= UCTXSTT; // Send repeated start
    if (RXByteCtr == 1)
    {
    //Must send stop since this is the N-1 byte
    while((UCB1CTLW0 & UCTXSTT));
    UCB1CTLW0 |= UCTXSTP; // Send stop condition
    }
    break;
    
    case TX_DATA_MODE:
    if (TXByteCtr)
    {
    UCB1TXBUF = TransmitBuffer[TransmitIndex++];
    TXByteCtr--;
    }
    else
    {
    //Done with transmission
    UCB1CTLW0 |= UCTXSTP; // Send stop condition
    MasterMode = IDLE_MODE;
    UCB1IE &= ~UCTXIE; // disable TX interrupt
    __bic_SR_register_on_exit(CPUOFF); // Exit LPM0
    }
    break;
    
    default:
    __no_operation();
    break;
    }
    break;
    default: break;
    }
    }
    
    
    #pragma vector = PORT2_VECTOR
    __interrupt void PORT2_ISR(void)
    {
    switch(__even_in_range(P2IV, P2IV_P2IFG7))
    {
    case P2IV_NONE : break;
    case P2IV_P2IFG0 : break;
    case P2IV_P2IFG1 : break;
    case P2IV_P2IFG2 : break;
    case P2IV_P2IFG3 : break;
    case P2IV_P2IFG4 : break;
    case P2IV_P2IFG5 : //Int2 sensor interrupt
    P2IFG = P2IFG & ~(BIT2);
    break;
    case P2IV_P2IFG6 : break;
    case P2IV_P2IFG7 : break;
    default : _never_executed();
    }
    }
    
    
    // Timer_0 Interrupt Service Routine
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void Timer_A0 (void)
    {
    TA0CTL = TA0CTL & (~TAIFG); // Reset Timer_0 so it keeps counting
    }
    

     

    7 REPLIES 7

    FAE_CA1
    Community Moderator
    Community Moderator

    Hi,

    Here is what you can do to verify your code.

    In your initialization function, you can configure BMI160 as below.

    Write value of 0x11 to register 0x7E;     // set ACC to normal mode, by default ACC is +/-2g full scale range and 100Hz ODR
    Delay 5ms;                                                        // the max time of 3.8ms from datasheet
    Write value of 0x15 to register 0x7E;    // optional, set GYR to normal mode, by default GYR is +/-2000dps full scale range and 100Hz ODR
    Delay 80ms;                                                     // the max time of 80ms from datasheet

    unsigned char value = read register 0x03;

    If (value == 0x14) then it means both ACC and GYR are in normal mode now

    In your loop function for example you can burst read BMI160 data registers from 0x0C to 0x17 total 12 bytes in one single I2C transaction at 1s time interval. Then you can plot Ax, Ay, Az values on the terminal to see if you can get about 16384 integer when you place any axis pointing to sky and about -16384 integer when any axis is pointing to ground.

    If yes, then you can change BMI160 ACC full scale range to +/-8g by writing the value of 0x08 to register 0x41 and then repeat the above steps. You should get about 4096 integer when you place any axis pointing to sky and about -4096 integer when any axis is pointing to ground.

    Thanks.

     

    Hello @FAE_CA1 ,

    Thanks again for showing me the method. I have written the code based on your instructions, and it worked, but when I went back to the self-test code, the accelerometer value changed back to the same old wrong value. I am unable to preserve the calibration data. Am I missing something, or, by mistake, have I overwritten the calibration data? I would appreciate it greatly if you could tell me how to keep the calibration data intact.

    Thanks

    FAE_CA1
    Community Moderator
    Community Moderator

    Hi,

    BMI160 self-test is to check if the ACC and GYR work properly or not after BMI160 is soldered on the PCB board. You said that you are able to get correct values from ACC and GYR from my instructions above. Then you don't need to go back to self-test. If you do, then please perform a soft-reset by writing value of 0xB6 to register 0x7E and then delay 100ms so that BMI160 goes back to default state. Then you can configure BMI160 again to get sensor data.

    I am not sure what you mean by calibration data. You will not have access to the BMI160 calibration parameters in each sensor's NVM. But if you want to do a quick inline calibration, then please see the attached "How to perform BMI160 inline calibration ver1.1.pdf".

    Thanks.

    Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist