05-28-2024 12:21 PM
Hello,
Im trying to use BMi160 as an external interrupt with MSP430 in low power mode. So far interrupt feature works perfectly and I can wake up MSP430 from sleep mode by moving BMI160. However I also want to read the accel, after its being moved and show data on console. Which does not work correctly. I am using a function process() to read z-axis accel and printing the values, but i see wrong values as :
Output in console when accelerometer is laying on table without any movement: Z-axis: -24767.000000 Z-axis: -28095.000000 Z-axis: 23617.000000 Z-axis: -4031.000000 Z-axis: -31167.000000 Z-axis: -8895.000000 Z-axis: 2625.000000 Z-axis: -19390.000000 Z-axis: 14401.000000 Z-axis: 31553.000000 Z-axis: 9281.000000 Z-axis: 10305.000000 Z-axis: -32703.000000 | Output in console when accelerometer is moved: Z-axis: 12865.000000 Z-axis: -185.000000 Z-axis: -129.000000 Z-axis: -129.000000 Z-axis: 127.000000 Z-axis: -128.000000 Z-axis: 18559.000000 Z-axis: 51.000000 Z-axis: -128.000000 Z-axis: 127.000000 Z-axis: -128.000000 Z-axis: -32385.000000 Z-axis: -25285.000000 Z-axis: 10561.000000 Z-axis: 67.000000 |
Here it can be seen that when accelerometer is on rest, i get higher values and when accelerometer is being moved, output comes closer to 127 or 128. Sometimes, I can also see random jump in values in between.
My Code:
#include "driverlib.h"
#include <gpio.h>
#include <msp430fr5xx_6xxgeneric.h>
#include <stdint.h>
#include <stdio.h>
// Address of the BMI160
#define SLAVE_ADDR 0x69
#define MAX_BUFFER_SIZE 20
#define SAMPLES 1000
#define ACCEL_SCALE 16384.0 // Scale factor for ±2g range (default)
int16_t input[SAMPLES] = {0}; // Store samples
void initI2C() {
UCB1CTLW0 = UCSWRST; // Enable SW reset
UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC; // I2C master mode, SMCLK
UCB1BRW = 160; // fSCL = SMCLK/160 = ~100kHz
UCB1I2CSA = SLAVE_ADDR; // Slave Address
UCB1CTLW0 &= ~UCSWRST; // Clear SW reset, resume operation
}
void I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t count) {
// Send start condition
UCB1CTLW0 |= UCTR | UCTXSTT;
while (!(UCB1IFG & UCTXIFG)); // Wait for TX buffer to be ready
// Send device address with write flag
UCB1TXBUF = dev_addr << 1; // Address with write bit
while (!(UCB1IFG & UCTXIFG)); // Wait for TX buffer to be ready
// Send register address
UCB1TXBUF = reg_addr;
while (!(UCB1IFG & UCTXIFG)); // Wait for TX buffer to be ready
// Send data
for (int i = 0; i < count; i++) {
UCB1TXBUF = data[i];
while (!(UCB1IFG & UCTXIFG)); // Wait for TX buffer to be ready
}
// Send stop condition
UCB1CTLW0 |= UCTXSTP;
while (UCB1CTLW0 & UCTXSTP); // Wait for stop condition
}
void I2C_Master_ReadReg(uint8_t dev_addr, uint8_t *data, uint8_t count) {
// Send repeated start and switch to receive mode
UCB1CTLW0 &= ~UCTR;
UCB1CTLW0 |= UCTXSTT;
while (UCB1CTLW0 & UCTXSTT);
// Receive data
for (int i = 0; i < count; i++) {
while (!(UCB1IFG & UCRXIFG0));
data[i] = UCB1RXBUF;
}
// Send stop condition
UCB1CTLW0 |= UCTXSTP;
while (UCB1CTLW0 & UCTXSTP);
}
void initGPIO() {
// I2C pins (P4.0 is SDA, P4.1 is SCL)
P4SEL1 |= BIT0 | BIT1;
P4SEL0 &= ~(BIT0 | BIT1);
// Configure INT1 pin (P3.2) as input
P3DIR &= ~BIT2;
P3IES &= ~BIT2; // Interrupt on rising edge
P3IFG &= ~BIT2; // Clear interrupt flag
P3IE |= BIT2; // Enable interrupt
// Configure INT2 pin (P3.3) as input
P3DIR &= ~BIT3;
P3IES &= ~BIT3; // Interrupt on rising edge
P3IFG &= ~BIT3; // Clear interrupt flag
P3IE |= BIT3; // Enable interrupt
PM5CTL0 &= ~LOCKLPM5; // Disable the GPIO power-on default high-impedance mode
}
void init_BMI160_ACC() {
uint8_t writeData[2];
// Soft reset BMI160
writeData[0] = 0xB6;
I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1);
__delay_cycles(55000); // Delay 55ms for BMI160 to stabilize
// Set accelerometer to LPM mode
writeData[0] = 0x12;
I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1);
__delay_cycles(5000); // Delay 5ms for accelerometer to stabilize
// Set ODR to 100Hz with no average
writeData[0] = 0x86;
I2C_Master_WriteReg(SLAVE_ADDR, 0x40, writeData, 1);
// Set both INT1 pin as output, active-high, push-pull
writeData[0] = 0x0A;
I2C_Master_WriteReg(SLAVE_ADDR, 0x53, writeData, 1);
// Temporarily latch the interrupt for 80ms
writeData[0] = 0x09;
I2C_Master_WriteReg(SLAVE_ADDR, 0x54, writeData, 1);
// Route single-tap interrupt to INT1 pin
writeData[0] = 0x04;
I2C_Master_WriteReg(SLAVE_ADDR, 0x55, writeData, 1);
// Configure tap sensing
writeData[0] = 0x14; // Default values
I2C_Master_WriteReg(SLAVE_ADDR, 0x60, writeData, 1);
writeData[0] = 0x00; // Default threshold value
I2C_Master_WriteReg(SLAVE_ADDR, 0x5F, writeData, 1);
// Enable single-tap and double-tap interrupt
writeData[0] = 0x07;
I2C_Master_WriteReg(SLAVE_ADDR, 0x50, writeData, 1);
}
#pragma vector=PORT3_VECTOR
__interrupt void Port_3(void) {
if (P3IFG & BIT2) {
P3IFG &= ~BIT2; // Clear the interrupt flag for INT1
//printf("Single-tap detected!\n");
process();
}
}
void process() {
for (int i = 0; i < SAMPLES; i++) {
uint8_t reg_data[2] = {0};
uint8_t reg_addr = 0x16; // Register address for the Z-axis data (low byte)
// Write register address
I2C_Master_WriteReg(SLAVE_ADDR, reg_addr, NULL, 0);
// Read data
I2C_Master_ReadReg(SLAVE_ADDR, reg_data, 2);
// Interpret the received data (Z-axis)
int16_t raw_data = (int16_t)((reg_data[1] << 😎 | reg_data[0]);
// Convert raw data to G
float acceleration_g = raw_data ;
printf("Z-axis: %f\n", acceleration_g);
}
}
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
initGPIO();
initI2C();
init_BMI160_ACC();
__enable_interrupt(); // Enable global interrupts
int i = 0;
while (1) {
__low_power_mode_3(); // Enter LPM3
}
return 0;
}
05-28-2024 06:14 PM
Hi,
Thanks for your inquiry.
Please check your code below.
// Interpret the received data (Z-axis)
int16_t raw_data = (int16_t)((reg_data[1] << | reg_data[0]);
// Convert raw data to G
float acceleration_g = raw_data ;
printf("Z-axis: %f\n", acceleration_g);
(1) It should be (reg_data[1] << 8 | reg_data[0])
(2) BMI160 accel data has the sensitivity of 16384 LSB/g for x/y/z axes at +/-2g full scale range. So when you want to print z axis g values, you need to divide raw data by 16384 as accelration_g = raw data / 16384.0
Thanks.