11-03-2022 04:21 PM
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
}
11-07-2022 05:31 PM
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.
11-10-2022 12:49 PM
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
11-10-2022 04:38 PM
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.