diff --git a/CMakeLists.txt b/CMakeLists.txt index cdfe8fc38ffb106eeb966de8c630f26b9a0dc5fd..6798867219d444c49cf6c84becb4e1c970dd684c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -338,11 +338,17 @@ sbs_target(test-calibration-benchmark stm32f407vg_stm32f4discovery) add_executable(test-calibration-stats src/tests/sensors/calibration/test-calibration-stats.cpp) sbs_target(test-calibration-stats stm32f407vg_stm32f4discovery) -add_executable(test-bme280 src/tests/sensors/test-bme280.cpp) -sbs_target(test-bme280 stm32f429zi_stm32f4discovery) +add_executable(test-bme280-spi src/tests/sensors/test-bme280-spi.cpp) +sbs_target(test-bme280-spi stm32f429zi_stm32f4discovery) -add_executable(test-bmp280 src/tests/sensors/test-bmp280.cpp) -sbs_target(test-bmp280 stm32f429zi_stm32f4discovery) +add_executable(test-bme280-i2c src/tests/sensors/test-bme280-i2c.cpp) +sbs_target(test-bme280-i2c stm32f429zi_stm32f4discovery) + +add_executable(test-bmp280-spi src/tests/sensors/test-bmp280-spi.cpp) +sbs_target(test-bmp280-spi stm32f429zi_stm32f4discovery) + +add_executable(test-bmp280-i2c src/tests/sensors/test-bmp280-i2c.cpp) +sbs_target(test-bmp280-i2c 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 777fad422c136021d0b1f3d5255bc3867c72ab0a..2036b43467026eca06f315b8d689f7f81484e08c 100644 --- a/cmake/boardcore.cmake +++ b/cmake/boardcore.cmake @@ -82,7 +82,9 @@ foreach(OPT_BOARD ${BOARDS}) ${SBS_BASE}/src/shared/sensors/ADS1118/ADS1118.cpp ${SBS_BASE}/src/shared/sensors/ADS131M04/ADS131M04.cpp ${SBS_BASE}/src/shared/sensors/BME280/BME280.cpp + ${SBS_BASE}/src/shared/sensors/BME280/BME280I2C.cpp ${SBS_BASE}/src/shared/sensors/BMP280/BMP280.cpp + ${SBS_BASE}/src/shared/sensors/BMP280/BMP280I2C.cpp ${SBS_BASE}/src/shared/sensors/BMX160/BMX160.cpp ${SBS_BASE}/src/shared/sensors/BMX160/BMX160WithCorrection.cpp ${SBS_BASE}/src/shared/sensors/HX711/HX711.cpp diff --git a/src/shared/sensors/BME280/BME280.cpp b/src/shared/sensors/BME280/BME280.cpp index 80ab597f187c771a6e69c4febbef423d0f2b1b66..1ece0a1019bc4fbb657031832dcd04e480ad6040 100644 --- a/src/shared/sensors/BME280/BME280.cpp +++ b/src/shared/sensors/BME280/BME280.cpp @@ -54,64 +54,39 @@ BME280::BME280(SPISlave spiSlave, BME280Config config) bool BME280::init() { - // Check WHO AM I if (!checkWhoAmI()) { LOG_ERR(logger, "Invalid WHO AM I"); lastError = SensorErrors::INVALID_WHOAMI; - return false; } - loadCompensationParameters(); + reset(); + miosix::Thread::sleep(3); - // Set the configuration 10 times to be sure - for (int i = 0; i < 10; i++) - { - // Read once the temperature to compute fineTemperature - setConfiguration(BME280_CONFIG_TEMP_SINGLE); - miosix::Thread::sleep( - calculateMaxMeasurementTime(BME280_CONFIG_TEMP_SINGLE)); - readTemperature(); - - setConfiguration(); - } + loadCompensationParameters(); - // Set a sleep time to allow the sensor to change internally the data - miosix::Thread::sleep(100); + // Read once the temperature to compute fineTemperature + setConfiguration(BME280_CONFIG_TEMP_SINGLE); + miosix::Thread::sleep( + calculateMaxMeasurementTime(BME280_CONFIG_TEMP_SINGLE)); + readTemperature(); - // I create the config state which represents the logic or of all the - // 5 readConfiguration controls (We perform 5 checks to avoid that the - // sensor is busy implicating in wrong responses) - bool readConfigResult = false; - BME280Config readBackConfig; + // Set the target configuration + setConfiguration(); - for (int i = 0; i < 10; i++) - { - readBackConfig = readConfiguration(); - // Check if the configration on the device matches ours - if (config.bytes.ctrlHumidity == readBackConfig.bytes.ctrlHumidity && - config.bytes.ctrlPressureAndTemperature == - readBackConfig.bytes.ctrlPressureAndTemperature && - config.bytes.config == readBackConfig.bytes.config) - { - readConfigResult = true; - break; - } - - // After the check i sleep 100 milliseconds - miosix::Thread::sleep(20); - } + BME280Config readBackConfig = readConfiguration(); - // If after the 5 iterations the sensor didn't report the configuration - // set I can report the init error - if (!readConfigResult) + // Check if the configuration on the device matches ours + if (config.bytes.ctrlHumidity != readBackConfig.bytes.ctrlHumidity || + config.bytes.ctrlPressureAndTemperature != + readBackConfig.bytes.ctrlPressureAndTemperature || + config.bytes.config != readBackConfig.bytes.config) { - LOG_ERR(logger, "Device configuration incorrect, setup failed"); + LOG_ERR(logger, "Device configuration incorrect, setup failed."); lastError = SensorErrors::NOT_INIT; - return false; } @@ -163,77 +138,72 @@ void BME280::setStandbyTime(StandbyTime standbyTime) HumidityData BME280::readHumidity() { uint8_t buffer[2]; - int32_t adc_H = 0; - { SPITransaction transaction(spiSlave); transaction.readRegisters(REG_HUM_MSB, buffer, 2); } - adc_H |= ((uint32_t)buffer[0] << 8); + int32_t adc_H = ((uint32_t)buffer[0] << 8); adc_H |= buffer[1]; - // Compensate humidity - lastSample.humidityTimestamp = TimestampTimer::getTimestamp(); - lastSample.humidity = - (float)compensateHumidity(adc_H) / 1024; // Converto to %RH + HumidityData data; + data.humidityTimestamp = TimestampTimer::getTimestamp(); + data.humidity = compensateHumidity(adc_H); + data.humidity /= 1024; // Convert to to %RH - return lastSample; + return data; } PressureData BME280::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; + int32_t 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::getTimestamp(); - lastSample.pressure = - (float)compensatePressure(adc_P) / 256; // Convert to Pa + PressureData data; + data.pressureTimestamp = TimestampTimer::getTimestamp(); + data.pressure = compensatePressure(adc_P); + data.pressure /= 256; // Convert to Pa - return lastSample; + return data; } TemperatureData BME280::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; + int32_t 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::getTimestamp(); - lastSample.temperature = (float)compensateTemperature(fineTemperature) / - 100; // Converto to DegC + fineTemperature = computeFineTemperature(adcTemperature); + + TemperatureData data; + data.temperatureTimestamp = TimestampTimer::getTimestamp(); + data.temperature = compensateTemperature(fineTemperature); + data.temperature /= 100; // Convert to to DegC - return lastSample; + return data; } -unsigned int BME280::calculateMaxMeasurementTime(BME280Config config_) +unsigned int BME280::calculateMaxMeasurementTime(BME280Config config) { - return ceil(1.25 + (2.3 * config_.bits.oversamplingTemperature) + - (2.3 * config_.bits.oversamplingPressure + 0.575) + - (2.3 * config_.bits.oversamplingHumidity + 0.575)); + return ceil(1.25 + (2.3 * config.bits.oversamplingTemperature) + + (2.3 * config.bits.oversamplingPressure + 0.575) + + (2.3 * config.bits.oversamplingHumidity + 0.575)); } unsigned int BME280::getMaxMeasurementTime() @@ -245,49 +215,54 @@ bool BME280::selfTest() { return checkWhoAmI(); } BME280Data BME280::sampleImpl() { - uint8_t buffer[8]; - int32_t adcTemperature = 0; - int32_t adc_P = 0; - int32_t adc_H = 0; - BME280Data data; - // TODO: implement selective read! - // Burst read pressure, temperature and humidity + uint8_t buffer[8]; { SPITransaction transaction(spiSlave); transaction.readRegisters(REG_PRESS_MSB, buffer, 8); } - adcTemperature |= ((uint32_t)buffer[3]) << 12; + BME280Data data; + + int32_t adcTemperature = ((uint32_t)buffer[3]) << 12; adcTemperature |= ((uint32_t)buffer[4]) << 4; adcTemperature |= (buffer[5] >> 4) & 0x0F; - adc_P |= ((uint32_t)buffer[0]) << 12; + int32_t 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); + int32_t adc_H = ((uint32_t)buffer[6] << 8); adc_H |= buffer[7]; // Compensate temperature fineTemperature = computeFineTemperature(adcTemperature); data.temperatureTimestamp = TimestampTimer::getTimestamp(); - data.temperature = (float)compensateTemperature(fineTemperature) / - 100; // Converto to DegC + data.temperature = compensateTemperature(fineTemperature); + data.temperature /= 100; // Convert to to DegC // Compensate pressure data.pressureTimestamp = TimestampTimer::getTimestamp(); - data.pressure = (float)compensatePressure(adc_P) / 256; // Convert to Pa + data.pressure = compensatePressure(adc_P); + data.pressure /= 256; // Convert to Pa // Compensate humidity data.humidityTimestamp = TimestampTimer::getTimestamp(); - data.humidity = (float)compensateHumidity(adc_H) / 1024; // Converto to %RH + data.humidity = compensateHumidity(adc_H); + data.humidity /= 1024; // Convert to to %RH return data; } +void BME280::reset() +{ + SPITransaction transaction(spiSlave); + + transaction.writeRegister(REG_RESET, 0xB6); +} + bool BME280::checkWhoAmI() { SPITransaction transaction(spiSlave); @@ -299,14 +274,14 @@ bool BME280::checkWhoAmI() void BME280::setConfiguration() { setConfiguration(config); } -void BME280::setConfiguration(BME280Config config_) +void BME280::setConfiguration(BME280Config config) { SPITransaction transaction(spiSlave); - transaction.writeRegister(REG_CONFIG & 0x7F, config_.bytes.config); - transaction.writeRegister(REG_CTRL_HUM & 0x7F, config_.bytes.ctrlHumidity); - transaction.writeRegister(REG_CTRL_MEAS & 0x7F, - config_.bytes.ctrlPressureAndTemperature); + transaction.writeRegister(REG_CONFIG, config.bytes.config); + transaction.writeRegister(REG_CTRL_HUM, config.bytes.ctrlHumidity); + transaction.writeRegister(REG_CTRL_MEAS, + config.bytes.ctrlPressureAndTemperature); } BME280::BME280Config BME280::readConfiguration() @@ -328,7 +303,7 @@ void BME280::loadCompensationParameters() transaction.readRegisters(REG_CALIB_0, (uint8_t *)&compParams, 25); } - // Reat second batch of compensation parameters + // Read second batch of compensation parameters { SPITransaction transaction(spiSlave); diff --git a/src/shared/sensors/BME280/BME280.h b/src/shared/sensors/BME280/BME280.h index 7da38ced045595836d85fcd9b59925f25f9d579d..1e7e9f1b764dee8da541f2e0294d4ee626eeb551 100644 --- a/src/shared/sensors/BME280/BME280.h +++ b/src/shared/sensors/BME280/BME280.h @@ -148,12 +148,14 @@ public: static constexpr uint8_t REG_ID_VAL = 0x60; ///< Who am I value - static const BME280Config - BME280_DEFAULT_CONFIG; ///< Default register values - static const BME280Config - BME280_CONFIG_ALL_ENABLED; ///< Datasheet values for indoor navigation - static const BME280Config - BME280_CONFIG_TEMP_SINGLE; ///< Temperature enabled in forced mode + ///< Default register values + static const BME280Config BME280_DEFAULT_CONFIG; + + ///< Datasheet values for indoor navigation + static const BME280Config BME280_CONFIG_ALL_ENABLED; + + ///< Temperature enabled in forced mode + static const BME280Config BME280_CONFIG_TEMP_SINGLE; explicit BME280(SPISlave spiSlave, BME280Config config = BME280_CONFIG_ALL_ENABLED); @@ -225,7 +227,7 @@ public: * * @return Time in milliseconds */ - static unsigned int calculateMaxMeasurementTime(BME280Config config_); + static unsigned int calculateMaxMeasurementTime(BME280Config config); unsigned int getMaxMeasurementTime(); @@ -239,9 +241,11 @@ public: private: BME280Data sampleImpl() override; + void reset(); + void setConfiguration(); - void setConfiguration(BME280Config config_); + void setConfiguration(BME280Config config); BME280Config readConfiguration(); @@ -269,25 +273,25 @@ private: REG_CALIB_0 = 0x88, // Calibration register 1-25 - REG_ID = 0xD0, - REG_RESET = 0xE0, + REG_ID = 0x50, + REG_RESET = 0x60, REG_CALIB_26 = 0xE1, // Calibration register 27-41 - REG_CTRL_HUM = 0xF2, - 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, - REG_HUM_MSB = 0xFD, - REG_HUM_LSB = 0xFE, + REG_CTRL_HUM = 0x72, + REG_STATUS = 0x73, + REG_CTRL_MEAS = 0x74, + REG_CONFIG = 0x75, + + REG_PRESS_MSB = 0x77, + REG_PRESS_LSB = 0x78, + REG_PRESS_XLSB = 0x79, + REG_TEMP_MSB = 0x7A, + REG_TEMP_LSB = 0x7B, + REG_TEMP_XLSB = 0x7C, + REG_HUM_MSB = 0x7D, + REG_HUM_LSB = 0x7E, }; const SPISlave spiSlave; diff --git a/src/shared/sensors/BME280/BME280I2C.cpp b/src/shared/sensors/BME280/BME280I2C.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d0e67c566dc816000f55f74e0efc71d42795519 --- /dev/null +++ b/src/shared/sensors/BME280/BME280I2C.cpp @@ -0,0 +1,431 @@ +/* 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 "BME280I2C.h" + +#include <drivers/timer/TimestampTimer.h> +#include <math.h> + +using namespace std; + +namespace Boardcore +{ + +const BME280I2C::BME280Config BME280I2C::BME280_DEFAULT_CONFIG = { + SKIPPED, 0, 0, SLEEP_MODE, SKIPPED, SKIPPED, 0, FILTER_OFF, STB_TIME_0_5}; + +const BME280I2C::BME280Config BME280I2C::BME280_CONFIG_ALL_ENABLED = { + OVERSAMPLING_1, + 0, + 0, + NORMAL_MODE, + OVERSAMPLING_16, + OVERSAMPLING_2, + 0, + FILTER_COEFF_16, + STB_TIME_0_5}; + +const BME280I2C::BME280Config BME280I2C::BME280_CONFIG_TEMP_SINGLE = { + SKIPPED, 0, 0, FORCED_MODE, SKIPPED, + OVERSAMPLING_1, 0, FILTER_OFF, STB_TIME_0_5}; + +BME280I2C::BME280I2C(I2C &bus, BME280Config config) : bus(bus), config(config) +{ +} + +bool BME280I2C::init() +{ + if (!checkWhoAmI()) + { + LOG_ERR(logger, "Invalid WHO AM I"); + + lastError = SensorErrors::INVALID_WHOAMI; + return false; + } + + if (!reset()) + { + return false; + } + miosix::Thread::sleep(3); + + loadCompensationParameters(); + + // Read once the temperature to compute fineTemperature + setConfiguration(BME280_CONFIG_TEMP_SINGLE); + miosix::Thread::sleep( + calculateMaxMeasurementTime(BME280_CONFIG_TEMP_SINGLE)); + readTemperature(); + + // Set the target configuration + setConfiguration(); + + BME280Config readBackConfig = readConfiguration(); + + // Check if the configuration on the device matches ours + if (config.bytes.ctrlHumidity != readBackConfig.bytes.ctrlHumidity || + 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 BME280I2C::setSensorMode(Mode mode) +{ + config.bits.mode = mode; + + setConfiguration(); +} + +void BME280I2C::setHumidityOversampling(Oversampling oversampling) +{ + config.bits.oversamplingHumidity = oversampling; + + setConfiguration(); +} + +void BME280I2C::setPressureOversampling(Oversampling oversampling) +{ + config.bits.oversamplingPressure = oversampling; + + setConfiguration(); +} + +void BME280I2C::setTemperatureOversampling(Oversampling oversampling) +{ + config.bits.oversamplingTemperature = oversampling; + + setConfiguration(); +} + +void BME280I2C::setFilterCoeff(FilterCoeff filterCoeff) +{ + config.bits.filter = filterCoeff; + + setConfiguration(); +} + +void BME280I2C::setStandbyTime(StandbyTime standbyTime) +{ + config.bits.standbyTime = standbyTime; + + setConfiguration(); +} + +HumidityData BME280I2C::readHumidity() +{ + uint8_t buffer[2]; + if (bus.readFromRegister(slaveConfig, REG_HUM_MSB, buffer, 2)) + { + + int32_t adc_H = ((uint32_t)buffer[0] << 8); + adc_H |= buffer[1]; + + HumidityData data; + data.humidityTimestamp = TimestampTimer::getTimestamp(); + data.humidity = compensateHumidity(adc_H); + data.humidity /= 1024; // Convert to to %RH + + return data; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return lastSample; + } +} + +PressureData BME280I2C::readPressure() +{ + uint8_t buffer[3]; + if (bus.readFromRegister(slaveConfig, REG_PRESS_MSB, buffer, 3)) + { + + int32_t adc_P = ((uint32_t)buffer[0]) << 12; + adc_P |= ((uint32_t)buffer[1]) << 4; + adc_P |= (buffer[2] >> 4) & 0x0F; + + PressureData data; + data.pressureTimestamp = TimestampTimer::getTimestamp(); + data.pressure = compensatePressure(adc_P); + data.pressure /= 256; // Convert to Pa + + return data; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return lastSample; + } +} + +TemperatureData BME280I2C::readTemperature() +{ + uint8_t buffer[3]; + if (bus.readFromRegister(slaveConfig, REG_TEMP_MSB, buffer, 3)) + { + int32_t adcTemperature = ((uint32_t)buffer[0]) << 12; + adcTemperature |= ((uint32_t)buffer[1]) << 4; + adcTemperature |= (buffer[2] >> 4) & 0x0F; + + fineTemperature = computeFineTemperature(adcTemperature); + + TemperatureData data; + data.temperatureTimestamp = TimestampTimer::getTimestamp(); + data.temperature = compensateTemperature(fineTemperature); + data.temperature /= 100; // Convert to to DegC + + return data; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return lastSample; + } +} + +unsigned int BME280I2C::calculateMaxMeasurementTime(BME280Config config) +{ + return ceil(1.25 + (2.3 * config.bits.oversamplingTemperature) + + (2.3 * config.bits.oversamplingPressure + 0.575) + + (2.3 * config.bits.oversamplingHumidity + 0.575)); +} + +unsigned int BME280I2C::getMaxMeasurementTime() +{ + return calculateMaxMeasurementTime(config); +} + +bool BME280I2C::selfTest() { return checkWhoAmI(); } + +BME280Data BME280I2C::sampleImpl() +{ + // TODO: implement selective read! + + uint8_t buffer[8]; + if (bus.readFromRegister(slaveConfig, REG_PRESS_MSB, buffer, 8)) + { + BME280Data data; + + int32_t adcTemperature = ((uint32_t)buffer[3]) << 12; + adcTemperature |= ((uint32_t)buffer[4]) << 4; + adcTemperature |= (buffer[5] >> 4) & 0x0F; + + int32_t adc_P = ((uint32_t)buffer[0]) << 12; + adc_P |= ((uint32_t)buffer[1]) << 4; + adc_P |= (buffer[2] >> 4) & 0x0F; + + int32_t adc_H = ((uint32_t)buffer[6] << 8); + adc_H |= buffer[7]; + + // Compensate temperature + fineTemperature = computeFineTemperature(adcTemperature); + data.temperatureTimestamp = TimestampTimer::getTimestamp(); + data.temperature = compensateTemperature(fineTemperature); + data.temperature /= 100; // Convert to to DegC + + // Compensate pressure + data.pressureTimestamp = TimestampTimer::getTimestamp(); + data.pressure = compensatePressure(adc_P); + data.pressure /= 256; // Convert to Pa + + // Compensate humidity + data.humidityTimestamp = TimestampTimer::getTimestamp(); + data.humidity = compensateHumidity(adc_H); + data.humidity /= 1024; // Convert to to %RH + + return data; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return lastSample; + } +} + +bool BME280I2C::reset() +{ + if (!bus.writeRegister(slaveConfig, REG_RESET, 0xB6)) + { + lastError = SensorErrors::BUS_FAULT; + return false; + } + + return true; +} + +bool BME280I2C::checkWhoAmI() +{ + uint8_t whoAmIValue; + + if (bus.readRegister(slaveConfig, REG_ID, whoAmIValue)) + { + + return whoAmIValue == REG_ID_VAL; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return false; + } +} + +void BME280I2C::setConfiguration() { setConfiguration(config); } + +void BME280I2C::setConfiguration(BME280Config config) +{ + if (!bus.writeRegister(slaveConfig, REG_CONFIG, config.bytes.config)) + { + LOG_ERR(logger, "Error while writing to register REG_CONFIG"); + return; + } + + if (!bus.writeRegister(slaveConfig, REG_CTRL_HUM, + config.bytes.ctrlHumidity)) + { + LOG_ERR(logger, "Error while writing to register REG_CTRL_HUM"); + return; + } + + if (!bus.writeRegister(slaveConfig, REG_CTRL_MEAS, + config.bytes.ctrlPressureAndTemperature)) + { + LOG_ERR(logger, "Error while writing to register REG_CTRL_MEAS"); + return; + } +} + +BME280I2C::BME280Config BME280I2C::readConfiguration() +{ + BME280Config tmp; + + if (bus.readFromRegister(slaveConfig, REG_CTRL_HUM, (uint8_t *)&tmp, 4)) + { + return tmp; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return BME280_DEFAULT_CONFIG; + } +} + +void BME280I2C::loadCompensationParameters() +{ + // Read first batch of compensation parameters + if (!bus.readFromRegister(slaveConfig, REG_CALIB_0, (uint8_t *)&compParams, + 25)) + { + lastError = SensorErrors::BUS_FAULT; + return; + } + + // Read second batch of compensation parameters + if (!bus.readFromRegister(slaveConfig, REG_CALIB_26, + (uint8_t *)&compParams.bits.dig_H2, 7)) + { + lastError = SensorErrors::BUS_FAULT; + return; + } + + // Adjust unaligned data + compParams.bytesArray[29] = + (compParams.bytesArray[29] << 4) | (compParams.bytesArray[29] >> 4); + compParams.bits.dig_H4 = + (compParams.bits.dig_H4 << 4) | (compParams.bits.dig_H4 >> 8); +} + +int32_t BME280I2C::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 BME280I2C::compensateTemperature(int32_t fineTemperature) +{ + return (fineTemperature * 5 + 128) >> 8; +} + +uint32_t BME280I2C::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; +} + +uint32_t BME280I2C::compensateHumidity(int32_t adc_H) +{ + int32_t v_x1_u32r; + + v_x1_u32r = (fineTemperature - ((int32_t)768000)); + v_x1_u32r = (((((adc_H << 14) - (((int32_t)compParams.bits.dig_H4) << 20) - + (((int32_t)compParams.bits.dig_H5) * v_x1_u32r)) + + ((int32_t)16384)) >> + 15) * + (((((((v_x1_u32r * ((int32_t)compParams.bits.dig_H6)) >> 10) * + (((v_x1_u32r * ((int32_t)compParams.bits.dig_H3)) >> 11) + + ((int32_t)32768))) >> + 10) + + ((int32_t)2097152)) * + ((int32_t)compParams.bits.dig_H2) + + 8192) >> + 14)); + v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * + ((int32_t)compParams.bits.dig_H1)) >> + 4)); + v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r); + v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r); + return (uint32_t)(v_x1_u32r >> 12); +} + +} // namespace Boardcore diff --git a/src/shared/sensors/BME280/BME280I2C.h b/src/shared/sensors/BME280/BME280I2C.h new file mode 100644 index 0000000000000000000000000000000000000000..fcc512bdb16ae7210753fdb2f454273f09f4df6f --- /dev/null +++ b/src/shared/sensors/BME280/BME280I2C.h @@ -0,0 +1,308 @@ +/* Copyright (c) 2023 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/i2c/I2C.h> +#include <sensors/Sensor.h> + +#include "BME280Data.h" + +namespace Boardcore +{ + +class BME280I2C : public Sensor<BME280Data> +{ +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_10 = 0x6, ///< 10 ms + STB_TIME_20 = 0x7 ///< 20 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 BME280Config + { + struct __attribute__((packed)) BME280ConfigBits + { + Oversampling + oversamplingHumidity : 3; ///< Oversampling of humidity + uint8_t : 5; + + // 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 ctrlHumidity; ///< Humidity options + uint8_t status; ///< Device status + uint8_t ctrlPressureAndTemperature; ///< Pressure and temperature + ///< options + uint8_t config; ///< Rate, filter and interface options + } bytes; + + uint8_t bytesArray[4]; + }; + + union BME280Comp + { + 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; + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4 : 12; + int16_t dig_H5 : 12; + int8_t dig_H6; + } bits; + + uint8_t bytesArray[32]; + }; + + static constexpr uint8_t REG_ID_VAL = 0x60; ///< Who am I value + + ///< Default register values + static const BME280Config BME280_DEFAULT_CONFIG; + + ///< Datasheet values for indoor navigation + static const BME280Config BME280_CONFIG_ALL_ENABLED; + + ///< Temperature enabled in forced mode + static const BME280Config BME280_CONFIG_TEMP_SINGLE; + + explicit BME280I2C(I2C& bus, + BME280Config config = BME280_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 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 + */ + 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 humidity, does not set the configuration + */ + HumidityData readHumidity(); + + /** + * @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(BME280Config config); + + unsigned int getMaxMeasurementTime(); + + /** + * @brief Reads the WHO AM I register + * + * @return True if everything ok + */ + bool selfTest() override; + +private: + BME280Data sampleImpl() override; + + bool reset(); + + void setConfiguration(); + + void setConfiguration(BME280Config config); + + BME280Config 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); + + uint32_t compensateHumidity(int32_t adcHumidity); + + /** + * @brief Check the WHO AM I code from the device. + * + * @return true if the device is recognized + */ + bool checkWhoAmI(); + + enum Registers : uint8_t + { + REG_CALIB_0 = 0x88, + // Calibration register 1-25 + + REG_ID = 0xD0, + REG_RESET = 0xE0, + + REG_CALIB_26 = 0xE1, + // Calibration register 27-41 + + REG_CTRL_HUM = 0xF2, + 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, + REG_HUM_MSB = 0xFD, + REG_HUM_LSB = 0xFE, + }; + + I2C& bus; + I2CDriver::I2CSlaveConfig slaveConfig{0x76, I2CDriver::Addressing::BIT7, + I2CDriver::Speed::STANDARD}; + + BME280Config config; + BME280Comp compParams; + int32_t fineTemperature; // Used in compensation algorithm + + PrintLogger logger = Logging::getLogger("bme280"); +}; + +} // namespace Boardcore diff --git a/src/shared/sensors/BMP280/BMP280.cpp b/src/shared/sensors/BMP280/BMP280.cpp index 45dcc1db2e050fb297e486fcc09e0ea95487e153..325ca0982f745e3d69618258c5eaed0c28387736 100644 --- a/src/shared/sensors/BMP280/BMP280.cpp +++ b/src/shared/sensors/BMP280/BMP280.cpp @@ -52,16 +52,17 @@ BMP280::BMP280(SPISlave spiSlave, BMP280Config config) bool BMP280::init() { - // Check WHO AM I if (!checkWhoAmI()) { LOG_ERR(logger, "Invalid WHO AM I"); lastError = SensorErrors::INVALID_WHOAMI; - return false; } + reset(); + miosix::Thread::sleep(3); + loadCompensationParameters(); // Read once the temperature to compute fineTemperature @@ -70,11 +71,12 @@ bool BMP280::init() calculateMaxMeasurementTime(BMP280_CONFIG_TEMP_SINGLE)); readTemperature(); + // Set the target configuration setConfiguration(); BMP280Config readBackConfig = readConfiguration(); - // Check if the configration on the device matches ours + // Check if the configuration on the device matches ours if (config.bytes.ctrlPressureAndTemperature != readBackConfig.bytes.ctrlPressureAndTemperature || config.bytes.config != readBackConfig.bytes.config) @@ -82,7 +84,6 @@ bool BMP280::init() LOG_ERR(logger, "Device configuration incorrect, setup failed"); lastError = SensorErrors::NOT_INIT; - return false; } @@ -127,7 +128,6 @@ void BMP280::setStandbyTime(StandbyTime standbyTime) PressureData BMP280::readPressure() { uint8_t buffer[3]; - int32_t adc_P = 0; { SPITransaction transaction(spiSlave); @@ -135,22 +135,21 @@ PressureData BMP280::readPressure() transaction.readRegisters(REG_PRESS_MSB, buffer, 3); } - adc_P |= ((uint32_t)buffer[0]) << 12; + int32_t 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::getTimestamp(); - lastSample.pressure = - (float)compensatePressure(adc_P) / 256; // Convert to Pa + PressureData data; + data.pressureTimestamp = TimestampTimer::getTimestamp(); + data.pressure = compensatePressure(adc_P); + data.pressure /= 256; // Convert to Pa - return lastSample; + return data; } TemperatureData BMP280::readTemperature() { uint8_t buffer[3]; - int32_t adcTemperature = 0; { SPITransaction transaction(spiSlave); @@ -158,25 +157,26 @@ TemperatureData BMP280::readTemperature() transaction.readRegisters(REG_TEMP_MSB, buffer, 3); } - adcTemperature |= ((uint32_t)buffer[0]) << 12; + int32_t 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::getTimestamp(); - lastSample.temperature = (float)compensateTemperature(fineTemperature) / - 100; // Converto to DegC + fineTemperature = computeFineTemperature(adcTemperature); + + TemperatureData data; + data.temperatureTimestamp = TimestampTimer::getTimestamp(); + data.temperature = compensateTemperature(fineTemperature); + data.temperature /= 100; // Convert to to DegC - return lastSample; + return data; } -unsigned int BMP280::calculateMaxMeasurementTime(BMP280Config config_) +unsigned int BMP280::calculateMaxMeasurementTime(BMP280Config config) { - // TODO: This folrmula is not present in the BMP280's datasheet, it should + // TODO: This formula 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)); + return ceil(1.25 + (2.3 * config.bits.oversamplingTemperature) + + (2.3 * config.bits.oversamplingPressure + 0.575)); } unsigned int BMP280::getMaxMeasurementTime() @@ -188,41 +188,46 @@ bool BMP280::selfTest() { return checkWhoAmI(); } BMP280Data BMP280::sampleImpl() { - uint8_t buffer[8]; - int32_t adcTemperature = 0; - int32_t adc_P = 0; - BMP280Data data; - // TODO: implement selective read! - // Burst read pressure, temperature and humidity + uint8_t buffer[8]; { SPITransaction transaction(spiSlave); transaction.readRegisters(REG_PRESS_MSB, buffer, 8); } - adcTemperature |= ((uint32_t)buffer[3]) << 12; + BMP280Data data; + + int32_t adcTemperature = ((uint32_t)buffer[3]) << 12; adcTemperature |= ((uint32_t)buffer[4]) << 4; adcTemperature |= (buffer[5] >> 4) & 0x0F; - adc_P |= ((uint32_t)buffer[0]) << 12; + int32_t adc_P = ((uint32_t)buffer[0]) << 12; adc_P |= ((uint32_t)buffer[1]) << 4; adc_P |= (buffer[2] >> 4) & 0x0F; // Compensate temperature fineTemperature = computeFineTemperature(adcTemperature); data.temperatureTimestamp = TimestampTimer::getTimestamp(); - data.temperature = (float)compensateTemperature(fineTemperature) / - 100; // Converto to DegC + data.temperature = compensateTemperature(fineTemperature); + data.temperature /= 100; // Convert to to DegC // Compensate pressure data.pressureTimestamp = TimestampTimer::getTimestamp(); - data.pressure = (float)compensatePressure(adc_P) / 256; // Convert to Pa + data.pressure = compensatePressure(adc_P); + data.pressure /= 256; // Convert to Pa return data; } +void BMP280::reset() +{ + SPITransaction transaction(spiSlave); + + transaction.writeRegister(REG_RESET, 0xB6); +} + bool BMP280::checkWhoAmI() { SPITransaction transaction(spiSlave); @@ -234,13 +239,13 @@ bool BMP280::checkWhoAmI() void BMP280::setConfiguration() { setConfiguration(config); } -void BMP280::setConfiguration(BMP280Config 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); + transaction.writeRegister(REG_CONFIG, config.bytes.config); + transaction.writeRegister(REG_CTRL_MEAS, + config.bytes.ctrlPressureAndTemperature); } BMP280::BMP280Config BMP280::readConfiguration() diff --git a/src/shared/sensors/BMP280/BMP280.h b/src/shared/sensors/BMP280/BMP280.h index 5786a0c4854d033077e8f91249c6fec5b740e0d0..8ba79d6f49f2ba7c2faac1fd91d95ea7dbf3d415 100644 --- a/src/shared/sensors/BMP280/BMP280.h +++ b/src/shared/sensors/BMP280/BMP280.h @@ -137,15 +137,14 @@ public: 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 + ///< Default register values + static const BMP280Config BMP280_DEFAULT_CONFIG; + + ///< Datasheet values for indoor navigation + static const BMP280Config BMP280_CONFIG_ALL_ENABLED; + + ///< Temperature enabled in forced mode + static const BMP280Config BMP280_CONFIG_TEMP_SINGLE; explicit BMP280(SPISlave spiSlave, BMP280Config config = BMP280_CONFIG_ALL_ENABLED); @@ -206,7 +205,7 @@ public: * * @return Time in milliseconds */ - static unsigned int calculateMaxMeasurementTime(BMP280Config config_); + static unsigned int calculateMaxMeasurementTime(BMP280Config config); unsigned int getMaxMeasurementTime(); @@ -220,9 +219,11 @@ public: private: BMP280Data sampleImpl() override; + void reset(); + void setConfiguration(); - void setConfiguration(BMP280Config config_); + void setConfiguration(BMP280Config config); BMP280Config readConfiguration(); @@ -244,22 +245,22 @@ private: enum Registers : uint8_t { - REG_CALIB_0 = 0x88, + REG_CALIB_0 = 0x08, // Calibration register 1-25 - REG_ID = 0xD0, - REG_RESET = 0xE0, + REG_ID = 0x50, + REG_RESET = 0x60, - REG_STATUS = 0xF3, - REG_CTRL_MEAS = 0xF4, - REG_CONFIG = 0xF5, + REG_STATUS = 0x73, + REG_CTRL_MEAS = 0x74, + REG_CONFIG = 0x75, - REG_PRESS_MSB = 0xF7, - REG_PRESS_LSB = 0xF8, - REG_PRESS_XLSB = 0xF9, - REG_TEMP_MSB = 0xFA, - REG_TEMP_LSB = 0xFB, - REG_TEMP_XLSB = 0xFC + REG_PRESS_MSB = 0x77, + REG_PRESS_LSB = 0x78, + REG_PRESS_XLSB = 0x79, + REG_TEMP_MSB = 0x7A, + REG_TEMP_LSB = 0x7B, + REG_TEMP_XLSB = 0x7C }; const SPISlave spiSlave; diff --git a/src/shared/sensors/BMP280/BMP280I2C.cpp b/src/shared/sensors/BMP280/BMP280I2C.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66c1a1212ca0dc0c228e2245cb4748f00ed1fd58 --- /dev/null +++ b/src/shared/sensors/BMP280/BMP280I2C.cpp @@ -0,0 +1,345 @@ +/* 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 "BMP280I2C.h" + +#include <drivers/timer/TimestampTimer.h> +#include <math.h> + +using namespace std; + +namespace Boardcore +{ + +const BMP280I2C::BMP280Config BMP280I2C::BMP280_DEFAULT_CONFIG = { + 0, 0, SLEEP_MODE, SKIPPED, SKIPPED, 0, FILTER_OFF, STB_TIME_0_5}; + +const BMP280I2C::BMP280Config BMP280I2C::BMP280_CONFIG_ALL_ENABLED = { + 0, + 0, + NORMAL_MODE, + OVERSAMPLING_16, + OVERSAMPLING_2, + 0, + FILTER_COEFF_16, + STB_TIME_0_5}; + +const BMP280I2C::BMP280Config BMP280I2C::BMP280_CONFIG_TEMP_SINGLE = { + 0, 0, FORCED_MODE, SKIPPED, OVERSAMPLING_1, 0, FILTER_OFF, STB_TIME_0_5}; + +BMP280I2C::BMP280I2C(I2C &bus, BMP280Config config) : bus(bus), config(config) +{ +} + +bool BMP280I2C::init() +{ + if (!checkWhoAmI()) + { + LOG_ERR(logger, "Invalid WHO AM I"); + + lastError = SensorErrors::INVALID_WHOAMI; + return false; + } + + if (!reset()) + { + return false; + } + miosix::Thread::sleep(3); + + loadCompensationParameters(); + + // Read once the temperature to compute fineTemperature + setConfiguration(BMP280_CONFIG_TEMP_SINGLE); + miosix::Thread::sleep( + calculateMaxMeasurementTime(BMP280_CONFIG_TEMP_SINGLE)); + readTemperature(); + + // Set the target configuration + setConfiguration(); + + BMP280Config readBackConfig = readConfiguration(); + + // Check if the configuration 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 BMP280I2C::setSensorMode(Mode mode) +{ + config.bits.mode = mode; + + setConfiguration(); +} + +void BMP280I2C::setPressureOversampling(Oversampling oversampling) +{ + config.bits.oversamplingPressure = oversampling; + + setConfiguration(); +} + +void BMP280I2C::setTemperatureOversampling(Oversampling oversampling) +{ + config.bits.oversamplingTemperature = oversampling; + + setConfiguration(); +} + +void BMP280I2C::setFilterCoeff(FilterCoeff filterCoeff) +{ + config.bits.filter = filterCoeff; + + setConfiguration(); +} + +void BMP280I2C::setStandbyTime(StandbyTime standbyTime) +{ + config.bits.standbyTime = standbyTime; + + setConfiguration(); +} + +PressureData BMP280I2C::readPressure() +{ + uint8_t buffer[3]; + if (bus.readFromRegister(slaveConfig, REG_PRESS_MSB, buffer, 3)) + { + + int32_t adc_P = ((uint32_t)buffer[0]) << 12; + adc_P |= ((uint32_t)buffer[1]) << 4; + adc_P |= (buffer[2] >> 4) & 0x0F; + + PressureData data; + data.pressureTimestamp = TimestampTimer::getTimestamp(); + data.pressure = compensatePressure(adc_P); + data.pressure /= 256; // Convert to Pa + + return data; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return lastSample; + } +} + +TemperatureData BMP280I2C::readTemperature() +{ + uint8_t buffer[3]; + if (bus.readFromRegister(slaveConfig, REG_TEMP_MSB, buffer, 3)) + { + int32_t adcTemperature = ((uint32_t)buffer[0]) << 12; + adcTemperature |= ((uint32_t)buffer[1]) << 4; + adcTemperature |= (buffer[2] >> 4) & 0x0F; + + fineTemperature = computeFineTemperature(adcTemperature); + + TemperatureData data; + data.temperatureTimestamp = TimestampTimer::getTimestamp(); + data.temperature = compensateTemperature(fineTemperature); + data.temperature /= 100; // Convert to to DegC + + return data; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return lastSample; + } +} + +unsigned int BMP280I2C::calculateMaxMeasurementTime(BMP280Config config) +{ + // TODO: This formula 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 BMP280I2C::getMaxMeasurementTime() +{ + return calculateMaxMeasurementTime(config); +} + +bool BMP280I2C::selfTest() { return checkWhoAmI(); } + +BMP280Data BMP280I2C::sampleImpl() +{ + // TODO: implement selective read! + + uint8_t buffer[6]; + if (bus.readFromRegister(slaveConfig, REG_PRESS_MSB, buffer, 6)) + { + BMP280Data data; + + int32_t adcTemperature = ((uint32_t)buffer[3]) << 12; + adcTemperature |= ((uint32_t)buffer[4]) << 4; + adcTemperature |= (buffer[5] >> 4) & 0x0F; + + int32_t adc_P = ((uint32_t)buffer[0]) << 12; + adc_P |= ((uint32_t)buffer[1]) << 4; + adc_P |= (buffer[2] >> 4) & 0x0F; + + // Compensate temperature + fineTemperature = computeFineTemperature(adcTemperature); + data.temperatureTimestamp = TimestampTimer::getTimestamp(); + data.temperature = compensateTemperature(fineTemperature); + data.temperature /= 100; // Convert to to DegC + + // Compensate pressure + data.pressureTimestamp = TimestampTimer::getTimestamp(); + data.pressure = compensatePressure(adc_P); + data.pressure /= 256; // Convert to Pa + + return data; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return lastSample; + } +} + +bool BMP280I2C::reset() +{ + if (!bus.writeRegister(slaveConfig, REG_RESET, 0xB6)) + { + lastError = SensorErrors::BUS_FAULT; + return false; + } + + return true; +} + +bool BMP280I2C::checkWhoAmI() +{ + uint8_t whoAmIValue; + + if (bus.readRegister(slaveConfig, REG_ID, whoAmIValue)) + { + + return whoAmIValue == REG_ID_VAL; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return false; + } +} + +void BMP280I2C::setConfiguration() { setConfiguration(config); } + +void BMP280I2C::setConfiguration(BMP280Config config) +{ + if (!bus.writeRegister(slaveConfig, REG_CONFIG, config.bytes.config)) + { + LOG_ERR(logger, "Error while writing to register REG_CONFIG"); + return; + } + + if (!bus.writeRegister(slaveConfig, REG_CTRL_MEAS, + config.bytes.ctrlPressureAndTemperature)) + { + LOG_ERR(logger, "Error while writing to register REG_CTRL_MEAS"); + return; + } +} + +BMP280I2C::BMP280Config BMP280I2C::readConfiguration() +{ + BMP280Config tmp; + + if (bus.readFromRegister(slaveConfig, REG_STATUS, (uint8_t *)&tmp, 3)) + { + return tmp; + } + else + { + lastError = SensorErrors::BUS_FAULT; + return BMP280_DEFAULT_CONFIG; + } +} + +void BMP280I2C::loadCompensationParameters() +{ + // Read first batch of compensation parameters + if (!bus.readFromRegister(slaveConfig, REG_CALIB_0, (uint8_t *)&compParams, + 25)) + { + lastError = SensorErrors::BUS_FAULT; + return; + } +} + +int32_t BMP280I2C::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 BMP280I2C::compensateTemperature(int32_t fineTemperature) +{ + return (fineTemperature * 5 + 128) >> 8; +} + +uint32_t BMP280I2C::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/BMP280I2C.h b/src/shared/sensors/BMP280/BMP280I2C.h new file mode 100644 index 0000000000000000000000000000000000000000..1c682f6a290f7fb821ab965a36ed36724db77c9f --- /dev/null +++ b/src/shared/sensors/BMP280/BMP280I2C.h @@ -0,0 +1,277 @@ +/* Copyright (c) 2023 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/i2c/I2C.h> +#include <sensors/Sensor.h> + +#include "BMP280Data.h" + +namespace Boardcore +{ + +class BMP280I2C : 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 + + ///< Default register values + static const BMP280Config BMP280_DEFAULT_CONFIG; + + ///< Datasheet values for indoor navigation + static const BMP280Config BMP280_CONFIG_ALL_ENABLED; + + ///< Temperature enabled in forced mode + static const BMP280Config BMP280_CONFIG_TEMP_SINGLE; + + explicit BMP280I2C(I2C& bus, + 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; + + bool reset(); + + 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 Registers : 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 + }; + + I2C& bus; + I2CDriver::I2CSlaveConfig slaveConfig{0x76, I2CDriver::Addressing::BIT7, + I2CDriver::Speed::STANDARD}; + + BMP280Config config; + BMP280Comp compParams; + int32_t fineTemperature; // Used in compensation algorithm + + PrintLogger logger = Logging::getLogger("bmp280"); +}; + +} // namespace Boardcore diff --git a/src/tests/sensors/test-bme280-i2c.cpp b/src/tests/sensors/test-bme280-i2c.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7345a1f3d8136781e527396123ff789cd7475f6 --- /dev/null +++ b/src/tests/sensors/test-bme280-i2c.cpp @@ -0,0 +1,71 @@ +/* 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 <miosix.h> +#include <sensors/BME280/BME280I2C.h> + +using namespace miosix; +using namespace Boardcore; + +GpioPin scl(GPIOA_BASE, 8); +GpioPin sda(GPIOC_BASE, 9); + +int main() +{ + I2C bus(I2C3, scl, sda); + BME280I2C bme280(bus); + bme280.init(); + + if (!bme280.selfTest()) + printf("Self test failed!\n"); + + printf("Forced mode\n"); + for (int i = 0; i < 10; i++) + { + bme280.setSensorMode(BME280I2C::FORCED_MODE); + + Thread::sleep(bme280.getMaxMeasurementTime()); + + bme280.sample(); + + printf("temp: %.2f DegC\tpress: %.2f hPa\thumid: %.2f %%RH\n", + bme280.getLastSample().temperature, + bme280.getLastSample().pressure, + bme280.getLastSample().humidity); + + Thread::sleep(1000); + } + + printf("Normal mode\n"); + bme280.setSensorMode(BME280I2C::NORMAL_MODE); + while (true) + { + bme280.sample(); + + printf("temp: %.2f DegC\tpress: %.2f Pa\thumid: %.2f %%RH\n", + bme280.getLastSample().temperature, + bme280.getLastSample().pressure, + bme280.getLastSample().humidity); + + Thread::sleep(50); // 25Hz + } +} diff --git a/src/tests/sensors/test-bme280.cpp b/src/tests/sensors/test-bme280-spi.cpp similarity index 100% rename from src/tests/sensors/test-bme280.cpp rename to src/tests/sensors/test-bme280-spi.cpp diff --git a/src/tests/sensors/test-bmp280-i2c.cpp b/src/tests/sensors/test-bmp280-i2c.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58edd892e2c6d8235bccc7ef5c19988a4adcc466 --- /dev/null +++ b/src/tests/sensors/test-bmp280-i2c.cpp @@ -0,0 +1,69 @@ +/* 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 <miosix.h> +#include <sensors/BMP280/BMP280I2C.h> + +using namespace miosix; +using namespace Boardcore; + +GpioPin scl(GPIOA_BASE, 8); +GpioPin sda(GPIOC_BASE, 9); + +int main() +{ + I2C bus(I2C3, scl, sda); + BMP280I2C bmp280(bus); + bmp280.init(); + + if (!bmp280.selfTest()) + printf("Self test failed!\n"); + + printf("Forced mode\n"); + for (int i = 0; i < 10; i++) + { + bmp280.setSensorMode(BMP280I2C::FORCED_MODE); + + Thread::sleep(bmp280.getMaxMeasurementTime()); + + bmp280.sample(); + + printf("temp: %.2f DegC\tpress: %.2f hPa\n", + bmp280.getLastSample().temperature, + bmp280.getLastSample().pressure); + + Thread::sleep(1000); + } + + printf("Normal mode\n"); + bmp280.setSensorMode(BMP280I2C::NORMAL_MODE); + while (true) + { + bmp280.sample(); + + printf("temp: %.2f DegC\tpress: %.2f Pa\n", + bmp280.getLastSample().temperature, + bmp280.getLastSample().pressure); + + Thread::sleep(50); // 25Hz + } +} diff --git a/src/tests/sensors/test-bmp280.cpp b/src/tests/sensors/test-bmp280-spi.cpp similarity index 100% rename from src/tests/sensors/test-bmp280.cpp rename to src/tests/sensors/test-bmp280-spi.cpp