diff --git a/CMakeLists.txt b/CMakeLists.txt
index ea116b5211996b039464de1848fedba46988f799..8e5162364a0b16ffce590db067bfe8abc5401265 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -232,6 +232,9 @@ sbs_target(test-calibration stm32f407vg_stm32f4discovery)
add_executable(test-bme280 src/tests/sensors/test-bme280.cpp)
sbs_target(test-bme280 stm32f429zi_stm32f4discovery)
+add_executable(test-bmp280 src/tests/sensors/test-bmp280.cpp)
+sbs_target(test-bmp280 stm32f429zi_stm32f4discovery)
+
add_executable(test-bmx160 src/tests/sensors/test-bmx160.cpp)
sbs_target(test-bmx160 stm32f429zi_skyward_death_stack_x)
diff --git a/cmake/boardcore.cmake b/cmake/boardcore.cmake
index 979aa24005d368b63bb645051dc14523a4164089..9d99de5a811713715c005a7a24a917ecdb1ff5ae 100644
--- a/cmake/boardcore.cmake
+++ b/cmake/boardcore.cmake
@@ -68,6 +68,7 @@ foreach(OPT_BOARD ${BOARDS})
${SBS_BASE}/src/shared/sensors/ADS131M04/ADS131M04.cpp
${SBS_BASE}/src/shared/sensors/ADS131M04/ADS131M04HighFreq.cpp
${SBS_BASE}/src/shared/sensors/BME280/BME280.cpp
+ ${SBS_BASE}/src/shared/sensors/BMP280/BMP280.cpp
${SBS_BASE}/src/shared/sensors/BMX160/BMX160.cpp
${SBS_BASE}/src/shared/sensors/BMX160/BMX160WithCorrection.cpp
${SBS_BASE}/src/shared/sensors/calibration/SensorDataExtra.cpp
diff --git a/src/shared/sensors/BME280/BME280.cpp b/src/shared/sensors/BME280/BME280.cpp
index 907b92432b0c724c122ba60085ff714e262c37d6..4701793dfe05f765013c3a2a672a9f2276933808 100644
--- a/src/shared/sensors/BME280/BME280.cpp
+++ b/src/shared/sensors/BME280/BME280.cpp
@@ -54,16 +54,6 @@ BME280::BME280(SPISlave spiSlave_, BME280Config config_)
bool BME280::init()
{
- // Check if already initialized
- if (initialized)
- {
- LOG_ERR(logger, "Already initialized");
-
- lastError = SensorErrors::ALREADY_INIT;
-
- return false;
- }
-
// Check WHO AM I
if (!checkWhoAmI())
{
@@ -99,20 +89,19 @@ bool BME280::init()
return false;
}
- initialized = true;
return true;
}
-void BME280::setHumidityOversampling(Oversampling oversampling)
+void BME280::setSensorMode(Mode mode)
{
- config.bits.oversamplingHumidity = oversampling;
+ config.bits.mode = mode;
setConfiguration();
}
-void BME280::setSensorMode(Mode mode)
+void BME280::setHumidityOversampling(Oversampling oversampling)
{
- config.bits.mode = mode;
+ config.bits.oversamplingHumidity = oversampling;
setConfiguration();
}
@@ -215,12 +204,6 @@ TemperatureData BME280::readTemperature()
return lastSample;
}
-HumidityData BME280::getHumidity() { return lastSample; }
-
-PressureData BME280::getPressure() { return lastSample; }
-
-TemperatureData BME280::getTemperature() { return lastSample; }
-
unsigned int BME280::calculateMaxMeasurementTime(BME280Config config_)
{
return ceil(1.25 + (2.3 * config_.bits.oversamplingTemperature) +
@@ -286,6 +269,8 @@ bool BME280::checkWhoAmI()
uint8_t whoAmIValue = transaction.readRegister(REG_ID);
+ printf("%2X\n", whoAmIValue);
+
return whoAmIValue == REG_ID_VAL;
}
diff --git a/src/shared/sensors/BME280/BME280.h b/src/shared/sensors/BME280/BME280.h
index 3dd66cce83dc94db771992ce508560981cdfe1a7..7ab2c6cdd39e4d1973091a4c4c40d24e546369db 100644
--- a/src/shared/sensors/BME280/BME280.h
+++ b/src/shared/sensors/BME280/BME280.h
@@ -163,12 +163,6 @@ public:
*/
bool init() override;
- /**
- * @brief Sets the oversampling for humidity readings, use SKIPPED to
- * disable humidity sampling
- */
- void setHumidityOversampling(Oversampling oversampling);
-
/**
* @brief Sets the sensor mode
*
@@ -182,6 +176,12 @@ public:
*/
void setSensorMode(Mode mode);
+ /**
+ * @brief Sets the oversampling for humidity readings, use SKIPPED to
+ * disable humidity sampling
+ */
+ void setHumidityOversampling(Oversampling oversampling);
+
/**
* @brief Sets the oversampling for pressure readings, use SKIPPED to
* disable pressure sampling
@@ -220,12 +220,6 @@ public:
*/
TemperatureData readTemperature();
- HumidityData getHumidity();
-
- PressureData getPressure();
-
- TemperatureData getTemperature();
-
/**
* @brief Maximum measurement time formula from datasheet page 51
*
@@ -301,8 +295,6 @@ private:
BME280Comp compParams;
int32_t fineTemperature; // Used in compensation algorithm
- bool initialized = false; // Whether the sensor has been initialized
-
PrintLogger logger = Logging::getLogger("bme280");
};
diff --git a/src/shared/sensors/BME280/BME280Data.h b/src/shared/sensors/BME280/BME280Data.h
index 4cfe0e90794942102f34641687ff22763e9d557d..473989e103fe62904a75f1c13a1ee425102f5e4f 100644
--- a/src/shared/sensors/BME280/BME280Data.h
+++ b/src/shared/sensors/BME280/BME280Data.h
@@ -46,9 +46,8 @@ struct BME280Data : public TemperatureData,
static std::string header()
{
- return "temperatureTimestamp,temp,pressureTimestamp,press,humid_"
- "timestamp,"
- "humid\n";
+ return "temperatureTimestamp,temperature,pressureTimestamp,pressure,"
+ "humid_timestamp,humidity\n";
}
void print(std::ostream& os) const
diff --git a/src/shared/sensors/BMP280/BMP280.cpp b/src/shared/sensors/BMP280/BMP280.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..12a1f15b75f826078d5f7dc11a35270d80cd6368
--- /dev/null
+++ b/src/shared/sensors/BMP280/BMP280.cpp
@@ -0,0 +1,315 @@
+/* Copyright (c) 2021 Skyward Experimental Rocketry
+ * Author: Alberto Nidasio
+ *
+ * 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 "BMP280.h"
+
+#include <drivers/timer/TimestampTimer.h>
+#include <math.h>
+
+using namespace std;
+
+namespace Boardcore
+{
+
+const BMP280::BMP280Config BMP280::BMP280_DEFAULT_CONFIG = {
+ 0, 0, SLEEP_MODE, SKIPPED, SKIPPED, 0, FILTER_OFF, STB_TIME_0_5};
+
+const BMP280::BMP280Config BMP280::BMP280_CONFIG_ALL_ENABLED = {0,
+ 0,
+ NORMAL_MODE,
+ OVERSAMPLING_16,
+ OVERSAMPLING_2,
+ 0,
+ FILTER_COEFF_16,
+ STB_TIME_0_5};
+
+const BMP280::BMP280Config BMP280::BMP280_CONFIG_TEMP_SINGLE = {
+ 0, 0, FORCED_MODE, SKIPPED, OVERSAMPLING_1, 0, FILTER_OFF, STB_TIME_0_5};
+
+BMP280::BMP280(SPISlave spiSlave_, BMP280Config config_)
+ : spiSlave(spiSlave_), config(config_)
+{
+}
+
+bool BMP280::init()
+{
+ // Check WHO AM I
+ if (!checkWhoAmI())
+ {
+ LOG_ERR(logger, "Invalid WHO AM I");
+
+ lastError = SensorErrors::INVALID_WHOAMI;
+
+ return false;
+ }
+
+ loadCompensationParameters();
+
+ // Read once the temperature to compute fineTemperature
+ setConfiguration(BMP280_CONFIG_TEMP_SINGLE);
+ miosix::Thread::sleep(
+ calculateMaxMeasurementTime(BMP280_CONFIG_TEMP_SINGLE));
+ readTemperature();
+
+ setConfiguration();
+
+ BMP280Config readBackConfig = readConfiguration();
+
+ // Check if the configration on the device matches ours
+ if (config.bytes.ctrlPressureAndTemperature !=
+ readBackConfig.bytes.ctrlPressureAndTemperature ||
+ config.bytes.config != readBackConfig.bytes.config)
+ {
+ LOG_ERR(logger, "Device configuration incorrect, setup failed");
+
+ lastError = SensorErrors::NOT_INIT;
+
+ return false;
+ }
+
+ return true;
+}
+
+void BMP280::setSensorMode(Mode mode)
+{
+ config.bits.mode = mode;
+
+ setConfiguration();
+}
+
+void BMP280::setPressureOversampling(Oversampling oversampling)
+{
+ config.bits.oversamplingPressure = oversampling;
+
+ setConfiguration();
+}
+
+void BMP280::setTemperatureOversampling(Oversampling oversampling)
+{
+ config.bits.oversamplingTemperature = oversampling;
+
+ setConfiguration();
+}
+
+void BMP280::setFilterCoeff(FilterCoeff filterCoeff)
+{
+ config.bits.filter = filterCoeff;
+
+ setConfiguration();
+}
+
+void BMP280::setStandbyTime(StandbyTime standbyTime)
+{
+ config.bits.standbyTime = standbyTime;
+
+ setConfiguration();
+}
+
+PressureData BMP280::readPressure()
+{
+ uint8_t buffer[3];
+ int32_t adc_P = 0;
+
+ {
+ SPITransaction transaction(spiSlave);
+
+ transaction.readRegisters(REG_PRESS_MSB, buffer, 3);
+ }
+
+ adc_P |= ((uint32_t)buffer[0]) << 12;
+ adc_P |= ((uint32_t)buffer[1]) << 4;
+ adc_P |= (buffer[2] >> 4) & 0x0F;
+
+ // Compensate pressure
+ lastSample.pressureTimestamp = TimestampTimer::getInstance().getTimestamp();
+ lastSample.pressure =
+ (float)compensatePressure(adc_P) / 256; // Convert to Pa
+
+ return lastSample;
+}
+
+TemperatureData BMP280::readTemperature()
+{
+ uint8_t buffer[3];
+ int32_t adcTemperature = 0;
+
+ {
+ SPITransaction transaction(spiSlave);
+
+ transaction.readRegisters(REG_TEMP_MSB, buffer, 3);
+ }
+
+ adcTemperature |= ((uint32_t)buffer[0]) << 12;
+ adcTemperature |= ((uint32_t)buffer[1]) << 4;
+ adcTemperature |= (buffer[2] >> 4) & 0x0F;
+
+ // Compensate temperature
+ fineTemperature = computeFineTemperature(adcTemperature);
+ lastSample.temperatureTimestamp =
+ TimestampTimer::getInstance().getTimestamp();
+ lastSample.temperature = (float)compensateTemperature(fineTemperature) /
+ 100; // Converto to DegC
+
+ return lastSample;
+}
+
+unsigned int BMP280::calculateMaxMeasurementTime(BMP280Config config_)
+{
+ // TODO: This folrmula is not present in the BMP280's datasheet, it should
+ // be checked
+ return ceil(1.25 + (2.3 * config_.bits.oversamplingTemperature) +
+ (2.3 * config_.bits.oversamplingPressure + 0.575));
+}
+
+unsigned int BMP280::getMaxMeasurementTime()
+{
+ return calculateMaxMeasurementTime(config);
+}
+
+bool BMP280::selfTest() { return checkWhoAmI(); }
+
+BMP280Data BMP280::sampleImpl()
+{
+ uint8_t buffer[8];
+ int32_t adcTemperature = 0;
+ int32_t adc_P = 0;
+ int32_t adc_H = 0;
+ BMP280Data data;
+
+ // TODO: implement selective read!
+
+ // Burst read pressure, temperature and humidity
+ {
+ SPITransaction transaction(spiSlave);
+
+ transaction.readRegisters(REG_PRESS_MSB, buffer, 8);
+ }
+
+ adcTemperature |= ((uint32_t)buffer[3]) << 12;
+ adcTemperature |= ((uint32_t)buffer[4]) << 4;
+ adcTemperature |= (buffer[5] >> 4) & 0x0F;
+
+ adc_P |= ((uint32_t)buffer[0]) << 12;
+ adc_P |= ((uint32_t)buffer[1]) << 4;
+ adc_P |= (buffer[2] >> 4) & 0x0F;
+
+ adc_H |= ((uint32_t)buffer[6] << 8);
+ adc_H |= buffer[7];
+
+ // Compensate temperature
+ fineTemperature = computeFineTemperature(adcTemperature);
+ data.temperatureTimestamp = TimestampTimer::getInstance().getTimestamp();
+ data.temperature = (float)compensateTemperature(fineTemperature) /
+ 100; // Converto to DegC
+
+ // Compensate pressure
+ data.pressureTimestamp = TimestampTimer::getInstance().getTimestamp();
+ data.pressure = (float)compensatePressure(adc_P) / 256; // Convert to Pa
+
+ return data;
+}
+
+bool BMP280::checkWhoAmI()
+{
+ SPITransaction transaction(spiSlave);
+
+ uint8_t whoAmIValue = transaction.readRegister(REG_ID);
+
+ printf("%2X\n", whoAmIValue);
+
+ return whoAmIValue == REG_ID_VAL;
+}
+
+void BMP280::setConfiguration() { setConfiguration(config); }
+
+void BMP280::setConfiguration(BMP280Config config_)
+{
+ SPITransaction transaction(spiSlave);
+
+ transaction.writeRegister(REG_CONFIG & 0x7F, config_.bytes.config);
+ transaction.writeRegister(REG_CTRL_MEAS & 0x7F,
+ config_.bytes.ctrlPressureAndTemperature);
+}
+
+BMP280::BMP280Config BMP280::readConfiguration()
+{
+ BMP280Config tmp;
+ SPITransaction transaction(spiSlave);
+
+ transaction.readRegisters(REG_STATUS, (uint8_t *)&tmp, 3);
+
+ return tmp;
+}
+
+void BMP280::loadCompensationParameters()
+{
+ // Read compensation parameters
+ {
+ SPITransaction transaction(spiSlave);
+
+ transaction.readRegisters(REG_CALIB_0, (uint8_t *)&compParams, 25);
+ }
+}
+
+int32_t BMP280::computeFineTemperature(int32_t adcTemperature)
+{
+ int32_t var1, var2;
+ var1 = ((((adcTemperature >> 3) - ((int32_t)compParams.bits.dig_T1 << 1))) *
+ ((int32_t)compParams.bits.dig_T2)) >>
+ 11;
+ var2 = (((((adcTemperature >> 4) - ((int32_t)compParams.bits.dig_T1)) *
+ ((adcTemperature >> 4) - ((int32_t)compParams.bits.dig_T1))) >>
+ 12) *
+ ((int32_t)compParams.bits.dig_T3)) >>
+ 14;
+ return var1 + var2;
+}
+
+int32_t BMP280::compensateTemperature(int32_t fineTemperature)
+{
+ return (fineTemperature * 5 + 128) >> 8;
+}
+
+uint32_t BMP280::compensatePressure(int32_t adc_P)
+{
+ int64_t var1, var2, p;
+ var1 = ((int64_t)fineTemperature) - 128000;
+ var2 = var1 * var1 * (int64_t)compParams.bits.dig_P6;
+ var2 = var2 + ((var1 * (int64_t)compParams.bits.dig_P5) << 17);
+ var2 = var2 + (((int64_t)compParams.bits.dig_P4) << 35);
+ var1 = ((var1 * var1 * (int64_t)compParams.bits.dig_P3) >> 8) +
+ ((var1 * ((int64_t)compParams.bits.dig_P2) << 12));
+ var1 =
+ ((((int64_t)1) << 47) + var1) * ((int64_t)compParams.bits.dig_P1) >> 33;
+ if (var1 == 0)
+ {
+ return 0; // avoid exception caused by division by zero
+ }
+ p = 1048576 - adc_P;
+ p = (((p << 31) - var2) * 3125) / var1;
+ var1 = (((int64_t)compParams.bits.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
+ var2 = (((int64_t)compParams.bits.dig_P8) * p) >> 19;
+ p = ((p + var1 + var2) >> 8) + (((int64_t)compParams.bits.dig_P7) << 4);
+ return (uint32_t)p;
+}
+
+} // namespace Boardcore
diff --git a/src/shared/sensors/BMP280/BMP280.h b/src/shared/sensors/BMP280/BMP280.h
new file mode 100644
index 0000000000000000000000000000000000000000..385a40695fc386cc647cd051431198c150f9b835
--- /dev/null
+++ b/src/shared/sensors/BMP280/BMP280.h
@@ -0,0 +1,273 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Author: Alberto Nidasio
+ *
+ * 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 <diagnostic/PrintLogger.h>
+#include <drivers/spi/SPIDriver.h>
+#include <sensors/Sensor.h>
+
+#include "BMP280Data.h"
+
+namespace Boardcore
+{
+
+class BMP280 : public Sensor<BMP280Data>
+{
+public:
+ enum Oversampling
+ {
+ SKIPPED = 0x0, ///< Skipped (output set to 0x8000)
+ OVERSAMPLING_1 = 0x1, ///< Oversampling x1
+ OVERSAMPLING_2 = 0x2, ///< Oversampling x2
+ OVERSAMPLING_4 = 0x3, ///< Oversampling x4
+ OVERSAMPLING_8 = 0x4, ///< Oversampling x8
+ OVERSAMPLING_16 = 0x5, ///< Oversampling x16
+ };
+
+ enum Mode
+ {
+ SLEEP_MODE = 0x0, ///< Sleep mode
+ FORCED_MODE = 0x1, ///< Forced mode
+ NORMAL_MODE = 0x3 ///< Normal mode
+ };
+
+ enum StandbyTime
+ {
+ STB_TIME_0_5 = 0x0, ///< 0.5 ms
+ STB_TIME_62_5 = 0x1, ///< 62.5 ms
+ STB_TIME_125 = 0x2, ///< 125 ms
+ STB_TIME_250 = 0x3, ///< 250 ms
+ STB_TIME_500 = 0x4, ///< 500 ms
+ STB_TIME_1000 = 0x5, ///< 1000 ms
+ STB_TIME_20 = 0x6, ///< 20 ms
+ STB_TIME_40 = 0x7 ///< 40 ms
+ };
+
+ enum FilterCoeff
+ {
+ FILTER_OFF = 0x0, ///< Filter off
+ FILTER_COEFF_2 = 0x1, ///< Filter coefficient = 2
+ FILTER_COEFF_4 = 0x2, ///< Filter coefficient = 4
+ FILTER_COEFF_8 = 0x3, ///< Filter coefficient = 8
+ FILTER_COEFF_16 = 0x4 ///< Filter coefficient = 16
+ };
+
+ union BMP280Config
+ {
+ struct __attribute__((packed)) BMP280ConfigBits
+ {
+ // status
+ /**
+ * '1' when the NVM data are being copied to image registers, '0'
+ * when the copying is done
+ */
+ uint8_t imUpdate : 1;
+ uint8_t : 2;
+ /**
+ * '1' whenever a conversion is running, '0' when the result have
+ * been transferred to the data registers
+ */
+ uint8_t measuring : 1;
+ uint8_t : 4;
+
+ Mode mode : 2; ///< Device modes
+ Oversampling
+ oversamplingPressure : 3; ///< Oversampling of pressure
+ Oversampling
+ oversamplingTemperature : 3; ///< Oversampling of temperature
+
+ // config
+ uint8_t spi3wEn : 1; ///< Enables 3-wire SPI interface
+ uint8_t : 1;
+ FilterCoeff filter : 3; ///< Time constant of the IIR filter
+ StandbyTime standbyTime : 3; ///< Inactive duration in normal mode
+ } bits;
+
+ struct
+ {
+ uint8_t status; ///< Device status
+ uint8_t ctrlPressureAndTemperature; ///< Pressure and temperature
+ ///< options
+ uint8_t config; ///< Rate, filter and interface options
+ } bytes;
+
+ uint8_t bytesArray[3];
+ };
+
+ union BMP280Comp
+ {
+ struct __attribute__((packed))
+ {
+ uint16_t dig_T1;
+ int16_t dig_T2;
+ int16_t dig_T3;
+ uint16_t dig_P1;
+ int16_t dig_P2;
+ int16_t dig_P3;
+ int16_t dig_P4;
+ int16_t dig_P5;
+ int16_t dig_P6;
+ int16_t dig_P7;
+ int16_t dig_P8;
+ int16_t dig_P9;
+ } bits;
+
+ uint8_t bytesArray[24];
+ };
+
+ static constexpr uint8_t REG_ID_VAL = 0x58; ///< Who am I value
+
+ static const BMP280Config BMP280_DEFAULT_CONFIG; ///< Default register
+ ///< values
+ static const BMP280Config BMP280_CONFIG_ALL_ENABLED; ///< Datasheet
+ ///< values for
+ ///< indoor
+ ///< navigation
+ static const BMP280Config BMP280_CONFIG_TEMP_SINGLE; ///< Temperature
+ ///< enabled in
+ ///< forced mode
+
+ explicit BMP280(SPISlave spiSlave_,
+ BMP280Config config_ = BMP280_CONFIG_ALL_ENABLED);
+
+ /**
+ * @brief Initialize the device with the specified configuration
+ */
+ bool init() override;
+
+ /**
+ * @brief Sets the sensor mode
+ *
+ * Values:
+ * - SLEEP_MODE: No measurements are performed
+ * - FORCED_MODE: A single measurement is performed when this function
+ * writes the configuration, after the measurement the sensor return to
+ * sleep mode
+ * - NORMAL_MODE: Automated cycling between measurements, standby time can
+ * be set using setStandbyTime()
+ */
+ void setSensorMode(Mode mode);
+
+ /**
+ * @brief Sets the oversampling for pressure readings, use SKIPPED to
+ * disable pressure sampling
+ */
+ void setPressureOversampling(Oversampling oversampling);
+
+ /**
+ * @brief Sets the oversampling for temperature readings, use SKIPPED to
+ * disable temperature sampling
+ */
+ void setTemperatureOversampling(Oversampling oversampling);
+
+ /**
+ * @brief Sets the coefficient for the IIR filter (applied to temperature
+ * and pressure)
+ */
+ void setFilterCoeff(FilterCoeff filterCoeff);
+
+ /**
+ * @brief Sets the standby time between readings in normal mode
+ */
+ void setStandbyTime(StandbyTime standbyTime);
+
+ /**
+ * @brief Reads only the pressure, does not set the configuration
+ */
+ PressureData readPressure();
+
+ /**
+ * @brief Reads only the temperature, does not set the configuration
+ */
+ TemperatureData readTemperature();
+
+ /**
+ * @brief Maximum measurement time formula from datasheet page 51
+ *
+ * @return Time in milliseconds
+ */
+ static unsigned int calculateMaxMeasurementTime(BMP280Config config_);
+
+ unsigned int getMaxMeasurementTime();
+
+ /**
+ * @brief Reads the WHO AM I register
+ *
+ * @return True if everything ok
+ */
+ bool selfTest() override;
+
+private:
+ BMP280Data sampleImpl() override;
+
+ void setConfiguration();
+
+ void setConfiguration(BMP280Config config_);
+
+ BMP280Config readConfiguration();
+
+ void loadCompensationParameters();
+
+ // Compensation algorithm rev.1.1 from Bosh datasheet
+
+ int32_t computeFineTemperature(int32_t adcTemperature);
+
+ int32_t compensateTemperature(int32_t fineTemperature);
+
+ uint32_t compensatePressure(int32_t adcPressure);
+ /**
+ * @brief Check the WHO AM I code from the device.
+ *
+ * @return true if the device is recognized
+ */
+ bool checkWhoAmI();
+
+ enum BMP280Registers : uint8_t
+ {
+ REG_CALIB_0 = 0x88,
+ // Calibration register 1-25
+
+ REG_ID = 0xD0,
+ REG_RESET = 0xE0,
+
+ REG_STATUS = 0xF3,
+ REG_CTRL_MEAS = 0xF4,
+ REG_CONFIG = 0xF5,
+
+ REG_PRESS_MSB = 0xF7,
+ REG_PRESS_LSB = 0xF8,
+ REG_PRESS_XLSB = 0xF9,
+ REG_TEMP_MSB = 0xFA,
+ REG_TEMP_LSB = 0xFB,
+ REG_TEMP_XLSB = 0xFC
+ };
+
+ const SPISlave spiSlave;
+ BMP280Config config;
+ BMP280Comp compParams;
+ int32_t fineTemperature; // Used in compensation algorithm
+
+ PrintLogger logger = Logging::getLogger("bmp280");
+};
+
+} // namespace Boardcore
diff --git a/src/shared/sensors/BMP280/BMP280Data.h b/src/shared/sensors/BMP280/BMP280Data.h
new file mode 100644
index 0000000000000000000000000000000000000000..cfd3cecc200fb8be00b137bc725a6a62a2776f45
--- /dev/null
+++ b/src/shared/sensors/BMP280/BMP280Data.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2021 Skyward Experimental Rocketry
+ * Author: Alberto Nidasio
+ *
+ * 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 <sensors/SensorData.h>
+
+namespace Boardcore
+{
+
+struct BMP280Data : public TemperatureData, public PressureData
+{
+ BMP280Data() : TemperatureData{0, 0.0}, PressureData{0, 0.0} {}
+
+ BMP280Data(uint64_t timestamp, float temperature, float pressure,
+ float humidity)
+ : TemperatureData{timestamp, temperature}, PressureData{timestamp,
+ pressure}
+
+ {
+ }
+
+ static std::string header()
+ {
+ return "temperatureTimestamp,temperature,pressureTimestamp,pressure,\n";
+ }
+
+ void print(std::ostream& os) const
+ {
+ os << temperatureTimestamp << "," << temperature << ","
+ << pressureTimestamp << "," << pressure << ","
+ << "\n";
+ }
+};
+
+} // namespace Boardcore
diff --git a/src/tests/sensors/test-bme280.cpp b/src/tests/sensors/test-bme280.cpp
index ab960d91ffcd84e51929f4deb927f596b4fd6875..afa223a4a46bab257afa859e1f4fd0ea1fad2cf4 100644
--- a/src/tests/sensors/test-bme280.cpp
+++ b/src/tests/sensors/test-bme280.cpp
@@ -54,15 +54,15 @@ GpioPin csPin = GpioPin(GPIOC_BASE, 1);
void initBoard()
{
// Alternate function configuration for SPI pins
- sckPin.mode(miosix::Mode::ALTERNATE);
+ sckPin.mode(Mode::ALTERNATE);
sckPin.alternateFunction(5); // SPI function
- mosiPin.mode(miosix::Mode::ALTERNATE);
+ mosiPin.mode(Mode::ALTERNATE);
mosiPin.alternateFunction(5); // SPI function
- misoPin.mode(miosix::Mode::ALTERNATE);
+ misoPin.mode(Mode::ALTERNATE);
misoPin.alternateFunction(5); // SPI function
// Chip select pin as output starting high
- csPin.mode(miosix::Mode::OUTPUT);
+ csPin.mode(Mode::OUTPUT);
csPin.high();
}
@@ -98,7 +98,7 @@ int main()
{
bme280.setSensorMode(BME280::FORCED_MODE);
- miosix::Thread::sleep(bme280.getMaxMeasurementTime());
+ Thread::sleep(bme280.getMaxMeasurementTime());
bme280.sample();
@@ -106,7 +106,7 @@ int main()
bme280.getLastSample().temperature,
bme280.getLastSample().pressure, bme280.getLastSample().humidity);
- miosix::Thread::sleep(1000);
+ Thread::sleep(1000);
}
TRACE("Normal mode\n");
@@ -119,6 +119,6 @@ int main()
bme280.getLastSample().temperature,
bme280.getLastSample().pressure, bme280.getLastSample().humidity);
- miosix::Thread::sleep(50); // 25Hz
+ Thread::sleep(50); // 25Hz
}
}
diff --git a/src/tests/sensors/test-bmp280.cpp b/src/tests/sensors/test-bmp280.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d83478dede299492b607e2434a70c35b559b0906
--- /dev/null
+++ b/src/tests/sensors/test-bmp280.cpp
@@ -0,0 +1,107 @@
+/* Copyright (c) 2021 Skyward Experimental Rocketry
+ * Author: Alberto Nidasio
+ *
+ * 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 <drivers/spi/SPIDriver.h>
+#include <drivers/timer/TimestampTimer.h>
+#include <miosix.h>
+#include <sensors/BMP280/BMP280.h>
+#include <utils/Debug.h>
+
+using namespace miosix;
+using namespace Boardcore;
+
+GpioPin sckPin = GpioPin(GPIOA_BASE, 5);
+GpioPin misoPin = GpioPin(GPIOB_BASE, 4);
+GpioPin mosiPin = GpioPin(GPIOA_BASE, 7);
+GpioPin csPin = GpioPin(GPIOB_BASE, 2);
+
+void initBoard()
+{
+ // Alternate function configuration for SPI pins
+ sckPin.mode(Mode::ALTERNATE);
+ sckPin.alternateFunction(5); // SPI function
+ mosiPin.mode(Mode::ALTERNATE);
+ mosiPin.alternateFunction(5); // SPI function
+ misoPin.mode(Mode::ALTERNATE);
+ misoPin.alternateFunction(5); // SPI function
+
+ // Chip select pin as output starting high
+ csPin.mode(Mode::OUTPUT);
+ csPin.high();
+}
+
+int main()
+{
+ // Enable SPI clock and set gpios
+ initBoard();
+
+ // SPI configuration setup
+ SPIBusConfig spiConfig;
+ // spiConfig.clockDivider = SPI::ClockDivider::DIV_32;
+ spiConfig.mode = SPI::Mode::MODE_0;
+ SPIBus spiBus(SPI1);
+ SPISlave spiSlave(spiBus, csPin, spiConfig);
+
+ // Device initialization
+ BMP280 bmp280(spiSlave);
+
+ bmp280.init();
+
+ // In practice the self test reads the who am i reagister, this is already
+ // done in init()
+ if (!bmp280.selfTest())
+ {
+ TRACE("Self test failed!\n");
+
+ return -1;
+ }
+
+ // Try forced mode
+ TRACE("Forced mode\n");
+ for (int i = 0; i < 10; i++)
+ {
+ bmp280.setSensorMode(BMP280::FORCED_MODE);
+
+ Thread::sleep(bmp280.getMaxMeasurementTime());
+
+ bmp280.sample();
+
+ TRACE("temp: %.2f DegC\tpress: %.2f hPa\n",
+ bmp280.getLastSample().temperature,
+ bmp280.getLastSample().pressure);
+
+ Thread::sleep(1000);
+ }
+
+ TRACE("Normal mode\n");
+ bmp280.setSensorMode(BMP280::NORMAL_MODE);
+ while (true)
+ {
+ bmp280.sample();
+
+ TRACE("temp: %.2f DegC\tpress: %.2f Pa\thumid: %.2f %%RH\n",
+ bmp280.getLastSample().temperature,
+ bmp280.getLastSample().pressure);
+
+ Thread::sleep(50); // 25Hz
+ }
+}