From aac885357869069dce9a2b4ce03f2cfdab1dab1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Schulz-Andres?= Date: Mon, 2 Mar 2026 23:44:36 +0100 Subject: [PATCH 1/8] [driver] bmp581 pressure sensor --- examples/nucleo_h723zg/bmp581/main.cpp | 164 +++++++ examples/nucleo_h723zg/bmp581/project.xml | 12 + src/modm/driver/pressure/bmp581.hpp | 432 ++++++++++++++++++ src/modm/driver/pressure/bmp581.lb | 52 +++ src/modm/driver/pressure/bmp581_impl.hpp | 340 ++++++++++++++ src/modm/driver/pressure/bmp581_transport.hpp | 128 ++++++ .../driver/pressure/bmp581_transport_impl.hpp | 139 ++++++ 7 files changed, 1267 insertions(+) create mode 100644 examples/nucleo_h723zg/bmp581/main.cpp create mode 100644 examples/nucleo_h723zg/bmp581/project.xml create mode 100644 src/modm/driver/pressure/bmp581.hpp create mode 100644 src/modm/driver/pressure/bmp581.lb create mode 100644 src/modm/driver/pressure/bmp581_impl.hpp create mode 100644 src/modm/driver/pressure/bmp581_transport.hpp create mode 100644 src/modm/driver/pressure/bmp581_transport_impl.hpp diff --git a/examples/nucleo_h723zg/bmp581/main.cpp b/examples/nucleo_h723zg/bmp581/main.cpp new file mode 100644 index 0000000000..7dc2c1b479 --- /dev/null +++ b/examples/nucleo_h723zg/bmp581/main.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2026, Joel Schulz-Andres + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#include +#include + +using namespace Board; + +// I2C2 Bus Configuration +using I2c = I2cMaster2; +using Scl = GpioB10; +using Sda = GpioB11; + +// Interrupt Pin +using BaroInt = GpioA4; + +// BMP581 Driver Setup +using Transport = modm::Bmp581I2cTransport; +using Baro = modm::Bmp581; + +// BMP581 I2C address (0x46 with SDO to GND, 0x47 with SDO to VDDIO) +constexpr uint8_t BaroAddress = 0x47; +Baro baro{BaroAddress}; +volatile bool dataReady = false; + +bool +initializeBaro() +{ + // Initialize the sensor + if (!baro.initialize()) { + MODM_LOG_ERROR << "BMP581 initialization failed!\n"; + return false; + } + + // Configure oversampling: 4x for both pressure and temperature + if (!baro.setOversampling(Baro::Osr::X4, Baro::Osr::X4, true)) { + MODM_LOG_ERROR << "Failed to set oversampling!\n"; + return false; + } + + // Configure output data rate: 50 Hz + if (!baro.setOdr(Baro::Odr::Hz50)) { + MODM_LOG_ERROR << "Failed to set ODR!\n"; + return false; + } + + // Configure IIR filter: coefficient 3 for both + if (!baro.setIirFilter(Baro::IirFilter::Coef3, Baro::IirFilter::Coef3)) { + MODM_LOG_ERROR << "Failed to set IIR filter!\n"; + return false; + } + + // Configure interrupt: active high, push-pull, pulsed mode + const auto intConfig = Baro::IntConfig::Enable | + Baro::IntConfig::Polarity; // Active high + if (!baro.setIntConfig(intConfig)) { + MODM_LOG_ERROR << "Failed to set interrupt config!\n"; + return false; + } + + // Enable data ready interrupt + if (!baro.setIntSource(Baro::IntSource::DataReadyEnable)) { + MODM_LOG_ERROR << "Failed to set interrupt source!\n"; + return false; + } + + // Set power mode to normal (continuous measurement) + if (!baro.setPowerMode(Baro::PowerMode::Normal)) { + MODM_LOG_ERROR << "Failed to set power mode!\n"; + return false; + } + + return true; +} + +int +main() +{ + Board::initialize(); + Leds::setOutput(); + + // Initialize I2C2 + I2c::connect(I2c::PullUps::Internal); + I2c::initialize(); + + MODM_LOG_INFO << "BMP581 Barometric Pressure Sensor Example\n"; + MODM_LOG_INFO << "=========================================\n\n"; + // Configure interrupt pin + BaroInt::setInput(BaroInt::InputType::PullDown); + + // Initialize sensor with retries + while (!initializeBaro()) { + LedRed::toggle(); + MODM_LOG_ERROR << "Retrying initialization...\n"; + modm::delay(250ms); + } + + MODM_LOG_INFO << "BMP581 initialized successfully!\n\n"; + + // Read chip ID for verification + if (const auto chipId = baro.readChipId(); chipId) { + MODM_LOG_INFO.printf("Chip ID: 0x%02X (expected 0x50)\n\n", *chipId); + } + + MODM_LOG_INFO << "Starting continuous measurement (DRDY EXTI)...\n\n"; + + Exti::connect(Exti::Trigger::RisingEdge, [](auto) { + dataReady = true; + LedYellow::toggle(); + }); + + modm::bmp581::Data data; + uint32_t sampleCount = 0; + uint32_t readErrorCount = 0; + while (true) + { + if (!dataReady) { + continue; + } + dataReady = false; + + if (baro.readData(data)) { + const float temperature = data.getTemperature(); + const float pressure = data.getPressure(); + const float pressureHpa = data.getPressureHpa(); + + // Calculate approximate altitude (simplified barometric formula) + // Using standard sea level pressure of 1013.25 hPa + constexpr float seaLevelPressure = 1013.25f; + const float altitude = 44330.0f * (1.0f - powf(pressureHpa / seaLevelPressure, 0.1903f)); + + sampleCount++; + + // Print every 25th sample (~2 Hz at 50Hz sampling) + if (sampleCount % 25 == 0) { + MODM_LOG_INFO.printf("Sample #%lu\n", sampleCount); + MODM_LOG_INFO.printf(" Temperature: %7.3f C\n", temperature); + MODM_LOG_INFO.printf(" Pressure: %9.2f Pa (%7.2f hPa)\n", pressure, pressureHpa); + MODM_LOG_INFO.printf(" Altitude: %7.1f m (approx)\n\n", altitude); + } + + LedGreen::toggle(); + readErrorCount = 0; + } + else { + readErrorCount++; + if (readErrorCount % 50 == 0) { + MODM_LOG_ERROR << "Failed to read sensor data!\n"; + } + LedRed::set(); + } + + } + + return 0; +} diff --git a/examples/nucleo_h723zg/bmp581/project.xml b/examples/nucleo_h723zg/bmp581/project.xml new file mode 100644 index 0000000000..d4f5f761b0 --- /dev/null +++ b/examples/nucleo_h723zg/bmp581/project.xml @@ -0,0 +1,12 @@ + + modm:nucleo-h723zg + + + + + modm:build:scons + modm:platform:exti + modm:platform:i2c:2 + modm:driver:bmp581 + + diff --git a/src/modm/driver/pressure/bmp581.hpp b/src/modm/driver/pressure/bmp581.hpp new file mode 100644 index 0000000000..3450c1a8ba --- /dev/null +++ b/src/modm/driver/pressure/bmp581.hpp @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2026, Joel Schulz-Andres + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_BMP581_HPP +#define MODM_BMP581_HPP + +#include +#include +#include +#include +#include +#include +#include "bmp581_transport.hpp" + +namespace modm +{ + +/// @ingroup modm_driver_bmp581 +struct bmp581 +{ + /// Chip ID value for BMP581 + static constexpr uint8_t ChipId = 0x50; + + /// Soft reset command value + static constexpr uint8_t ResetCommand = 0xB6; + + /// I2C addresses + static constexpr uint8_t AddressLow = 0x46; //< SDO to GND + static constexpr uint8_t AddressHigh = 0x47; //< SDO to VDDIO + + /// Register addresses + enum class Register : uint8_t + { + ChipId = 0x01, + RevId = 0x02, + ChipStatus = 0x11, + DriveConfig = 0x13, + IntConfig = 0x14, + IntSource = 0x15, + FifoConfig = 0x16, + FifoCount = 0x17, + FifoSel = 0x18, + TempDataXlsb = 0x1D, + TempDataLsb = 0x1E, + TempDataMsb = 0x1F, + PressDataXlsb = 0x20, + PressDataLsb = 0x21, + PressDataMsb = 0x22, + IntStatus = 0x27, + Status = 0x28, + FifoData = 0x29, + NvmAddr = 0x2B, + NvmDataLsb = 0x2C, + NvmDataMsb = 0x2D, + DspConfig = 0x30, + DspIir = 0x31, + OorThrPLsb = 0x32, + OorThrPMsb = 0x33, + OorRange = 0x34, + OorConfig = 0x35, + OsrConfig = 0x36, + OdrConfig = 0x37, + OsrEff = 0x38, + Cmd = 0x7E, + }; + + /// Power modes + enum class PowerMode : uint8_t + { + Standby = 0b00, //< Standby mode (default after reset) + Normal = 0b01, //< Normal mode (continuous measurement) + Forced = 0b10, //< Forced mode (single measurement) + Continuous = 0b11, //< Continuous mode + }; + + /// Output data rate configuration + enum class Odr : uint8_t + { + Hz240 = 0x00, + Hz218 = 0x01, + Hz199 = 0x02, + Hz179 = 0x03, + Hz160 = 0x04, + Hz149 = 0x05, + Hz140 = 0x06, + Hz129 = 0x07, + Hz120 = 0x08, + Hz110 = 0x09, + Hz100 = 0x0A, + Hz89 = 0x0B, + Hz80 = 0x0C, + Hz70 = 0x0D, + Hz60 = 0x0E, + Hz50 = 0x0F, + Hz45 = 0x10, + Hz40 = 0x11, + Hz35 = 0x12, + Hz30 = 0x13, + Hz25 = 0x14, + Hz20 = 0x15, + Hz15 = 0x16, + Hz10 = 0x17, + Hz5 = 0x18, + Hz4 = 0x19, + Hz3 = 0x1A, + Hz2 = 0x1B, + Hz1 = 0x1C, + Hz0_5 = 0x1D, + Hz0_25 = 0x1E, + Hz0_125 = 0x1F, + }; + + /// Oversampling rate configuration + enum class Osr : uint8_t + { + X1 = 0b000, //< No oversampling + X2 = 0b001, //< 2x oversampling + X4 = 0b010, //< 4x oversampling + X8 = 0b011, //< 8x oversampling + X16 = 0b100, //< 16x oversampling + X32 = 0b101, //< 32x oversampling + X64 = 0b110, //< 64x oversampling + X128 = 0b111, //< 128x oversampling + }; + + /// IIR filter coefficient + enum class IirFilter : uint8_t + { + Bypass = 0b000, //< No filtering + Coef1 = 0b001, //< Coefficient 1 + Coef3 = 0b010, //< Coefficient 3 + Coef7 = 0b011, //< Coefficient 7 + Coef15 = 0b100, //< Coefficient 15 + Coef31 = 0b101, //< Coefficient 31 + Coef63 = 0b110, //< Coefficient 63 + Coef127 = 0b111, //< Coefficient 127 + }; + + /// Status register (0x28) bit definitions + enum class Status : uint8_t + { + CoreReady = Bit0, //< Digital core domain accessible + NvmReady = Bit1, //< Ready for NVM operations + NvmError = Bit2, //< NVM error detected + NvmCmdError = Bit3, //< Boot command error + BootErrCorrected = Bit4, //< ECC error corrected during boot + CrackPass = Bit7, //< Crack check passed + }; + MODM_FLAGS8(Status); + + /// Interrupt status register (0x27) bit definitions + enum class IntStatus : uint8_t + { + DataReady = Bit0, //< Data ready interrupt + FifoFull = Bit1, //< FIFO full interrupt + FifoThreshold = Bit2, //< FIFO threshold interrupt + OorPressure = Bit3, //< Out-of-range pressure interrupt + PowerOnReset = Bit4, //< Power-on reset detected + }; + MODM_FLAGS8(IntStatus); + + /// Interrupt source enable register (0x15) bit definitions + enum class IntSource : uint8_t + { + DataReadyEnable = Bit0, //< Enable data ready interrupt + FifoFullEnable = Bit1, //< Enable FIFO full interrupt + FifoThresholdEnable = Bit2, //< Enable FIFO threshold interrupt + OorPressureEnable = Bit3, //< Enable OOR pressure interrupt + }; + MODM_FLAGS8(IntSource); + + /// Interrupt configuration register (0x14) bit definitions + enum class IntConfig : uint8_t + { + Mode = Bit0, //< 0: Pulsed, 1: Latched + Polarity = Bit1, //< 0: Active low, 1: Active high + OpenDrain = Bit2, //< 0: Push-pull, 1: Open-drain + Enable = Bit3, //< Enable interrupt output + }; + MODM_FLAGS8(IntConfig); + + /// OSR configuration register (0x36) bit definitions + enum class OsrConfig : uint8_t + { + OsrT0 = Bit0, //< Temperature OSR bit 0 + OsrT1 = Bit1, //< Temperature OSR bit 1 + OsrT2 = Bit2, //< Temperature OSR bit 2 + OsrP0 = Bit3, //< Pressure OSR bit 0 + OsrP1 = Bit4, //< Pressure OSR bit 1 + OsrP2 = Bit5, //< Pressure OSR bit 2 + PressEn = Bit6, //< Pressure measurement enable + }; + MODM_FLAGS8(OsrConfig); + + /// Configuration types for OSR settings + typedef Configuration TemperatureOsr; + typedef Configuration PressureOsr; + + /// ODR configuration register (0x37) bit definitions + enum class OdrConfig : uint8_t + { + Mode0 = Bit0, //< Power mode bit 0 + Mode1 = Bit1, //< Power mode bit 1 + Odr0 = Bit2, //< ODR bit 0 + Odr1 = Bit3, //< ODR bit 1 + Odr2 = Bit4, //< ODR bit 2 + Odr3 = Bit5, //< ODR bit 3 + Odr4 = Bit6, //< ODR bit 4 + DeepDis = Bit7, //< Disable deep standby + }; + MODM_FLAGS8(OdrConfig); + + /// Configuration types for ODR settings + typedef Configuration PowerMode_t; + typedef Configuration Odr_t; + + /// DSP configuration register (0x30) bit definitions + enum class DspConfig : uint8_t + { + CompPtEn = Bit0, //< Enable pressure/temperature compensation + CompPtSel = Bit1, //< Compensation source selection + IirFlushForced = Bit2, //< IIR flush forced enable + ShdwSelIir_T = Bit3, //< IIR temperature shadow selection + FifoSelIir_T = Bit4, //< IIR temperature FIFO selection + ShdwSelIir_P = Bit5, //< IIR pressure shadow selection + FifoSelIir_P = Bit6, //< IIR pressure FIFO selection + OorSelIir_P = Bit7, //< IIR pressure OOR selection + }; + MODM_FLAGS8(DspConfig); + + /// DSP IIR register (0x31) bit definitions + enum class DspIir : uint8_t + { + SetIir_T0 = Bit0, //< Temperature IIR coefficient bit 0 + SetIir_T1 = Bit1, //< Temperature IIR coefficient bit 1 + SetIir_T2 = Bit2, //< Temperature IIR coefficient bit 2 + SetIir_P0 = Bit3, //< Pressure IIR coefficient bit 0 + SetIir_P1 = Bit4, //< Pressure IIR coefficient bit 1 + SetIir_P2 = Bit5, //< Pressure IIR coefficient bit 2 + }; + MODM_FLAGS8(DspIir); + + /// Configuration types for IIR filter settings + typedef Configuration TemperatureIir; + typedef Configuration PressureIir; + + /// Measurement data container + struct Data + { + /// Get temperature in degrees Celsius + float + getTemperature() const + { + int32_t raw = (static_cast(rawTemp[2]) << 16) | + (static_cast(rawTemp[1]) << 8) | + (static_cast(rawTemp[0])); + // Sign-extend 24-bit signed value to 32-bit + if (raw & 0x00800000) { + raw |= 0xFF000000; + } + return static_cast(raw) / 65536.0f; + } + + /// Get pressure in Pascals + float + getPressure() const + { + uint32_t raw = (static_cast(rawPress[2]) << 16) | + (static_cast(rawPress[1]) << 8) | + (static_cast(rawPress[0])); + return static_cast(raw) / 64.0f; + } + + /// Get pressure in hectopascals (hPa) / millibars (mbar) + float + getPressureHpa() const + { + return getPressure() / 100.0f; + } + + /// Raw temperature data (XLSB, LSB, MSB) + std::array rawTemp{}; + + /// Raw pressure data (XLSB, LSB, MSB) + std::array rawPress{}; + }; + +protected: + /// @cond + static constexpr uint8_t + i(Register reg) { return static_cast(reg); } + /// @endcond +}; + +/** + * Bosch BMP581 Barometric Pressure Sensor Driver + * + * The BMP581 is a high-performance barometric pressure sensor with: + * - Absolute pressure range: 30 to 125 kPa + * - Pressure resolution: 1/64 Pa + * - Temperature resolution: 1/65536 C + * - Low power consumption + * - FIFO buffer (32 frames) + * - Interrupt support + * + * Unlike older BMP sensors like the BMP085, the BMP581 outputs calibrated data directly, + * which means no calibration coefficient compensation needs to be done in software. + * + * @tparam Transport Transport layer (use @ref Bmp581I2cTransport or @ref Bmp581SpiTransport) + * @ingroup modm_driver_bmp581 + */ +template +class Bmp581 : public bmp581, public Transport +{ +public: + /// @arg transportArgs Arguments to transport layer. + /// Pass address for I2C, none for SPI. + template + Bmp581(Args... transportArgs); + + /// Initialize device. Call before any other member function. + /// @return true on success, false on error + bool + initialize(); + + /// Perform soft reset and wait for device ready + /// @return true on success, false on error + bool + reset(); + + /// Read chip ID register + /// @return chip ID value, or std::nullopt on error + std::optional + readChipId(); + + /// Read status register + /// @return status flags, or std::nullopt on error + std::optional + readStatus(); + + /// Read interrupt status register (clears latched interrupts) + /// @return interrupt status flags, or std::nullopt on error + std::optional + readIntStatus(); + + /// Configure power mode + /// @return true on success, false on error + bool + setPowerMode(PowerMode mode); + + /// Configure output data rate + /// @return true on success, false on error + bool + setOdr(Odr odr); + + /// Configure oversampling for pressure and temperature + /// @param pressOsr Pressure oversampling rate + /// @param tempOsr Temperature oversampling rate + /// @param enablePressure Enable pressure measurement (default true) + /// @return true on success, false on error + bool + setOversampling(Osr pressOsr, Osr tempOsr, bool enablePressure = true); + + /// Configure IIR filter coefficients + /// @param pressIir Pressure IIR filter coefficient + /// @param tempIir Temperature IIR filter coefficient + /// @return true on success, false on error + bool + setIirFilter(IirFilter pressIir, IirFilter tempIir); + + /// Configure interrupt output + /// @param config Interrupt configuration flags + /// @return true on success, false on error + bool + setIntConfig(IntConfig_t config); + + /// Configure interrupt sources + /// @param sources Interrupt source enable flags + /// @return true on success, false on error + bool + setIntSource(IntSource_t sources); + + /// Read temperature and pressure data + /// @param data Reference to Data struct to fill + /// @return true on success, false on error + bool + readData(Data& data); + + /// Read temperature only + /// @return Temperature in Celsius, or std::nullopt on error + std::optional + readTemperature(); + + /// Read pressure only + /// @return Pressure in Pascals, or std::nullopt on error + std::optional + readPressure(); + + /// Check if data is ready + /// @return true if data ready, false otherwise + bool + isDataReady(); + +private: + void + waitForCommandGap(); + + std::optional + readRegister(Register reg); + + bool + writeRegister(Register reg, uint8_t value); + + bool + updateRegister(Register reg, uint8_t mask, uint8_t value); + + modm::PreciseTimeout timer_; +}; + +} // namespace modm + +#include "bmp581_impl.hpp" + +#endif // MODM_BMP581_HPP diff --git a/src/modm/driver/pressure/bmp581.lb b/src/modm/driver/pressure/bmp581.lb new file mode 100644 index 0000000000..e28c86b195 --- /dev/null +++ b/src/modm/driver/pressure/bmp581.lb @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2026, Joel Schulz-Andres +# +# This file is part of the modm project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# ----------------------------------------------------------------------------- + + +def init(module): + module.name = ":driver:bmp581" + module.description = """\ +# BMP581 Barometric Pressure Sensor + +The BMP581 is a high-performance barometric pressure sensor from Bosch Sensortec +with excellent accuracy and low power consumption. + +Key features: +- Absolute pressure range: 30 to 125 kPa +- Pressure resolution: 1/64 Pa +- Temperature resolution: 1/65536 C +- I2C and SPI interfaces +- 32-frame FIFO buffer +- Interrupt support +- Low power consumption + +Unlike older BMP sensors like the BMP085, the BMP581 outputs calibrated data directly, +which means no calibration coefficient compensation needs to be done in software. + +[Datasheet](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp581-ds004.pdf) +""" + +def prepare(module, options): + module.depends( + ":architecture:gpio", + ":architecture:register", + ":architecture:spi.device", + ":architecture:i2c.device", + ":processing:fiber", + ":processing:timer") + return True + +def build(env): + env.outbasepath = "modm/src/modm/driver/pressure" + env.copy("bmp581.hpp") + env.copy("bmp581_impl.hpp") + env.copy("bmp581_transport.hpp") + env.copy("bmp581_transport_impl.hpp") diff --git a/src/modm/driver/pressure/bmp581_impl.hpp b/src/modm/driver/pressure/bmp581_impl.hpp new file mode 100644 index 0000000000..bfa4c093a6 --- /dev/null +++ b/src/modm/driver/pressure/bmp581_impl.hpp @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2026, Joel Schulz-Andres + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_BMP581_HPP +#error "Don't include this file directly, use 'bmp581.hpp' instead!" +#endif + +namespace modm +{ + +template +template +Bmp581::Bmp581(Args... transportArgs) + : Transport{transportArgs...} +{ +} + +template +void +Bmp581::waitForCommandGap() +{ + if (timer_.isArmed()) { + timer_.wait(); + } +} + +template +bool +Bmp581::initialize() +{ + if (!Transport::initialize()) { + return false; + } + + if (!reset()) { + return false; + } + + const auto chipId = readChipId(); + if (!chipId || *chipId != ChipId) { + return false; + } + + const auto status = readStatus(); + if (!status) { + return false; + } + // Check NvmReady is set and NvmError/NvmCmdError are clear + if (!(*status & Status::NvmReady) || + (*status & Status::NvmError) || + (*status & Status::NvmCmdError)) { + return false; + } + + const auto intStatus = readIntStatus(); + if (!intStatus || !(*intStatus & IntStatus::PowerOnReset)) { + return false; + } + + // Disable deep standby mode + if (!updateRegister(Register::OdrConfig, uint8_t(OdrConfig::DeepDis), uint8_t(OdrConfig::DeepDis))) { + return false; + } + + return true; +} + +template +bool +Bmp581::reset() +{ + waitForCommandGap(); + + if (!writeRegister(Register::Cmd, ResetCommand)) { + return false; + } + + // Wait for reset to complete (datasheet: 2ms typical) + timer_.restart(std::chrono::milliseconds{5}); + timer_.wait(); + + // Re-initialize transport (needed for SPI mode) + if (!Transport::initialize()) { + return false; + } + + // Dummy read to prime SPI state machine after reset (Bosch recommendation) + // First SPI transaction after reset can be unreliable; discard result + (void)readRegister(Register::ChipId); + + timer_.restart(std::chrono::microseconds{2}); + return true; +} + +template +std::optional +Bmp581::readChipId() +{ + return readRegister(Register::ChipId); +} + +template +std::optional +Bmp581::readStatus() +{ + const auto value = readRegister(Register::Status); + if (!value) { + return std::nullopt; + } + return Status_t{*value}; +} + +template +std::optional +Bmp581::readIntStatus() +{ + const auto value = readRegister(Register::IntStatus); + if (!value) { + return std::nullopt; + } + return IntStatus_t{*value}; +} + +template +bool +Bmp581::setPowerMode(PowerMode mode) +{ + waitForCommandGap(); + + const uint8_t mask = uint8_t(OdrConfig::Mode0) | uint8_t(OdrConfig::Mode1); + const uint8_t targetMode = static_cast(mode); + const uint8_t standbyMode = static_cast(PowerMode::Standby); + + const auto current = readRegister(Register::OdrConfig); + if (!current) { + return false; + } + + // Per datasheet, active mode transitions should go through STANDBY first. + if ((*current & mask) != standbyMode) { + if (!updateRegister(Register::OdrConfig, mask, standbyMode)) { + return false; + } + // Maximum transition time to STANDBY. + timer_.restart(std::chrono::microseconds{2500}); + timer_.wait(); + } + + if (targetMode != standbyMode) { + if (!updateRegister(Register::OdrConfig, mask, targetMode)) { + return false; + } + } + + timer_.restart(std::chrono::microseconds{2}); + return true; +} + +template +bool +Bmp581::setOdr(Odr odr) +{ + waitForCommandGap(); + + const uint8_t mask = uint8_t(OdrConfig::Odr0) | uint8_t(OdrConfig::Odr1) | + uint8_t(OdrConfig::Odr2) | uint8_t(OdrConfig::Odr3) | + uint8_t(OdrConfig::Odr4); + const uint8_t value = static_cast(odr) << 2; + + const bool ok = updateRegister(Register::OdrConfig, mask, value); + timer_.restart(std::chrono::microseconds{2}); + return ok; +} + +template +bool +Bmp581::setOversampling(Osr pressOsr, Osr tempOsr, bool enablePressure) +{ + waitForCommandGap(); + + uint8_t value = (static_cast(tempOsr) << 0) | + (static_cast(pressOsr) << 3); + if (enablePressure) { + value |= uint8_t(OsrConfig::PressEn); + } + + const bool ok = writeRegister(Register::OsrConfig, value); + timer_.restart(std::chrono::microseconds{2}); + return ok; +} + +template +bool +Bmp581::setIirFilter(IirFilter pressIir, IirFilter tempIir) +{ + // IIR writes require STANDBY mode per datasheet section 4.3.8 + // Save current ODR config, switch to standby, write IIR, restore mode + const auto odrConfig = readRegister(Register::OdrConfig); + if (!odrConfig) { + return false; + } + + // Switch to standby mode + const uint8_t modeMask = uint8_t(OdrConfig::Mode0) | uint8_t(OdrConfig::Mode1); + if (!writeRegister(Register::OdrConfig, (*odrConfig & ~modeMask) | uint8_t(PowerMode::Standby))) { + return false; + } + + // Wait for STANDBY transition (tstandby = 2.5ms max per datasheet) + timer_.restart(std::chrono::microseconds{2500}); + waitForCommandGap(); + + // Temperature IIR at [2:0], Pressure IIR at [5:3] + const uint8_t value = (static_cast(tempIir) << 0) | + (static_cast(pressIir) << 3); + + const bool iirOk = writeRegister(Register::DspIir, value); + + // Restore original power mode + const bool restoreOk = writeRegister(Register::OdrConfig, *odrConfig); + + timer_.restart(std::chrono::microseconds{2}); + return iirOk && restoreOk; +} + +template +bool +Bmp581::setIntConfig(IntConfig_t config) +{ + waitForCommandGap(); + + // Read-modify-write to preserve upper nibble (pad drive strength) + constexpr uint8_t intConfigMask = uint8_t(IntConfig::Mode) | uint8_t(IntConfig::Polarity) | + uint8_t(IntConfig::OpenDrain) | uint8_t(IntConfig::Enable); + const bool ok = updateRegister(Register::IntConfig, intConfigMask, config.value); + + timer_.restart(std::chrono::microseconds{2}); + return ok; +} + +template +bool +Bmp581::setIntSource(IntSource_t sources) +{ + waitForCommandGap(); + const bool ok = writeRegister(Register::IntSource, sources.value); + timer_.restart(std::chrono::microseconds{2}); + return ok; +} + +template +bool +Bmp581::readData(Data& data) +{ + // Read temperature (3 bytes) and pressure (3 bytes) in one transaction + // Registers are contiguous: TEMP_XLSB(0x1D) to PRESS_MSB(0x22) + uint8_t buffer[6]; + if (!this->read(i(Register::TempDataXlsb), buffer, 6)) { + return false; + } + + data.rawTemp[0] = buffer[0]; + data.rawTemp[1] = buffer[1]; + data.rawTemp[2] = buffer[2]; + data.rawPress[0] = buffer[3]; + data.rawPress[1] = buffer[4]; + data.rawPress[2] = buffer[5]; + + return true; +} + +template +std::optional +Bmp581::readTemperature() +{ + Data data; + if (!this->read(i(Register::TempDataXlsb), data.rawTemp.data(), 3)) { + return std::nullopt; + } + return data.getTemperature(); +} + +template +std::optional +Bmp581::readPressure() +{ + Data data; + if (!this->read(i(Register::PressDataXlsb), data.rawPress.data(), 3)) { + return std::nullopt; + } + return data.getPressure(); +} + +template +bool +Bmp581::isDataReady() +{ + const auto status = readIntStatus(); + return status && (*status & IntStatus::DataReady); +} + +template +std::optional +Bmp581::readRegister(Register reg) +{ + uint8_t value; + if (!this->read(i(reg), &value, 1)) { + return std::nullopt; + } + return value; +} + +template +bool +Bmp581::writeRegister(Register reg, uint8_t value) +{ + return this->write(i(reg), value); +} + +template +bool +Bmp581::updateRegister(Register reg, uint8_t mask, uint8_t value) +{ + const auto current = readRegister(reg); + if (!current) { + return false; + } + const uint8_t newValue = (*current & ~mask) | (value & mask); + return writeRegister(reg, newValue); +} + +} // namespace modm diff --git a/src/modm/driver/pressure/bmp581_transport.hpp b/src/modm/driver/pressure/bmp581_transport.hpp new file mode 100644 index 0000000000..de6ea03f2a --- /dev/null +++ b/src/modm/driver/pressure/bmp581_transport.hpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2026, Joel Schulz-Andres + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_BMP581_TRANSPORT_HPP +#define MODM_BMP581_TRANSPORT_HPP + +#include +#include +#include +#include +#include +#include + +namespace modm +{ + +/// @ingroup modm_driver_bmp581 +/// @{ + +/** + * Concept for BMP581 transport layer + * + * A transport must provide methods for reading and writing registers. + */ +template +concept Bmp581Transport = requires(T transport, uint8_t reg, uint8_t data, + uint8_t* buffer, std::size_t length) +{ + { transport.initialize() } -> std::same_as; + { transport.read(reg, buffer, length) } -> std::same_as; + { transport.write(reg, data) } -> std::same_as; + { transport.write(reg, buffer, length) } -> std::same_as; +}; + +/** + * BMP581 I2C Transport Layer + * + * Implements register read/write operations over I2C. + * + * @tparam I2cMaster I2C master peripheral + */ +template +class Bmp581I2cTransport : public modm::I2cDevice +{ +public: + /** + * Constructor + * @param address I2C address (0x46 with SDO to GND, 0x47 with SDO to VDDIO) + */ + Bmp581I2cTransport(uint8_t address = 0x46); + + /// Initialize the transport layer + bool + initialize(); + + /// Read one or more registers starting at the given address + bool + read(uint8_t reg, uint8_t* buffer, std::size_t length); + + /// Write a single byte to a register + bool + write(uint8_t reg, uint8_t data); + + /// Write multiple bytes starting at the given register address + bool + write(uint8_t reg, const uint8_t* data, std::size_t length); + +protected: + uint8_t buffer_[8]; +}; + +/** + * BMP581 SPI Transport Layer + * + * Implements register read/write operations over SPI. + * SPI Mode 0 (CPOL=0, CPHA=0) is used. + * Maximum SPI clock: 10 MHz. + * + * @tparam SpiMaster SPI master peripheral + * @tparam Cs Chip select GPIO pin + */ +template +class Bmp581SpiTransport : public modm::SpiDevice +{ +public: + /** + * Constructor + */ + Bmp581SpiTransport(); + + /// Initialize the transport layer (configures CS pin) + bool + initialize(); + + /// Read one or more registers starting at the given address + bool + read(uint8_t reg, uint8_t* buffer, std::size_t length); + + /// Write a single byte to a register + bool + write(uint8_t reg, uint8_t data); + + /// Write multiple bytes starting at the given register address + bool + write(uint8_t reg, const uint8_t* data, std::size_t length); + +protected: + /// SPI read flag (bit 7 set for read operations) + static constexpr uint8_t ReadFlag = 0x80; + + uint8_t buffer_[8]; +}; + +/// @} + +} // namespace modm + +#include "bmp581_transport_impl.hpp" + +#endif // MODM_BMP581_TRANSPORT_HPP diff --git a/src/modm/driver/pressure/bmp581_transport_impl.hpp b/src/modm/driver/pressure/bmp581_transport_impl.hpp new file mode 100644 index 0000000000..8ae2f96edc --- /dev/null +++ b/src/modm/driver/pressure/bmp581_transport_impl.hpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2026, Joel Schulz-Andres + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_BMP581_TRANSPORT_HPP +#error "Don't include this file directly, use 'bmp581_transport.hpp' instead!" +#endif + +namespace modm +{ + +// ---------------------------------------------------------------------------- +// I2C Transport Implementation +// ---------------------------------------------------------------------------- + +template +Bmp581I2cTransport::Bmp581I2cTransport(uint8_t address) + : I2cDevice(address) +{ +} + +template +bool +Bmp581I2cTransport::initialize() +{ + return true; +} + +template +bool +Bmp581I2cTransport::read(uint8_t reg, uint8_t* data, std::size_t length) +{ + buffer_[0] = reg; + return I2cDevice::writeRead(&buffer_[0], 1, data, length); +} + +template +bool +Bmp581I2cTransport::write(uint8_t reg, uint8_t data) +{ + buffer_[0] = reg; + buffer_[1] = data; + return I2cDevice::write(&buffer_[0], 2); +} + +template +bool +Bmp581I2cTransport::write(uint8_t reg, const uint8_t* data, std::size_t length) +{ + if (length > sizeof(buffer_) - 1) { + return false; + } + buffer_[0] = reg; + for (std::size_t i = 0; i < length; ++i) { + buffer_[i + 1] = data[i]; + } + return I2cDevice::write(&buffer_[0], length + 1); +} + +// ---------------------------------------------------------------------------- +// SPI Transport Implementation +// ---------------------------------------------------------------------------- + +template +Bmp581SpiTransport::Bmp581SpiTransport() +{ +} + +template +bool +Bmp581SpiTransport::initialize() +{ + Cs::setOutput(true); + return true; +} + +template +bool +Bmp581SpiTransport::read(uint8_t reg, uint8_t* data, std::size_t length) +{ + modm::this_fiber::poll([this]{ return this->acquireMaster(); }); + Cs::reset(); + + // Send register address with read flag, then clock out data + buffer_[0] = reg | ReadFlag; + SpiMaster::transfer(&buffer_[0], nullptr, 1); + SpiMaster::transfer(nullptr, data, length); + + if (this->releaseMaster()) { + Cs::set(); + } + + return true; +} + +template +bool +Bmp581SpiTransport::write(uint8_t reg, uint8_t data) +{ + modm::this_fiber::poll([this]{ return this->acquireMaster(); }); + Cs::reset(); + + buffer_[0] = reg & ~ReadFlag; // Clear read flag for write + buffer_[1] = data; + SpiMaster::transfer(&buffer_[0], nullptr, 2); + + if (this->releaseMaster()) { + Cs::set(); + } + + return true; +} + +template +bool +Bmp581SpiTransport::write(uint8_t reg, const uint8_t* data, std::size_t length) +{ + modm::this_fiber::poll([this]{ return this->acquireMaster(); }); + Cs::reset(); + + buffer_[0] = reg & ~ReadFlag; // Clear read flag for write + SpiMaster::transfer(&buffer_[0], nullptr, 1); + SpiMaster::transfer(data, nullptr, length); + + if (this->releaseMaster()) { + Cs::set(); + } + + return true; +} + +} // namespace modm From 161c680bbe2ff7602e643817a208e90cb279de1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Schulz-Andres?= Date: Tue, 3 Mar 2026 11:09:35 +0100 Subject: [PATCH 2/8] [driver] bmp581 pressure sensor: fix ci --- README.md | 27 +- examples/nucleo_h723zg/bmp581/main.cpp | 55 ++-- examples/nucleo_h723zg/bmp581/project.xml | 2 +- src/modm/driver/pressure/bmp581.hpp | 268 +++++++++--------- src/modm/driver/pressure/bmp581.lb | 2 +- src/modm/driver/pressure/bmp581_impl.hpp | 120 +++----- src/modm/driver/pressure/bmp581_transport.hpp | 23 +- .../driver/pressure/bmp581_transport_impl.hpp | 34 +-- 8 files changed, 245 insertions(+), 286 deletions(-) diff --git a/README.md b/README.md index 71048b94fe..f301b18204 100644 --- a/README.md +++ b/README.md @@ -858,97 +858,98 @@ your specific needs. BMI088 BMP085 +BMP581 BNO055 CAT24AA CYCLE-COUNTER DRV832X DS1302 -DS1631 +DS1631 DS18B20 DW3110 EA-DOG Encoder Input Encoder Input BitBang -Encoder Output BitBang +Encoder Output BitBang FT245 FT6x06 Gpio Sampler HCLAx HD44780 -HMC58x +HMC58x HMC6343 HX711 I2C-EEPROM ILI9341 IS31FL3733 -ITG3200 +ITG3200 IXM42XXX L3GD20 LAN8720A LAWICEL LIS302DL -LIS3DSH +LIS3DSH LIS3MDL LM75 LP503x LSM303A LSM6DS33 -LSM6DSO +LSM6DSO LTC2984 MAX31855 MAX31865 MAX6966 MAX7219 -MCP23x17 +MCP23x17 MCP2515 MCP3008 MCP7941x MCP990X MMC5603 -MS5611 +MS5611 MS5837 NOKIA5110 NRF24 TFT-DISPLAY PAT9125EL -PCA8574 +PCA8574 PCA9535 PCA9548A PCA9685 QMC5883L SH1106 -SIEMENS-S65 +SIEMENS-S65 SIEMENS-S75 SK6812 SK9822 SSD1306 ST7586S -ST7789 +ST7789 STTS22H STUSB4500 SX1276 SX128X TCS3414 -TCS3472 +TCS3472 TLC594x TMP102 TMP12x TMP175 TOUCH2046 -VL53L0 +VL53L0 VL6180 WS2812 diff --git a/examples/nucleo_h723zg/bmp581/main.cpp b/examples/nucleo_h723zg/bmp581/main.cpp index 7dc2c1b479..502dfb52d6 100644 --- a/examples/nucleo_h723zg/bmp581/main.cpp +++ b/examples/nucleo_h723zg/bmp581/main.cpp @@ -35,45 +35,51 @@ bool initializeBaro() { // Initialize the sensor - if (!baro.initialize()) { + if (!baro.initialize()) + { MODM_LOG_ERROR << "BMP581 initialization failed!\n"; return false; } // Configure oversampling: 4x for both pressure and temperature - if (!baro.setOversampling(Baro::Osr::X4, Baro::Osr::X4, true)) { + if (!baro.setOversampling(Baro::Osr::X4, Baro::Osr::X4, true)) + { MODM_LOG_ERROR << "Failed to set oversampling!\n"; return false; } // Configure output data rate: 50 Hz - if (!baro.setOdr(Baro::Odr::Hz50)) { + if (!baro.setOdr(Baro::Odr::Hz50)) + { MODM_LOG_ERROR << "Failed to set ODR!\n"; return false; } // Configure IIR filter: coefficient 3 for both - if (!baro.setIirFilter(Baro::IirFilter::Coef3, Baro::IirFilter::Coef3)) { + if (!baro.setIirFilter(Baro::IirFilter::Coef3, Baro::IirFilter::Coef3)) + { MODM_LOG_ERROR << "Failed to set IIR filter!\n"; return false; } // Configure interrupt: active high, push-pull, pulsed mode - const auto intConfig = Baro::IntConfig::Enable | - Baro::IntConfig::Polarity; // Active high - if (!baro.setIntConfig(intConfig)) { + const auto intConfig = Baro::IntConfig::Enable | Baro::IntConfig::Polarity; // Active high + if (!baro.setIntConfig(intConfig)) + { MODM_LOG_ERROR << "Failed to set interrupt config!\n"; return false; } // Enable data ready interrupt - if (!baro.setIntSource(Baro::IntSource::DataReadyEnable)) { + if (!baro.setIntSource(Baro::IntSource::DataReadyEnable)) + { MODM_LOG_ERROR << "Failed to set interrupt source!\n"; return false; } // Set power mode to normal (continuous measurement) - if (!baro.setPowerMode(Baro::PowerMode::Normal)) { + if (!baro.setPowerMode(Baro::PowerMode::Normal)) + { MODM_LOG_ERROR << "Failed to set power mode!\n"; return false; } @@ -97,7 +103,8 @@ main() BaroInt::setInput(BaroInt::InputType::PullDown); // Initialize sensor with retries - while (!initializeBaro()) { + while (!initializeBaro()) + { LedRed::toggle(); MODM_LOG_ERROR << "Retrying initialization...\n"; modm::delay(250ms); @@ -106,7 +113,8 @@ main() MODM_LOG_INFO << "BMP581 initialized successfully!\n\n"; // Read chip ID for verification - if (const auto chipId = baro.readChipId(); chipId) { + if (const auto chipId = baro.readChipId(); chipId) + { MODM_LOG_INFO.printf("Chip ID: 0x%02X (expected 0x50)\n\n", *chipId); } @@ -122,12 +130,11 @@ main() uint32_t readErrorCount = 0; while (true) { - if (!dataReady) { - continue; - } + if (!dataReady) { continue; } dataReady = false; - if (baro.readData(data)) { + if (baro.readData(data)) + { const float temperature = data.getTemperature(); const float pressure = data.getPressure(); const float pressureHpa = data.getPressureHpa(); @@ -135,29 +142,29 @@ main() // Calculate approximate altitude (simplified barometric formula) // Using standard sea level pressure of 1013.25 hPa constexpr float seaLevelPressure = 1013.25f; - const float altitude = 44330.0f * (1.0f - powf(pressureHpa / seaLevelPressure, 0.1903f)); + const float altitude = + 44330.0f * (1.0f - powf(pressureHpa / seaLevelPressure, 0.1903f)); sampleCount++; // Print every 25th sample (~2 Hz at 50Hz sampling) - if (sampleCount % 25 == 0) { + if (sampleCount % 25 == 0) + { MODM_LOG_INFO.printf("Sample #%lu\n", sampleCount); MODM_LOG_INFO.printf(" Temperature: %7.3f C\n", temperature); - MODM_LOG_INFO.printf(" Pressure: %9.2f Pa (%7.2f hPa)\n", pressure, pressureHpa); + MODM_LOG_INFO.printf(" Pressure: %9.2f Pa (%7.2f hPa)\n", pressure, + pressureHpa); MODM_LOG_INFO.printf(" Altitude: %7.1f m (approx)\n\n", altitude); } LedGreen::toggle(); readErrorCount = 0; - } - else { + } else + { readErrorCount++; - if (readErrorCount % 50 == 0) { - MODM_LOG_ERROR << "Failed to read sensor data!\n"; - } + if (readErrorCount % 50 == 0) { MODM_LOG_ERROR << "Failed to read sensor data!\n"; } LedRed::set(); } - } return 0; diff --git a/examples/nucleo_h723zg/bmp581/project.xml b/examples/nucleo_h723zg/bmp581/project.xml index d4f5f761b0..49d45089fc 100644 --- a/examples/nucleo_h723zg/bmp581/project.xml +++ b/examples/nucleo_h723zg/bmp581/project.xml @@ -1,7 +1,7 @@ modm:nucleo-h723zg - + modm:build:scons diff --git a/src/modm/driver/pressure/bmp581.hpp b/src/modm/driver/pressure/bmp581.hpp index 3450c1a8ba..43fd465e40 100644 --- a/src/modm/driver/pressure/bmp581.hpp +++ b/src/modm/driver/pressure/bmp581.hpp @@ -15,9 +15,10 @@ #include #include #include -#include #include #include +#include + #include "bmp581_transport.hpp" namespace modm @@ -39,163 +40,163 @@ struct bmp581 /// Register addresses enum class Register : uint8_t { - ChipId = 0x01, - RevId = 0x02, - ChipStatus = 0x11, - DriveConfig = 0x13, - IntConfig = 0x14, - IntSource = 0x15, - FifoConfig = 0x16, - FifoCount = 0x17, - FifoSel = 0x18, - TempDataXlsb = 0x1D, - TempDataLsb = 0x1E, - TempDataMsb = 0x1F, - PressDataXlsb = 0x20, - PressDataLsb = 0x21, - PressDataMsb = 0x22, - IntStatus = 0x27, - Status = 0x28, - FifoData = 0x29, - NvmAddr = 0x2B, - NvmDataLsb = 0x2C, - NvmDataMsb = 0x2D, - DspConfig = 0x30, - DspIir = 0x31, - OorThrPLsb = 0x32, - OorThrPMsb = 0x33, - OorRange = 0x34, - OorConfig = 0x35, - OsrConfig = 0x36, - OdrConfig = 0x37, - OsrEff = 0x38, - Cmd = 0x7E, + ChipId = 0x01, + RevId = 0x02, + ChipStatus = 0x11, + DriveConfig = 0x13, + IntConfig = 0x14, + IntSource = 0x15, + FifoConfig = 0x16, + FifoCount = 0x17, + FifoSel = 0x18, + TempDataXlsb = 0x1D, + TempDataLsb = 0x1E, + TempDataMsb = 0x1F, + PressDataXlsb = 0x20, + PressDataLsb = 0x21, + PressDataMsb = 0x22, + IntStatus = 0x27, + Status = 0x28, + FifoData = 0x29, + NvmAddr = 0x2B, + NvmDataLsb = 0x2C, + NvmDataMsb = 0x2D, + DspConfig = 0x30, + DspIir = 0x31, + OorThrPLsb = 0x32, + OorThrPMsb = 0x33, + OorRange = 0x34, + OorConfig = 0x35, + OsrConfig = 0x36, + OdrConfig = 0x37, + OsrEff = 0x38, + Cmd = 0x7E, }; /// Power modes enum class PowerMode : uint8_t { - Standby = 0b00, //< Standby mode (default after reset) - Normal = 0b01, //< Normal mode (continuous measurement) - Forced = 0b10, //< Forced mode (single measurement) + Standby = 0b00, //< Standby mode (default after reset) + Normal = 0b01, //< Normal mode (continuous measurement) + Forced = 0b10, //< Forced mode (single measurement) Continuous = 0b11, //< Continuous mode }; /// Output data rate configuration enum class Odr : uint8_t { - Hz240 = 0x00, - Hz218 = 0x01, - Hz199 = 0x02, - Hz179 = 0x03, - Hz160 = 0x04, - Hz149 = 0x05, - Hz140 = 0x06, - Hz129 = 0x07, - Hz120 = 0x08, - Hz110 = 0x09, - Hz100 = 0x0A, - Hz89 = 0x0B, - Hz80 = 0x0C, - Hz70 = 0x0D, - Hz60 = 0x0E, - Hz50 = 0x0F, - Hz45 = 0x10, - Hz40 = 0x11, - Hz35 = 0x12, - Hz30 = 0x13, - Hz25 = 0x14, - Hz20 = 0x15, - Hz15 = 0x16, - Hz10 = 0x17, - Hz5 = 0x18, - Hz4 = 0x19, - Hz3 = 0x1A, - Hz2 = 0x1B, - Hz1 = 0x1C, - Hz0_5 = 0x1D, - Hz0_25 = 0x1E, - Hz0_125 = 0x1F, + Hz240 = 0x00, + Hz218 = 0x01, + Hz199 = 0x02, + Hz179 = 0x03, + Hz160 = 0x04, + Hz149 = 0x05, + Hz140 = 0x06, + Hz129 = 0x07, + Hz120 = 0x08, + Hz110 = 0x09, + Hz100 = 0x0A, + Hz89 = 0x0B, + Hz80 = 0x0C, + Hz70 = 0x0D, + Hz60 = 0x0E, + Hz50 = 0x0F, + Hz45 = 0x10, + Hz40 = 0x11, + Hz35 = 0x12, + Hz30 = 0x13, + Hz25 = 0x14, + Hz20 = 0x15, + Hz15 = 0x16, + Hz10 = 0x17, + Hz5 = 0x18, + Hz4 = 0x19, + Hz3 = 0x1A, + Hz2 = 0x1B, + Hz1 = 0x1C, + Hz0_5 = 0x1D, + Hz0_25 = 0x1E, + Hz0_125 = 0x1F, }; /// Oversampling rate configuration enum class Osr : uint8_t { - X1 = 0b000, //< No oversampling - X2 = 0b001, //< 2x oversampling - X4 = 0b010, //< 4x oversampling - X8 = 0b011, //< 8x oversampling - X16 = 0b100, //< 16x oversampling - X32 = 0b101, //< 32x oversampling - X64 = 0b110, //< 64x oversampling + X1 = 0b000, //< No oversampling + X2 = 0b001, //< 2x oversampling + X4 = 0b010, //< 4x oversampling + X8 = 0b011, //< 8x oversampling + X16 = 0b100, //< 16x oversampling + X32 = 0b101, //< 32x oversampling + X64 = 0b110, //< 64x oversampling X128 = 0b111, //< 128x oversampling }; /// IIR filter coefficient enum class IirFilter : uint8_t { - Bypass = 0b000, //< No filtering - Coef1 = 0b001, //< Coefficient 1 - Coef3 = 0b010, //< Coefficient 3 - Coef7 = 0b011, //< Coefficient 7 - Coef15 = 0b100, //< Coefficient 15 - Coef31 = 0b101, //< Coefficient 31 - Coef63 = 0b110, //< Coefficient 63 - Coef127 = 0b111, //< Coefficient 127 + Bypass = 0b000, //< No filtering + Coef1 = 0b001, //< Coefficient 1 + Coef3 = 0b010, //< Coefficient 3 + Coef7 = 0b011, //< Coefficient 7 + Coef15 = 0b100, //< Coefficient 15 + Coef31 = 0b101, //< Coefficient 31 + Coef63 = 0b110, //< Coefficient 63 + Coef127 = 0b111, //< Coefficient 127 }; /// Status register (0x28) bit definitions enum class Status : uint8_t { - CoreReady = Bit0, //< Digital core domain accessible - NvmReady = Bit1, //< Ready for NVM operations - NvmError = Bit2, //< NVM error detected - NvmCmdError = Bit3, //< Boot command error - BootErrCorrected = Bit4, //< ECC error corrected during boot - CrackPass = Bit7, //< Crack check passed + CoreReady = Bit0, //< Digital core domain accessible + NvmReady = Bit1, //< Ready for NVM operations + NvmError = Bit2, //< NVM error detected + NvmCmdError = Bit3, //< Boot command error + BootErrCorrected = Bit4, //< ECC error corrected during boot + CrackPass = Bit7, //< Crack check passed }; MODM_FLAGS8(Status); /// Interrupt status register (0x27) bit definitions enum class IntStatus : uint8_t { - DataReady = Bit0, //< Data ready interrupt - FifoFull = Bit1, //< FIFO full interrupt - FifoThreshold = Bit2, //< FIFO threshold interrupt - OorPressure = Bit3, //< Out-of-range pressure interrupt - PowerOnReset = Bit4, //< Power-on reset detected + DataReady = Bit0, //< Data ready interrupt + FifoFull = Bit1, //< FIFO full interrupt + FifoThreshold = Bit2, //< FIFO threshold interrupt + OorPressure = Bit3, //< Out-of-range pressure interrupt + PowerOnReset = Bit4, //< Power-on reset detected }; MODM_FLAGS8(IntStatus); /// Interrupt source enable register (0x15) bit definitions enum class IntSource : uint8_t { - DataReadyEnable = Bit0, //< Enable data ready interrupt - FifoFullEnable = Bit1, //< Enable FIFO full interrupt + DataReadyEnable = Bit0, //< Enable data ready interrupt + FifoFullEnable = Bit1, //< Enable FIFO full interrupt FifoThresholdEnable = Bit2, //< Enable FIFO threshold interrupt - OorPressureEnable = Bit3, //< Enable OOR pressure interrupt + OorPressureEnable = Bit3, //< Enable OOR pressure interrupt }; MODM_FLAGS8(IntSource); /// Interrupt configuration register (0x14) bit definitions enum class IntConfig : uint8_t { - Mode = Bit0, //< 0: Pulsed, 1: Latched - Polarity = Bit1, //< 0: Active low, 1: Active high - OpenDrain = Bit2, //< 0: Push-pull, 1: Open-drain - Enable = Bit3, //< Enable interrupt output + Mode = Bit0, //< 0: Pulsed, 1: Latched + Polarity = Bit1, //< 0: Active low, 1: Active high + OpenDrain = Bit2, //< 0: Push-pull, 1: Open-drain + Enable = Bit3, //< Enable interrupt output }; MODM_FLAGS8(IntConfig); /// OSR configuration register (0x36) bit definitions enum class OsrConfig : uint8_t { - OsrT0 = Bit0, //< Temperature OSR bit 0 - OsrT1 = Bit1, //< Temperature OSR bit 1 - OsrT2 = Bit2, //< Temperature OSR bit 2 - OsrP0 = Bit3, //< Pressure OSR bit 0 - OsrP1 = Bit4, //< Pressure OSR bit 1 - OsrP2 = Bit5, //< Pressure OSR bit 2 + OsrT0 = Bit0, //< Temperature OSR bit 0 + OsrT1 = Bit1, //< Temperature OSR bit 1 + OsrT2 = Bit2, //< Temperature OSR bit 2 + OsrP0 = Bit3, //< Pressure OSR bit 0 + OsrP1 = Bit4, //< Pressure OSR bit 1 + OsrP2 = Bit5, //< Pressure OSR bit 2 PressEn = Bit6, //< Pressure measurement enable }; MODM_FLAGS8(OsrConfig); @@ -207,14 +208,14 @@ struct bmp581 /// ODR configuration register (0x37) bit definitions enum class OdrConfig : uint8_t { - Mode0 = Bit0, //< Power mode bit 0 - Mode1 = Bit1, //< Power mode bit 1 - Odr0 = Bit2, //< ODR bit 0 - Odr1 = Bit3, //< ODR bit 1 - Odr2 = Bit4, //< ODR bit 2 - Odr3 = Bit5, //< ODR bit 3 - Odr4 = Bit6, //< ODR bit 4 - DeepDis = Bit7, //< Disable deep standby + Mode0 = Bit0, //< Power mode bit 0 + Mode1 = Bit1, //< Power mode bit 1 + Odr0 = Bit2, //< ODR bit 0 + Odr1 = Bit3, //< ODR bit 1 + Odr2 = Bit4, //< ODR bit 2 + Odr3 = Bit5, //< ODR bit 3 + Odr4 = Bit6, //< ODR bit 4 + DeepDis = Bit7, //< Disable deep standby }; MODM_FLAGS8(OdrConfig); @@ -225,14 +226,14 @@ struct bmp581 /// DSP configuration register (0x30) bit definitions enum class DspConfig : uint8_t { - CompPtEn = Bit0, //< Enable pressure/temperature compensation - CompPtSel = Bit1, //< Compensation source selection - IirFlushForced = Bit2, //< IIR flush forced enable - ShdwSelIir_T = Bit3, //< IIR temperature shadow selection - FifoSelIir_T = Bit4, //< IIR temperature FIFO selection - ShdwSelIir_P = Bit5, //< IIR pressure shadow selection - FifoSelIir_P = Bit6, //< IIR pressure FIFO selection - OorSelIir_P = Bit7, //< IIR pressure OOR selection + CompPtEn = Bit0, //< Enable pressure/temperature compensation + CompPtSel = Bit1, //< Compensation source selection + IirFlushForced = Bit2, //< IIR flush forced enable + ShdwSelIir_T = Bit3, //< IIR temperature shadow selection + FifoSelIir_T = Bit4, //< IIR temperature FIFO selection + ShdwSelIir_P = Bit5, //< IIR pressure shadow selection + FifoSelIir_P = Bit6, //< IIR pressure FIFO selection + OorSelIir_P = Bit7, //< IIR pressure OOR selection }; MODM_FLAGS8(DspConfig); @@ -260,12 +261,10 @@ struct bmp581 getTemperature() const { int32_t raw = (static_cast(rawTemp[2]) << 16) | - (static_cast(rawTemp[1]) << 8) | - (static_cast(rawTemp[0])); + (static_cast(rawTemp[1]) << 8) | + (static_cast(rawTemp[0])); // Sign-extend 24-bit signed value to 32-bit - if (raw & 0x00800000) { - raw |= 0xFF000000; - } + if (raw & 0x00800000) { raw |= 0xFF000000; } return static_cast(raw) / 65536.0f; } @@ -274,8 +273,8 @@ struct bmp581 getPressure() const { uint32_t raw = (static_cast(rawPress[2]) << 16) | - (static_cast(rawPress[1]) << 8) | - (static_cast(rawPress[0])); + (static_cast(rawPress[1]) << 8) | + (static_cast(rawPress[0])); return static_cast(raw) / 64.0f; } @@ -296,7 +295,10 @@ struct bmp581 protected: /// @cond static constexpr uint8_t - i(Register reg) { return static_cast(reg); } + i(Register reg) + { + return static_cast(reg); + } /// @endcond }; @@ -311,7 +313,7 @@ struct bmp581 * - FIFO buffer (32 frames) * - Interrupt support * - * Unlike older BMP sensors like the BMP085, the BMP581 outputs calibrated data directly, + * Unlike older BMP sensors like the BMP085, the BMP581 outputs calibrated data directly, * which means no calibration coefficient compensation needs to be done in software. * * @tparam Transport Transport layer (use @ref Bmp581I2cTransport or @ref Bmp581SpiTransport) @@ -425,8 +427,8 @@ class Bmp581 : public bmp581, public Transport modm::PreciseTimeout timer_; }; -} // namespace modm +} // namespace modm #include "bmp581_impl.hpp" -#endif // MODM_BMP581_HPP +#endif // MODM_BMP581_HPP diff --git a/src/modm/driver/pressure/bmp581.lb b/src/modm/driver/pressure/bmp581.lb index e28c86b195..51973a5e2f 100644 --- a/src/modm/driver/pressure/bmp581.lb +++ b/src/modm/driver/pressure/bmp581.lb @@ -28,7 +28,7 @@ Key features: - Interrupt support - Low power consumption -Unlike older BMP sensors like the BMP085, the BMP581 outputs calibrated data directly, +Unlike older BMP sensors like the BMP085, the BMP581 outputs calibrated data directly, which means no calibration coefficient compensation needs to be done in software. [Datasheet](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp581-ds004.pdf) diff --git a/src/modm/driver/pressure/bmp581_impl.hpp b/src/modm/driver/pressure/bmp581_impl.hpp index bfa4c093a6..25db156e4a 100644 --- a/src/modm/driver/pressure/bmp581_impl.hpp +++ b/src/modm/driver/pressure/bmp581_impl.hpp @@ -18,55 +18,43 @@ namespace modm template template -Bmp581::Bmp581(Args... transportArgs) - : Transport{transportArgs...} -{ -} +Bmp581::Bmp581(Args... transportArgs) : Transport{transportArgs...} +{} template void Bmp581::waitForCommandGap() { - if (timer_.isArmed()) { - timer_.wait(); - } + if (timer_.isArmed()) { timer_.wait(); } } template bool Bmp581::initialize() { - if (!Transport::initialize()) { - return false; - } + if (!Transport::initialize()) { return false; } - if (!reset()) { - return false; - } + if (!reset()) { return false; } const auto chipId = readChipId(); - if (!chipId || *chipId != ChipId) { - return false; - } + if (!chipId || *chipId != ChipId) { return false; } const auto status = readStatus(); - if (!status) { - return false; - } + if (!status) { return false; } // Check NvmReady is set and NvmError/NvmCmdError are clear - if (!(*status & Status::NvmReady) || - (*status & Status::NvmError) || - (*status & Status::NvmCmdError)) { + if (!(*status & Status::NvmReady) || (*status & Status::NvmError) || + (*status & Status::NvmCmdError)) + { return false; } const auto intStatus = readIntStatus(); - if (!intStatus || !(*intStatus & IntStatus::PowerOnReset)) { - return false; - } + if (!intStatus || !(*intStatus & IntStatus::PowerOnReset)) { return false; } // Disable deep standby mode - if (!updateRegister(Register::OdrConfig, uint8_t(OdrConfig::DeepDis), uint8_t(OdrConfig::DeepDis))) { + if (!updateRegister(Register::OdrConfig, uint8_t(OdrConfig::DeepDis), + uint8_t(OdrConfig::DeepDis))) + { return false; } @@ -79,18 +67,14 @@ Bmp581::reset() { waitForCommandGap(); - if (!writeRegister(Register::Cmd, ResetCommand)) { - return false; - } + if (!writeRegister(Register::Cmd, ResetCommand)) { return false; } // Wait for reset to complete (datasheet: 2ms typical) timer_.restart(std::chrono::milliseconds{5}); timer_.wait(); // Re-initialize transport (needed for SPI mode) - if (!Transport::initialize()) { - return false; - } + if (!Transport::initialize()) { return false; } // Dummy read to prime SPI state machine after reset (Bosch recommendation) // First SPI transaction after reset can be unreliable; discard result @@ -112,9 +96,7 @@ std::optional Bmp581::readStatus() { const auto value = readRegister(Register::Status); - if (!value) { - return std::nullopt; - } + if (!value) { return std::nullopt; } return Status_t{*value}; } @@ -123,9 +105,7 @@ std::optional Bmp581::readIntStatus() { const auto value = readRegister(Register::IntStatus); - if (!value) { - return std::nullopt; - } + if (!value) { return std::nullopt; } return IntStatus_t{*value}; } @@ -140,24 +120,20 @@ Bmp581::setPowerMode(PowerMode mode) const uint8_t standbyMode = static_cast(PowerMode::Standby); const auto current = readRegister(Register::OdrConfig); - if (!current) { - return false; - } + if (!current) { return false; } // Per datasheet, active mode transitions should go through STANDBY first. - if ((*current & mask) != standbyMode) { - if (!updateRegister(Register::OdrConfig, mask, standbyMode)) { - return false; - } + if ((*current & mask) != standbyMode) + { + if (!updateRegister(Register::OdrConfig, mask, standbyMode)) { return false; } // Maximum transition time to STANDBY. timer_.restart(std::chrono::microseconds{2500}); timer_.wait(); } - if (targetMode != standbyMode) { - if (!updateRegister(Register::OdrConfig, mask, targetMode)) { - return false; - } + if (targetMode != standbyMode) + { + if (!updateRegister(Register::OdrConfig, mask, targetMode)) { return false; } } timer_.restart(std::chrono::microseconds{2}); @@ -171,8 +147,8 @@ Bmp581::setOdr(Odr odr) waitForCommandGap(); const uint8_t mask = uint8_t(OdrConfig::Odr0) | uint8_t(OdrConfig::Odr1) | - uint8_t(OdrConfig::Odr2) | uint8_t(OdrConfig::Odr3) | - uint8_t(OdrConfig::Odr4); + uint8_t(OdrConfig::Odr2) | uint8_t(OdrConfig::Odr3) | + uint8_t(OdrConfig::Odr4); const uint8_t value = static_cast(odr) << 2; const bool ok = updateRegister(Register::OdrConfig, mask, value); @@ -186,11 +162,8 @@ Bmp581::setOversampling(Osr pressOsr, Osr tempOsr, bool enablePressur { waitForCommandGap(); - uint8_t value = (static_cast(tempOsr) << 0) | - (static_cast(pressOsr) << 3); - if (enablePressure) { - value |= uint8_t(OsrConfig::PressEn); - } + uint8_t value = (static_cast(tempOsr) << 0) | (static_cast(pressOsr) << 3); + if (enablePressure) { value |= uint8_t(OsrConfig::PressEn); } const bool ok = writeRegister(Register::OsrConfig, value); timer_.restart(std::chrono::microseconds{2}); @@ -204,13 +177,12 @@ Bmp581::setIirFilter(IirFilter pressIir, IirFilter tempIir) // IIR writes require STANDBY mode per datasheet section 4.3.8 // Save current ODR config, switch to standby, write IIR, restore mode const auto odrConfig = readRegister(Register::OdrConfig); - if (!odrConfig) { - return false; - } + if (!odrConfig) { return false; } // Switch to standby mode const uint8_t modeMask = uint8_t(OdrConfig::Mode0) | uint8_t(OdrConfig::Mode1); - if (!writeRegister(Register::OdrConfig, (*odrConfig & ~modeMask) | uint8_t(PowerMode::Standby))) { + if (!writeRegister(Register::OdrConfig, (*odrConfig & ~modeMask) | uint8_t(PowerMode::Standby))) + { return false; } @@ -219,8 +191,8 @@ Bmp581::setIirFilter(IirFilter pressIir, IirFilter tempIir) waitForCommandGap(); // Temperature IIR at [2:0], Pressure IIR at [5:3] - const uint8_t value = (static_cast(tempIir) << 0) | - (static_cast(pressIir) << 3); + const uint8_t value = + (static_cast(tempIir) << 0) | (static_cast(pressIir) << 3); const bool iirOk = writeRegister(Register::DspIir, value); @@ -239,7 +211,7 @@ Bmp581::setIntConfig(IntConfig_t config) // Read-modify-write to preserve upper nibble (pad drive strength) constexpr uint8_t intConfigMask = uint8_t(IntConfig::Mode) | uint8_t(IntConfig::Polarity) | - uint8_t(IntConfig::OpenDrain) | uint8_t(IntConfig::Enable); + uint8_t(IntConfig::OpenDrain) | uint8_t(IntConfig::Enable); const bool ok = updateRegister(Register::IntConfig, intConfigMask, config.value); timer_.restart(std::chrono::microseconds{2}); @@ -263,9 +235,7 @@ Bmp581::readData(Data& data) // Read temperature (3 bytes) and pressure (3 bytes) in one transaction // Registers are contiguous: TEMP_XLSB(0x1D) to PRESS_MSB(0x22) uint8_t buffer[6]; - if (!this->read(i(Register::TempDataXlsb), buffer, 6)) { - return false; - } + if (!this->read(i(Register::TempDataXlsb), buffer, 6)) { return false; } data.rawTemp[0] = buffer[0]; data.rawTemp[1] = buffer[1]; @@ -282,9 +252,7 @@ std::optional Bmp581::readTemperature() { Data data; - if (!this->read(i(Register::TempDataXlsb), data.rawTemp.data(), 3)) { - return std::nullopt; - } + if (!this->read(i(Register::TempDataXlsb), data.rawTemp.data(), 3)) { return std::nullopt; } return data.getTemperature(); } @@ -293,9 +261,7 @@ std::optional Bmp581::readPressure() { Data data; - if (!this->read(i(Register::PressDataXlsb), data.rawPress.data(), 3)) { - return std::nullopt; - } + if (!this->read(i(Register::PressDataXlsb), data.rawPress.data(), 3)) { return std::nullopt; } return data.getPressure(); } @@ -312,9 +278,7 @@ std::optional Bmp581::readRegister(Register reg) { uint8_t value; - if (!this->read(i(reg), &value, 1)) { - return std::nullopt; - } + if (!this->read(i(reg), &value, 1)) { return std::nullopt; } return value; } @@ -330,11 +294,9 @@ bool Bmp581::updateRegister(Register reg, uint8_t mask, uint8_t value) { const auto current = readRegister(reg); - if (!current) { - return false; - } + if (!current) { return false; } const uint8_t newValue = (*current & ~mask) | (value & mask); return writeRegister(reg, newValue); } -} // namespace modm +} // namespace modm diff --git a/src/modm/driver/pressure/bmp581_transport.hpp b/src/modm/driver/pressure/bmp581_transport.hpp index de6ea03f2a..7a9113b5a5 100644 --- a/src/modm/driver/pressure/bmp581_transport.hpp +++ b/src/modm/driver/pressure/bmp581_transport.hpp @@ -12,11 +12,11 @@ #ifndef MODM_BMP581_TRANSPORT_HPP #define MODM_BMP581_TRANSPORT_HPP -#include #include +#include +#include #include #include -#include #include namespace modm @@ -31,14 +31,13 @@ namespace modm * A transport must provide methods for reading and writing registers. */ template -concept Bmp581Transport = requires(T transport, uint8_t reg, uint8_t data, - uint8_t* buffer, std::size_t length) -{ - { transport.initialize() } -> std::same_as; - { transport.read(reg, buffer, length) } -> std::same_as; - { transport.write(reg, data) } -> std::same_as; - { transport.write(reg, buffer, length) } -> std::same_as; -}; +concept Bmp581Transport = + requires(T transport, uint8_t reg, uint8_t data, uint8_t* buffer, std::size_t length) { + { transport.initialize() } -> std::same_as; + { transport.read(reg, buffer, length) } -> std::same_as; + { transport.write(reg, data) } -> std::same_as; + { transport.write(reg, buffer, length) } -> std::same_as; + }; /** * BMP581 I2C Transport Layer @@ -121,8 +120,8 @@ class Bmp581SpiTransport : public modm::SpiDevice /// @} -} // namespace modm +} // namespace modm #include "bmp581_transport_impl.hpp" -#endif // MODM_BMP581_TRANSPORT_HPP +#endif // MODM_BMP581_TRANSPORT_HPP diff --git a/src/modm/driver/pressure/bmp581_transport_impl.hpp b/src/modm/driver/pressure/bmp581_transport_impl.hpp index 8ae2f96edc..a7a05d6efa 100644 --- a/src/modm/driver/pressure/bmp581_transport_impl.hpp +++ b/src/modm/driver/pressure/bmp581_transport_impl.hpp @@ -23,8 +23,7 @@ namespace modm template Bmp581I2cTransport::Bmp581I2cTransport(uint8_t address) : I2cDevice(address) -{ -} +{} template bool @@ -54,13 +53,9 @@ template bool Bmp581I2cTransport::write(uint8_t reg, const uint8_t* data, std::size_t length) { - if (length > sizeof(buffer_) - 1) { - return false; - } + if (length > sizeof(buffer_) - 1) { return false; } buffer_[0] = reg; - for (std::size_t i = 0; i < length; ++i) { - buffer_[i + 1] = data[i]; - } + for (std::size_t i = 0; i < length; ++i) { buffer_[i + 1] = data[i]; } return I2cDevice::write(&buffer_[0], length + 1); } @@ -70,8 +65,7 @@ Bmp581I2cTransport::write(uint8_t reg, const uint8_t* data, std::size template Bmp581SpiTransport::Bmp581SpiTransport() -{ -} +{} template bool @@ -85,7 +79,7 @@ template bool Bmp581SpiTransport::read(uint8_t reg, uint8_t* data, std::size_t length) { - modm::this_fiber::poll([this]{ return this->acquireMaster(); }); + modm::this_fiber::poll([this] { return this->acquireMaster(); }); Cs::reset(); // Send register address with read flag, then clock out data @@ -93,9 +87,7 @@ Bmp581SpiTransport::read(uint8_t reg, uint8_t* data, std::size_t SpiMaster::transfer(&buffer_[0], nullptr, 1); SpiMaster::transfer(nullptr, data, length); - if (this->releaseMaster()) { - Cs::set(); - } + if (this->releaseMaster()) { Cs::set(); } return true; } @@ -104,16 +96,14 @@ template bool Bmp581SpiTransport::write(uint8_t reg, uint8_t data) { - modm::this_fiber::poll([this]{ return this->acquireMaster(); }); + modm::this_fiber::poll([this] { return this->acquireMaster(); }); Cs::reset(); buffer_[0] = reg & ~ReadFlag; // Clear read flag for write buffer_[1] = data; SpiMaster::transfer(&buffer_[0], nullptr, 2); - if (this->releaseMaster()) { - Cs::set(); - } + if (this->releaseMaster()) { Cs::set(); } return true; } @@ -122,18 +112,16 @@ template bool Bmp581SpiTransport::write(uint8_t reg, const uint8_t* data, std::size_t length) { - modm::this_fiber::poll([this]{ return this->acquireMaster(); }); + modm::this_fiber::poll([this] { return this->acquireMaster(); }); Cs::reset(); buffer_[0] = reg & ~ReadFlag; // Clear read flag for write SpiMaster::transfer(&buffer_[0], nullptr, 1); SpiMaster::transfer(data, nullptr, length); - if (this->releaseMaster()) { - Cs::set(); - } + if (this->releaseMaster()) { Cs::set(); } return true; } -} // namespace modm +} // namespace modm From d001bdf69d5a3caac1be3c54984f80aed6b7421c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Schulz-Andres?= Date: Tue, 3 Mar 2026 11:18:04 +0100 Subject: [PATCH 3/8] [driver] bmp581 pressure sensor: drop _timer member --- src/modm/driver/pressure/bmp581.hpp | 8 +--- src/modm/driver/pressure/bmp581_impl.hpp | 57 ++++++------------------ 2 files changed, 15 insertions(+), 50 deletions(-) diff --git a/src/modm/driver/pressure/bmp581.hpp b/src/modm/driver/pressure/bmp581.hpp index 43fd465e40..e982c547d0 100644 --- a/src/modm/driver/pressure/bmp581.hpp +++ b/src/modm/driver/pressure/bmp581.hpp @@ -13,10 +13,9 @@ #define MODM_BMP581_HPP #include -#include #include #include -#include +#include #include #include "bmp581_transport.hpp" @@ -412,9 +411,6 @@ class Bmp581 : public bmp581, public Transport isDataReady(); private: - void - waitForCommandGap(); - std::optional readRegister(Register reg); @@ -423,8 +419,6 @@ class Bmp581 : public bmp581, public Transport bool updateRegister(Register reg, uint8_t mask, uint8_t value); - - modm::PreciseTimeout timer_; }; } // namespace modm diff --git a/src/modm/driver/pressure/bmp581_impl.hpp b/src/modm/driver/pressure/bmp581_impl.hpp index 25db156e4a..ec577b29de 100644 --- a/src/modm/driver/pressure/bmp581_impl.hpp +++ b/src/modm/driver/pressure/bmp581_impl.hpp @@ -13,21 +13,18 @@ #error "Don't include this file directly, use 'bmp581.hpp' instead!" #endif +#include + namespace modm { +using namespace std::chrono_literals; + template template Bmp581::Bmp581(Args... transportArgs) : Transport{transportArgs...} {} -template -void -Bmp581::waitForCommandGap() -{ - if (timer_.isArmed()) { timer_.wait(); } -} - template bool Bmp581::initialize() @@ -65,13 +62,10 @@ template bool Bmp581::reset() { - waitForCommandGap(); - if (!writeRegister(Register::Cmd, ResetCommand)) { return false; } - // Wait for reset to complete (datasheet: 2ms typical) - timer_.restart(std::chrono::milliseconds{5}); - timer_.wait(); + // Wait for reset to complete (datasheet: 2ms typical, use 5ms for margin) + modm::this_fiber::sleep_for(5ms); // Re-initialize transport (needed for SPI mode) if (!Transport::initialize()) { return false; } @@ -80,7 +74,6 @@ Bmp581::reset() // First SPI transaction after reset can be unreliable; discard result (void)readRegister(Register::ChipId); - timer_.restart(std::chrono::microseconds{2}); return true; } @@ -113,8 +106,6 @@ template bool Bmp581::setPowerMode(PowerMode mode) { - waitForCommandGap(); - const uint8_t mask = uint8_t(OdrConfig::Mode0) | uint8_t(OdrConfig::Mode1); const uint8_t targetMode = static_cast(mode); const uint8_t standbyMode = static_cast(PowerMode::Standby); @@ -122,13 +113,12 @@ Bmp581::setPowerMode(PowerMode mode) const auto current = readRegister(Register::OdrConfig); if (!current) { return false; } - // Per datasheet, active mode transitions should go through STANDBY first. + // Per datasheet, active mode transitions should go through STANDBY first if ((*current & mask) != standbyMode) { if (!updateRegister(Register::OdrConfig, mask, standbyMode)) { return false; } - // Maximum transition time to STANDBY. - timer_.restart(std::chrono::microseconds{2500}); - timer_.wait(); + // Maximum transition time to STANDBY (tstandby = 2.5ms) + modm::this_fiber::sleep_for(2500us); } if (targetMode != standbyMode) @@ -136,7 +126,6 @@ Bmp581::setPowerMode(PowerMode mode) if (!updateRegister(Register::OdrConfig, mask, targetMode)) { return false; } } - timer_.restart(std::chrono::microseconds{2}); return true; } @@ -144,30 +133,22 @@ template bool Bmp581::setOdr(Odr odr) { - waitForCommandGap(); - const uint8_t mask = uint8_t(OdrConfig::Odr0) | uint8_t(OdrConfig::Odr1) | uint8_t(OdrConfig::Odr2) | uint8_t(OdrConfig::Odr3) | uint8_t(OdrConfig::Odr4); const uint8_t value = static_cast(odr) << 2; - const bool ok = updateRegister(Register::OdrConfig, mask, value); - timer_.restart(std::chrono::microseconds{2}); - return ok; + return updateRegister(Register::OdrConfig, mask, value); } template bool Bmp581::setOversampling(Osr pressOsr, Osr tempOsr, bool enablePressure) { - waitForCommandGap(); - uint8_t value = (static_cast(tempOsr) << 0) | (static_cast(pressOsr) << 3); if (enablePressure) { value |= uint8_t(OsrConfig::PressEn); } - const bool ok = writeRegister(Register::OsrConfig, value); - timer_.restart(std::chrono::microseconds{2}); - return ok; + return writeRegister(Register::OsrConfig, value); } template @@ -187,8 +168,7 @@ Bmp581::setIirFilter(IirFilter pressIir, IirFilter tempIir) } // Wait for STANDBY transition (tstandby = 2.5ms max per datasheet) - timer_.restart(std::chrono::microseconds{2500}); - waitForCommandGap(); + modm::this_fiber::sleep_for(2500us); // Temperature IIR at [2:0], Pressure IIR at [5:3] const uint8_t value = @@ -199,7 +179,6 @@ Bmp581::setIirFilter(IirFilter pressIir, IirFilter tempIir) // Restore original power mode const bool restoreOk = writeRegister(Register::OdrConfig, *odrConfig); - timer_.restart(std::chrono::microseconds{2}); return iirOk && restoreOk; } @@ -207,25 +186,17 @@ template bool Bmp581::setIntConfig(IntConfig_t config) { - waitForCommandGap(); - // Read-modify-write to preserve upper nibble (pad drive strength) constexpr uint8_t intConfigMask = uint8_t(IntConfig::Mode) | uint8_t(IntConfig::Polarity) | uint8_t(IntConfig::OpenDrain) | uint8_t(IntConfig::Enable); - const bool ok = updateRegister(Register::IntConfig, intConfigMask, config.value); - - timer_.restart(std::chrono::microseconds{2}); - return ok; + return updateRegister(Register::IntConfig, intConfigMask, config.value); } template bool Bmp581::setIntSource(IntSource_t sources) { - waitForCommandGap(); - const bool ok = writeRegister(Register::IntSource, sources.value); - timer_.restart(std::chrono::microseconds{2}); - return ok; + return writeRegister(Register::IntSource, sources.value); } template From 99c6d746be21ebf91a7436fe19c3d8f9e72c1c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Schulz-Andres?= Date: Tue, 3 Mar 2026 11:34:00 +0100 Subject: [PATCH 4/8] [driver] bmp581 pressure sensor: add fifo helpers --- examples/nucleo_h723zg/bmp581/main.cpp | 14 +++ src/modm/driver/pressure/bmp581.hpp | 83 +++++++++++++++ src/modm/driver/pressure/bmp581_impl.hpp | 130 +++++++++++++++++++++++ 3 files changed, 227 insertions(+) diff --git a/examples/nucleo_h723zg/bmp581/main.cpp b/examples/nucleo_h723zg/bmp581/main.cpp index 502dfb52d6..4010ccc23f 100644 --- a/examples/nucleo_h723zg/bmp581/main.cpp +++ b/examples/nucleo_h723zg/bmp581/main.cpp @@ -77,6 +77,20 @@ initializeBaro() return false; } + /* + * FIFO usage example: + * + * baro.setFifoSelect(Baro::FifoFrameSelect::PressureAndTemperature, + * Baro::FifoDecimation::None); + * baro.setFifoThreshold(8); + * baro.setIntSource(Baro::IntSource::FifoThresholdEnable); + * baro.setFifoEnabled(true); + * + * // On interrupt/main loop: + * // const auto count = baro.getFifoCount(); + * // read up to `count` entries with readFifoFrames(...) + */ + // Set power mode to normal (continuous measurement) if (!baro.setPowerMode(Baro::PowerMode::Normal)) { diff --git a/src/modm/driver/pressure/bmp581.hpp b/src/modm/driver/pressure/bmp581.hpp index e982c547d0..e022d0256f 100644 --- a/src/modm/driver/pressure/bmp581.hpp +++ b/src/modm/driver/pressure/bmp581.hpp @@ -252,6 +252,43 @@ struct bmp581 typedef Configuration TemperatureIir; typedef Configuration PressureIir; + /// FIFO configuration register (0x16) bit definitions + enum class FifoConfig : uint8_t + { + Mode = Bit0, //< FIFO mode: 0=bypass, 1=stream + Threshold0 = Bit1, //< FIFO threshold bit 0 + Threshold1 = Bit2, //< FIFO threshold bit 1 + Threshold2 = Bit3, //< FIFO threshold bit 2 + Threshold3 = Bit4, //< FIFO threshold bit 3 + Threshold4 = Bit5, //< FIFO threshold bit 4 + }; + MODM_FLAGS8(FifoConfig); + + /// FIFO frame selection (what data to store in FIFO) + enum class FifoFrameSelect : uint8_t + { + Disabled = 0b00, //< FIFO not enabled + TemperatureOnly = 0b01, //< Temperature only (3 bytes per frame) + PressureOnly = 0b10, //< Pressure only (3 bytes per frame) + PressureAndTemperature = 0b11 //< Pressure and temperature (6 bytes per frame) + }; + + /// FIFO decimation factor + enum class FifoDecimation : uint8_t + { + None = 0b000, //< No decimation (store every sample) + By2 = 0b001, //< Store every 2nd sample + By4 = 0b010, //< Store every 4th sample + By8 = 0b011, //< Store every 8th sample + By16 = 0b100, //< Store every 16th sample + By32 = 0b101, //< Store every 32nd sample + By64 = 0b110, //< Store every 64th sample + By128 = 0b111, //< Store every 128th sample + }; + + /// Maximum FIFO frame count + static constexpr uint8_t FifoMaxFrames = 32; + /// Measurement data container struct Data { @@ -410,6 +447,52 @@ class Bmp581 : public bmp581, public Transport bool isDataReady(); + // ------------------------------------------------------------------------- + // FIFO Functions + // ------------------------------------------------------------------------- + + /// Enable or disable FIFO streaming mode + /// @param enable true to enable FIFO, false for bypass mode + /// @return true on success, false on error + bool + setFifoEnabled(bool enable); + + /// Configure FIFO threshold for interrupt generation + /// @param threshold Number of frames (0-31) to trigger threshold interrupt + /// @return true on success, false on error + bool + setFifoThreshold(uint8_t threshold); + + /// Configure FIFO frame selection and decimation + /// @param frameSelect What data to store in FIFO + /// @param decimation Decimation factor (store every Nth sample) + /// @return true on success, false on error + bool + setFifoSelect(FifoFrameSelect frameSelect, FifoDecimation decimation = FifoDecimation::None); + + /// Get current FIFO frame count + /// @return Number of frames in FIFO, or std::nullopt on error + std::optional + getFifoCount(); + + /// Read single frame from FIFO + /// @param data Reference to Data struct to fill + /// @return true on success, false on error + bool + readFifoFrame(Data& data); + + /// Read multiple frames from FIFO + /// @param data Pointer to array of Data structs + /// @param count Number of frames to read + /// @return Number of frames actually read, or 0 on error + uint8_t + readFifoFrames(Data* data, uint8_t count); + + /// Flush FIFO (clear all data) + /// @return true on success, false on error + bool + flushFifo(); + private: std::optional readRegister(Register reg); diff --git a/src/modm/driver/pressure/bmp581_impl.hpp b/src/modm/driver/pressure/bmp581_impl.hpp index ec577b29de..5390f26ee1 100644 --- a/src/modm/driver/pressure/bmp581_impl.hpp +++ b/src/modm/driver/pressure/bmp581_impl.hpp @@ -244,6 +244,136 @@ Bmp581::isDataReady() return status && (*status & IntStatus::DataReady); } +// ----------------------------------------------------------------------------- +// FIFO Functions +// ----------------------------------------------------------------------------- + +template +bool +Bmp581::setFifoEnabled(bool enable) +{ + return updateRegister(Register::FifoConfig, uint8_t(FifoConfig::Mode), + enable ? uint8_t(FifoConfig::Mode) : 0); +} + +template +bool +Bmp581::setFifoThreshold(uint8_t threshold) +{ + if (threshold > 31) { return false; } + constexpr uint8_t thresholdMask = + uint8_t(FifoConfig::Threshold0) | uint8_t(FifoConfig::Threshold1) | + uint8_t(FifoConfig::Threshold2) | uint8_t(FifoConfig::Threshold3) | + uint8_t(FifoConfig::Threshold4); + return updateRegister(Register::FifoConfig, thresholdMask, threshold << 1); +} + +template +bool +Bmp581::setFifoSelect(FifoFrameSelect frameSelect, FifoDecimation decimation) +{ + const auto odrConfig = readRegister(Register::OdrConfig); + if (!odrConfig) { return false; } + + const uint8_t modeMask = uint8_t(OdrConfig::Mode0) | uint8_t(OdrConfig::Mode1); + const uint8_t oldMode = *odrConfig & modeMask; + + // Datasheet: FIFO_SEL must be changed in STANDBY mode. + if (oldMode != uint8_t(PowerMode::Standby)) + { + if (!writeRegister(Register::OdrConfig, + (*odrConfig & ~modeMask) | uint8_t(PowerMode::Standby))) + { + return false; + } + modm::this_fiber::sleep_for(2500us); + } + + // FIFO_SEL(0x18): frame select in bits [1:0], decimation in bits [4:2] + const uint8_t value = + static_cast(frameSelect) | (static_cast(decimation) << 2); + const bool selectOk = writeRegister(Register::FifoSel, value); + if (!selectOk) { return false; } + + if (oldMode != uint8_t(PowerMode::Standby)) + { + return writeRegister(Register::OdrConfig, (*odrConfig & ~modeMask) | oldMode); + } + + return true; +} + +template +std::optional +Bmp581::getFifoCount() +{ + const auto value = readRegister(Register::FifoCount); + if (!value) { return std::nullopt; } + // FIFO_COUNT uses bits [5:0] + return *value & 0x3f; +} + +template +bool +Bmp581::readFifoFrame(Data& data) +{ + const auto fifoSel = readRegister(Register::FifoSel); + if (!fifoSel) { return false; } + + const auto frameSelect = static_cast(*fifoSel & 0x03); + switch (frameSelect) + { + case FifoFrameSelect::PressureAndTemperature: { + uint8_t buffer[6]; + if (!this->read(i(Register::FifoData), buffer, 6)) { return false; } + data.rawTemp[0] = buffer[0]; + data.rawTemp[1] = buffer[1]; + data.rawTemp[2] = buffer[2]; + data.rawPress[0] = buffer[3]; + data.rawPress[1] = buffer[4]; + data.rawPress[2] = buffer[5]; + return true; + } + case FifoFrameSelect::TemperatureOnly: { + if (!this->read(i(Register::FifoData), data.rawTemp.data(), 3)) { return false; } + data.rawPress = {0, 0, 0}; + return true; + } + case FifoFrameSelect::PressureOnly: { + if (!this->read(i(Register::FifoData), data.rawPress.data(), 3)) { return false; } + data.rawTemp = {0, 0, 0}; + return true; + } + case FifoFrameSelect::Disabled: + default: + return false; + } +} + +template +uint8_t +Bmp581::readFifoFrames(Data* data, uint8_t count) +{ + const auto available = getFifoCount(); + if (!available) { return 0; } + + const uint8_t toRead = (*available < count) ? *available : count; + for (uint8_t i = 0; i < toRead; ++i) + { + if (!readFifoFrame(data[i])) { return i; } + } + return toRead; +} + +template +bool +Bmp581::flushFifo() +{ + // Writing 0xB0 to CMD register flushes the FIFO + static constexpr uint8_t FifoFlushCommand = 0xB0; + return writeRegister(Register::Cmd, FifoFlushCommand); +} + template std::optional Bmp581::readRegister(Register reg) From 333cd737561a08a837d7735727942b93f665c43c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Schulz-Andres?= Date: Thu, 5 Mar 2026 20:48:58 +0100 Subject: [PATCH 5/8] [driver] bmp581 pressure sensor: implement review remarks use std::atomic_bool in example better sign-extension for both pressure and temperature support blocking usage on smol mcus remove deprecated nested layers replace buffer accesses with something more modern --- examples/nucleo_h723zg/bmp581/main.cpp | 3 ++- src/modm/driver/pressure/bmp581.hpp | 18 ++++++------- src/modm/driver/pressure/bmp581.lb | 2 +- src/modm/driver/pressure/bmp581_transport.hpp | 4 +-- .../driver/pressure/bmp581_transport_impl.hpp | 27 +++++++++---------- 5 files changed, 24 insertions(+), 30 deletions(-) diff --git a/examples/nucleo_h723zg/bmp581/main.cpp b/examples/nucleo_h723zg/bmp581/main.cpp index 4010ccc23f..80bb8e9707 100644 --- a/examples/nucleo_h723zg/bmp581/main.cpp +++ b/examples/nucleo_h723zg/bmp581/main.cpp @@ -9,6 +9,7 @@ */ // ---------------------------------------------------------------------------- +#include #include #include @@ -29,7 +30,7 @@ using Baro = modm::Bmp581; // BMP581 I2C address (0x46 with SDO to GND, 0x47 with SDO to VDDIO) constexpr uint8_t BaroAddress = 0x47; Baro baro{BaroAddress}; -volatile bool dataReady = false; +std::atomic dataReady{false}; bool initializeBaro() diff --git a/src/modm/driver/pressure/bmp581.hpp b/src/modm/driver/pressure/bmp581.hpp index e022d0256f..4646907768 100644 --- a/src/modm/driver/pressure/bmp581.hpp +++ b/src/modm/driver/pressure/bmp581.hpp @@ -296,22 +296,20 @@ struct bmp581 float getTemperature() const { - int32_t raw = (static_cast(rawTemp[2]) << 16) | - (static_cast(rawTemp[1]) << 8) | - (static_cast(rawTemp[0])); - // Sign-extend 24-bit signed value to 32-bit - if (raw & 0x00800000) { raw |= 0xFF000000; } - return static_cast(raw) / 65536.0f; + const uint32_t u = (static_cast(rawTemp[2]) << 24) | + (static_cast(rawTemp[1]) << 16) | + (static_cast(rawTemp[0]) << 8); + return static_cast(static_cast(u)) / (65536.0f * 256.0f); } /// Get pressure in Pascals float getPressure() const { - uint32_t raw = (static_cast(rawPress[2]) << 16) | - (static_cast(rawPress[1]) << 8) | - (static_cast(rawPress[0])); - return static_cast(raw) / 64.0f; + const uint32_t u = (static_cast(rawPress[2]) << 24) | + (static_cast(rawPress[1]) << 16) | + (static_cast(rawPress[0]) << 8); + return static_cast(static_cast(u)) / (64.0f * 256.0f); } /// Get pressure in hectopascals (hPa) / millibars (mbar) diff --git a/src/modm/driver/pressure/bmp581.lb b/src/modm/driver/pressure/bmp581.lb index 51973a5e2f..9626d8de6e 100644 --- a/src/modm/driver/pressure/bmp581.lb +++ b/src/modm/driver/pressure/bmp581.lb @@ -40,7 +40,7 @@ def prepare(module, options): ":architecture:register", ":architecture:spi.device", ":architecture:i2c.device", - ":processing:fiber", + ":architecture:fiber", ":processing:timer") return True diff --git a/src/modm/driver/pressure/bmp581_transport.hpp b/src/modm/driver/pressure/bmp581_transport.hpp index 7a9113b5a5..c93453f7a3 100644 --- a/src/modm/driver/pressure/bmp581_transport.hpp +++ b/src/modm/driver/pressure/bmp581_transport.hpp @@ -47,7 +47,7 @@ concept Bmp581Transport = * @tparam I2cMaster I2C master peripheral */ template -class Bmp581I2cTransport : public modm::I2cDevice +class Bmp581I2cTransport : public modm::I2cDevice { public: /** @@ -114,8 +114,6 @@ class Bmp581SpiTransport : public modm::SpiDevice protected: /// SPI read flag (bit 7 set for read operations) static constexpr uint8_t ReadFlag = 0x80; - - uint8_t buffer_[8]; }; /// @} diff --git a/src/modm/driver/pressure/bmp581_transport_impl.hpp b/src/modm/driver/pressure/bmp581_transport_impl.hpp index a7a05d6efa..afe53e5a94 100644 --- a/src/modm/driver/pressure/bmp581_transport_impl.hpp +++ b/src/modm/driver/pressure/bmp581_transport_impl.hpp @@ -22,7 +22,7 @@ namespace modm template Bmp581I2cTransport::Bmp581I2cTransport(uint8_t address) - : I2cDevice(address) + : I2cDevice(address) {} template @@ -36,17 +36,16 @@ template bool Bmp581I2cTransport::read(uint8_t reg, uint8_t* data, std::size_t length) { - buffer_[0] = reg; - return I2cDevice::writeRead(&buffer_[0], 1, data, length); + uint8_t reg_addr = reg; + return I2cDevice::writeRead(®_addr, 1, data, length); } template bool Bmp581I2cTransport::write(uint8_t reg, uint8_t data) { - buffer_[0] = reg; - buffer_[1] = data; - return I2cDevice::write(&buffer_[0], 2); + uint8_t buffer[]{reg, data}; + return I2cDevice::write(buffer, sizeof(buffer)); } template @@ -56,7 +55,7 @@ Bmp581I2cTransport::write(uint8_t reg, const uint8_t* data, std::size if (length > sizeof(buffer_) - 1) { return false; } buffer_[0] = reg; for (std::size_t i = 0; i < length; ++i) { buffer_[i + 1] = data[i]; } - return I2cDevice::write(&buffer_[0], length + 1); + return I2cDevice::write(&buffer_[0], length + 1); } // ---------------------------------------------------------------------------- @@ -82,9 +81,8 @@ Bmp581SpiTransport::read(uint8_t reg, uint8_t* data, std::size_t modm::this_fiber::poll([this] { return this->acquireMaster(); }); Cs::reset(); - // Send register address with read flag, then clock out data - buffer_[0] = reg | ReadFlag; - SpiMaster::transfer(&buffer_[0], nullptr, 1); + uint8_t cmd = reg | ReadFlag; + SpiMaster::transfer(&cmd, nullptr, 1); SpiMaster::transfer(nullptr, data, length); if (this->releaseMaster()) { Cs::set(); } @@ -99,9 +97,8 @@ Bmp581SpiTransport::write(uint8_t reg, uint8_t data) modm::this_fiber::poll([this] { return this->acquireMaster(); }); Cs::reset(); - buffer_[0] = reg & ~ReadFlag; // Clear read flag for write - buffer_[1] = data; - SpiMaster::transfer(&buffer_[0], nullptr, 2); + uint8_t buffer[]{uint8_t(reg & ~ReadFlag), data}; + SpiMaster::transfer(buffer, nullptr, sizeof(buffer)); if (this->releaseMaster()) { Cs::set(); } @@ -115,8 +112,8 @@ Bmp581SpiTransport::write(uint8_t reg, const uint8_t* data, std:: modm::this_fiber::poll([this] { return this->acquireMaster(); }); Cs::reset(); - buffer_[0] = reg & ~ReadFlag; // Clear read flag for write - SpiMaster::transfer(&buffer_[0], nullptr, 1); + uint8_t cmd = reg & ~ReadFlag; + SpiMaster::transfer(&cmd, nullptr, 1); SpiMaster::transfer(data, nullptr, length); if (this->releaseMaster()) { Cs::set(); } From c42d75a5fe62fb8da5207a8326a28df2ba0e02f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Schulz-Andres?= Date: Thu, 5 Mar 2026 20:52:36 +0100 Subject: [PATCH 6/8] [driver] bmp581 pressure sensor: formatting/whitespace --- src/modm/driver/pressure/bmp581_transport_impl.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modm/driver/pressure/bmp581_transport_impl.hpp b/src/modm/driver/pressure/bmp581_transport_impl.hpp index afe53e5a94..50c8580ea5 100644 --- a/src/modm/driver/pressure/bmp581_transport_impl.hpp +++ b/src/modm/driver/pressure/bmp581_transport_impl.hpp @@ -21,8 +21,7 @@ namespace modm // ---------------------------------------------------------------------------- template -Bmp581I2cTransport::Bmp581I2cTransport(uint8_t address) - : I2cDevice(address) +Bmp581I2cTransport::Bmp581I2cTransport(uint8_t address) : I2cDevice(address) {} template From 819d9434b0e7dfbcf82b2e1105a7ffa2663d165a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Schulz-Andres?= Date: Fri, 6 Mar 2026 09:19:23 +0100 Subject: [PATCH 7/8] [driver] bmp581 pressure sensor: reduce quantization impact Co-authored-by: Niklas Hauser --- src/modm/driver/pressure/bmp581.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modm/driver/pressure/bmp581.hpp b/src/modm/driver/pressure/bmp581.hpp index 4646907768..a1f1be325e 100644 --- a/src/modm/driver/pressure/bmp581.hpp +++ b/src/modm/driver/pressure/bmp581.hpp @@ -299,7 +299,7 @@ struct bmp581 const uint32_t u = (static_cast(rawTemp[2]) << 24) | (static_cast(rawTemp[1]) << 16) | (static_cast(rawTemp[0]) << 8); - return static_cast(static_cast(u)) / (65536.0f * 256.0f); + return static_cast(static_cast(u) / 256) / (65536.0f); } /// Get pressure in Pascals From d30e8dff400619b7b007b5b5fd936cf3ce70e4e7 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Fri, 6 Mar 2026 21:15:50 +0100 Subject: [PATCH 8/8] fixup! [driver] bmp581 pressure sensor: reduce quantization impact --- src/modm/driver/pressure/bmp581.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modm/driver/pressure/bmp581.hpp b/src/modm/driver/pressure/bmp581.hpp index a1f1be325e..3a472a9b81 100644 --- a/src/modm/driver/pressure/bmp581.hpp +++ b/src/modm/driver/pressure/bmp581.hpp @@ -299,7 +299,7 @@ struct bmp581 const uint32_t u = (static_cast(rawTemp[2]) << 24) | (static_cast(rawTemp[1]) << 16) | (static_cast(rawTemp[0]) << 8); - return static_cast(static_cast(u) / 256) / (65536.0f); + return static_cast(static_cast(u) / 256) / 65536.0f; } /// Get pressure in Pascals @@ -309,7 +309,7 @@ struct bmp581 const uint32_t u = (static_cast(rawPress[2]) << 24) | (static_cast(rawPress[1]) << 16) | (static_cast(rawPress[0]) << 8); - return static_cast(static_cast(u)) / (64.0f * 256.0f); + return static_cast(static_cast(u) / 256) / 64.0f; } /// Get pressure in hectopascals (hPa) / millibars (mbar)