diff --git a/sbs.conf b/sbs.conf index 6fb11ea4a1c011f2b6f176d684f27dd20f3509ca..7a57bd1566ea29088fa093087a2f412e55410c9f 100644 --- a/sbs.conf +++ b/sbs.conf @@ -151,6 +151,11 @@ Files: src/shared/sensors/SensorManager.cpp Type: srcfiles Files: src/shared/drivers/gamma868/Gamma868.cpp +[lsm9ds1] +Type: srcfiles +Files: src/shared/sensors/LSM9DS1/LSM9DS1_AxelGyro.cpp + src/shared/sensors/LSM9DS1/LSM9DS1_Magneto.cpp + [xbee] Type: srcfiles Files: src/shared/drivers/Xbee/Xbee.cpp @@ -517,7 +522,7 @@ Main: test-rls Type: test BoardId: stm32f407vg_skyward_tortellino BinName: test-lsm9ds1-fifo -Include: %shared %spi %logger +Include: %shared %spi %logger %lsm9ds1 Defines: -DDEBUG Main: drivers/test-lsm9ds1-fifo diff --git a/src/shared/sensors/LSM9DS1/LSM9DS1_AxelGyro.cpp b/src/shared/sensors/LSM9DS1/LSM9DS1_AxelGyro.cpp new file mode 100644 index 0000000000000000000000000000000000000000..255b4134ebfa0f1f94d6d7ff5bf4a4b6953705f0 --- /dev/null +++ b/src/shared/sensors/LSM9DS1/LSM9DS1_AxelGyro.cpp @@ -0,0 +1,332 @@ +/* LSM9DS1 accelerometer + giroscope Driver + * + * Copyright (c) 2016,2020 Skyward Experimental Rocketry + * Authors: Andrea Milluzzo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "LSM9DS1_AxelGyro.h" + +using miosix::GpioPin; +using std::array; + +LSM9DS1_XLG::LSM9DS1_XLG(SPIBusInterface& bus, GpioPin cs, + AxelFSR axelRange = AxelFSR::FS_2, + GyroFSR gyroRange = GyroFSR::FS_245, + ODR odr = ODR::ODR_15, bool fifo_enabled = false, + unsigned int fifo_watermark = 24) + : fifo_enabled(fifo_enabled), fifo_watermark(fifo_watermark), + spislave(bus, cs, {}), axelFSR(axelRange), gyroFSR(gyroRange), odr(odr) +{ + // SPI config + spislave.config.clock_div = SPIClockDivider::DIV64; +} + +LSM9DS1_XLG::LSM9DS1_XLG(SPIBusInterface& bus, GpioPin cs, SPIBusConfig config, + AxelFSR axelRange = AxelFSR::FS_2, + GyroFSR gyroRange = GyroFSR::FS_245, + ODR odr = ODR::ODR_15, bool fifo_enabled = false, + unsigned int fifo_watermark = 24) + : fifo_enabled(fifo_enabled), fifo_watermark(fifo_watermark), + spislave(bus, cs, config), axelFSR(axelRange), gyroFSR(gyroRange), + odr(odr) +{ +} + +bool LSM9DS1_XLG::init() +{ + // Set FSR + switch (axelFSR) // DA RIGUARDARE I COEFFICIENTI: SU DS C'E' + // SENSITIVITY IN mg/LSB + { + case AxelFSR::FS_2: + axelSensitivity = 0.598f; + break; + case AxelFSR::FS_4: + axelSensitivity = 1.196f; + break; + case AxelFSR::FS_8: + axelSensitivity = 2.393f; + break; + case AxelFSR::FS_16: + axelSensitivity = 7.178f; + break; + default: + axelSensitivity = 0.598f; + break; + } + + switch (gyroFSR) + { + case GyroFSR::FS_245: + gyroSensitivity = 8.75f; + break; + case GyroFSR::FS_500: + gyroSensitivity = 17.50f; + break; + case GyroFSR::FS_2000: + gyroSensitivity = 70.0f; + break; + default: + gyroSensitivity = 8.75f; + break; + } + + switch (odr) + { + case ODR::PWR_DW: + odrHz = 0.0f; + break; + case ODR::ODR_15: + odrHz = 14.9f; + break; + case ODR::ODR_60: + odrHz = 59.5f; + break; + case ODR::ODR_119: + odrHz = 119.0f; + break; + case ODR::ODR_238: + odrHz = 238.0f; + break; + case ODR::ODR_476: + odrHz = 476.0f; + break; + case ODR::ODR_952: + odrHz = 952.0f; + break; + default: + odrHz = 14.9f; + break; + } + + SPITransaction spi(spislave); + + // Who Am I check: + uint8_t whoami = spi.read(regMapXLG::WHO_AM_I); + if (whoami != WHO_AM_I_XLG_VAL) + { + TRACE("LSM9DS1 AXEL+GYRO WAMI: %02X\n", whoami); + last_error = ERR_NOT_ME; + return false; + } + + // common setup + spi.write(regMapXLG::CTRL_REG8, + CTRL_REG8_VAL); // addr auto-increment while reading/writing + + // FIFO setup: FIFO enabled in continous mode, decimation OFF, + // temperature on FIFO ON. + if (fifo_enabled) + { + + spi.write( + regMapXLG::FIFO_CTRL, + (FIFO_CTRL_VAL | fifo_watermark)); // FIFO continous mode + fifo + // watermark threshold setup + spi.write(regMapXLG::INT1_CTRL, + INT1_CTRL_VAL); // interrupt on FIFO treshold + spi.write( + regMapXLG::CTRL_REG9, + (CTRL_REG9_VAL | 0x02)); // DRDY_mask_bit OFF, I2C OFF, FIFO ON + } + else + { + spi.write(regMapXLG::CTRL_REG9, + CTRL_REG9_VAL); // DRDY_mask_bit OFF, I2C OFF, FIFO OFF + } + + // Axel Setup: ODR, FSR defined by constructor, auto anti-aliasing BW + // (max), LPF2/HPF bypassed and disabled, axel output enabled by default + // @ startup + uint8_t CTRL_REG6_XL_VAL = (int)odr << 5 | (int)axelFSR << 3; + spi.write(regMapXLG::CTRL_REG6_XL, + CTRL_REG6_XL_VAL); // ODR, FSR, auto BW (max) function of ODR + + // Gyro Setup : ODR, FSR defined by constructor, LPF2/HPF bypassed and + // disabled, gyro output enabled by default @ startup + uint8_t CTRL_REG1_G_VAL = (int)odr << 5 | (int)gyroFSR << 3; + spi.write(regMapXLG::CTRL_REG1_G, CTRL_REG1_G_VAL); // ODR,FSR + // spi.write(regMapXLG::ORIENT_CFG_G, ORIENT_CFG_VAL); //angular rate + // sign and orientation Setup <--- BOARD DEPENDENT + + // Check all the registers have been written correctly + if (spi.read(regMapXLG::CTRL_REG8) != CTRL_REG8_VAL) + { + return false; + } + if (fifo_enabled) + { + if (spi.read(regMapXLG::FIFO_CTRL) != (FIFO_CTRL_VAL | fifo_watermark)) + { + return false; + } + if (spi.read(regMapXLG::INT1_CTRL) != INT1_CTRL_VAL) + { + return false; + } + if (spi.read(regMapXLG::CTRL_REG9) != (CTRL_REG9_VAL | 0x02)) + { + return false; + } + } + else + { + if (spi.read(regMapXLG::CTRL_REG9) != CTRL_REG9_VAL) + { + return false; + } + } + if (spi.read(regMapXLG::CTRL_REG6_XL) != CTRL_REG6_XL_VAL) + { + return false; + } + if (spi.read(regMapXLG::CTRL_REG1_G) != CTRL_REG1_G_VAL) + { + return false; + } + + LSM9DS1_XLG::discardSamples(spi); // LUCA SCS MERDA (x2) <3 + + return true; +} + +bool LSM9DS1_XLG::selfTest() { return true; } + +bool LSM9DS1_XLG::onSimpleUpdate() +{ + if (!fifo_enabled) + { // if FIFO disabled + uint8_t data[12], tempData[2]; + // Read output axel+gyro data X,Y,Z + { + SPITransaction spi(spislave); + spi.read(regMapXLG::OUT_X_L_G, data, 12); + spi.read(regMapXLG::OUT_TEMP_L, tempData, 2); + } + + int16_t x_gy = data[0] | data[1] << 8; + int16_t y_gy = data[2] | data[3] << 8; + int16_t z_gy = data[4] | data[5] << 8; + + int16_t x_xl = data[6] | data[7] << 8; + int16_t y_xl = data[8] | data[9] << 8; + int16_t z_xl = data[10] | data[11] << 8; + + int16_t temp = tempData[0] | tempData[1] << 8; + + mLastAccel = + Vec3(x_xl * axelSensitivity / 1000, y_xl * axelSensitivity / 1000, + z_xl * axelSensitivity / 1000); + + mLastGyro = + Vec3(x_gy * gyroSensitivity / 1000, y_gy * gyroSensitivity / 1000, + z_gy * gyroSensitivity / 1000); + + mLastTemp = + tempZero + (temp / tempSensistivity); // 25°C + TEMP*S devo + // castare a float "temp"? + } + else + { // if FIFO enabled: do not store temperature, it can be read using + // "temperatureUpdate()" function at low sampling frequency + uint8_t buf[384]; // 2 bytes per data * 3 axes * 2 (axel+gyro) * + // 32(FIFO DEPTH MAX) = 384 samples + { + SPITransaction spi(spislave); + + spi.read( + OUT_X_L_G, buf, + fifo_watermark * + 12); // format: + // gxl,gxh,gyl,gyh,gzl,gzh,axl,axh,ayl,ayh,azl,azh + // for each sample + } + // convert & store + for (int i = 0; i < fifo_watermark; i++) + { + int16_t x_gy = buf[i * 12] | buf[i * 12 + 1] << 8; + int16_t y_gy = buf[i * 12 + 2] | buf[i * 12 + 3] << 8; + int16_t z_gy = buf[i * 12 + 4] | buf[i * 12 + 5] << 8; + + int16_t x_xl = buf[i * 12 + 6] | buf[i * 12 + 7] << 8; + int16_t y_xl = buf[i * 12 + 8] | buf[i * 12 + 9] << 8; + int16_t z_xl = buf[i * 12 + 10] | buf[i * 12 + 11] << 8; + + fifo[i].gyroData = Vec3(x_gy * gyroSensitivity / 1000, + y_gy * gyroSensitivity / 1000, + z_gy * gyroSensitivity / 1000); + fifo[i].axelData = Vec3(x_xl * axelSensitivity / 1000, + y_xl * axelSensitivity / 1000, + z_xl * axelSensitivity / 1000); + } + } + return true; +} + +bool LSM9DS1_XLG::temperatureUpdate() +{ + uint8_t tempData[2]; + { + SPITransaction spi(spislave); + spi.read(regMapXLG::OUT_TEMP_L, tempData, 2); + } + + int16_t temp = tempData[0] | tempData[1] << 8; + mLastTemp = + tempZero + + temp / tempSensistivity; // 25°C + TEMP/S devo castare a float "temp"? + return true; +} + +void LSM9DS1_XLG::clearFIFO() +{ + SPITransaction spi(spislave); + spi.write(FIFO_CTRL, 0); // Bypass Mode + miosix::Thread::sleep(20); // Wait + spi.write(FIFO_CTRL, FIFO_CTRL_VAL | fifo_watermark); // re-enable FIFO + LSM9DS1_XLG::discardSamples(spi); +} + +const array<lsm9ds1XLGSample, 32>& LSM9DS1_XLG::getLsm9ds1FIFO() const +{ + return fifo; +} + +void LSM9DS1_XLG::discardSamples(SPITransaction& spi) +{ + //@ startup, some samples have to be discarded (datasheet) + if (odr != ODR::PWR_DW) + { + uint16_t toWait_ms = samplesToDiscard * 1000 / odrHz; + // TRACE("toWait_ms: %d", toWait_ms); + miosix::Thread::sleep(toWait_ms); // if FIFO is disabled, just wait + if (fifo_enabled) + { + // if FIFO is enabled, read first <samplesToDiscard> samples and + // discard them + for (int i = 0; i < samplesToDiscard; i++) + { + spi.read(regMapXLG::OUT_X_L_XL, 6); + spi.read(regMapXLG::OUT_X_L_G, 6); + } + } + } +} \ No newline at end of file diff --git a/src/shared/sensors/LSM9DS1/LSM9DS1_AxelGyro.h b/src/shared/sensors/LSM9DS1/LSM9DS1_AxelGyro.h index f1d35e83f940115ccd05962cb57e0e36591bc3c3..62801a5bf797107062f671c6e4fcd8771ba23667 100644 --- a/src/shared/sensors/LSM9DS1/LSM9DS1_AxelGyro.h +++ b/src/shared/sensors/LSM9DS1/LSM9DS1_AxelGyro.h @@ -24,27 +24,18 @@ #pragma once #include <miosix.h> + #include <array> -#include "../Sensor.h" +#include "LSM9DS1_Data.h" #include "drivers/spi/SPIDriver.h" using miosix::GpioPin; using std::array; -// data Structs -struct lsm9ds1XLGSample -{ - uint64_t timestamp; - Vec3 axelData; - Vec3 gyroData; -}; - -struct lsm9ds1TSample -{ - uint64_t timestamp; - float tempData; -}; +/** + * @brief descrizione classe + */ class LSM9DS1_XLG : public GyroSensor, public AccelSensor, @@ -78,11 +69,10 @@ public: }; /** - * @brief Creates an instance of an LSM9DS1 accelerometer + gyroscope sensor + * @brief Creates an instance of an LSM9DS1 accelerometer + gyroscope sensor. * * @param bus SPI bus the sensor is connected to * @param cs Chip Select GPIO - * @param config (OPTIONAL) custom SPIBusConfig * @param axelRange accelerometer Full Scale Range (See datasheet) * @param gyroRange gyroscope Full Scale Range (See datasheet) * @param odr Output Data Rate (See datasheet) @@ -91,254 +81,78 @@ public: * interrupt generation, see datasheet). */ - LSM9DS1_XLG(SPIBusInterface& bus, GpioPin cs, - AxelFSR axelRange = AxelFSR::FS_2, - GyroFSR gyroRange = GyroFSR::FS_245, ODR odr = ODR::ODR_15, - bool fifo_enabled = false, unsigned int fifo_watermark = 24) - : fifo_enabled(fifo_enabled), fifo_watermark(fifo_watermark), - spislave(bus, cs, {}), axelFSR(axelRange), gyroFSR(gyroRange), odr(odr) - { - // SPI config - spislave.config.clock_div = SPIClockDivider::DIV64; - } + LSM9DS1_XLG(SPIBusInterface& bus, GpioPin cs, AxelFSR axelRange, + GyroFSR gyroRange, ODR odr, bool fifo_enabled, + unsigned int fifo_watermark); + + /** + * @brief Creates an instance of an LSM9DS1 accelerometer + gyroscope sensor. + * + * @param bus SPI bus the sensor is connected to + * @param cs Chip Select GPIO + * @param config (OPTIONAL) custom SPIBusConfig + * @param axelRange accelerometer Full Scale Range (See datasheet) + * @param gyroRange gyroscope Full Scale Range (See datasheet) + * @param odr Output Data Rate (See datasheet) + * @param fifo_enabled Fifo enabled + * @param fifo_watermark FIFO watermark level in range [1,32] (used for + * interrupt generation, see datasheet). + */ LSM9DS1_XLG(SPIBusInterface& bus, GpioPin cs, SPIBusConfig config, - AxelFSR axelRange = AxelFSR::FS_2, - GyroFSR gyroRange = GyroFSR::FS_245, ODR odr = ODR::ODR_15, - bool fifo_enabled = false, unsigned int fifo_watermark = 24) - : fifo_enabled(fifo_enabled), fifo_watermark(fifo_watermark), - spislave(bus, cs, config), axelFSR(axelRange), gyroFSR(gyroRange), - odr(odr) - { - } + AxelFSR axelRange, GyroFSR gyroRange, ODR odr, + bool fifo_enabled, unsigned int fifo_watermark); - bool init() override - { - // Set FSR - switch (axelFSR) // DA RIGUARDARE I COEFFICIENTI: SU DS C'E' - // SENSITIVITY IN mg/LSB - { - case AxelFSR::FS_2: - axelSensitivity = 0.598f; - break; - case AxelFSR::FS_4: - axelSensitivity = 1.196f; - break; - case AxelFSR::FS_8: - axelSensitivity = 2.393f; - break; - case AxelFSR::FS_16: - axelSensitivity = 7.178f; - break; - default: - axelSensitivity = 0.598f; - break; - } - - switch (gyroFSR) - { - case GyroFSR::FS_245: - gyroSensitivity = 8.75f; - break; - case GyroFSR::FS_500: - gyroSensitivity = 17.50f; - break; - case GyroFSR::FS_2000: - gyroSensitivity = 70.0f; - break; - default: - gyroSensitivity = 8.75f; - break; - } - - switch (odr) - { - case ODR::PWR_DW: - odrHz = 0.0f; - break; - case ODR::ODR_15: - odrHz = 14.9f; - break; - case ODR::ODR_60: - odrHz = 59.5f; - break; - case ODR::ODR_119: - odrHz = 119.0f; - break; - case ODR::ODR_238: - odrHz = 238.0f; - break; - case ODR::ODR_476: - odrHz = 476.0f; - break; - case ODR::ODR_952: - odrHz = 952.0f; - break; - default: - odrHz = 14.9f; - break; - } - - SPITransaction spi(spislave); - - // Who Am I check: - uint8_t whoami = spi.read(regMapXLG::WHO_AM_I); - if (whoami != WHO_AM_I_XLG_VAL) - { - TRACE("LSM9DS1 AXEL+GYRO WAMI: %02X\n", whoami); - last_error = ERR_NOT_ME; - return false; - } - - // common setup - spi.write(regMapXLG::CTRL_REG8, CTRL_REG8_VAL); // addr auto-increment while reading/writing - - // FIFO setup: FIFO enabled in continous mode, decimation OFF, - // temperature on FIFO ON. - if (fifo_enabled) - { - - spi.write(regMapXLG::FIFO_CTRL,(FIFO_CTRL_VAL | fifo_watermark)); // FIFO continous mode + fifo watermark threshold setup - spi.write(regMapXLG::INT1_CTRL,INT1_CTRL_VAL); // interrupt on FIFO treshold - spi.write(regMapXLG::CTRL_REG9,(CTRL_REG9_VAL | 0x02)); // DRDY_mask_bit OFF, I2C OFF, FIFO ON - } - else - { - spi.write(regMapXLG::CTRL_REG9,CTRL_REG9_VAL); // DRDY_mask_bit OFF, I2C OFF, FIFO OFF - } - - // Axel Setup: ODR, FSR defined by constructor, auto anti-aliasing BW - // (max), LPF2/HPF bypassed and disabled, axel output enabled by default - // @ startup - uint8_t CTRL_REG6_XL_VAL = (int)odr << 5 | (int)axelFSR << 3; - spi.write(regMapXLG::CTRL_REG6_XL, CTRL_REG6_XL_VAL); // ODR, FSR, auto BW (max) function of ODR - - // Gyro Setup : ODR, FSR defined by constructor, LPF2/HPF bypassed and - // disabled, gyro output enabled by default @ startup - uint8_t CTRL_REG1_G_VAL = (int)odr << 5 | (int)gyroFSR << 3; - spi.write(regMapXLG::CTRL_REG1_G, CTRL_REG1_G_VAL); // ODR,FSR - // spi.write(regMapXLG::ORIENT_CFG_G, ORIENT_CFG_VAL); //angular rate - // sign and orientation Setup <--- BOARD DEPENDENT - - // Check all the registers have been written correctly - if (spi.read(regMapXLG::CTRL_REG8) != CTRL_REG8_VAL) { return false; } - if (fifo_enabled) - { - if (spi.read(regMapXLG::FIFO_CTRL) != (FIFO_CTRL_VAL | fifo_watermark)) { return false; } - if (spi.read(regMapXLG::INT1_CTRL) != INT1_CTRL_VAL) { return false; } - if (spi.read(regMapXLG::CTRL_REG9) != (CTRL_REG9_VAL | 0x02)) { return false; } - } - else - { - if (spi.read(regMapXLG::CTRL_REG9) != CTRL_REG9_VAL) { return false; } - } - if (spi.read(regMapXLG::CTRL_REG6_XL) != CTRL_REG6_XL_VAL) { return false; } - if (spi.read(regMapXLG::CTRL_REG1_G) != CTRL_REG1_G_VAL) { return false; } - - discardSamples(spi); //LUCA SCS MERDA (x2) <3 - - return true; - } - - bool selfTest() override { return true; } - - bool onSimpleUpdate() override - { + /** + * @brief initializes the LSM9DS1 Sensor (Accelerometer + Gyroscope). + * @return true if all setup registers of the sensor have been written + * correctly + */ - if (!fifo_enabled) - { // if FIFO disabled - uint8_t data[12], tempData[2]; - // Read output axel+gyro data X,Y,Z - { - SPITransaction spi(spislave); - spi.read(regMapXLG::OUT_X_L_G, data, 12); - spi.read(regMapXLG::OUT_TEMP_L, tempData, 2); - } - - int16_t x_gy = data[0] | data[1] << 8; - int16_t y_gy = data[2] | data[3] << 8; - int16_t z_gy = data[4] | data[5] << 8; - - int16_t x_xl = data[6] | data[7] << 8; - int16_t y_xl = data[8] | data[9] << 8; - int16_t z_xl = data[10] | data[11] << 8; - - int16_t temp = tempData[0] | tempData[1] << 8; - - mLastAccel = Vec3(x_xl * axelSensitivity / 1000, - y_xl * axelSensitivity / 1000, - z_xl * axelSensitivity / 1000); - - mLastGyro = Vec3(x_gy * gyroSensitivity / 1000, - y_gy * gyroSensitivity / 1000, - z_gy * gyroSensitivity / 1000); - - mLastTemp = tempZero + - (temp / tempSensistivity); // 25°C + TEMP*S devo - // castare a float "temp"? - } - else - { // if FIFO enabled: do not store temperature, it can be read using - // "temperatureUpdate()" function at low sampling frequency - uint8_t buf[384]; // 2 bytes per data * 3 axes * 2 (axel+gyro) * - // 32(FIFO DEPTH MAX) = 384 samples - { - SPITransaction spi(spislave); - - spi.read( - OUT_X_L_G, buf, - fifo_watermark * - 12); // format: - // gxl,gxh,gyl,gyh,gzl,gzh,axl,axh,ayl,ayh,azl,azh - // for each sample - } - // convert & store - for (int i = 0; i < fifo_watermark; i++) - { - int16_t x_gy = buf[i * 12] | buf[i * 12 + 1] << 8; - int16_t y_gy = buf[i * 12 + 2] | buf[i * 12 + 3] << 8; - int16_t z_gy = buf[i * 12 + 4] | buf[i * 12 + 5] << 8; - - int16_t x_xl = buf[i * 12 + 6] | buf[i * 12 + 7] << 8; - int16_t y_xl = buf[i * 12 + 8] | buf[i * 12 + 9] << 8; - int16_t z_xl = buf[i * 12 + 10] | buf[i * 12 + 11] << 8; - - fifo[i].gyroData = Vec3(x_gy * gyroSensitivity / 1000, - y_gy * gyroSensitivity / 1000, - z_gy * gyroSensitivity / 1000); - fifo[i].axelData = Vec3(x_xl * axelSensitivity / 1000, - y_xl * axelSensitivity / 1000, - z_xl * axelSensitivity / 1000); - } - } - return true; - } - - bool temperatureUpdate() - { - uint8_t tempData[2]; - { - SPITransaction spi(spislave); - spi.read(regMapXLG::OUT_TEMP_L, tempData, 2); - } - - int16_t temp = tempData[0] | tempData[1] << 8; - mLastTemp = tempZero + temp / tempSensistivity; // 25°C + TEMP/S devo castare a float "temp"? - return true; - } - - void clearFIFO() // FIFO clearing routine (see datasheet) - { - SPITransaction spi(spislave); - spi.write(FIFO_CTRL, 0); // Bypass Mode - miosix::Thread::sleep(20); // Wait - spi.write(FIFO_CTRL, FIFO_CTRL_VAL | fifo_watermark); // re-enable FIFO - discardSamples(spi); - } + bool init() override; + + /** + * @brief Run a self-test of the Sensor. + * @return true if sensor behave correclty + */ + + bool selfTest() override; + + /** + * @brief Dump single reading of Axel+Gyro+Temp from the sensor through SPI. + * @return true if sensor sends data + */ + + bool onSimpleUpdate() override; - const array<lsm9ds1XLGSample, 32>& getLsm9ds1FIFO() const { return fifo; } + /** + * @brief Dump single read of Temperature from the sensor through SPI. + * @return true if sensor sends data + */ + + bool temperatureUpdate(); + + /** + * @brief Clear the FIFO register inside the LSM9DS1 sensor. + */ + + void clearFIFO(); + + /** + * @brief get FIFO dumped after calling onSimpleUpdate() - Just on FIFO mode. + * @return array containing the whole FIFO + */ + + const array<lsm9ds1XLGSample, 32>& getLsm9ds1FIFO() const; private: + /** + * @brief discard some samples from the sensor. Must be used when switching. + * from FIFO mode to CONTINUOUS mode (or viceversa) and during power on + */ + + void discardSamples(SPITransaction& spi); + bool fifo_enabled; uint8_t fifo_watermark; array<lsm9ds1XLGSample, 32> fifo; @@ -356,28 +170,6 @@ private: float tempSensistivity = 16.0f; static const uint8_t samplesToDiscard = 8; // max possible val - void discardSamples(SPITransaction& spi) - { - - //@ startup, some samples have to be discarded (datasheet) - if (odr != ODR::PWR_DW) - { - uint16_t toWait_ms = samplesToDiscard * 1000 / odrHz; - // TRACE("toWait_ms: %d", toWait_ms); - miosix::Thread::sleep(toWait_ms); // if FIFO is disabled, just wait - if (fifo_enabled) - { - // if FIFO is enabled, read first <samplesToDiscard> samples and - // discard them - for (int i = 0; i < samplesToDiscard; i++) - { - spi.read(regMapXLG::OUT_X_L_XL, 6); - spi.read(regMapXLG::OUT_X_L_G, 6); - } - } - } - } - enum regMapXLG { ACT_THS = 0x04, diff --git a/src/shared/sensors/LSM9DS1/LSM9DS1_Data.h b/src/shared/sensors/LSM9DS1/LSM9DS1_Data.h new file mode 100644 index 0000000000000000000000000000000000000000..51e68aa98a9a689115599a3c6301caa78418642c --- /dev/null +++ b/src/shared/sensors/LSM9DS1/LSM9DS1_Data.h @@ -0,0 +1,85 @@ +/* LSM9DS1 accelerometer + giroscope Driver + * + * Copyright (c) 2016,2020 Skyward Experimental Rocketry + * Authors: Andrea Milluzzo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include <miosix.h> +#include "../Sensor.h" + +// data Structs + +//ACCELEROMETER + GYROSCOPE +struct lsm9ds1XLGSample +{ + uint64_t timestamp; + Vec3 axelData; + Vec3 gyroData; + + static std::string header() + { + return "timestamp,acc_x,acc_y,acc_z,gyro_x,gyro_y,gyro_z\n"; + } + + void print(std::ostream& os) const + { + os << timestamp << "," << + axelData.getX() << "," << axelData.getY() << "," << axelData.getZ() << "," << + gyroData.getX() << "," << gyroData.getY() << "," << gyroData.getZ() << "\n"; + } +}; + +//TEMPERATURE +struct lsm9ds1TSample +{ + uint64_t timestamp; + float tempData; + + static std::string header() + { + return "timestamp,temp\n"; + } + + void print(std::ostream& os) const + { + os << timestamp << "," << tempData << "\n"; + } +}; + +//MAGNETOMETER +struct lsm9ds1MSample +{ + uint64_t timestamp; + Vec3 magData; + + static std::string header() + { + return "timestamp,mag_x,mag_y,mag_z\n"; + } + + void print(std::ostream& os) const + { + os << timestamp << "," << + magData.getX() << "," << magData.getY() << "," << magData.getZ() << "\n"; + } +}; diff --git a/src/shared/sensors/LSM9DS1/LSM9DS1_Magneto.cpp b/src/shared/sensors/LSM9DS1/LSM9DS1_Magneto.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7879bc7dfd10f0faa9234f3befbcdc752481632e --- /dev/null +++ b/src/shared/sensors/LSM9DS1/LSM9DS1_Magneto.cpp @@ -0,0 +1,164 @@ +/* LSM9DS1 magnetometer Driver + * + * Copyright (c) 2016,2020 Skyward Experimental Rocketry + * Authors: Andrea Milluzzo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "LSM9DS1_Magneto.h" + +using miosix::GpioPin; +using std::vector; + +LSM9DS1_M::LSM9DS1_M(SPIBusInterface& bus, GpioPin cs, + MagFSR magRange = MagFSR::FS_8, ODR odr = ODR::ODR_0_625) + : spislave(bus, cs, {}), magFSR(magRange), odr(odr) +{ + // SPI config + spislave.config.clock_div = SPIClockDivider::DIV64; +} + +LSM9DS1_M::LSM9DS1_M(SPIBusInterface& bus, GpioPin cs, SPIBusConfig config, + MagFSR magRange = MagFSR::FS_8, ODR odr = ODR::ODR_0_625) + : spislave(bus, cs, config), magFSR(magRange), odr(odr) +{ +} + +bool LSM9DS1_M::init() +{ + // Set FSR + switch (magFSR) + { + case MagFSR::FS_4: + magSensitivity = 0.14f; + break; + case MagFSR::FS_8: + magSensitivity = 0.29f; + break; + case MagFSR::FS_12: + magSensitivity = 0.43f; + break; + case MagFSR::FS_16: + magSensitivity = 0.58f; + break; + default: + magSensitivity = 0.14f; + break; + } + + SPITransaction spi(spislave); + + // Who Am I check: + uint8_t whoami = spi.read(WHO_AM_I_M); // regMapM::WHO_AM_I_M); + + if (whoami != WHO_AM_I_M_VAL) + { + TRACE("LSM9DS1 MAG WAMI: 0x%02X\n", whoami); + last_error = ERR_NOT_ME; + return false; + } + + // setup + uint8_t CTRL_REG1_M_VAL = 0x60 | (int)odr << 2; + spi.write(regMapM::CTRL_REG1_M, + CTRL_REG1_M_VAL); // X,Y axes in ultra-high performance mode, + // NO auto-temp compensation and ODR + // defined by constructor + + uint8_t CTRL_REG2_M_VAL = (int)magFSR << 5; + spi.write(regMapM::CTRL_REG2_M, + CTRL_REG2_M_VAL); // FSR defined by constructor + + spi.write(regMapM::CTRL_REG4_M, + CTRL_REG4_M_VAL); // Z axis in ultra-high performance mode + spi.write(regMapM::CTRL_REG3_M, + CTRL_REG3_M_VAL); // I2C disabled, SPI mode: read/write + + spi.write(regMapM::INT_CFG_M, INT_CFG_M_VAL); // disable all interrupts + + // check that all registers have been written correctly + + if (spi.read(regMapM::CTRL_REG1_M) != CTRL_REG1_M_VAL) + { + return false; + } + if (spi.read(regMapM::CTRL_REG2_M) != CTRL_REG2_M_VAL) + { + return false; + } + if (spi.read(regMapM::CTRL_REG3_M) != CTRL_REG3_M_VAL) + { + return false; + } + if (spi.read(regMapM::CTRL_REG4_M) != CTRL_REG4_M_VAL) + { + return false; + } + if (spi.read(regMapM::INT_CFG_M) != INT_CFG_M_VAL) + { + return false; + } + + return true; +} + +bool LSM9DS1_M::selfTest() { return true; } + +bool LSM9DS1_M::onSimpleUpdate() +{ + + uint8_t magData[6]; + // read output data X,Y,Z + { + SPITransaction spi(spislave); + // bit 1 of SPI transaction = 1 means "auto-increment address" (see + // DS). + spi.read(regMapM::OUT_X_L_M | 0x40, magData, + 6); // so bit 6 of the address = 1 + } + + int16_t x = magData[0] | magData[1] << 8; + int16_t y = magData[2] | magData[3] << 8; + int16_t z = magData[4] | magData[5] << 8; + + // TRACE("LSM9DS1 mageto: %02X,%02X,%02X\n", x, y, z); + + mLastCompass = Vec3(x * magSensitivity / 1000, y * magSensitivity / 1000, + z * magSensitivity / 1000); + return true; +} + +void LSM9DS1_M::setOffset(vector<uint16_t>& offVect) +{ + if (offVect.size() < 3) + return; + uint8_t toStore[6]; + for (int i = 6; i > 0; i = i - 2) + { + toStore[i - 1] = offVect.back() & 0x00FF; // LSB + toStore[i - 2] = offVect.back() >> 8; // MSB + offVect.pop_back(); + } + + SPITransaction spi(spislave); + // bit 1 of SPI transaction = 1 means "auto-increment address". + spi.write(regMapM::OFFSET_X_REG_L_M | 0x40, toStore, + 6); // so bit 6 of the address = 1 +} \ No newline at end of file diff --git a/src/shared/sensors/LSM9DS1/LSM9DS1_Magneto.h b/src/shared/sensors/LSM9DS1/LSM9DS1_Magneto.h index 5e94c7f257a18a8a8a8e89554dceed513793d4a0..6bfdad5520af21fe85fc4463bd67dbee00faf7e1 100644 --- a/src/shared/sensors/LSM9DS1/LSM9DS1_Magneto.h +++ b/src/shared/sensors/LSM9DS1/LSM9DS1_Magneto.h @@ -24,215 +24,132 @@ #pragma once #include <miosix.h> + #include <vector> +#include "LSM9DS1_Data.h" #include "drivers/spi/SPIDriver.h" -#include "../Sensor.h" using miosix::GpioPin; using std::vector; -// data Structs -struct lsm9ds1MSample -{ - uint64_t timestamp; - Vec3 magData; -}; +/** + * @brief descrizione classe + */ class LSM9DS1_M : public CompassSensor { - public: - - enum MagFSR - { - FS_4 = 0x00, - FS_8 = 0x01, - FS_12 = 0x02, - FS_16 = 0x03 - }; - - enum ODR - { - ODR_0_625 = 0X00, - ODR_1_25 = 0x01, - ODR_2_5 = 0x02, - ODR_5 = 0x03, - ODR_10 = 0x04, - ODR_20 = 0x05, - ODR_40 = 0x06, - ODR_80 = 0x07 - }; - - /** - * @brief Creates an instance of an LSM9DS1 accelerometer + gyroscope sensor - * - * @param bus SPI bus the sensor is connected to - * @param cs Chip Select GPIO - * @param config (OPTIONAL) custom SPIBusConfig - * @param magRange magnetometer Full Scale Range (See datasheet) - * @param odr Output Data Rate (See datasheet) - */ - - LSM9DS1_M( - SPIBusInterface& bus, - GpioPin cs, - MagFSR magRange = MagFSR::FS_8, - ODR odr = ODR::ODR_0_625 - ): spislave(bus, cs, {}), magFSR(magRange), odr(odr){ - //SPI config - spislave.config.clock_div=SPIClockDivider::DIV64; - } - - LSM9DS1_M( - SPIBusInterface& bus, - GpioPin cs, - SPIBusConfig config, - MagFSR magRange = MagFSR::FS_8, - ODR odr = ODR::ODR_0_625 - ): spislave(bus, cs, config), magFSR(magRange), odr(odr){ - - } - - bool init() override - { - //Set FSR - switch(magFSR) - { - case MagFSR::FS_4: - magSensitivity = 0.14f; - break; - case MagFSR::FS_8: - magSensitivity = 0.29f; - break; - case MagFSR::FS_12: - magSensitivity = 0.43f; - break; - case MagFSR::FS_16: - magSensitivity = 0.58f; - break; - default: - magSensitivity = 0.14f; - break; - } - - SPITransaction spi(spislave); - - //Who Am I check: - uint8_t whoami = spi.read(WHO_AM_I_M);//regMapM::WHO_AM_I_M); - - if(whoami != WHO_AM_I_M_VAL){ - TRACE("LSM9DS1 MAG WAMI: 0x%02X\n", whoami); - last_error = ERR_NOT_ME; - return false; - } - - //setup - uint8_t CTRL_REG1_M_VAL = 0x60 | (int)odr<<2; - spi.write(regMapM::CTRL_REG1_M, CTRL_REG1_M_VAL); //X,Y axes in ultra-high performance mode, NO auto-temp compensation and ODR defined by constructor - - uint8_t CTRL_REG2_M_VAL = (int)magFSR<<5; - spi.write(regMapM::CTRL_REG2_M, CTRL_REG2_M_VAL); //FSR defined by constructor - - spi.write(regMapM::CTRL_REG4_M, CTRL_REG4_M_VAL); //Z axis in ultra-high performance mode - spi.write(regMapM::CTRL_REG3_M, CTRL_REG3_M_VAL); //I2C disabled, SPI mode: read/write - - spi.write(regMapM::INT_CFG_M, INT_CFG_M_VAL); //disable all interrupts - - - //check that all registers have been written correctly - - if(spi.read(regMapM::CTRL_REG1_M) != CTRL_REG1_M_VAL) {return false;} - if(spi.read(regMapM::CTRL_REG2_M) != CTRL_REG2_M_VAL) {return false;} - if(spi.read(regMapM::CTRL_REG3_M) != CTRL_REG3_M_VAL) {return false;} - if(spi.read(regMapM::CTRL_REG4_M) != CTRL_REG4_M_VAL) {return false;} - if(spi.read(regMapM::INT_CFG_M) != INT_CFG_M_VAL) {return false;} - - return true; - } - - bool selfTest() override - { - return true; - } - - bool onSimpleUpdate() override - { - uint8_t magData[6]; - //read output data X,Y,Z - { - SPITransaction spi(spislave); - //bit 1 of SPI transaction = 1 means "auto-increment address" (see DS). - spi.read(regMapM::OUT_X_L_M | 0x40, magData, 6);//so bit 6 of the address = 1 - } - - int16_t x = magData[0] | magData[1] << 8; - int16_t y = magData[2] | magData[3] << 8; - int16_t z = magData[4] | magData[5] << 8; - - // TRACE("LSM9DS1 mageto: %02X,%02X,%02X\n", x, y, z); - - mLastCompass = - Vec3(x * magSensitivity / 1000, - y * magSensitivity / 1000, - z * magSensitivity / 1000); - return true; - } - - void setOffset(vector<uint16_t>& offVect) //X,Y,Z - { - if(offVect.size() < 3) return; - uint8_t toStore[6]; - for(int i=6; i > 0 ; i=i-2){ - toStore[i-1] = offVect.back() & 0x00FF; //LSB - toStore[i-2] = offVect.back() >> 8; //MSB - offVect.pop_back(); - } - - SPITransaction spi(spislave); - //bit 1 of SPI transaction = 1 means "auto-increment address". - spi.write(OFFSET_X_REG_L_M | 0x40, toStore, 6); //so bit 6 of the address = 1 - } - - private: - - SPISlave spislave; - - MagFSR magFSR; - ODR odr; - - float magSensitivity; - - enum regMapM - { - OFFSET_X_REG_L_M = 0x05, - OFFSET_X_REG_H_M = 0x06, - OFFSET_Y_REG_L_M = 0x07, - OFFSET_Y_REG_H_M = 0x08, - OFFSET_Z_REG_L_M = 0x09, - OFFSET_Z_REG_H_M = 0x0A, - WHO_AM_I_M = 0x0F, - CTRL_REG1_M = 0x20, - CTRL_REG2_M = 0x21, - CTRL_REG3_M = 0x22, - CTRL_REG4_M = 0x23, - CTRL_REG5_M = 0x24, - STATUS_REG_M = 0x27, - OUT_X_L_M = 0x28, - OUT_X_H_M = 0x29, - OUT_Y_L_M = 0x2A, - OUT_Y_H_M = 0x2B, - OUT_Z_L_M = 0x2C, - OUT_Z_H_M = 0x2D, - INT_CFG_M = 0x30, - INT_SRC_M = 0x31, - INT_THS_L_M = 0x32, - INT_THS_H_M = 0x33 - }; - - static const uint8_t WHO_AM_I_M_VAL = 0x3D; - static const uint8_t CTRL_REG3_M_VAL = 0x80; - static const uint8_t CTRL_REG4_M_VAL = 0x0C; - static const uint8_t INT_CFG_M_VAL = 0x00; - - +public: + enum MagFSR + { + FS_4 = 0x00, + FS_8 = 0x01, + FS_12 = 0x02, + FS_16 = 0x03 + }; + + enum ODR + { + ODR_0_625 = 0X00, + ODR_1_25 = 0x01, + ODR_2_5 = 0x02, + ODR_5 = 0x03, + ODR_10 = 0x04, + ODR_20 = 0x05, + ODR_40 = 0x06, + ODR_80 = 0x07 + }; + + /** + * @brief Creates an instance of an LSM9DS1 magnetometer sensor. + * + * @param bus SPI bus the sensor is connected to + * @param cs Chip Select GPIO + * @param magRange magnetometer Full Scale Range (See datasheet) + * @param odr Output Data Rate (See datasheet) + */ + + LSM9DS1_M(SPIBusInterface& bus, GpioPin cs, MagFSR magRange, ODR odr); + + /** + * @brief Creates an instance of an LSM9DS1 magnetometer sensor. + * + * @param bus SPI bus the sensor is connected to + * @param cs Chip Select GPIO + * @param config custom SPIBusConfig + * @param magRange magnetometer Full Scale Range (See datasheet) + * @param odr Output Data Rate (See datasheet) + */ + + LSM9DS1_M(SPIBusInterface& bus, GpioPin cs, SPIBusConfig config, + MagFSR magRange, ODR odr); + + /** + * @brief initializes the LSM9DS1 Sensor (Magnetometer). + * @return true if all setup registers of the sensor have been written + * correctly + */ + + bool init() override; + + /** + * @brief Run a self-test of the Sensor. + * @return true if sensor behave correclty + */ + + bool selfTest() override; + + /** + * @brief Dump single reading of Magneto from the sensor through SPI. + * @return true if sensor sends data + */ + + bool onSimpleUpdate() override; + + /** + * @brief set offset of the compass sensor in case of offset errors. + * @param offVect offset values (X,Y,Z) + */ + + void setOffset(vector<uint16_t>& offVect); + +private: + SPISlave spislave; + + MagFSR magFSR; + ODR odr; + + float magSensitivity; + + enum regMapM + { + OFFSET_X_REG_L_M = 0x05, + OFFSET_X_REG_H_M = 0x06, + OFFSET_Y_REG_L_M = 0x07, + OFFSET_Y_REG_H_M = 0x08, + OFFSET_Z_REG_L_M = 0x09, + OFFSET_Z_REG_H_M = 0x0A, + WHO_AM_I_M = 0x0F, + CTRL_REG1_M = 0x20, + CTRL_REG2_M = 0x21, + CTRL_REG3_M = 0x22, + CTRL_REG4_M = 0x23, + CTRL_REG5_M = 0x24, + STATUS_REG_M = 0x27, + OUT_X_L_M = 0x28, + OUT_X_H_M = 0x29, + OUT_Y_L_M = 0x2A, + OUT_Y_H_M = 0x2B, + OUT_Z_L_M = 0x2C, + OUT_Z_H_M = 0x2D, + INT_CFG_M = 0x30, + INT_SRC_M = 0x31, + INT_THS_L_M = 0x32, + INT_THS_H_M = 0x33 + }; + + static const uint8_t WHO_AM_I_M_VAL = 0x3D; + static const uint8_t CTRL_REG3_M_VAL = 0x80; + static const uint8_t CTRL_REG4_M_VAL = 0x0C; + static const uint8_t INT_CFG_M_VAL = 0x00; }; \ No newline at end of file diff --git a/src/tests/drivers/test-lsm9ds1-fifo.cpp b/src/tests/drivers/test-lsm9ds1-fifo.cpp index 83a65c72a673b9c32890fe11583b15f47e0d08e1..8abc4f5b18cb120f60481f37cd0e2f7dc5dee008 100644 --- a/src/tests/drivers/test-lsm9ds1-fifo.cpp +++ b/src/tests/drivers/test-lsm9ds1-fifo.cpp @@ -26,7 +26,7 @@ #include "drivers/HardwareTimer.h" #include "drivers/spi/SPIDriver.h" #include "sensors/LSM9DS1/LSM9DS1_AxelGyro.h" -#include "sensors/LSM9DS1/LSM9DSI_Magneto.h" +#include "sensors/LSM9DS1/LSM9DS1_Magneto.h" #include "diagnostic/CpuMeter.h" #include "logger/Logger.h" diff --git a/src/tests/drivers/test-lsm9ds1.cpp b/src/tests/drivers/test-lsm9ds1.cpp index 1299f8d4ef531496dbd7f8844ad26e52ff5a4b79..378b8b3218db7785a247a956525549b871fd5109 100644 --- a/src/tests/drivers/test-lsm9ds1.cpp +++ b/src/tests/drivers/test-lsm9ds1.cpp @@ -25,7 +25,7 @@ #include "drivers/spi/SPIDriver.h" #include "sensors/LSM9DS1/LSM9DS1_AxelGyro.h" -#include "sensors/LSM9DS1/LSM9DSI_Magneto.h" +#include "sensors/LSM9DS1/LSM9DS1_Magneto.h" using namespace miosix;