Featherboard M0 and BMI160
BMI160 is the 6 axis MEMS inertial (3 axis Accelerometer + 3 axis Gyroscope) that is used for motion detection, gesture recognition, pedometer, orientation tracking, and so on. It has analog-to--digital converter inside and supports digital interface (SPI or I2C) to obtain the inertial data of gravity and/or acceleration as G and angular velocity as DPS (degree per second).The driver code is available from here.
The breakout board is available from here.
Code
Since I am just using Arduino IDE for the test, I downloaded the driver code from the above link and renamed bmi160.c as bmi160.ino.I did not add the driver file to the Arduino library folder this time.
bmi160-test.ino is basically referring to the bmi160_support.c which is included in the sample driver files. The functions defined in the bmi160_support.h are defined in the bmi160-test.ino.
Now let's see the each key functions.
I2C write function is listed below.
s8 bmi160_i2c_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
s32 ierror = BMI160_INIT_VALUE;
Wire.beginTransmission(dev_addr);
Wire.write((uint8_t)reg_addr);
for (uint8_t i = 0; i < cnt; i++)
{
Wire.write(reg_data[i]);
}
Wire.endTransmission();
return (s8)ierror;
}
I2C read functions is like this.
s8 bmi160_i2c_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
s32 ierror = BMI160_INIT_VALUE;
Wire.beginTransmission(dev_addr);
Wire.write((uint8_t)reg_addr);
Wire.endTransmission();
Wire.requestFrom(dev_addr, (byte)cnt);
for (uint8_t i = 0; i < cnt; i++)
{
reg_data[i] = Wire.read();
}
return (s8)ierror;
}
The above 2 functions are referred by the "i2c_routine" function and make sure the function name is same as the one referred from this function.
Next is the setup function.
void setup()It is very useful to add "while(!Serial)" before you print out any debug comment. This sentence waits until the serial terminal is connected so you will not miss the debug messages.
{
Serial.begin(115200);
Wire.begin();
while(!Serial);
bmi160_read_reg(BMI160_USER_CHIP_ID__REG, &id, BMI160_GEN_READ_WRITE_DATA_LENGTH);
Serial.print("Device ID: ");
Serial.println(id, HEX);
delay(1000);
Serial.println("Start Initialization");
bmi160_initialize_sensor();
Serial.println("End Initialization");
}
The function called "bmi160_initialize_sensor()" is the same as the one defined in the original "bmi160_support.c" file and you can just modify the following line depending on what mode you want to use.
com_rslt += bmi160_config_running_mode(STANDARD_UI_IMU);In my case, I am using "STANDARD_UI_IMU" mode and as you can see the comments in the original "bmi160_support.c" file, the following modes are supported in this code.
* Description | valueNext is the loop function.
* ----------------------------------------------------------|----------
* STANDARD_UI_9DOF_FIFO | 0
* STANDARD_UI_IMU_FIFO | 1
* STANDARD_UI_IMU | 2
* STANDARD_UI_ADVANCEPOWERSAVE | 3
* ACCEL_PEDOMETER | 4
* APPLICATION_HEAD_TRACKING | 5
* APPLICATION_NAVIGATION | 6
* APPLICATION_REMOTE_CONTROL | 7
* APPLICATION_INDOOR_NAVIGATION | 8
void loop()GYRO_SENS and ACC_SENS are the sensitivity value of Gyroscope and Accelerometer respectively. I am using the default register settings for those 2 parameters, so simply referring to the datasheet and defined the values as below.
{
// If data ready bit set, all data registers have new data
bmi160_read_reg(0x1B, &dr, BMI160_GEN_READ_WRITE_DATA_LENGTH);
if(dr & 0xC0) { // check if data ready interrupt
bmi160_read_gyro_xyz(&gxyz);
bmi160_read_accel_xyz(&axyz);
Now = micros();
}
gx = (float)gxyz.x/GYRO_SENS;
gy = (float)gxyz.y/GYRO_SENS;
gz = (float)gxyz.z/GYRO_SENS;
ax = (float)axyz.x/ACC_SENS;
ay = (float)axyz.y/ACC_SENS;
az = (float)axyz.z/ACC_SENS;
deltat = ((Now - lastUpdate)/1000000.0f);
lastUpdate = Now;
Serial.print("ax = "); Serial.print(ax);
Serial.print(" ay = "); Serial.print(ay);
Serial.print(" az = "); Serial.print(az); Serial.println(" g");
Serial.print("gx = "); Serial.print( gx, 2);
Serial.print(" gy = "); Serial.print( gy, 2);
Serial.print(" gz = "); Serial.print( gz, 2); Serial.println(" deg/s");
Serial.print("rate = "); Serial.print((float)1/deltat, 2); Serial.println(" Hz");
Serial.println("");
}
ACC_SENS = 16384 (LSB/g)By dividing the raw data of each sensor values, you can convert unit from the ADC counts to g or dps units.
GYRO_SENS = 16.4 (LSB/dps)