Fully featured I2C and SPI driver for CEVA (Hilcrest)'s BNO080 and FSM300 Inertial Measurement Units.

Dependents:   BNO080-Examples BNO080-Examples

BNO080 Driver

by Jamie Smith / USC Rocket Propulsion Lab

After lots of development, we are proud to present our driver for the Hilcrest BNO080 IMU! This driver is inspired by SparkFun and Nathan Seidle's Arduino driver for this chip, but has been substantially rewritten and adapted.

It supports the main features of the chip, such as reading rotation and acceleration data, as well as some of its more esoteric functionality, such as counting steps and detecting whether the device is being hand-held.

Features

  • Support for 15 different data reports from the IMU, from acceleration to rotation to tap detection
  • Support for reading of sensor data, and automatic checking of update rate against allowed values in metadata
  • BNO_DEBUG switch enabling verbose, detailed output about communications with the chip for ease of debugging
  • Ability to tare sensor rotation and set mounting orientation
  • Can operate in several execution modes: polling I2C, polling SPI, and threaded SPI (which handles timing-critical functions in a dedicated thread, and automatically activates when the IMU has data available)
    • Also has experimental support for using asynchronous SPI transactions, allowing other threads to execute while communication with the BNO is occurring. Note that this functionality requires a patch to Mbed OS source code due to Mbed bug #13941
  • Calibration function
  • Reasonable code size for what you get: the library uses about 4K of flash and one instance of the object uses about 1700 bytes of RAM.

Documentation

Full Doxygen documentation is available online here

Example Code

Here's a simple example:

BNO080 Rotation Vector and Acceleration

#include <mbed.h>
#include <BNO080.h>

int main()
{
	Serial pc(USBTX, USBRX);

	// Create IMU, passing in output stream, pins, I2C address, and I2C frequency
	// These pin assignments are specific to my dev setup -- you'll need to change them
	BNO080I2C imu(&pc, p28, p27, p16, p30, 0x4a, 100000); 

	pc.baud(115200);
	pc.printf("============================================================\n");

	// Tell the IMU to report rotation every 100ms and acceleration every 200ms
	imu.enableReport(BNO080::ROTATION, 100);
	imu.enableReport(BNO080::TOTAL_ACCELERATION, 200);

	while (true)
	{
		wait(.001f);
		
		// poll the IMU for new data -- this returns true if any packets were received
		if(imu.updateData())
		{
			// now check for the specific type of data that was received (can be multiple at once)
			if (imu.hasNewData(BNO080::ROTATION))
			{
				// convert quaternion to Euler degrees and print
				pc.printf("IMU Rotation Euler: ");
				TVector3 eulerRadians = imu.rotationVector.euler();
				TVector3 eulerDegrees = eulerRadians * (180.0 / M_PI);
				eulerDegrees.print(pc, true);
				pc.printf("\n");
			}
			if (imu.hasNewData(BNO080::TOTAL_ACCELERATION))
			{
				// print the acceleration vector using its builtin print() method
				pc.printf("IMU Total Acceleration: ");
				imu.totalAcceleration.print(pc, true);
				pc.printf("\n");
			}
		}
	}

}


If you want more, a comprehensive, ready-to-run set of examples is available on my BNO080-Examples repository.

Credits

This driver makes use of a lightweight, public-domain library for vectors and quaternions available here.

Changelog

Version 2.1 (Nov 24 2020)

  • Added BNO080Async, which provides a threaded implementation of the SPI driver. This should help get the best performance and remove annoying timing requirements on the code calling the driver
  • Added experimental USE_ASYNC_SPI option
  • Fixed bug in v2.0 causing calibrations to fail

Version 2.0 (Nov 18 2020)

  • Added SPI support
  • Refactored buffer system so that SPI could be implemented as a subclass. Unfortunately this does substantially increase the memory usage of the driver, but I believe that the benefits are worth it.

Version 1.3 (Jul 21 2020)

  • Fix deprecation warnings and compile errors in Mbed 6
  • Fix compile errors in Arm Compiler (why doesn't it have M_PI????)

Version 1.2 (Jan 30 2020)

  • Removed accidental IRQ change
  • Fixed hard iron offset reading incorrectly due to missing cast

Version 1.1 (Jun 14 2019)

  • Added support for changing permanent orientation
  • Add FRS writing functions
  • Removed some errant printfs

Version 1.0 (Dec 29 2018)

  • Initial Mbed OS release
Committer:
Jamie Smith
Date:
Thu Jan 30 02:16:15 2020 -0800
Revision:
4:70d05578f041
Parent:
3:197ad972fb7c
Child:
8:199c7fad233d
Fix a couple more minor issues

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jamie Smith 1:aac28ffd63ed 1 //
Jamie Smith 1:aac28ffd63ed 2 // Constants used in communication with the BNO080
Jamie Smith 1:aac28ffd63ed 3 //
Jamie Smith 1:aac28ffd63ed 4
Jamie Smith 1:aac28ffd63ed 5 #ifndef HAMSTER_BNO080CONSTANTS_H
Jamie Smith 1:aac28ffd63ed 6 #define HAMSTER_BNO080CONSTANTS_H
Jamie Smith 1:aac28ffd63ed 7
Jamie Smith 1:aac28ffd63ed 8
Jamie Smith 1:aac28ffd63ed 9 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Jamie Smith 1:aac28ffd63ed 10
Jamie Smith 3:197ad972fb7c 11 // Channels
Jamie Smith 1:aac28ffd63ed 12 #define CHANNEL_COMMAND 0
Jamie Smith 1:aac28ffd63ed 13 #define CHANNEL_EXECUTABLE 1
Jamie Smith 1:aac28ffd63ed 14 #define CHANNEL_CONTROL 2
Jamie Smith 1:aac28ffd63ed 15 #define CHANNEL_REPORTS 3
Jamie Smith 1:aac28ffd63ed 16 #define CHANNEL_WAKE_REPORTS 4
Jamie Smith 1:aac28ffd63ed 17 #define CHANNEL_GYRO 5
Jamie Smith 1:aac28ffd63ed 18
Jamie Smith 1:aac28ffd63ed 19 // Report IDs on the command channel.
Jamie Smith 1:aac28ffd63ed 20 // Unlike the other constants, these come from the Sensor Hub Transport Protocol datasheet, section 5.1
Jamie Smith 1:aac28ffd63ed 21 #define COMMAND_REPORTID_ADVERTISEMENT 0x0
Jamie Smith 1:aac28ffd63ed 22 #define COMMAND_REPORTID_ERRORLIST 0x1
Jamie Smith 1:aac28ffd63ed 23
Jamie Smith 1:aac28ffd63ed 24 //All the ways we can configure or talk to the BNO080, figure 34, page 36 reference manual
Jamie Smith 1:aac28ffd63ed 25 //These are used for low level communication with the sensor, on channel 2
Jamie Smith 1:aac28ffd63ed 26 #define SHTP_REPORT_COMMAND_RESPONSE 0xF1
Jamie Smith 1:aac28ffd63ed 27 #define SHTP_REPORT_COMMAND_REQUEST 0xF2
Jamie Smith 1:aac28ffd63ed 28 #define SHTP_REPORT_FRS_READ_RESPONSE 0xF3
Jamie Smith 1:aac28ffd63ed 29 #define SHTP_REPORT_FRS_READ_REQUEST 0xF4
Jamie Smith 3:197ad972fb7c 30 #define SHTP_REPORT_FRS_WRITE_RESPONSE 0xF5
Jamie Smith 3:197ad972fb7c 31 #define SHTP_REPORT_FRS_WRITE_DATA 0xF6
Jamie Smith 3:197ad972fb7c 32 #define SHTP_REPORT_FRS_WRITE_REQUEST 0xF7
Jamie Smith 1:aac28ffd63ed 33 #define SHTP_REPORT_PRODUCT_ID_RESPONSE 0xF8
Jamie Smith 1:aac28ffd63ed 34 #define SHTP_REPORT_PRODUCT_ID_REQUEST 0xF9
Jamie Smith 1:aac28ffd63ed 35 #define SHTP_REPORT_BASE_TIMESTAMP 0xFB
Jamie Smith 1:aac28ffd63ed 36 #define SHTP_REPORT_SET_FEATURE_COMMAND 0xFD
Jamie Smith 1:aac28ffd63ed 37 #define SHTP_REPORT_GET_FEATURE_RESPONSE 0xFC
Jamie Smith 1:aac28ffd63ed 38
Jamie Smith 1:aac28ffd63ed 39 //All the different sensors and features we can get reports from
Jamie Smith 1:aac28ffd63ed 40 //These are used when enabling a given sensor
Jamie Smith 1:aac28ffd63ed 41 #define SENSOR_REPORTID_TIMESTAMP_REBASE 0xFA
Jamie Smith 1:aac28ffd63ed 42 #define SENSOR_REPORTID_ACCELEROMETER 0x01
Jamie Smith 1:aac28ffd63ed 43 #define SENSOR_REPORTID_GYROSCOPE_CALIBRATED 0x02
Jamie Smith 1:aac28ffd63ed 44 #define SENSOR_REPORTID_MAGNETIC_FIELD_CALIBRATED 0x03
Jamie Smith 1:aac28ffd63ed 45 #define SENSOR_REPORTID_LINEAR_ACCELERATION 0x04
Jamie Smith 1:aac28ffd63ed 46 #define SENSOR_REPORTID_ROTATION_VECTOR 0x05
Jamie Smith 1:aac28ffd63ed 47 #define SENSOR_REPORTID_GRAVITY 0x06
Jamie Smith 1:aac28ffd63ed 48 #define SENSOR_REPORTID_GAME_ROTATION_VECTOR 0x08
Jamie Smith 1:aac28ffd63ed 49 #define SENSOR_REPORTID_GEOMAGNETIC_ROTATION_VECTOR 0x09
Jamie Smith 1:aac28ffd63ed 50 #define SENSOR_REPORTID_MAGNETIC_FIELD_UNCALIBRATED 0x0F
Jamie Smith 1:aac28ffd63ed 51 #define SENSOR_REPORTID_TAP_DETECTOR 0x10
Jamie Smith 1:aac28ffd63ed 52 #define SENSOR_REPORTID_STEP_COUNTER 0x11
Jamie Smith 1:aac28ffd63ed 53 #define SENSOR_REPORTID_SIGNIFICANT_MOTION 0x12
Jamie Smith 1:aac28ffd63ed 54 #define SENSOR_REPORTID_STABILITY_CLASSIFIER 0x13
Jamie Smith 1:aac28ffd63ed 55 #define SENSOR_REPORTID_STEP_DETECTOR 0x18
Jamie Smith 1:aac28ffd63ed 56 #define SENSOR_REPORTID_SHAKE_DETECTOR 0x19
Jamie Smith 1:aac28ffd63ed 57
Jamie Smith 1:aac28ffd63ed 58 // sensor report ID with the largest numeric value
Jamie Smith 1:aac28ffd63ed 59 #define MAX_SENSOR_REPORTID SENSOR_REPORTID_SHAKE_DETECTOR
Jamie Smith 1:aac28ffd63ed 60
Jamie Smith 1:aac28ffd63ed 61 // Q points for various sensor data elements
Jamie Smith 1:aac28ffd63ed 62 #define ACCELEROMETER_Q_POINT 8 // for accelerometer based data
Jamie Smith 1:aac28ffd63ed 63 #define GYRO_Q_POINT 9 // for gyroscope data
Jamie Smith 1:aac28ffd63ed 64 #define MAGNETOMETER_Q_POINT 4 // for magnetometer data
Jamie Smith 1:aac28ffd63ed 65 #define ROTATION_Q_POINT 14 // for rotation data
Jamie Smith 1:aac28ffd63ed 66 #define ROTATION_ACCURACY_Q_POINT 12 // for rotation accuracy data
Jamie Smith 1:aac28ffd63ed 67 #define POWER_Q_POINT 10 // for power information in the metadata
Jamie Smith 1:aac28ffd63ed 68 #define ORIENTATION_QUAT_Q_POINT 14 // for the set orientation command
Jamie Smith 3:197ad972fb7c 69 #define FRS_ORIENTATION_Q_POINT 30 // for the sensor orientation FRS record
Jamie Smith 1:aac28ffd63ed 70
Jamie Smith 1:aac28ffd63ed 71 // Report IDs on the Executable channel
Jamie Smith 1:aac28ffd63ed 72 // See Figure 1-27 in the BNO080 datasheet
Jamie Smith 1:aac28ffd63ed 73 #define EXECUTABLE_REPORTID_RESET 0x1
Jamie Smith 1:aac28ffd63ed 74
Jamie Smith 1:aac28ffd63ed 75 //Record IDs from SH-2 figure 28
Jamie Smith 1:aac28ffd63ed 76 //These are used to read and set various configuration options
Jamie Smith 1:aac28ffd63ed 77 #define FRS_RECORDID_SERIAL_NUMBER 0x4B4B
Jamie Smith 3:197ad972fb7c 78 #define FRS_RECORDID_SYSTEM_ORIENTATION 0x2D3E
Jamie Smith 1:aac28ffd63ed 79
Jamie Smith 1:aac28ffd63ed 80 //Command IDs from section 6.4, page 42
Jamie Smith 1:aac28ffd63ed 81 //These are used to calibrate, initialize, set orientation, tare etc the sensor
Jamie Smith 1:aac28ffd63ed 82 #define COMMAND_ERRORS 1
Jamie Smith 1:aac28ffd63ed 83 #define COMMAND_COUNTER 2
Jamie Smith 1:aac28ffd63ed 84 #define COMMAND_TARE 3
Jamie Smith 1:aac28ffd63ed 85 #define COMMAND_INITIALIZE 4
Jamie Smith 1:aac28ffd63ed 86 #define COMMAND_SAVE_DCD 6
Jamie Smith 1:aac28ffd63ed 87 #define COMMAND_ME_CALIBRATE 7
Jamie Smith 1:aac28ffd63ed 88 #define COMMAND_DCD_PERIOD_SAVE 9
Jamie Smith 1:aac28ffd63ed 89 #define COMMAND_OSCILLATOR 10
Jamie Smith 1:aac28ffd63ed 90 #define COMMAND_CLEAR_DCD 11
Jamie Smith 1:aac28ffd63ed 91 #define COMMAND_UNSOLICITED_INITIALIZE 0x84
Jamie Smith 1:aac28ffd63ed 92
Jamie Smith 1:aac28ffd63ed 93 #define CALIBRATE_ACCEL 0
Jamie Smith 1:aac28ffd63ed 94 #define CALIBRATE_GYRO 1
Jamie Smith 1:aac28ffd63ed 95 #define CALIBRATE_MAG 2
Jamie Smith 1:aac28ffd63ed 96 #define CALIBRATE_PLANAR_ACCEL 3
Jamie Smith 1:aac28ffd63ed 97 #define CALIBRATE_ACCEL_GYRO_MAG 4
Jamie Smith 1:aac28ffd63ed 98 #define CALIBRATE_STOP 5
Jamie Smith 1:aac28ffd63ed 99
Jamie Smith 1:aac28ffd63ed 100 // timing for reset
Jamie Smith 1:aac28ffd63ed 101 // per my measurement, reset takes about 90ms, so let's take twice that
Jamie Smith 3:197ad972fb7c 102 // By the way, I discovered (by accident) that a symptom of brownout is the chip taking
Jamie Smith 3:197ad972fb7c 103 // a long time to reset. So if you had to increase this, check that your Vcc is
Jamie Smith 3:197ad972fb7c 104 // within the allowed range.
Jamie Smith 1:aac28ffd63ed 105 #define BNO080_RESET_TIMEOUT .18f
Jamie Smith 1:aac28ffd63ed 106
Jamie Smith 1:aac28ffd63ed 107 #endif //HAMSTER_BNO080CONSTANTS_H