diff --git a/src/shared/sensors/LIS2MDL/LIS2MDL.cpp b/src/shared/sensors/LIS2MDL/LIS2MDL.cpp index 65937053d3663ba2e2f9b7c833f77d4bd60b70b6..4984c9d3b8c4e8629fff8a69cce6b811f6a0b078 100644 --- a/src/shared/sensors/LIS2MDL/LIS2MDL.cpp +++ b/src/shared/sensors/LIS2MDL/LIS2MDL.cpp @@ -34,8 +34,6 @@ LIS2MDL::LIS2MDL(SPIBusInterface& bus, miosix::GpioPin pin, { } -bool LIS2MDL::applyConfig(Config config) { return true; } - bool LIS2MDL::init() { if (isInitialized) @@ -69,8 +67,154 @@ bool LIS2MDL::init() return applyConfig(mConfig); } -bool LIS2MDL::selfTest() { return true; } +bool LIS2MDL::selfTest() +{ + if (!isInitialized) + { + LOG_ERR(logger, "Invoked selfTest() but sensor was uninitialized"); + lastError = NOT_INIT; + return false; + } + return true; + + constexpr int NUM_SAMPLES = 5; + constexpr int SLEEP_TIME = 50; + + // Absolute value of extra tolerance + constexpr float t = 0.1f; + + // Range which delta must be between, one for axis and expressed as {min, + // max}. The unit is gauss. + constexpr float deltaRange[3][2] = {{1.f, 3.f}, {1.f, 3.f}, {0.1f, 1.f}}; + + float avgX = 0.f, avgY = 0.f, avgZ = 0.f; + + { + SPITransaction spi(mSlave); + spi.writeRegister(CFG_REG_C, 4); + } + + for (int i = 0; i < NUM_SAMPLES; ++i) + { + miosix::Thread::sleep(SLEEP_TIME); + + LIS2MDLData lastData = sampleImpl(); + avgX += lastData.magneticFieldX; + avgY += lastData.magneticFieldY; + avgZ += lastData.magneticFieldZ; + } + + avgX /= NUM_SAMPLES; + avgY /= NUM_SAMPLES; + avgZ /= NUM_SAMPLES; + + // Deltas: absolute difference between the values measured before and after + float deltas[3]; + + miosix::Thread::sleep(SLEEP_TIME); + + LIS2MDLData lastData = sampleImpl(); + deltas[0] = std::abs(lastData.magneticFieldX - avgX); + deltas[1] = std::abs(lastData.magneticFieldY - avgY); + deltas[2] = std::abs(lastData.magneticFieldZ - avgZ); + + bool passed = true; + for (int j = 0; j < 3; ++j) + if (deltas[j] < (deltaRange[j][0] - t) || + deltas[j] > (deltaRange[j][1] + t)) + passed = false; + + if (!passed) + { + // reset configuration, then return + applyConfig(mConfig); + + lastError = SELF_TEST_FAIL; + return false; + } + + return applyConfig(mConfig); +} + +bool LIS2MDL::applyConfig(Config config) +{ + SPITransaction spi(mSlave); + uint8_t reg = 0, err = 0; + + // CFG_REG_A + reg |= config.odr << 2; + reg |= config.deviceMode; + reg |= (spi.readRegister(CFG_REG_A) & 0b11110000); + spi.writeRegister(CFG_REG_A, reg); + + if (err) + { + LOG_ERR(logger, "Spi error"); + lastError = BUS_FAULT; + return false; + } + + return true; +} + +LIS2MDLData LIS2MDL::sampleImpl() +{ + if (!isInitialized) + { + LOG_ERR(logger, "Invoked sampleImpl() but sensor was uninitialized"); + lastError = NOT_INIT; + return lastSample; + } + + SPITransaction spi(mSlave); + + if (!spi.readRegister(STATUS_REG)) + { + lastError = NO_NEW_DATA; + return lastSample; + } -LIS2MDLData LIS2MDL::sampleImpl() { return LIS2MDLData{}; } + // Reset any error + lastError = SensorErrors::NO_ERRORS; + + int16_t val; + LIS2MDLData newData{}; + + if (mConfig.temperatureDivider != 0) + { + if (currDiv == 0) + { + val = spi.readRegister(TEMP_OUT_L_REG); + val |= spi.readRegister(TEMP_OUT_H_REG) << 8; + + newData.temperatureTimestamp = TimestampTimer::getTimestamp(); + newData.temperature = static_cast<float>(val) / LSB_PER_CELSIUS + + REFERENCE_TEMPERATURE; + } + else + { + // Keep old value + newData.temperature = lastSample.temperature; + } + + currDiv = (currDiv + 1) % mConfig.temperatureDivider; + } + + newData.magneticFieldTimestamp = TimestampTimer::getTimestamp(); + + val = spi.readRegister(OUTX_L_REG); + val |= spi.readRegister(OUTX_H_REG) << 8; + newData.magneticFieldX = mUnit * val; + + val = spi.readRegister(OUTY_L_REG); + val |= spi.readRegister(OUTY_H_REG) << 8; + newData.magneticFieldY = mUnit * val; + + val = spi.readRegister(OUTZ_L_REG); + val |= spi.readRegister(OUTY_H_REG) << 8; + newData.magneticFieldZ = mUnit * val; + + return newData; +} } // namespace Boardcore \ No newline at end of file diff --git a/src/tests/sensors/test-lis2mdl.cpp b/src/tests/sensors/test-lis2mdl.cpp index 6722967ecea593d70156ed926f572d746d06361a..71eeaef1c01ec137ecc1a70d8645d64b8f6abfca 100644 --- a/src/tests/sensors/test-lis2mdl.cpp +++ b/src/tests/sensors/test-lis2mdl.cpp @@ -49,7 +49,7 @@ int main() SPIBusConfig busConfig; busConfig.clockDivider = SPI::ClockDivider::DIV_256; - busConfig.mode = SPI::Mode::MODE_0; + busConfig.mode = SPI::Mode::MODE_3; LIS2MDL::Config config; config.odr = LIS2MDL::ODR_10_HZ; @@ -64,4 +64,22 @@ int main() return 1; } TRACE("LIS2MDL: Init done"); + + TRACE("Doing self test!\n"); + if (!sensor.selfTest()) + { + TRACE("Error: selfTest() returned false!\n"); + } + TRACE("selfTest returned true\n"); + TRACE("Now printing some sensor data:\n"); + Thread::sleep(100); + + while (true) + { + sensor.sample(); + LIS2MDLData data __attribute__((unused)) = sensor.getLastSample(); + TRACE("%f C | x: %f | y: %f | z %f\n", data.temperature, + data.magneticFieldX, data.magneticFieldY, data.magneticFieldZ); + miosix::Thread::sleep(2000); + } }