A Simple Example
my BNO_ReadMacros.h (And for writing BNO_WriteMacros.h) contains a series of macros that basically configure a simple read i2c function. Here is a list of macros that match the documented BNO055 pg 51 of the registry map:
#define R_AXIS_MAP_SIGN_X(Data) PG(0).ReadBit(0x42, 1, 2, (uint8_t *)Data) // Remapped X axis sign
#define R_AXIS_MAP_SIGN_Y(Data) PG(0).ReadBit(0x42, 1, 1, (uint8_t *)Data) // Remapped Y axis sign
#define R_AXIS_MAP_SIGN_Z(Data) PG(0).ReadBit(0x42, 1, 0, (uint8_t *)Data) // Remapped Z axis sign
#define R_AXIS_MAP_CONFIG_X(Data) PG(0).ReadBit(0x41, 2, 1, (uint8_t *)Data) // Remapped X axis value
#define R_AXIS_MAP_CONFIG_Y(Data) PG(0).ReadBit(0x41, 2, 3, (uint8_t *)Data) // Remapped Y axis value
#define R_AXIS_MAP_CONFIG_Z(Data) PG(0).ReadBit(0x41, 2, 5, (uint8_t *)Data) // Remapped Z axis value
#define R_TEMP_SOURCE(Data) PG(0).ReadBit(0x40, 2, 1, (uint8_t *)Data) // TEMP_Source <1:0>
#define R_PWR_MODE(Data) PG(0).ReadBit(0x3E, 2, 1, (uint8_t *)Data) // Power Mode <1:0>
#define R_OPR_MODE(Data) PG(0).ReadBit(0x3D, 4, 3, (uint8_t *)Data) // Operation Mode <3:0> Default 0x1C
//0x3C Reserved
#define R_UNIT_SEL(Data) PG(0).ReadByte(0x3B, (uint8_t *)Data) // Units Selection
#define R_UNIT_SEL_ORI_Android_Windows(Data) PG(0).ReadBit(0x3B, 1, 7, (uint8_t *)Data) // ORI_Android_Windows
#define R_UNIT_SEL_TEMP_Unit(Data) PG(0).ReadBit(0x3B, 1, 4, (uint8_t *)Data) // TEMP_Unit
#define R_UNIT_SEL_EUL_Unit(Data) PG(0).ReadBit(0x3B, 1, 2, (uint8_t *)Data) // EUL_Unit
#define R_UNIT_SEL_GYR_Unit(Data) PG(0).ReadBit(0x3B, 1, 1, (uint8_t *)Data) // GYR_Unit
#define R_UNIT_SEL_ACC_Uni(Data) PG(0).ReadBit(0x3B, 1, 0, (uint8_t *)Data) // ACC_Uni
#define R_SYS_ERR(Data) PG(0).ReadByte(0x3A, (uint8_t *)Data) // System Error Code
#define R_SYS_STATUS(Data) PG(0).ReadByte(0x39, (uint8_t *)Data) // System Status Code
#define R_SYS_CLK_STATUS(Data) PG(0).ReadBit(0x38, 1, 0, (uint8_t *)Data) // ST_MAIN_CLK
#define R_INT_STA_ACC_NM(Data) PG(0).ReadBit(0x37, 1, 7, (uint8_t *)Data) // ACC_NM
#define R_INT_STA_ACC_AM(Data) PG(0).ReadBit(0x37, 1, 6, (uint8_t *)Data) // ACC_AM
#define R_INT_STA_ACC_HIGH_G(Data) PG(0).ReadBit(0x37, 1, 5, (uint8_t *)Data) // ACC_HIGH_G
#define R_INT_STA_GYR_HIGH_G(Data) PG(0).ReadBit(0x37, 1, 3, (uint8_t *)Data) // ACC_HIGH_G
#define R_INT_STA_GYR_AM(Data) PG(0).ReadBit(0x37, 1, 2, (uint8_t *)Data) // ACC_AM
#define R_ST_RESULT(Data) PG(0).ReadBit(0x36, 4, 3, (uint8_t *)Data) // Bit 0 = Acc, 1 = Mag, 2 = Gyro, 3 = MCU
#define R_ST_RESULT_ST_MCU(Data) PG(0).ReadBit(0x36, 1, 3, (uint8_t *)Data) // ST_MCU
#define R_ST_RESULT_ST_GYR(Data) PG(0).ReadBit(0x36, 1, 2, (uint8_t *)Data) // ST_GYR
#define R_ST_RESULT_ST_MAG(Data) PG(0).ReadBit(0x36, 1, 1, (uint8_t *)Data) // ST_MAG
#define R_ST_RESULT_ST_ACC(Data) PG(0).ReadBit(0x36, 1, 0, (uint8_t *)Data) // ST_ACC
#define R_CALIB_STAT(Data) PG(0).ReadByte(0x35, (uint8_t *)Data) // Calibration Status
#define R_SYS_CALIB_STAT(Data) PG(0).ReadBit(0x35, 2, 7, (uint8_t *)Data) // SYS Calib Status 0:3
#define R_GYR_CALIB_STAT(Data) PG(0).ReadBit(0x35, 2, 5, (uint8_t *)Data) // GYR Calib Status 0:3
#define R_ACC_CALIB_STAT(Data) PG(0).ReadBit(0x35, 2, 3, (uint8_t *)Data) // ACC Calib Status 0:3
#define R_MAG_CALIB_STAT(Data) PG(0).ReadBit(0x35, 2, 1, (uint8_t *)Data) // MAG Calib Status 0:3
#define R_TEMP_Data(Data) PG(0).ReadByte(0x34, (uint8_t *)Data) // Temperature
#define R_GRV_Data(Data) PG(0).ReadInts(0x2E, 3, (int16_t *)Data) // Gravity Vector Data.
#define R_GRV_Data_X(Data) PG(0).ReadInt(0x2E, (int16_t *)Data) // Gravity Vector Data X <15:0>
#define R_GRV_Data_Y(Data) PG(0).ReadInt(0x30, (int16_t *)Data) // Gravity Vector Data Y <15:0>
#define R_GRV_Data_Z(Data) PG(0).ReadInt(0x32, (int16_t *)Data) // Gravity Vector Data Z <15:0>
#define R_LIA_Data(Data) PG(0).ReadInts(0x28, 3, (int16_t *)Data) // Linear Acceleration Data.
#define R_LIA_Data_X(Data) PG(0).ReadInt(0x28, (int16_t *)Data) // Linear Acceleration Data X <15:0>
#define R_LIA_Data_Y(Data) PG(0).ReadInt(0x2A, (int16_t *)Data) // Linear Acceleration Data Y <15:0>
#define R_LIA_Data_Z(Data) PG(0).ReadInt(0x2C, (int16_t *)Data) // Linear Acceleration Data Z <15:0>
#define R_QUA_Data(Data) PG(0).ReadInts(0x20, 4, (int16_t *)Data) // Quaternion Data.
#define R_QUA_Data_W(Data) PG(0).ReadInt(0x20, (int16_t *)Data) // Quaternion W Data <15:0>
#define R_QUA_Data_X(Data) PG(0).ReadInt(0x22, (int16_t *)Data) // Quaternion X Data <15:0>
#define R_QUA_Data_Y(Data) PG(0).ReadInt(0x24, (int16_t *)Data) // Quaternion Y Data <15:0>
#define R_QUA_Data_Z(Data) PG(0).ReadInt(0x26, (int16_t *)Data) // Quaternion Z Data <15:0>
#define R_EUL_Data(Data) PG(0).ReadInts(0x1A, 3, (int16_t *)Data) // Euler Heading Pitch and Roll.
#define R_EUL_Heading(Data) PG(0).ReadInt(0x1A, (int16_t *)Data) // Euler Heading Data < <15:0>
#define R_EUL_Roll(Data) PG(0).ReadInt(0x1C, (int16_t *)Data) // Euler Roll <15:0>
#define R_EUL_Pitch(Data) PG(0).ReadInt(0x1E, (int16_t *)Data) // Euler Pitch <15:0>
The following example will use the macros related to CALIB_STAT or the calibration state of the BNO055. the specific macro is: R_SYS_CALIB_STAT(Data)
//Example of its use:
Simple_BNO055 BNO; // Note that Simple_BNO055 extends the Simple_Wire library
// ... other code of course...
uint8_t CalStatus;
/*
Because the macros represent the Read*** functions of the Simple_Wire library they will return a
pointer to the library and not the value retrieved from the BNO055 IC. In order to use the value
in a single line, I needed to have the last item in the class... return the value retrieved. I was
hoping to make it as simple as possible For Example:
*/
if(BNO.R_SYS_CALIB_STAT(&CalStatus).Value(&CalStatus) == 3) {
Serial.println("Calibration Complete");
} else {
Serial.print("Calibration at level:");
Serial.println(CalStatus);
}
//Alternatively, it is probably just as simple to do the following:
BNO.R_SYS_CALIB_STAT(&CalStatus);
if(CalStatus == 3) {
Serial.println("Calibration Complete");
} else {
Serial.print("Calibration at level:");
Serial.println(CalStatus);
}
The option to do either is now available thanks to your help @J-M-L .
In Conclusion:
By using macros instead of a huge number of functions I have found it extremely simple to create a library that completely accesses every aspect of the i2c device. I have completed libraries for the MPU6050 which includes the MPU6500 and the MPU9*** series of i2c chips. I also in short order (about 3 days) created the library for the BNO055 i2c chip. The BNO055 is more expensive but far superior to the MPU6050 MPUs.
I've also resolved many of the issues I faced with compatibility between the Arduino Uno and the ESP32 processors I don't have any others to test but I can't see why minimal modifications wouldn't provide compatibility with them also.
Thanks, Everyone
Z
All the source code and examples can be found Here Simple_BNO055 and Here Simple_Wire