Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 

    BMI160 Sensor data conversion

    sensor512
    New Poster

    BMI160 Sensor data conversion

    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

    Re: BMI160 Sensor data conversion

    Hi,

    Thanks for your inquiry.

    According to BMI160 datasheet, the accel sensitivity is 4096LSB/g at +/-8g full scale range. So the integer 8664 is corresponding to 8664 LSBs / 4096LSB/g = 2.115g = 2.115 * 9.81m/s^2 = 20.748 m/s^2.

    Thanks.

    sensor512
    New Poster

    Re: BMI160 Sensor data conversion

    Thank you @FAE_CA1  , I have found some errors in my code and rewritten it with only the necessary values. I am still getting a wrong value based on that calculation. My device is completely stationary. In that case, I should read 1g in the "Z" axis or something close to 1g. 

    I have a few doubts:

    1. First of all, what does LSB mean? Is it the least significant bit in this context?

    2. As the accelerometer data is 16 bits long, I am using the following method to store the data. Is this the correct procedure to do it?

     

     

     

    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
    printf("Sent acc: %u\n",(unsigned)input[i]);

     

     

     

     

    3. Or should I only do the calculation with 8 least significant bits?

    4. In the 0x41 register, I have put the value "0b1000" to configure it as the +-8g range. So the LSB/g value should be 4096. Is it correct? Or, along with this register, do I need to configure some other registers as well to get the desired effect?

     

     

     

        writeData[0]=0b1000; //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");
        }

     

     

     

     

    5. Currently, the device is sitting on a table, so I am expecting 1 g on the "Z" axis. I am receiving this data on the serial terminal:

     

     

     

    Reading samples
    Sent acc: 2144
    Sent acc: 2113
    Sent acc: 2171
    Sent acc: 2124
    Sent acc: 2107
    Sent acc: 2121
    Sent acc: 2124
    Sent acc: 2132

     

     

     

     

    So based on the calculation method that you have shared, the result is 5.106 g, but the device is completely stationary, so I should read 1 g. Am I missing something?

     

     

     

    (2132/4096)*9.81= 5.106g

     

     

     

     

    Again, thank you very much for your time and consideration. I'm incredibly grateful for it.

     

     

    Here is my new modified code (I have removed most of the irrelevant codes):

     

     

     

    #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>
    
    
    //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 10
    
    /* Declare as persistent to move variable from RAM to FRAM */
    #pragma PERSISTENT(input)
    int16_t input[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
    
    //******************************************************************************
    // 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]=0b1000; //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 */
    
        // 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
    
        // 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');
    
        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
                   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;
      }
    }
    
    
    
    // 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
    }

     

     

     

     

    FAE_CA1
    Community Moderator

    Re: BMI160 Sensor data conversion

    Hi,

    LSB actually means signed integer value. After you read two byte BMI160 accel data registers, you can combine it as a signed integer. Multiplied by sensitivity you will get the meaningful acceleration such as 1g, 0g, -1g, etc. Please see the attached PDF file "How to perform BMI160 self-test v1.2.pdf" for more information.

    When you place the board with BMI160 z axis pointing to sky stationary, you should get around 0g for x and y axes and 1g for z axis. If you place the board upside down, then you should get around 0g for x and y axes and -1g for z axis.

    Thanks.

     

    sensor512
    New Poster

    Re: BMI160 Sensor data conversion

    Thank you @FAE_CA1  for your reply. I completed the self-test. The sensor passed the evaluation. However, if I return to my code, I receive the same outcome. Is the sensor's calibration changeable? How does one go about doing that?

     

    Thanks

     

    Here is the result of the self test (serial terminal):

    soft reset BMI160 complete
    Accelerometer set to normal mode
    enable self-test positive
    Sent acc pos X: -7575
    Sent acc pos Y: -28894
    Sent acc pos Z: -1575
    All sensor positive read complete
    enable self-test negative
    Sent acc neg X: 8999
    Sent acc neg Y: 28258
    Sent acc neg Z: 11586
    All sensor negative read complete
    Self test passed
    soft reset BMI160 complete

      

    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