Fully featured I2C and SPI driver for CEVA (Hilcrest)'s BNO080 and FSM300 Inertial Measurement Units.
Dependents: BNO080-Examples BNO080-Examples
BNO080.h
00001 /* 00002 * This is USC RPL's ARM MBed BNO080 IMU driver, by Jamie Smith. 00003 * 00004 * It is based on SparkFun and Nathan Seidle's Arduino driver for this chip, but is substantially rewritten and adapted. 00005 * It also supports some extra features, such as setting the mounting orientation and 00006 * enabling some additional data reports. 00007 * 00008 * This driver uses no dynamic allocation, but does allocate a couple hundred bytes of class variables as buffers. 00009 * This should allow you to monitor its memory usage using MBed's size printout. 00010 * 00011 * The BNO080 is a very complex chip; it's capable of monitoring and controlling other sensors and making 00012 * intelligent decisions and calculations using its data. Accordingly, the protocol for communicating with it 00013 * is quite complex, and it took me quite a while to wrap my head around it. If you need to modify or debug 00014 * this driver, look at the CPP file for an overview of the chip's communication protocol. 00015 * 00016 * Note: this driver only supports I2C. I attempted to create an SPI version, but as far as I can tell, 00017 * the BNO's SPI interface has a bug that causes you to be unable to wake the chip from sleep in some conditions. 00018 * Until this is fixed, SPI on it is virtually unusable. 00019 */ 00020 00021 #ifndef HAMSTER_BNO080_H 00022 #define HAMSTER_BNO080_H 00023 00024 #include <mbed.h> 00025 #include <Stream.h> 00026 #include <quaternion.h> 00027 00028 #include "BNO080Constants.h" 00029 00030 // useful define when working with orientation quaternions 00031 #define SQRT_2 1.414213562f 00032 00033 // Enable this to enable experimental support for Mbed's asynchronous SPI transfer API. 00034 // This will allow your processor to do other things while long SPI transfers are taking place 00035 // (and this IMU can end up transferring hundreds of bytes per packet, so this is useful). 00036 // To get this to work, you may need to use a slower clock rate (<1MHz on the STM32F429ZI I tested). 00037 // You also will need to edit Mbed OS code in order to use 0x00 as the SPI fill character for 00038 // asynchronous transfers (the API currently only allows changing this for synchronous transfers) 00039 // (I had to edit the SPI_FILL_CHAR constant in stm_spi_api.c). 00040 #define USE_ASYNC_SPI 0 00041 00042 // Note: I filed a bug about the SPI fill char issue: https://github.com/ARMmbed/mbed-os/issues/13941 00043 00044 /** 00045 Class to drive the BNO080 9-axis IMU. 00046 00047 There should be one instance of this class per IMU chip. I2C address and pin assignments are passed in the constructor. 00048 */ 00049 class BNO080Base 00050 { 00051 protected: 00052 /** 00053 * Serial stream to print debug info to. Used for errors, and debugging output if debugging is enabled. 00054 */ 00055 Stream * _debugPort; 00056 00057 /// Interrupt pin -- signals to the host that the IMU has data to send 00058 // Note: only ever used as a digital input by BNO080. 00059 // Used for interrupts by BNO080Async. 00060 InterruptIn _int; 00061 00062 // Reset pin -- resets IMU when held low. 00063 DigitalOut _rst; 00064 00065 // packet storage 00066 //----------------------------------------------------------------------------------------------------------------- 00067 00068 #define SHTP_HEADER_SIZE 4 00069 00070 // Size of the largest individual packet we can receive. 00071 // Min value is set by the advertisement packet (272 bytes) 00072 // If you enable lots of sensor reports and get an error, you might need to increase this. 00073 #define SHTP_RX_PACKET_SIZE 272 00074 00075 // Size of largest packet that we need to transmit (not including header) 00076 #define SHTP_MAX_TX_PACKET_SIZE 17 00077 00078 // scratch space buffers 00079 uint8_t txPacketBuffer[SHTP_HEADER_SIZE + SHTP_MAX_TX_PACKET_SIZE]; 00080 uint8_t rxPacketBuffer[SHTP_HEADER_SIZE + SHTP_RX_PACKET_SIZE + SHTP_HEADER_SIZE]; // need a second header worth of extra scratch space to write the header of a continued packet 00081 00082 /// Each SHTP packet starts with a header of 4 uint8_ts 00083 uint8_t * txShtpHeader = txPacketBuffer; 00084 uint8_t * rxShtpHeader = rxPacketBuffer; 00085 00086 /// Stores data contained in each packet. Packets can contain an arbitrary amount of data, but 00087 /// rarely get over a hundred bytes unless you have a million sensor reports enabled. 00088 /// The only long packets we actually care about are batched sensor data packets. 00089 uint8_t * txShtpData = txPacketBuffer + SHTP_HEADER_SIZE; 00090 uint8_t * rxShtpData = rxPacketBuffer + SHTP_HEADER_SIZE; 00091 00092 /// Length of packet that was received into buffer. Does NOT include header bytes. 00093 uint16_t rxPacketLength; 00094 00095 /// Current sequence number for each channel, incremented after transmission. 00096 uint8_t sequenceNumber[6]; 00097 00098 /// Commands have a seqNum as well. These are inside command packet, the header uses its own seqNum per channel 00099 uint8_t commandSequenceNumber; 00100 00101 // frs metadata 00102 //----------------------------------------------------------------------------------------------------------------- 00103 00104 /// Record ID of the metadata record currently stored in the metadataRecord[] buffer. 00105 /// Used so that we can avoid requerying the FRS record if we need to make multiple metadata reads 00106 /// in succession. 00107 uint16_t bufferMetadataRecord; 00108 00109 /// currently we only need the first 10 words of the metadata 00110 #define METADATA_BUFFER_LEN 10 00111 00112 /// Buffer for current metadata record. 00113 uint32_t metadataRecord[METADATA_BUFFER_LEN]; 00114 00115 // data storage 00116 //----------------------------------------------------------------------------------------------------------------- 00117 00118 // 1 larger than the largest sensor report ID 00119 #define STATUS_ARRAY_LEN MAX_SENSOR_REPORTID + 1 00120 00121 /// stores status of each sensor, indexed by report ID 00122 uint8_t reportStatus[STATUS_ARRAY_LEN]; 00123 00124 /// stores whether a sensor has been updated since the last call to hasNewData() 00125 bool reportHasBeenUpdated[STATUS_ARRAY_LEN]; 00126 00127 public: 00128 00129 // list of reports 00130 //----------------------------------------------------------------------------------------------------------------- 00131 00132 /// List of all sensor reports that the IMU supports. 00133 enum Report 00134 { 00135 /** 00136 * Total acceleration of the IMU in world space. 00137 * See BNO datasheet section 2.1.1 00138 */ 00139 TOTAL_ACCELERATION = SENSOR_REPORTID_ACCELEROMETER, 00140 00141 /** 00142 * Acceleration of the IMU not including the acceleration of gravity. 00143 * See BNO datasheet section 2.1.1 00144 */ 00145 LINEAR_ACCELERATION = SENSOR_REPORTID_LINEAR_ACCELERATION, 00146 00147 /** 00148 * Acceleration of gravity felt by the IMU. 00149 * See BNO datasheet section 2.1.1 00150 */ 00151 GRAVITY_ACCELERATION = SENSOR_REPORTID_GRAVITY, 00152 00153 /** 00154 * (calibrated) gyroscope reading of the rotational speed of the IMU. 00155 * See BNO datasheet section 2.1.2 00156 */ 00157 GYROSCOPE = SENSOR_REPORTID_GYROSCOPE_CALIBRATED, 00158 00159 /** 00160 * (calibrated) reading of Earth's magnetic field levels. 00161 * See BNO datasheet section 2.1.3 00162 */ 00163 MAG_FIELD = SENSOR_REPORTID_MAGNETIC_FIELD_CALIBRATED, 00164 00165 /** 00166 * Uncalibrated reading of magnetic field levels, without any hard iron offsets applied 00167 * See BNO datasheet section 2.1.3 00168 */ 00169 MAG_FIELD_UNCALIBRATED = SENSOR_REPORTID_MAGNETIC_FIELD_UNCALIBRATED, 00170 00171 /** 00172 * Fused reading of the IMU's rotation in space using all three sensors. This is the most accurate reading 00173 * of absolute orientation that the IMU can provide. 00174 * See BNO datasheet section 2.2.4 00175 */ 00176 ROTATION = SENSOR_REPORTID_ROTATION_VECTOR, 00177 00178 /** 00179 * Fused reading of rotation from accelerometer and magnetometer readings. This report is designed to decrease 00180 * power consumption (by turning off the gyroscope) in exchange for reduced responsiveness. 00181 */ 00182 GEOMAGNETIC_ROTATION = SENSOR_REPORTID_GEOMAGNETIC_ROTATION_VECTOR, 00183 00184 /** 00185 * Fused reading of the IMU's rotation in space. Unlike the regular rotation vector, the Game Rotation Vector 00186 * is not referenced against the magnetic field and the "zero yaw" point is arbitrary. 00187 * See BNO datasheet section 2.2.2 00188 */ 00189 GAME_ROTATION = SENSOR_REPORTID_GAME_ROTATION_VECTOR, 00190 00191 /** 00192 * Detects a user tapping on the device containing the IMU. 00193 * See BNO datasheet section 2.4.2 00194 */ 00195 TAP_DETECTOR = SENSOR_REPORTID_TAP_DETECTOR, 00196 00197 /** 00198 * Detects whether the device is on a table, being held stably, or being moved. 00199 * See BNO datasheet section 2.4.1 00200 */ 00201 STABILITY_CLASSIFIER = SENSOR_REPORTID_STABILITY_CLASSIFIER, 00202 00203 /** 00204 * Detects a user taking a step with the IMU worn on their person. 00205 * See BNO datasheet section 2.4.3 00206 */ 00207 STEP_DETECTOR = SENSOR_REPORTID_STEP_DETECTOR, 00208 00209 /** 00210 * Detects how many steps a user has taken. 00211 * See BNO datasheet section 2.4.4 00212 */ 00213 STEP_COUNTER = SENSOR_REPORTID_STEP_COUNTER, 00214 00215 /** 00216 * Detects when the IMU has made a "significant" motion, defined as moving a few steps and/or accelerating significantly. 00217 * 00218 * NOTE: this report automatically disables itself after sending a report, so you'll have to reenable it each time a motion i s detected. 00219 * See BNO datasheet section 2.4.6 00220 */ 00221 SIGNIFICANT_MOTION = SENSOR_REPORTID_SIGNIFICANT_MOTION, 00222 00223 /** 00224 * Detects when the IMU is being shaken. 00225 * See BNO datasheet section 2.4.7 00226 */ 00227 SHAKE_DETECTOR = SENSOR_REPORTID_SHAKE_DETECTOR 00228 }; 00229 00230 // data variables to read reports from 00231 //----------------------------------------------------------------------------------------------------------------- 00232 00233 // @{ 00234 /// Version info read from the IMU when it starts up 00235 uint8_t majorSoftwareVersion; 00236 uint8_t minorSoftwareVersion; 00237 uint16_t patchSoftwareVersion; 00238 uint32_t partNumber; 00239 uint32_t buildNumber; 00240 // @} 00241 00242 00243 /** 00244 * Readout from Accleration report. 00245 * Represents total acceleration in m/s^2 felt by the BNO's accelerometer. 00246 */ 00247 TVector3 totalAcceleration; 00248 00249 /** 00250 * Readout from Linear Acceleration report. 00251 * Represents acceleration felt in m/s^2 by the BNO's accelerometer not including the force of gravity. 00252 */ 00253 TVector3 linearAcceleration; 00254 00255 /** 00256 * Readout from Gravity report. 00257 * Represents the force of gravity in m/s^2 felt by the BNO's accelerometer. 00258 */ 00259 TVector3 gravityAcceleration; 00260 00261 /** 00262 * Readout from Calibrated Gyroscope report 00263 * Represents the angular velocities of the chip in rad/s in the X, Y, and Z axes 00264 */ 00265 TVector3 gyroRotation; 00266 00267 /** 00268 * Readout from the Magnetic Field Calibrated report. 00269 * Represents the magnetic field read by the chip in uT in the X, Y, and Z axes 00270 */ 00271 TVector3 magField; 00272 00273 /** 00274 * Readout from the Magnetic Field Uncalibrated report. 00275 * Represents the magnetic field read by the chip in uT in the X, Y, and Z axes, without hard iron offsets applied 00276 */ 00277 TVector3 magFieldUncalibrated; 00278 00279 /** 00280 * Auxiliary readout from the Magnetic Field Uncalibrated report. 00281 * Represents the hard iron offsets that the chip is using in each axis in uT. 00282 */ 00283 TVector3 hardIronOffset; 00284 00285 /** 00286 * Readout from the Rotation Vector report. 00287 * Represents the rotation of the IMU (relative to magnetic north) in radians. 00288 */ 00289 Quaternion rotationVector; 00290 00291 /** 00292 * Auxiliary accuracy readout from the Rotation Vector report. 00293 * Represents the estimated accuracy of the rotation vector in radians. 00294 */ 00295 float rotationAccuracy; 00296 00297 /** 00298 * Readout from the Game Rotation Vector report. 00299 * Represents the rotation of the IMU in radians. Unlike the regular rotation vector, the Game Rotation Vector 00300 * is not referenced against the magnetic field and the "zero yaw" point is arbitrary. 00301 */ 00302 Quaternion gameRotationVector; 00303 00304 /** 00305 * Readout from the Geomagnetic Rotation Vector report. 00306 * Represents the geomagnetic rotation of the IMU (relative to magnetic north) in radians. 00307 */ 00308 Quaternion geomagneticRotationVector; 00309 00310 /** 00311 * Auxiliary accuracy readout from the Geomagnetic Rotation Vector report. 00312 * Represents the estimated accuracy of the rotation vector in radians. 00313 */ 00314 float geomagneticRotationAccuracy; 00315 00316 /** 00317 * Tap readout from the Tap Detector report. This flag is set to true whenever a tap is detected, and you should 00318 * manually clear it when you have processed the tap. 00319 */ 00320 bool tapDetected; 00321 00322 /** 00323 * Whether the last tap detected was a single or double tap. 00324 */ 00325 bool doubleTap; 00326 00327 /** 00328 * Enum to represent the different stability types. 00329 * 00330 * See BNO datasheet section 2.4.1 and SH-2 section 6.5.31.2 for details. 00331 */ 00332 enum Stability 00333 { 00334 /// Unknown stability type. 00335 UNKNOWN = 0, 00336 00337 /// At rest on a stable surface with very little motion 00338 ON_TABLE = 1, 00339 00340 /// Motion is stable, but the duration requirement for stability has not been met. 00341 /// Can only occur during gyroscope calibration (why? beats me!) 00342 STATIONARY = 2, 00343 00344 /// Stable (has been below the acceleration threshold for the required duration) 00345 STABLE = 3, 00346 00347 /// IMU is moving. 00348 MOTION = 4 00349 }; 00350 00351 /** 00352 * Readout from the stability classifier. 00353 * Current stability status of the IMU. 00354 */ 00355 Stability stability; 00356 00357 /** 00358 * Readout from the Step Detector report. This flag is set to true whenever a step is detected, and you should 00359 * manually clear it when you have processed the step. 00360 */ 00361 bool stepDetected; 00362 00363 /** 00364 * Readout from the Step Counter report. This count increases as the user takes steps, but can also decrease 00365 * if the IMU decides that a motion was not a step. 00366 */ 00367 uint16_t stepCount; 00368 00369 /** 00370 * Readout from the Significant Motion Detector report. This flag is set to true whenever significant motion is detected, and you should 00371 * manually clear it when you have processed the event. 00372 */ 00373 bool significantMotionDetected; 00374 00375 /** 00376 * Readout from the Shake Detector report. This flag is set to true whenever shaking is detected, and you should 00377 * manually clear it when you have processed the event. 00378 */ 00379 bool shakeDetected; 00380 00381 // @{ 00382 /// The axis/axes that shaking was detected in in the latest shaking report. 00383 bool xAxisShake; 00384 bool yAxisShake; 00385 bool zAxisShake; 00386 // @} 00387 00388 // Management functions 00389 //----------------------------------------------------------------------------------------------------------------- 00390 00391 /** 00392 * Construct a BNO080, providing pins and parameters. 00393 * 00394 * This doesn't actally initialize the chip, you will need to call begin() for that. 00395 * 00396 * NOTE: while some schematics tell you to connect the BOOTN pin to the processor, this driver does not use or require it. 00397 * Just tie it to VCC per the datasheet. 00398 * 00399 * @param debugPort Serial port to write output to. Cannot be nullptr. 00400 */ 00401 BNO080Base(Stream *debugPort, PinName user_INTPin, PinName user_RSTPin); 00402 00403 /** 00404 * Resets and connects to the IMU. Verifies that it's connected, and reads out its version 00405 * info into the class variables above. 00406 * 00407 * If this function is failing, it would be a good idea to turn on BNO_DEBUG in the cpp file to get detailed output. 00408 * 00409 * Note: this function takes several hundred ms to execute, mainly due to waiting for the BNO to boot. 00410 * 00411 * @return whether or not initialization was successful 00412 */ 00413 virtual bool begin(); 00414 00415 /** 00416 * Tells the IMU to use its current rotation vector as the "zero" rotation vector and to reorient 00417 * all outputs accordingly. 00418 * 00419 * @param zOnly If true, only the rotation about the Z axis (the heading) will be tared. 00420 */ 00421 void tare(bool zOnly = false); 00422 00423 /** 00424 * Tells the IMU to begin a dynamic sensor calibration. To calibrate the IMU, call this function and move 00425 * the IMU according to the instructions in the "BNO080 Sensor Calibration Procedure" app note 00426 * (http://www.hillcrestlabs.com/download/59de9014566d0727bd002ae7). 00427 * 00428 * To tell when the calibration is complete, look at the status bits for Game Rotation Vector (for accel and gyro) 00429 * and Magnetic Field (for the magnetometer). 00430 * 00431 * The gyro and accelerometer should only need to be calibrated once, but the magnetometer will need to be recalibrated 00432 * every time the orientation of ferrous metals around the IMU changes (e.g. when it is put into a new enclosure). 00433 * 00434 * The new calibration will not be saved in flash until you call saveCalibration(). 00435 * 00436 * NOTE: calling this with all false values will cancel any calibration in progress. However, the calibration data being created will 00437 * remain in use until the next chip reset (I think!) 00438 * 00439 * @param calibrateAccel Whether to calibrate the accelerometer. 00440 * @param calibrateGyro Whether to calibrate the gyro. 00441 * @param calibrateMag Whether to calibrate the magnetometer. 00442 * 00443 * @return whether the operation succeeded 00444 */ 00445 bool enableCalibration(bool calibrateAccel, bool calibrateGyro, bool calibrateMag); 00446 00447 /** 00448 * Saves the calibration started with startCalibration() and ends the calibration. 00449 * You will want to call this once the status bits read as "accuracy high". 00450 * 00451 * WARNING: if you paid for a factory calibrated IMU, then this WILL OVERWRITE THE FACTORY CALIBRATION in whatever sensors 00452 * are being calibrated. Use with caution! 00453 * 00454 * @return whether the operation succeeded 00455 */ 00456 bool saveCalibration(); 00457 00458 /** 00459 * Sets the orientation quaternion, telling the sensor how it's mounted 00460 * in relation to world space. 00461 * See page 40 of the BNO080 datasheet. 00462 * 00463 * NOTE: this driver provides the macro SQRT_2 to help with entering values from that table. 00464 * 00465 * NOTE 2: this setting does not persist and will have to be re-applied every time the chip is reset. 00466 * Use setPermanentOrientation() for that. 00467 * 00468 * @param orientation quaternion mapping from IMU space to world space. 00469 */ 00470 void setSensorOrientation(Quaternion orientation); 00471 00472 /** 00473 * Sets the orientation quaternion, telling the sensor how it's mounted 00474 * in relation to world space. See page 40 of the BNO080 datasheet. 00475 * 00476 * Unlike setSensorOrientation(), this setting will persist across sensor restarts. 00477 * However, it will also take a few hundred milliseconds to write. 00478 * 00479 * @param orientation quaternion mapping from IMU space to world space. 00480 * 00481 * @return true if the operation succeeded, false if it failed. 00482 */ 00483 bool setPermanentOrientation(Quaternion orientation); 00484 00485 /** 00486 * No-op on synchronous driver. For compatibility with BNO080Async 00487 */ 00488 virtual void lockMutex() 00489 {} 00490 00491 /** 00492 * No-op on synchronous driver. For compatibility with BNO080Async 00493 */ 00494 virtual void unlockMutex() 00495 {} 00496 00497 // Report functions 00498 //----------------------------------------------------------------------------------------------------------------- 00499 00500 /** 00501 * Checks for new data packets queued on the IMU. 00502 * If there are packets queued, receives all of them and updates 00503 * the class variables with the results. 00504 * 00505 * Note that with some backends (SPI), sending commands will also update data, which can 00506 * cause updateData() to return false even though new data has been received. hasNewData() 00507 * is a more reliable way to determine if a sensor has new data. 00508 * 00509 * @return True iff new data packets of any kind were received. If you need more fine-grained data change reporting, 00510 * check out hasNewData(). 00511 */ 00512 virtual bool updateData(); 00513 00514 /** 00515 * Gets the status of a report as a 2 bit number. 00516 * per SH-2 section 6.5.1, this is interpreted as: <br> 00517 * 0 - unreliable <br> 00518 * 1 - accuracy low <br> 00519 * 2 - accuracy medium <br> 00520 * 3 - accuracy high <br> 00521 * of course, these are only updated if a given report is enabled. 00522 * @param report 00523 * @return 00524 */ 00525 uint8_t getReportStatus(Report report); 00526 00527 /** 00528 * Get a string for printout describing the status of a sensor. 00529 * @return 00530 */ 00531 const char* getReportStatusString(Report report); 00532 00533 /** 00534 * Checks if a specific report has gotten new data since the last call to this function. 00535 * @param report The report to check. 00536 * @return Whether the report has received new data. 00537 */ 00538 bool hasNewData(Report report); 00539 00540 /** 00541 * Enable a data report from the IMU. Look at the comments above to see what the reports do. 00542 * This function checks your polling period against the report's max speed in the IMU's metadata, 00543 * and reports an error if you're trying to poll too fast. 00544 * 00545 * @param timeBetweenReports time in milliseconds between data updates. 00546 */ 00547 void enableReport(Report report, uint16_t timeBetweenReports); 00548 00549 /** 00550 * Disable a data report from the IMU. 00551 * 00552 * @param report The report to disable. 00553 */ 00554 void disableReport(Report report); 00555 00556 /** 00557 * Gets the serial number (used to uniquely identify each individual device). 00558 * 00559 * NOTE: this function should work according to the datasheet, but the device I was testing with appears to have 00560 * an empty serial number record as shipped, and I could never get anything out of it. Your mileage may vary. 00561 * 00562 * @return The serial number, or 0 on error. 00563 */ 00564 uint32_t getSerialNumber(); 00565 00566 // Metadata functions 00567 //----------------------------------------------------------------------------------------------------------------- 00568 00569 /** 00570 * Gets the range of a report as reported by the IMU. Units are the same as the report's output data. 00571 * @return 00572 */ 00573 float getRange(Report report); 00574 00575 /** 00576 * Gets the resolution of a report as reported by the IMU. Units are the same as the report's output data. 00577 * @param report 00578 * @return 00579 */ 00580 float getResolution(Report report); 00581 00582 /** 00583 * Get the power used by a report when it's operating, according to the IMU. 00584 * @param report 00585 * @return Power used in mA. 00586 */ 00587 float getPower(Report report); 00588 00589 /** 00590 * Gets the smallest polling period that a report supports. 00591 * @return Period in seconds. 00592 */ 00593 float getMinPeriod(Report report); 00594 00595 /** 00596 * Gets the larges polling period that a report supports. 00597 * Some reports don't have a max period, in which case this function will return -1.0. 00598 * 00599 * @return Period in seconds, or -1.0 on error. 00600 */ 00601 float getMaxPeriod(Report report); 00602 00603 /** 00604 * Prints a summary of a report's metadata to the 00605 * debug stream. Should be useful for debugging and setting up reports since lots of this data 00606 * isn't given in the datasheets. 00607 * 00608 * Note: to save string constant space, this function is only available when BNO_DEBUG is 1. 00609 */ 00610 void printMetadataSummary(Report report); 00611 00612 protected: 00613 00614 // Internal metadata functions 00615 //----------------------------------------------------------------------------------------------------------------- 00616 00617 /** 00618 * Gets the version of the metadata stored in the buffer. 00619 * We might see version 3 and 4 records, and they have different layouts. 00620 * @return 00621 */ 00622 uint16_t getMetaVersion() {return static_cast<uint16_t>(metadataRecord[3] >> 16);} 00623 00624 // @{ 00625 /** 00626 * Gets the Q point from a report's metadata, which essentially defines where the decimal point goes in the sensor's output. 00627 * The 1/2/3 Q values are used in different places in the metadata, see SH-2 section 5.1 for details. 00628 * @param report 00629 * @return 00630 */ 00631 int16_t getQ1(Report report); 00632 int16_t getQ2(Report report); 00633 int16_t getQ3(Report report); 00634 // @} 00635 00636 // internal utility functions 00637 //----------------------------------------------------------------------------------------------------------------- 00638 00639 /** 00640 * Processes the packet currently stored in the buffer, and updates class variables to reflect the data it contains 00641 */ 00642 void processPacket(); 00643 00644 /** 00645 * Processes the sensor data packet currently stored in the buffer. 00646 * Only called from processPacket() 00647 */ 00648 void parseSensorDataPacket(); 00649 00650 /** 00651 * Call to wait for a packet with the given parameters to come in. 00652 * 00653 * Note: on BNO080Async, the received packet data will stay in the RX buffer 00654 * until either the public IMU function that was called returns, or you 00655 * call sendPacket() or waitForPacket() again. 00656 * 00657 * @param channel Channel of the packet 00658 * @param reportID Report ID (first data byte) of the packet 00659 * @param timeout how long to wait for the packet 00660 * @return true if the packet has been received, false if it timed out 00661 */ 00662 virtual bool waitForPacket(int channel, uint8_t reportID, std::chrono::milliseconds timeout = 125ms); 00663 00664 /** 00665 * Given a Q value, converts fixed point floating to regular floating point number. 00666 * @param fixedPointValue 00667 * @param qPoint 00668 * @return 00669 */ 00670 float qToFloat(int16_t fixedPointValue, uint8_t qPoint); 00671 00672 /** 00673 * Given a Q value, converts fixed point floating to regular floating point number. 00674 * This version is used for the unsigned 32-bit values in metadata records. 00675 * @param fixedPointValue 00676 * @param qPoint 00677 * @return 00678 */ 00679 float qToFloat_dword(uint32_t fixedPointValue, int16_t qPoint); 00680 00681 /** 00682 * Given a floating point value and a Q point, convert to Q 00683 * See https://en.wikipedia.org/wiki/Q_(number_format) 00684 * @param qFloat 00685 * @param qPoint 00686 * @return 00687 */ 00688 int16_t floatToQ(float qFloat, uint8_t qPoint); 00689 00690 /** 00691 * Given a floating point value and a Q point, convert to Q 00692 * See https://en.wikipedia.org/wiki/Q_(number_format) 00693 * 00694 * This version is used for the signed 32-bit values in metadata records. 00695 * 00696 * @param qFloat 00697 * @param qPoint 00698 * @return 00699 */ 00700 int32_t floatToQ_dword(float qFloat, uint16_t qPoint); 00701 00702 /** 00703 * Tell the sensor to do a command. 00704 * See SH-2 Reference Manual section 6.3.8 page 42, Command request 00705 * The caller is expected to set shtpData 3 though 11 prior to calling 00706 */ 00707 void sendCommand(uint8_t command); 00708 00709 /** 00710 * Given a sensor's report ID, this tells the BNO080 to begin reporting the values. 00711 * 00712 * @param reportID 00713 * @param timeBetweenReports 00714 * @param specificConfig the specific config word. Useful for personal activity classifier. 00715 */ 00716 void setFeatureCommand(uint8_t reportID, uint16_t timeBetweenReports, uint32_t specificConfig = 0); 00717 00718 /** 00719 * Read a record from the FRS (Flash Record System) on the IMU. FRS records are composed of 32-bit words, 00720 * with the size of each record determined by the record type. 00721 * 00722 * Will block until the entire record has been read. 00723 * @param recordID Record ID to read. See SH-2 figures 28 and 29 for a list of these. Sometimes also called 00724 * the "FRS Type" by the datasheet (???). 00725 * @param readBuffer Buffer to read data into. 00726 * @param readLength Amount of words to read from the record. Must be <= the length of the record. 00727 * 00728 * @return whether the request succeeded 00729 */ 00730 bool readFRSRecord(uint16_t recordID, uint32_t* readBuffer, uint16_t readLength); 00731 00732 /** 00733 * Write a record to the FRS (Flash Record System) on the IMU. FRS records are composed of 32-bit words, 00734 * with the size of each record determined by the record type. 00735 * 00736 * Will block until the entire record has been written. 00737 * @param recordID Record ID to write. See SH-2 figures 28 and 29 for a list of these. Sometimes also called 00738 * the "FRS Type" by the datasheet (???). 00739 * @param buffer Buffer to write data into. 00740 * @param length Amount of words to write to the record. Must be <= the length of the record. 00741 * 00742 * @return whether the request succeeded 00743 */ 00744 bool writeFRSRecord(uint16_t recordID, uint32_t* buffer, uint16_t length); 00745 00746 /** 00747 * Reads a packet from the IMU and stores it in the class variables. 00748 * 00749 * @param timeout how long to wait for there to be a packet 00750 * 00751 * @return whether a packet was recieved. 00752 */ 00753 virtual bool receivePacket(std::chrono::milliseconds timeout=200ms) = 0; 00754 00755 /** 00756 * Sends the current shtpData contents to the BNO. It's a good idea to disable interrupts before you call this. 00757 * 00758 * @param channelNumber the channel to send on 00759 * @param dataLength How many bits of shtpData to send 00760 * @return 00761 */ 00762 virtual bool sendPacket(uint8_t channelNumber, uint8_t dataLength) = 0; 00763 00764 /** 00765 * Prints the current shtp packet stored in the buffer. 00766 * @param length 00767 */ 00768 void printPacket(uint8_t * buffer); 00769 00770 /** 00771 * Erases the current SHTP TX packet buffer. 00772 * In BNO080Async, this blocks until the buffer is available. 00773 */ 00774 virtual void clearSendBuffer(); 00775 00776 /** 00777 * Loads the metadata for this report into the metadata buffer. 00778 * @param report 00779 * @return Whether the operation succeeded. 00780 */ 00781 bool loadReportMetadata(Report report); 00782 00783 }; 00784 00785 /** 00786 * Version of the BNO080 driver which uses the I2C interface 00787 */ 00788 class BNO080I2C : public BNO080Base 00789 { 00790 /** 00791 * I2C port object. Provides physical layer communications with the chip. 00792 */ 00793 I2C _i2cPort; 00794 00795 /// user defined port speed 00796 int _i2cPortSpeed; 00797 00798 /// i2c address of IMU (7 bits) 00799 uint8_t _i2cAddress; 00800 public: 00801 00802 /** 00803 * Construct a BNO080 driver for the I2C bus, providing pins and parameters. 00804 * 00805 * This doesn't actally initialize the chip, you will need to call begin() for that. 00806 * 00807 * NOTE: while some schematics tell you to connect the BOOTN pin to the processor, this driver does not use or require it. 00808 * Just tie it to VCC per the datasheet. 00809 * 00810 * @param debugPort Serial port to write output to. Cannot be nullptr. 00811 * @param user_SDApin Hardware I2C SDA pin connected to the IMU 00812 * @param user_SCLpin Hardware I2C SCL pin connected to the IMU 00813 * @param user_INTPin Input pin connected to HINTN 00814 * @param user_RSTPin Output pin connected to NRST 00815 * @param i2cAddress I2C address. The BNO defaults to 0x4a, but can also be set to 0x4b via a pin. 00816 * @param i2cPortSpeed I2C frequency. The BNO's max is 400kHz. 00817 */ 00818 BNO080I2C(Stream *debugPort, PinName user_SDApin, PinName user_SCLpin, PinName user_INTPin, PinName user_RSTPin, uint8_t i2cAddress=0x4a, int i2cPortSpeed=400000); 00819 00820 private: 00821 00822 bool receivePacket(std::chrono::milliseconds timeout=200ms) override; 00823 00824 bool sendPacket(uint8_t channelNumber, uint8_t dataLength) override; 00825 }; 00826 00827 // typedef for compatibility with old version of driver where there was no SPI 00828 typedef BNO080I2C BNO080; 00829 00830 /** 00831 * Version of the BNO080 driver which uses the SPI interface. 00832 * WARNING: The SPI interface, unlike the I2C interface, of this chip 00833 * has some god-awful timing requirements that are difficult to satisfy. 00834 * 00835 * In order for the chip to produce data, you must call updateData() at at more than 00836 * twice the frequency of the fastest sensor poll rate you have set. 00837 * Otherwise, for reasons that I don't exactly understand, the IMU 00838 * will have some kind of internal watchdog timeout error and shut itself down. 00839 * Also, you have about 500ms after calling begin() to configure reports and start 00840 * receiving data, or the same thing happens. 00841 * 00842 * If this timing error happens to you, the symptoms are strange: the IMU will just stop sending data, several seconds later. 00843 * No error or anything, just no data. 00844 * To recover from the error, you would have to call begin() again and reconfigure it from scratch. 00845 * 00846 */ 00847 class BNO080SPI : public BNO080Base 00848 { 00849 protected: 00850 /** 00851 * I2C port object. Provides physical layer communications with the chip. 00852 */ 00853 SPI _spiPort; 00854 00855 // Wake pin to signal the IMU to wake up 00856 DigitalOut _wakePin; 00857 00858 /// user defined port speed 00859 int _spiSpeed; 00860 public: 00861 00862 /** 00863 * Construct a BNO080 driver for the SPI bus, providing pins and parameters. 00864 * 00865 * This doesn't actually initialize the chip, you will need to call begin() for that. 00866 * 00867 * NOTE: while some schematics tell you to connect the BOOTN pin to the processor, this driver does not use or require it. 00868 * Just tie it to VCC per the datasheet. 00869 * 00870 * @param debugPort Serial port to write output to. Cannot be nullptr. 00871 * @param rstPin Hardware reset pin, resets the IMU 00872 * @param intPin Hardware interrupt pin, this is used for the IMU to signal the host that it has a message to send 00873 * @param wakePin Hardware wake pin, this is used by the processor to signal the BNO to wake up and receive a message 00874 * @param misoPin SPI MISO pin 00875 * @param mosiPin SPI MOSI pin 00876 * @param sclkPin SPI SCLK pin 00877 * @param csPin SPI CS pin 00878 * @param spiSpeed SPI frequency. The BNO's max is 3MHz. 00879 */ 00880 BNO080SPI(Stream *debugPort, PinName rstPin, PinName intPin, PinName wakePin, PinName misoPin, PinName mosiPin, PinName sclkPin, PinName csPin, int spiSpeed=3000000); 00881 00882 protected: 00883 00884 bool receivePacket(std::chrono::milliseconds timeout=200ms) override; 00885 00886 bool sendPacket(uint8_t channelNumber, uint8_t dataLength) override; 00887 00888 /** 00889 * Assuming that at least a packet header has been read into the RX buffer, receive the remainder of the packet. 00890 * @param bytesRead The number of bytes (including the header) of the packet that have already been read. 00891 * @return 00892 */ 00893 bool receiveCompletePacket(size_t bytesRead, std::chrono::milliseconds timeout=200ms); 00894 00895 #if USE_ASYNC_SPI 00896 00897 /** 00898 * Start an SPI transfer and suspend the current thread until it is complete. 00899 * Used by functions in BNO080SPI. 00900 * Note: should only be called by one thread at a time. 00901 * @param tx_buffer 00902 * @param tx_length 00903 * @param rx_buffer 00904 * @param rx_length 00905 */ 00906 void spiTransferAndWait(const uint8_t *tx_buffer, int tx_length, uint8_t *rx_buffer, int rx_length); 00907 00908 // callback for finished SPI transfers 00909 void onSPITransferComplete(int event); 00910 00911 // Signal whan an SPI transfer is complete. 00912 EventFlags spiCompleteFlag; 00913 00914 #else 00915 00916 /** 00917 * Start an SPI transfer and wait for it to complete. 00918 * BNO080Async swaps in a threaded implementation here. 00919 * API same as SPI::write(). 00920 */ 00921 void spiTransferAndWait(const uint8_t *tx_buffer, int tx_length, uint8_t *rx_buffer, int rx_length) 00922 { 00923 _spiPort.write(reinterpret_cast<const char *>(tx_buffer), tx_length, reinterpret_cast<char *>(rx_buffer), rx_length); 00924 } 00925 #endif 00926 }; 00927 00928 #endif //HAMSTER_BNO080_H
Generated on Wed Jul 13 2022 10:30:01 by
