42 : spiSlave(bus, cs, bus_config), config(config)
52 assert(!isInit &&
"init() should be called once");
57 LOG_ERR(logger,
"Got bad CHIPID");
66 LOG_ERR(logger,
"Not all interfaces are up and running!");
76 miosix::Thread::sleep(30);
87 assert(isInit &&
"init() was not called");
93 if (!testAcc() || !testGyr() || !testMag())
115 assert(isInit &&
"init() was not called");
175 static_cast<uint8_t
>(cmd) |
static_cast<uint8_t
>(pmu));
178void BMX160::pushSample(BMX160Data sample)
183void BMX160::confMag(SPITransaction& spi, uint8_t value)
186 miosix::Thread::sleep(10);
189void BMX160::mapMag(SPITransaction& spi, uint8_t reg)
192 miosix::Thread::sleep(10);
195uint8_t BMX160::readMag(SPITransaction& spi, uint8_t reg)
201void BMX160::readMag(SPITransaction& spi, uint8_t reg, uint8_t* data,
243void BMX160::writeMag(SPITransaction& spi, uint8_t reg, uint8_t value)
247 miosix::Thread::sleep(10);
250bool BMX160::checkChipid()
252 SPITransaction spi(spiSlave);
257 LOG_ERR(logger,
"CHIPID = {:02x}", chipId);
263void BMX160::softReset()
265 SPITransaction spi(spiSlave);
269 miosix::Thread::sleep(10);
273 miosix::Thread::sleep(10);
276bool BMX160::setPowerMode()
278 SPITransaction spi(spiSlave);
282 miosix::Thread::sleep(80);
286 miosix::Thread::sleep(80);
290 miosix::Thread::sleep(80);
298void BMX160::initAcc()
304 accSensibility = 1.0f / 16384.0f;
307 accSensibility = 1.0f / 8192.0f;
310 accSensibility = 1.0f / 4096.0f;
313 accSensibility = 1.0f / 2048.0f;
317 SPITransaction spi(spiSlave);
326void BMX160::initGyr()
332 gyrSensibility = 1.0f / 16.4f;
335 gyrSensibility = 1.0f / 32.8f;
338 gyrSensibility = 1.0f / 65.6f;
341 gyrSensibility = 1.0f / 131.2f;
344 gyrSensibility = 1.0f / 262.4f;
348 SPITransaction spi(spiSlave);
356void BMX160::initMag()
365 SPITransaction spi(spiSlave);
387 miosix::Thread::sleep(10);
393void BMX160::initFifo()
397 SPITransaction spi(spiSlave);
423void BMX160::initInt()
427 SPITransaction spi(spiSlave);
469bool BMX160::testAcc()
471 const uint16_t SELF_TEST_LIMIT = 8192;
472 const uint8_t ACC_CONF_TEST = 0x2C;
473 const uint8_t ACC_RANGE_TEST = 0x08;
475 SPITransaction spi(spiSlave);
486 miosix::Thread::sleep(50);
490 reinterpret_cast<uint8_t*
>(posAcc),
sizeof(posAcc));
496 miosix::Thread::sleep(50);
500 reinterpret_cast<uint8_t*
>(negAcc),
sizeof(negAcc));
502 if ((negAcc[0] - posAcc[0]) < SELF_TEST_LIMIT ||
503 (negAcc[1] - posAcc[1]) < SELF_TEST_LIMIT ||
504 (negAcc[2] - posAcc[2]) < SELF_TEST_LIMIT)
506 LOG_ERR(logger,
"Accelerometer self-test failed!");
507 LOG_ERR(logger,
"posAcc: {} {} {}", posAcc[0], posAcc[1], posAcc[2]);
508 LOG_ERR(logger,
"negAcc: {} {} {}", negAcc[0], negAcc[1], negAcc[2]);
518bool BMX160::testGyr()
521 SPITransaction spi(spiSlave);
525 miosix::Thread::sleep(50);
530 LOG_ERR(logger,
"Gyroscope self-test failed!");
539bool BMX160::testMag()
541 SPITransaction spi(spiSlave);
549 miosix::Thread::sleep(200);
555 LOG_ERR(logger,
"Magnetometer didn't finish self-test!");
565 if (!(mag[0] & 1) || !(mag[1] & 1) || !(mag[2] & 1))
567 LOG_ERR(logger,
"Magnetometer self-test failed!");
568 LOG_ERR(logger,
"result: %d %d %d %d\n", mag[0], mag[1], mag[2],
578MagnetometerData BMX160::buildMagData(BMX160Defs::MagRaw data,
589 return MagnetometerData{timestamp,
590 boschMagCompensateX(data.x, data.rhall),
591 boschMagCompensateY(data.y, data.rhall),
592 boschMagCompensateZ(data.z, data.rhall)};
602AccelerometerData BMX160::buildAccData(BMX160Defs::AccRaw data,
605 using namespace Constants;
607 return AccelerometerData{timestamp, data.x * accSensibility * g,
608 data.y * accSensibility * g,
609 data.z * accSensibility * g};
612GyroscopeData BMX160::buildGyrData(BMX160Defs::GyrRaw data, uint64_t timestamp)
614 using namespace Constants;
618 return GyroscopeData{timestamp, data.x * gyrSensibility,
619 data.y * gyrSensibility, data.z * gyrSensibility};
623 return GyroscopeData{timestamp,
624 data.x * gyrSensibility * DEGREES_TO_RADIANS,
625 data.y * gyrSensibility * DEGREES_TO_RADIANS,
626 data.z * gyrSensibility * DEGREES_TO_RADIANS};
630const char* BMX160::debugErr(SPITransaction& spi)
636 return "Chip not operable";
640 return "Dropped command to register 0x7E";
645 err = (err >> 1) & 0x0F;
652 return "Generic error";
654 return "LPM and interrupt uses pre-filtered data";
656 return "ODR do not match";
658 return "LPM uses pre-filtered data";
660 return "Reserved error";
669 uint8_t realOdr =
static_cast<uint64_t
>(odr) - (downs & 3);
675 return ((1 << (13 - realOdr)) * 10000) >> 5;
678void BMX160::readTemp()
680 SPITransaction spi(spiSlave);
689void BMX160::readData()
691 SPITransaction spi(spiSlave);
697 auto magRaw = parseStruct<BMX160Defs::MagRaw>(buf, idx);
698 auto gyrRaw = parseStruct<BMX160Defs::GyrRaw>(buf, idx);
699 auto accRaw = parseStruct<BMX160Defs::AccRaw>(buf, idx);
703 pushSample(BMX160Data{
704 buildAccData(accRaw, timestamp),
705 buildGyrData(gyrRaw, timestamp),
706 buildMagData(magRaw, timestamp),
710void BMX160::readFifo(
bool headerless)
714 SPITransaction spi(spiSlave);
726 uint8_t buf[FIFO_BUF_SIZE];
729 assert(len <=
static_cast<int>(
sizeof(buf)) &&
"Buffer overflow!");
742 uint64_t timeOffset = std::min({
751 uint64_t timestamp = 0;
752 uint64_t watermarkTimestamp = 0;
754 miosix::Lock<miosix::FastMutex>
l(
mutex);
760 auto magRaw = parseStruct<BMX160Defs::MagRaw>(buf, idx);
761 auto gyrRaw = parseStruct<BMX160Defs::GyrRaw>(buf, idx);
762 auto accRaw = parseStruct<BMX160Defs::AccRaw>(buf, idx);
764 oldMag = buildMagData(magRaw, timestamp);
765 oldGyr = buildGyrData(gyrRaw, timestamp);
766 oldAcc = buildAccData(accRaw, timestamp);
769 pushSample(BMX160Data{oldAcc, oldGyr, oldMag});
771 if (watermarkTimestamp == 0 && idx >= (config.
fifoWatermark * 4))
772 watermarkTimestamp = timestamp;
774 timestamp += timeOffset;
778 uint8_t header = buf[idx++];
791 auto magRaw = parseStruct<BMX160Defs::MagRaw>(buf, idx);
792 oldMag = buildMagData(magRaw, timestamp);
798 auto gyrRaw = parseStruct<BMX160Defs::GyrRaw>(buf, idx);
799 oldGyr = buildGyrData(gyrRaw, timestamp);
805 auto accRaw = parseStruct<BMX160Defs::AccRaw>(buf, idx);
806 oldAcc = buildAccData(accRaw, timestamp);
810 pushSample(BMX160Data{oldAcc, oldGyr, oldMag});
812 if (watermarkTimestamp == 0 &&
815 watermarkTimestamp = timestamp;
818 timestamp += timeOffset;
846 LOG_ERR(logger,
"Malformed packet! Aborting fifo transfer...");
865 lastFifo[i].accelerationTimestamp +=
867 lastFifo[i].angularSpeedTimestamp +=
869 lastFifo[i].magneticFieldTimestamp +=
877T BMX160::parseStruct(uint8_t* buf,
int& idx)
880 memcpy(&data, buf + idx,
sizeof(T));
893void BMX160::boschReadTrim(SPITransaction& spi)
895 uint8_t trimX1y1[2] = {0};
896 uint8_t trimXyzData[4] = {0};
897 uint8_t trimXy1xy2[10] = {0};
901 sizeof(trimXyzData));
905 trimData.
digX1 = trimX1y1[0];
906 trimData.
digY1 = trimX1y1[1];
907 trimData.
digX2 = trimXyzData[2];
908 trimData.
digY2 = trimXyzData[3];
909 trimData.
digZ1 = trimXy1xy2[2] | (trimXy1xy2[3] << 8);
910 trimData.
digZ2 = trimXy1xy2[0] | (trimXy1xy2[1] << 8);
911 trimData.
digZ3 = trimXy1xy2[6] | (trimXy1xy2[7] << 8);
912 trimData.
digZ4 = trimXyzData[0] | (trimXyzData[1] << 8);
913 trimData.
digXY1 = trimXy1xy2[9];
914 trimData.
digXY2 = trimXy1xy2[8];
915 trimData.
digXYZ1 = trimXy1xy2[4] | ((trimXy1xy2[5] & 0x7F) << 8);
918float BMX160::boschMagCompensateX(int16_t x, uint16_t rhall)
929 processCompX0 = (((float)trimData.
digXYZ1) * 16384.0f / rhall);
930 retval = (processCompX0 - 16384.0f);
931 processCompX1 = ((float)trimData.
digXY2) * (retval * retval / 268435456.0f);
932 processCompX2 = processCompX1 + retval * ((float)trimData.
digXY1) / 16384.0f;
933 processCompX3 = ((float)trimData.
digX2) + 160.0f;
934 processCompX4 = x * ((processCompX2 + 256.0f) * processCompX3);
935 retval = ((processCompX4 / 8192.0f) + (((
float)trimData.
digX1) * 8.0f)) / 16.0f;
941float BMX160::boschMagCompensateY(int16_t y, uint16_t rhall)
952 processCompY0 = ((float)trimData.
digXYZ1) * 16384.0f / rhall;
953 retval = processCompY0 - 16384.0f;
954 processCompY1 = ((float)trimData.
digXY2) * (retval * retval / 268435456.0f);
955 processCompY2 = processCompY1 + retval * ((float)trimData.
digXY1) / 16384.0f;
956 processCompY3 = ((float)trimData.
digY2) + 160.0f;
957 processCompY4 = y * (((processCompY2) + 256.0f) * processCompY3);
958 retval = ((processCompY4 / 8192.0f) + (((
float)trimData.
digY1) * 8.0f)) / 16.0f;
964float BMX160::boschMagCompensateZ(int16_t z, uint16_t rhall)
975 processCompZ0 = ((float)z) - ((float)trimData.
digZ4);
976 processCompZ1 = ((float)rhall) - ((float)trimData.
digXYZ1);
977 processCompZ2 = (((float)trimData.
digZ3) * processCompZ1);
978 processCompZ3 = ((float)trimData.
digZ1) * ((float)rhall) / 32768.0f;
979 processCompZ4 = ((float)trimData.
digZ2) + processCompZ3;
980 processCompZ5 = (processCompZ0 * 131072.0f) - processCompZ2;
981 retval = (processCompZ5 / ((processCompZ4)*4.0f)) / 16.0f;
#define LOG_ERR(logger,...)
BMX160Temperature getTemperature()
Get last read temperature.
BMX160Data sampleImpl() override
Gather data from FIFO/data registers and temperature sensor.
bool init() override
Initialize the driver.
BMX160FifoStats getFifoStats()
Retrieve last fifo stats.
BMX160(SPIBusInterface &bus, miosix::GpioPin cs, BMX160Config config={})
BMX160 Constructor.
bool selfTest() override
Perform selftest on the device.
void IRQupdateTimestamp(uint64_t ts) override
Sometimes the sensor pulls down the interrupt pin while reading data. We override this method and upd...
Interface for low level access of a SPI bus as a master.
Provides high-level access to the SPI Bus for a single transaction.
void writeRegister(uint8_t reg, uint8_t data)
Writes an 8 bit register.
std::array< BMX160Data, FifoSize > lastFifo
uint64_t interruptTimestampDelta
uint64_t lastInterruptTimestamp
virtual void IRQupdateTimestamp(uint64_t ts)
Called by the interrupt handling routine: provides the timestamp of the last interrupt (if FIFO is di...
void sample() override
Sample the sensor.
@ INT_MAP_1_INT_2_FIFO_WATERMARK
@ INT_MAP_1_INT_1_FIFO_FULL
@ INT_MAP_1_INT_1_FIFO_WATERMARK
@ INT_MAP_1_INT_2_FIFO_FULL
@ MAG_IF_0_BURST_8
8 byte of burst operation.
@ MAG_IF_0_BURST_2
2 byte of burst operation.
@ MAG_IF_0_BURST_1
1 byte of burst operation.
@ MAG_IF_0_BURST_6
6 byte of burst operation.
const uint8_t PMU_STATUS_ALL_MASK
Mask for PMU_STATUS register (Power Mode Unit).
const float TEMP_SENSIBILITY
Temperature sensor sensibility.
const uint8_t CHIPID
BMX160 Chip Id.
const uint8_t FIFO_HEADER_MODE_MASK
Mask for fifo header mode.
const uint8_t PMU_STATUS_ALL_NORMAL
Mask for PMU_STATUS register, normal status for all sensors.
@ FIFO_DOWNS_ACC_FILT_DATA
@ FIFO_DOWNS_GYR_FILT_DATA
const uint8_t FIFO_STOP_BYTE
This value indicates that the data in the FIFO stops prematurely.
@ MAG_IF_SET_PMU_MODE
Sets the PMU mode for the magnetometer.
@ FIFO_FLUSH
Clears all data in the fifo.
@ ACC_SET_PMU_MODE
Sets the PMU mode for the accelerometer.
@ GYR_SET_PMU_MODE
Sets the PMU mode for the gyroscope.
@ SOFTRESET
Triggers a reset including a reboot.
@ SELF_TEST_ACC_AMP
Select amplitude of the selftest deflection.
@ SELF_TEST_GYR
Starts selftest of the gyroscope.
@ SELF_TEST_ACC_ENABLE
Starts selftest of the accelerometer.
@ SELF_TEST_ACC_SIGN
Select sign of selftest exitation.
@ FIFO_HEADER_PARM_SENSORTIME
@ FIFO_HEADER_PARM_MAG_DATA
@ FIFO_HEADER_PARM_ACC_DATA
@ FIFO_HEADER_MODE_CONTROL
@ FIFO_HEADER_MODE_REGULAR
@ FIFO_HEADER_PARM_CONFIG
@ FIFO_HEADER_PARM_GYR_DATA
@ FIFO_CONFIG_1_ACC_EN
Store accelerometer data in fifo.
@ FIFO_CONFIG_1_GYR_EN
Store gyroscope data in fifo.
@ FIFO_CONFIG_1_HEADER_EN
Stores an header for each frame.
@ FIFO_CONFIG_1_MAG_EN
Store magnetometer data in fifo.
const uint8_t FIFO_HEADER_PARM_MASK
Mask for fifo header parm.
@ INT_EN_1_FIFO_FULL
Enables interrupt for FIFO full.
@ INT_EN_1_FIFO_WATERMARK
Enables interrupt for FIFO watermark.
@ MAG_RESET_POWER_CONTROL
const float MAG_SENSIBILITY
Magnetometer fixed sensibility.
@ INT_OUT_CTRL_INT2_OD
Open drain enable for INT2 pin.
@ INT_OUT_CTRL_INT1_OD
Open drain enable for INT1 pin.
@ INT_OUT_CTRL_INT1_OUT_EN
Output enable for INT1 pin.
@ INT_OUT_CTRL_INT2_OUT_EN
Output enable for INT2 pin.
uint64_t getTimestamp()
Returns the current timer value in microseconds.
Driver for the VN100S IMU.
SensorErrors
Generic error codes that a sensor can generate.
uint64_t accelerationTimestamp
uint8_t fifoWatermark
Fifo watermark to use, in multiples of 4.
uint8_t fifoGyroscopeDownsampling
Fifo gyroscope downsampling (between 0 and 15).
bool fifoGyroscopeFiltered
Should the fifo use gyroscope filtered data?
BandwidthParameter accelerometerBandwidth
bool fifoAccelerometerFiltered
Should the fifo use accelerometer filtered data?
@ G_16
Accelaration range ±16g.
@ G_8
Accelaration range ±8g.
@ G_2
Accelaration range ±2g.
@ G_4
Accelaration range ±4g.
AccelerometerRange accelerometerRange
uint8_t fifoAccelerationDownsampling
Fifo accelerometer downsampling (between 0 and 15).
OutputDataRate magnetometerRate
int temperatureDivider
Divide the temperature sampling rate.
@ DEG_2000
Gyroscope range 2000°/sec.
@ DEG_500
Gyroscope range 500°/sec.
@ DEG_125
Gyroscope range 125°/sec.
@ DEG_250
Gyroscope range 250°/sec.
@ DEG_1000
Gyroscope range 1000°/sec.
@ OPEN_DRAIN
Open drain behaviour.
OutputDataRate accelerometerDataRate
BandwidthParameter gyroscopeBandwidth
bool enableCompensation
Enable magnetometer data compensation.
@ DISABLED
The interrupts are completely disabled.
@ PIN_INT1
Interrupts are enabled on pin 2.
GyroscopeRange gyroscopeRange
uint8_t magnetometerRepetitionsZ
Repetitions for the Z axis.
FifoInterruptPin fifoInterrupt
GyroscopeMeasureUnit gyroscopeUnit
OutputDataRate gyroscopeDataRate
uint8_t magnetometerRepetitionsXY
Repetitions for the XY axis.
OutputDataRate
Output Data Rate expressed in Hz.
@ DISABLED
The fifo is completely disabled.
@ HEADER
Sensors can have different odr.
@ HEADERLESS
Sensors MUST have the same odr.
uint64_t fifoDuration
Total fifo duration.
int len
Fifo length in bytes.
uint64_t interruptTimestampDelta
uint64_t watermarkTimestamp
Watermark timestamp (from the start of.
uint64_t angularSpeedTimestamp
uint64_t magneticFieldTimestamp
SPI Bus configuration for a specific slave.
SPI::ClockDivider clockDivider
< Peripheral clock division
uint64_t temperatureTimestamp