Sitelet https://github.com/betaflight/betaflight/pull/14925
Skip to content

Feature/bmp580 barometer - #14925

Merged
haslinghuis merged 8 commits into
betaflight:masterfrom
gintaris:feature/bmp580-barometer
Feb 27, 2026
Merged

haslinghuis merged 8 commits into
betaflight:masterfrom
gintaris:feature/bmp580-barometer

Conversation

@gintaris

@gintaris gintaris commented Feb 16, 2026 •

Copy link
Copy Markdown
Contributor

BMP580/BMP581 Barometer Driver for Betaflight

Overview

This PR adds support for the Bosch BMP580/BMP581 next-generation barometer sensor to Betaflight.

Features

  • Full I2C driver for BMP580/BMP581 barometer
  • 128X pressure oversampling (lowest noise)
  • 4X temperature oversampling
  • IIR filter coefficient 4
  • Normal power mode continuous measurement
  • Compatible with both BMP580 and BMP581 variants

Hardware Specifications

Parameter Value
Chip Bosch BMP580/BMP581
Interface I2C (up to 3.4MHz)
I2C Address 0x46 or 0x47
Pressure Range 300-1250 hPa
Relative Accuracy ±0.06 hPa (±0.5m)
Temperature Range -40 to +85°C
Power Consumption ~3.9µA @ 1Hz

Files Modified

File Change
src/main/drivers/barometer/barometer_bmp580.c New BMP580 driver
src/main/drivers/barometer/barometer_bmp580.h Driver header
src/main/sensors/barometer.c Add BMP580 detection
src/main/sensors/barometer.h Add BARO_BMP580 enum
mk/source.mk Add bmp580 to build

Oversampling Configuration

Default configuration uses 128X pressure / 4X temperature oversampling:

Pressure OSR Temp OSR Noise (Pa RMS) Update Rate Use Case
8X 1X ~0.5 Pa ~80 Hz Fast response
64X 2X ~0.1 Pa ~15 Hz Balanced
128X 4X ~0.06 Pa ~10 Hz Lowest noise (default)

Testing

Test Hardware:

Test Results:

Test Result
Device detection ✅ Pass at 0x47
Chip ID read 0x50 (BMP580)
Temperature Stable readings
Pressure Stable readings
Altitude Displayed in OSD
Configurator ✅ Baro visible

Platform Compatibility

Platform Status Notes
RP2350 (PICO2) ✅ Tested MADFLIGHT_FC3 board
RP2040 (PICO) ⚠️ Should work Not tested
STM32F4 ⚠️ Should work Not tested (CI build only)
STM32F7 ⚠️ Should work Not tested (CI build only)
STM32H7 ⚠️ Should work Not tested (CI build only)

Note: Only RP2350B (MADFLIGHT_FC3) was tested on actual hardware. STM32 platforms should work but require community testing.

Commit Message

feat(driver): add BMP580/BMP581 barometer driver

Add support for Bosch BMP580/BMP581 next-gen barometer:
- New driver barometer_bmp580.c/h with I2C protocol
- 128X oversampling for pressure (lowest noise)
- 4X oversampling for temperature  
- IIR filter coefficient 4
- Normal power mode continuous measurement
- Compatible with BMP580 and BMP581 variants

Specifications:
- Pressure range: 300-1250 hPa
- Relative accuracy: ±0.06 hPa (±0.5m)
- Temperature range: -40 to +85°C
- I2C address: 0x46 or 0x47

Tested on RP2350B (Raspberry Pi Pico 2) at I2C address 0x47.

PR Checklist

  • Code follows Betaflight coding style guidelines
  • Single feature: BMP580 barometer driver
  • Build passes for PICO targets
  • Tested on real hardware (RP2350B)
  • STM32 testing (needs community verification)

Summary by CodeRabbit

  • New Features

    • Added support for the BMP580 barometer (SPI/I2C) for temperature and pressure.
    • BMP580 included in device auto-detection and shown in hardware selection / CLI/status outputs.
  • Chores

    • BMP580 driver compiled into standard and non-simulator builds.
    • Barometer configuration version bumped to persist settings for the new sensor.

Add support for Bosch BMP580/BMP581 next-gen barometer:
- New driver barometer_bmp580.c/h with I2C protocol
- 128X oversampling for pressure (lowest noise)
- 4X oversampling for temperature
- IIR filter coefficient 4
- Normal power mode continuous measurement
- Compatible with BMP580 and BMP581 variants

Specifications:
- Pressure range: 300-1250 hPa
- Relative accuracy: ±0.06 hPa (±0.5m)
- Temperature range: -40 to +85°C
- I2C address: 0x46 or 0x47

Tested on RP2350B (Raspberry Pi Pico 2) at I2C address 0x47.
@github-actions

Copy link
Copy Markdown

Do you want to test this code? You can flash it directly from the Betaflight App:

  • Simply put #14925 (this pull request number) in the Select commit field in the Firmware Flasher tab (you need to Enable expert mode, Show release candidates and Development).

WARNING: It may be unstable. Use only for testing!

@coderabbitai

coderabbitai Bot commented Feb 16, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new BMP580/BMP581 barometer driver (I2C/SPI), registers it in the build, integrates detection/initialization into the barometer subsystem, exposes BARO_BMP580, and adds a CLI/settings lookup entry. Detection, read, and compensation for UT/UP are implemented.

Changes

Cohort / File(s) Summary
Build Configuration
mk/source.mk
Adds drivers/barometer/barometer_bmp580.c to COMMON_SRC both unconditionally and inside the ifneq ($(SIMULATOR_BUILD),yes) block.
BMP580 Driver
src/main/drivers/barometer/barometer_bmp580.h, src/main/drivers/barometer/barometer_bmp580.c
New BMP580 driver and header: bmp580Detect public entry, register definitions, bus (I2C/SPI) abstraction, probe/init/reset/config, IRQ/EXTI hooks, read path for 6‑byte UT/UP, and compensation routine producing temperature and pressure.
Barometer Integration
src/main/sensors/barometer.h, src/main/sensors/barometer.c
Adds BARO_BMP580 enum, shifts BARO_VIRTUAL value, bumps PG registration version (3 → 4), includes BMP580 header, and extends baroDetect to call bmp580Detect (guarded by build flags).
CLI / Settings
src/main/cli/settings.c
Adds lookup table entry mapping BARO_BMP580 → "BMP580".

Sequence Diagram(s)

sequenceDiagram
    participant Init as System Init
    participant Baro as Baro Subsystem
    participant Bus as I2C/SPI Bus
    participant BMP580 as BMP580 Device

    Init->>Baro: request detection
    Baro->>Bus: bmp580Detect -> busInit / probe
    Bus->>BMP580: probe (I2C addr / SPI CS)
    alt device responds
        BMP580-->>Bus: chip id / ack
        Bus-->>Baro: device detected
        Baro->>BMP580: soft reset + configure (DSP/OSR/ODR/IRQ)
        BMP580-->>Baro: ack
        BMP580->>Baro: measurement ready (EXTI/IRQ)
        Baro->>Bus: read 6 bytes (UT[3], UP[3])
        Bus->>BMP580: read request
        BMP580-->>Bus: raw bytes
        Baro->>Baro: bmp580Calculate(raw) -> temperature, pressure
        Baro-->>Init: register device & report readiness
    else not found
        Bus-->>Baro: not found
        Baro-->>Init: detection failed / fallback
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

Tested

Suggested reviewers

  • blckmn
  • nerdCopter
  • Quick-Flash
  • haslinghuis
  • SteveCEvans
🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feature/bmp580 barometer' is directly related to the changeset, which adds a complete BMP580/BMP581 barometer driver to Betaflight.
Description check ✅ Passed The pull request description is comprehensive and well-structured, covering overview, features, hardware specifications, files modified, oversampling configuration, testing results, platform compatibility, and checklist items—exceeding typical requirements.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into master

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/sensors/barometer.c (1)

82-135: ⚠️ Potential issue | 🟠 Major

BMP580 missing from the default barometer auto-selection logic.

The preprocessor block that auto-defines DEFAULT_BARO_xxx based on USE_BARO_xxx flags (lines 88–135) has no entry for BMP580. Additionally, BMP580 is missing from the SPI defaults condition (line 141).

This means:

  • A target that defines USE_BARO_BMP580 (without an explicit DEFAULT_BARO_BMP580) won't trigger the auto-selection logic, so the condition on line 147 will not match.
  • The barometer config will fall to the #else branch (line 154), setting BARO_NONE and BUS_TYPE_NONE, preventing detection.
  • Similarly, USE_BARO_SPI_BMP580 won't get SPI bus defaults configured (line 141).

BMP580 should be added to the auto-selection logic following the same pattern as BMP388:

Proposed fix

Add to the outer #if condition on line 82:

defined(DEFAULT_BARO_BMP580) || defined(DEFAULT_BARO_SPI_BMP580)

Add to the #elif chain after line 135:

+#elif defined(USE_BARO_BMP580) || defined(USE_BARO_SPI_BMP580)
+#if defined(USE_BARO_SPI_BMP580)
+#define DEFAULT_BARO_SPI_BMP580
+#else
+#define DEFAULT_BARO_BMP580
+#endif

Add to the SPI defaults condition on line 141:

|| defined(DEFAULT_BARO_SPI_BMP580)
🤖 Fix all issues with AI agents
In `@src/main/drivers/barometer/barometer_bmp580.c`:
- Around line 194-198: The temperature oversampling macro is set to 128× but the
PR description says pressure=128× and temperature=4×; update the
BMP580_TEMPERATURE_OSR definition to use the 4× constant (change
BMP580_TEMPERATURE_OSR from BMP580_OSR_TEMP_128X to BMP580_OSR_TEMP_4X) so the
conversion time and effective update rate match the documented 128×/4×
configuration; leave BMP580_PRESSURE_OSR as BMP580_OSR_PRESS_128X.
- Around line 363-390: The driver never sets the combined_read flag, so the
barometer state machine still runs the dummy UT states; set baro->combined_read
= true in the BMP580 init sequence right after you assign the UT/UP callbacks
(the block that sets baro->ut_delay, baro->start_ut, baro->get_ut, baro->read_ut
and baro->start_up, baro->get_up, baro->read_up) so the state machine skips
temperature-only states; locate the init function containing
bmp580StartUT/bmp580GetUT/bmp580ReadUT and
bmp580StartUP/bmp580GetUP/bmp580ReadUP and add the single assignment there.

In `@src/main/sensors/barometer.h`:
- Around line 38-39: Add a lookup entry for the new enum and preserve EEPROM
compatibility: insert [BARO_BMP580] = "BMP580" into the lookupTableBaroHardware
array so index 12 is initialized; then handle the BARO_VIRTUAL value change by
bumping the barometer config PG version (the PG version constant in barometer.c)
and add migration logic that maps old stored value 11 to the new BARO_VIRTUAL
enum value (or alternatively change enum assignments so BARO_BMP580=11 and
BARO_VIRTUAL=12 if you prefer not to migrate). Ensure references to BARO_BMP580
and BARO_VIRTUAL in settings.c and barometer.c are consistent after the change.
🧹 Nitpick comments (2)
src/main/drivers/barometer/barometer_bmp580.c (2)

227-240: VLA in embedded context; consider a fixed-size buffer.

uint8_t buf[length + 1] is a variable-length array. While the callers currently pass small lengths (≤6), VLAs are generally avoided in embedded firmware due to unpredictable stack usage and are undefined behavior in some C standards when the size is zero. A fixed-size local buffer based on BMP580_DATA_FRAME_SIZE + 1 would be safer.

Proposed fix
 static bool bmp580ReadRegisterBuffer(const extDevice_t *dev, uint8_t reg, uint8_t *data, uint8_t length)
 {
     if (dev->bus->busType == BUS_TYPE_SPI) {
-        // For SPI: first byte is dummy on BMP5xx read
-        uint8_t buf[length + 1];
-        bool ret = busReadRegisterBuffer(dev, reg, buf, length + 1);
+        // For SPI: first byte is dummy on BMP5xx read
+        uint8_t buf[BMP580_DATA_FRAME_SIZE + 1 + 1]; // max data + SPI dummy + chip ID read
+        if (length + 1 > (int)sizeof(buf)) {
+            return false;
+        }
+        bool ret = busReadRegisterBuffer(dev, reg, buf, length + 1);
         if (ret) {
             memcpy(data, buf + 1, length);
         }

203-216: Static global state limits driver to a single instance and leaves debug variables in production.

The static globals (bmp580_up, bmp580_ut, bmp580_chip_id, sensor_data, bmp580_last_raw_temp, bmp580_last_raw_press) are typical for Betaflight barometer drivers (single-instance design). However, bmp580_last_raw_temp and bmp580_last_raw_press (lines 215-216) are only assigned but never read — they are dead code unless a debugger is attached.

Suggested: guard debug variables
+#ifdef DEBUG
 // Debug: last raw values for troubleshooting
 static uint32_t bmp580_last_raw_temp = 0;
 static uint32_t bmp580_last_raw_press = 0;
+#endif

And in bmp580GetUP:

+#ifdef DEBUG
     // Store for debug
     bmp580_last_raw_temp = bmp580_ut;
     bmp580_last_raw_press = bmp580_up;
+#endif

Comment thread src/main/drivers/barometer/barometer_bmp580.c Outdated
Comment thread src/main/drivers/barometer/barometer_bmp5xx.c
Comment thread src/main/sensors/barometer.h Outdated

@haslinghuis haslinghuis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add here:

// sync with baroSensor_e
const char * const lookupTableBaroHardware[BARO_HARDWARE_COUNT] = {
[BARO_DEFAULT] = "AUTO",
[BARO_NONE] = "NONE",
[BARO_BMP085] = "BMP085",
[BARO_MS5611] = "MS5611",
[BARO_BMP280] = "BMP280",
[BARO_LPS] = "LPS",
[BARO_QMP6988] = "QMP6988",
[BARO_BMP388] = "BMP388",
[BARO_DPS310] = "DPS310",
[BARO_2SMPB_02B] = "2SMPB_02B",
[BARO_LPS22DF] = "LPS22DF",
[BARO_VIRTUAL] = "VIRTUAL"
};

@gintaris
gintaris force-pushed the feature/bmp580-barometer branch from 42fa33a to 41dff12 Compare February 16, 2026 11:26

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/main/drivers/barometer/barometer_bmp580.c`:
- Around line 385-388: Update the misleading comment and clarify why up_delay is
set to 15000: state the actual configured oversampling (128× pressure, 4×
temperature) and note that per the BMP580 datasheet that conversion time for
those OSR settings is ~100ms, but the code uses 15ms because the sensor runs in
continuous/normal mode and samples are available from shadow registers;
reference the baro->up_delay assignment and the BMP580 operating mode/OSR
configuration in this comment so future readers understand the discrepancy
between datasheet conversion time and the chosen delay.
- Around line 356-362: The DSP IIR output was enabled by writing
BMP580_DSP_SHDW_SEL_IIR to BMP580_REG_DSP_CONFIG but the DSP IIR coefficient
register (BMP580_REG_DSP_IIR) was never set (it stays at POR 0x00 bypass after
the soft reset), so enable the actual filter by writing the correct coefficient
value (select coefficient 4 as stated in the PR) into BMP580_REG_DSP_IIR after
the soft reset and before finalizing configuration; keep the existing writes to
BMP580_REG_DSP_CONFIG and BMP580_REG_OSR_CONFIG
(BMP580_PRESSURE_OSR/BMP580_TEMPERATURE_OSR/BMP580_OSR_PRESS_EN) but add a
busWriteRegister(dev, BMP580_REG_DSP_IIR,
<value-for-coef-4-for-pressure-and-temperature>) call to apply the IIR
coefficient for both pressure and temperature.
🧹 Nitpick comments (2)
src/main/drivers/barometer/barometer_bmp580.c (2)

228-241: Replace VLA with a fixed-size stack buffer.

uint8_t buf[length + 1] (line 232) is a variable-length array. While length is always small here (1 or 6), VLAs are risky on resource-constrained MCUs and some compilers/configurations reject them. Use a fixed-size buffer based on the maximum expected read.

Proposed fix
 static bool bmp580ReadRegisterBuffer(const extDevice_t *dev, uint8_t reg, uint8_t *data, uint8_t length)
 {
     if (dev->bus->busType == BUS_TYPE_SPI) {
-        // For SPI: first byte is dummy on BMP5xx read
-        uint8_t buf[length + 1];
+        // For SPI: first byte is dummy on BMP5xx read
+        uint8_t buf[BMP580_DATA_FRAME_SIZE + 1];  // max read size + SPI dummy byte
+        if (length > BMP580_DATA_FRAME_SIZE) {
+            return false;
+        }
         bool ret = busReadRegisterBuffer(dev, reg, buf, length + 1);
         if (ret) {
             memcpy(data, buf + 1, length);
         }
         return ret;

215-217: Dead stores: debug variables are written but never read.

bmp580_last_raw_temp and bmp580_last_raw_press are set in bmp580GetUP (lines 449–450) but never consumed. They aren't guarded by #ifdef DEBUG either. Consider removing them or wrapping in #ifdef DEBUG to avoid dead writes in release builds.

Comment thread src/main/drivers/barometer/barometer_bmp580.c Outdated
@gintaris
gintaris force-pushed the feature/bmp580-barometer branch from 41dff12 to 84996b7 Compare February 16, 2026 11:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
src/main/drivers/barometer/barometer_bmp580.c (4)

243-256: VLA on constrained stack — prefer a fixed-size buffer.

uint8_t buf[length + 1] is a variable-length array. While callers in this file only pass small lengths (1 or 6), VLAs are fragile in embedded contexts and prohibited by MISRA C. Consider a fixed-size stack buffer based on the maximum expected read (data frame + 1 SPI dummy byte).

Proposed fix
 static bool bmp580ReadRegisterBuffer(const extDevice_t *dev, uint8_t reg, uint8_t *data, uint8_t length)
 {
     if (dev->bus->busType == BUS_TYPE_SPI) {
-        // For SPI: first byte is dummy on BMP5xx read
-        uint8_t buf[length + 1];
-        bool ret = busReadRegisterBuffer(dev, reg, buf, length + 1);
+        // For SPI: first byte is dummy on BMP5xx read
+        uint8_t buf[BMP580_DATA_FRAME_SIZE + 1 + 1]; // max read size + SPI dummy + margin
+        if (length + 1 > (int)sizeof(buf)) {
+            return false;
+        }
+        bool ret = busReadRegisterBuffer(dev, reg, buf, length + 1);
         if (ret) {
             memcpy(data, buf + 1, length);
         }

230-232: Remove unused debug variables.

bmp580_last_raw_temp and bmp580_last_raw_press are written (lines 472–473) but never read anywhere. They consume static RAM for no production benefit. Based on learnings, debug output was explicitly removed per Betaflight standards.

Proposed fix
-// Debug: last raw values for troubleshooting
-static uint32_t bmp580_last_raw_temp = 0;
-static uint32_t bmp580_last_raw_press = 0;

And remove the assignments at lines 472–473:

-    // Store for debug
-    bmp580_last_raw_temp = bmp580_ut;
-    bmp580_last_raw_press = bmp580_up;

375-378: Ambiguous IIR coefficient comment — clarify register value vs. filter order.

The comment says "coefficient 4" but the code uses BMP580_IIR_COEF_15, which per the defines means register value 0x04 mapping to a filter coefficient of 15. The PR description also says "IIR filter coefficient 4" which adds to the confusion. Consider clarifying:

-    // Configure IIR filter coefficient 4 (gives coefficient ~15) for both pressure and temperature
+    // Configure IIR filter: register value 4 selects coefficient 15 for both pressure and temperature

220-228: Consider making bmp580_chip_id local to bmp580Detect.

bmp580_chip_id is only used within bmp580Detect. Keeping it as a file-scoped static wastes a byte of static RAM after detection completes. The same applies to the sensor_data pointer setup at line 329 which duplicates the SPI dummy-byte handling already done inside bmp580ReadRegisterBuffer.

@gintaris
gintaris force-pushed the feature/bmp580-barometer branch 2 times, most recently from 4037092 to 974d1fe Compare February 16, 2026 12:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/sensors/barometer.c (1)

84-137: ⚠️ Potential issue | 🟠 Major

BMP580 missing from the default barometer auto-define cascade.

The preprocessor cascade (lines 90–136) auto-defines DEFAULT_BARO_xxx based on USE_BARO_xxx when no explicit default is set, but BMP580 is not included. This means boards that only define USE_BARO_BMP580 (without any other baro) will fall through to the #else at line 156, setting baro_hardware = BARO_NONE and baro_busType = BUS_TYPE_NONE, which prevents detection.

Add BMP580 to the cascade, e.g.:

`#elif` defined(USE_BARO_BMP580) || defined(USE_BARO_SPI_BMP580)
`#if` defined(USE_BARO_SPI_BMP580)
`#define` DEFAULT_BARO_SPI_BMP580
`#else`
`#define` DEFAULT_BARO_BMP580
`#endif`

Also update the SPI guard at line 143 to include DEFAULT_BARO_SPI_BMP580.

🤖 Fix all issues with AI agents
In `@src/main/sensors/barometer.c`:
- Around line 199-201: The UNUSED(dev) guard omits the SPI variant macro causing
false unused warnings when only USE_BARO_SPI_BMP580 is defined; update the
conditional in the `#if` that controls UNUSED(dev) to also check
!defined(USE_BARO_SPI_BMP580) so that the UNUSED(dev) macro is only emitted when
neither USE_BARO_BMP580 nor USE_BARO_SPI_BMP580 (and the other listed baro
macros) are defined; refer to the existing macros in the block (USE_BARO_BMP580,
USE_BARO_SPI_BMP580, USE_BARO_MS5611, etc.) to add the missing
!defined(USE_BARO_SPI_BMP580) check.
🧹 Nitpick comments (3)
src/main/drivers/barometer/barometer_bmp580.c (3)

254-257: VLA in embedded context.

uint8_t buf[length + 1] is a variable-length array on the stack. While length is always small in practice (1 or 6), VLAs are generally discouraged in embedded firmware due to unpredictable stack usage and potential issues with some compilers. Consider using a fixed-size buffer based on BMP580_DATA_FRAME_SIZE + 1.

Proposed fix
 static bool bmp580ReadRegisterBuffer(const extDevice_t *dev, uint8_t reg, uint8_t *data, uint8_t length)
 {
     if (dev->bus->busType == BUS_TYPE_SPI) {
         // For SPI: first byte is dummy on BMP5xx read
-        uint8_t buf[length + 1];
-        bool ret = busReadRegisterBuffer(dev, reg, buf, length + 1);
+        uint8_t buf[BMP580_DATA_FRAME_SIZE + 1 + 1]; // Max read size + SPI dummy
+        bool ret = busReadRegisterBuffer(dev, reg, buf, MIN(length + 1, (uint8_t)sizeof(buf)));
         if (ret) {
             memcpy(data, buf + 1, length);
         }

398-401: Misleading comment — "coefficient 4" is the register value, not the filter coefficient.

The comment says "IIR filter coefficient 4" but the actual IIR filter coefficient is 15 (register value 0x04 maps to coefficient 15 per the encoding at lines 169-177). The parenthetical "(gives coefficient ~15)" clarifies, but the leading text is confusing. The @note at line 325 correctly says "coefficient 15". Consider aligning the comment.

Proposed fix
-    // Configure IIR filter coefficient 4 (gives coefficient ~15) for both pressure and temperature
+    // Configure IIR filter coefficient 15 for both pressure and temperature
+    // (register value 0x04 = coefficient 15, per BMP580 datasheet)

230-232: Debug-only variables are always assigned but never consumed.

bmp580_last_raw_temp and bmp580_last_raw_press are written on every sample (line 531-532) but never read anywhere. If intended for debugger inspection, wrap them in #ifdef DEBUG to avoid dead stores in release builds.

Comment thread src/main/sensors/barometer.c Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/main/drivers/barometer/barometer_bmp580.c`:
- Around line 390-401: The PR description is inconsistent with the code: update
the PR description to state "IIR filter coefficient 15 (register value 4)" to
match the implementation and the in-code comment; verify that references to
BMP580_REG_DSP_IIR, BMP580_IIR_PRESS(BMP580_IIR_COEF_15),
BMP580_IIR_TEMP(BMP580_IIR_COEF_15) and the comment about "register value 4
selects coefficient 15" remain consistent so reviewers understand the datasheet
encoding.
- Around line 262-274: The EXTI ISR bmp580_extiHandler must not perform blocking
I2C reads (bmp580ReadRegisterBuffer); remove that call and instead mark the baro
device for deferred handling by setting a flag on the baroDev_t (e.g., set
baro->int_pending = true or re-use an existing field) inside bmp580_extiHandler
(use container_of(cb, baroDev_t, exti) to access baro), then perform the
INT_STATUS read in the regular context such as bmp580ReadUP where bus IO is
safe; alternatively, if using pulsed interrupt mode, simply drop the read
entirely and rely on auto-clear of the INT pin.

Comment thread src/main/drivers/barometer/barometer_bmp580.c Outdated
Comment thread src/main/drivers/barometer/barometer_bmp580.c Outdated
Add support for Bosch BMP580/BMP581 next-gen barometer:
- New driver barometer_bmp580.c/h with I2C protocol
- 128X oversampling for pressure (lowest noise)
- 4X oversampling for temperature (balanced)
- IIR filter coefficient 4
- Normal power mode continuous measurement
- Combined read mode (temp+pressure in single read)
- Compatible with BMP580 and BMP581 variants

Changes:
- Add BARO_BMP580=11 to baroSensor_e enum
- Add BMP580 to lookupTableBaroHardware
- Bump PG_BAROMETER_CONFIG version to 4 (BARO_VIRTUAL moved to 12)
- Set baro->combined_read = true to skip dummy UT states

Specifications:
- Pressure range: 300-1250 hPa
- Relative accuracy: ±0.06 hPa (±0.5m)
- Temperature range: -40 to +85°C
- I2C address: 0x46 or 0x47

Tested on RP2350B (Raspberry Pi Pico 2) at I2C address 0x47.
@gintaris
gintaris force-pushed the feature/bmp580-barometer branch from 974d1fe to c7ab5f7 Compare February 16, 2026 12:13
@gintaris

Copy link
Copy Markdown
Contributor Author

@coderabbitai please check committed all at once

@coderabbitai

coderabbitai Bot commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

@gintaris: I'll review all the changes in this PR that add BMP580/BMP581 barometer support to Betaflight.


🧠 Learnings used
Learnt from: heronprecision-1
Repo: betaflight/betaflight PR: 14378
File: src/main/pg/piniobox.c:73-76
Timestamp: 2025-05-13T18:41:35.781Z
Learning: PR `#14378` increases the PINIO limit from 4 to 8 to support flight controllers that use analog switches driven by GPIOs, requiring more configurable pins.

Learnt from: haslinghuis
Repo: betaflight/betaflight PR: 0
File: :0-0
Timestamp: 2025-10-06T14:46:51.765Z
Learning: For the betaflight/betaflight repository, automatically enhance minimal or missing PR descriptions to include comprehensive information (What Changed, Why This Change, Testing) while preserving any existing content, images, and auto-generated summaries. Users often rely on AI-generated summaries instead of writing descriptions.

Learnt from: ledvinap
Repo: betaflight/betaflight PR: 14578
File: src/main/telemetry/jetiexbus.c:547-556
Timestamp: 2025-08-12T18:26:17.016Z
Learning: For Betaflight Jeti ExBus backport PR `#14578`: ledvinap prefers to keep the PR focused on backporting fixes from iNavFlight rather than expanding into broader architectural improvements. Additional improvements to TX/RX state machine should be handled in separate PRs.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
src/main/drivers/barometer/barometer_bmp580.c (3)

246-260: Stack buffer in SPI read helper is silently bounded — consider a guard.

buf is fixed at BMP580_DATA_FRAME_SIZE + 1 (7 bytes), but length is an unchecked uint8_t. Currently all call sites pass length ≤ 6, so this is safe today. A defensive bounds check (or a _Static_assert / comment) would prevent a future caller from overflowing the stack buffer.

Optional: add a bounds check
 static bool bmp580ReadRegisterBuffer(const extDevice_t *dev, uint8_t reg, uint8_t *data, uint8_t length)
 {
     if (dev->bus->busType == BUS_TYPE_SPI) {
+        if (length > BMP580_DATA_FRAME_SIZE) {
+            return false;
+        }
         // For SPI: first byte is dummy on BMP5xx read
         // Max read size: BMP580_DATA_FRAME_SIZE (6) + 1 dummy = 7 bytes
         uint8_t buf[BMP580_DATA_FRAME_SIZE + 1];

262-268: EXTI handler is a no-op, yet full interrupt infrastructure is configured.

bmp580_extiHandler does nothing, but bmp580Detect (lines 320-326, 372-382) still sets up the EXTI pin, configures the BMP580 INT_CONFIG register, and enables the DRDY interrupt source. This means the sensor will fire hardware interrupts at 50 Hz that enter an empty ISR — unnecessary context switches. Consider either:

  • Removing the interrupt configuration entirely (lines 320-326 and 372-382) since polling is used, or
  • Keeping the infrastructure but skipping the sensor-side INT register writes.

This is consistent with other drivers that wire up EOC for future use, so not blocking, but worth noting the wasted cycles.


531-558: Verify that Betaflight's barometer subsystem expects pressure in Pa (not Pa×256 or hPa).

The misleading comment on line 547 ("Betaflight expects Pa * 256 for some baros") may cause confusion. In barometer.c, pressureToAltitude() divides by 101325.0f (standard atmospheric pressure in Pa), confirming that Pa is expected. The calculation here (bmp580_up / 64) yields Pa, which is correct.

However, the integer division on line 550 truncates fractional Pa. With 128× OSR, the BMP580's LSB resolution is ~0.016 Pa (1/64). Truncation to integer Pa loses this precision. Other Betaflight baro drivers (e.g., BMP388) also return integer Pa, so this is consistent, but worth documenting that the sub-Pa precision from the high OSR is discarded here.

Also, the comment on line 547 is misleading — consider removing the "Pa * 256" mention to avoid confusing future maintainers:

Clean up misleading comment
-    // Pressure in Pa (Betaflight expects Pa * 256 for some baros, but using Pa directly)
-    // raw / 64 = pressure in Pa
-    // Betaflight barometer interface expects pressure in Pa
+    // Pressure in Pa (Betaflight barometer interface expects integer Pa)
+    // raw / 64 = pressure in Pa
     uint32_t press_pa = bmp580_up / 64;
src/main/sensors/barometer.c (1)

84-137: DEFAULT_BARO_BMP580 is recognized in the I2C bus config (line 149) but is missing from the default baro inference chain.

Line 149 correctly enables I2C bus config when a target pre-defines DEFAULT_BARO_BMP580. However, BMP580 is absent from both:

  1. The outer exclusion guard (line 84–88) — if a target defines DEFAULT_BARO_BMP580, the inference block still runs and may additionally define a conflicting DEFAULT_BARO_* macro.
  2. The inference chain (lines 90–136) — USE_BARO_BMP580 / USE_BARO_SPI_BMP580 are never inferred as defaults.

No target currently uses DEFAULT_BARO_BMP580, so this doesn't break anything today. But when a target does define it, the conflicting double-definition from (1) could cause unexpected bus config. Consider adding BMP580 to the outer guard and the inference chain for completeness.

Also applies to: 149-149

// Read chip ID
bmp580ReadRegisterBuffer(dev, BMP580_REG_CHIP_ID, &chipId, 1);

if (chipId != BMP580_CHIP_ID && chipId != BMP581_CHIP_ID) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noticed this supports 580 and 581. Suggest use bmp5xx for driver - so we are able to identify device with whoami and could add more devices in this series in future when applicable. I have done the same for 426xx and QMC5883

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gintaris thanks, Please also add BMP580 / BMP581 as independent devices. This way we can see the device used in status and setup tab.

@gintaris
gintaris requested a review from haslinghuis February 16, 2026 12:42
Refactor naming to support future BMP5xx series devices (BMP580, BMP581,
BMP582, etc.) similar to existing ICM426xx and QMC5883 driver naming
conventions.

Changes:
- Rename barometer_bmp580.c/h → barometer_bmp5xx.c/h
- Rename USE_BARO_BMP580 → USE_BARO_BMP5XX
- Rename USE_BARO_SPI_BMP580 → USE_BARO_SPI_BMP5XX
- Rename BARO_BMP580 enum → BARO_BMP5XX
- Update CLI baro_hardware setting from BMP580 to BMP5XX
- Preserve specific chip ID detection (BMP580_CHIP_ID, BMP581_CHIP_ID)

Suggested-by: haslinghuis
- Add BARO_BMP580 (12) and BARO_BMP581 (13) to baroSensor_e enum
- Add BMP580, BMP581 entries to lookupTableBaroHardware
- Modify bmp5xxDetect() to return detected chip ID via parameter
- Barometer detection now reports specific model (BMP580/BMP581)
- Bump PG version to 5 for enum changes (BARO_VIRTUAL now 14)

This allows users to see the exact sensor model in status/setup tabs.
Auto-detection with BMP5XX still works and resolves to specific type.

Requested-by: haslinghuis
Comment thread src/main/cli/settings.c Outdated
Comment thread src/main/drivers/barometer/barometer_bmp5xx.c Outdated
Comment thread src/main/sensors/barometer.c Outdated
Comment thread src/main/sensors/barometer.c Outdated
- Remove BMP5XX from settings.c lookup table (keep BMP580/BMP581)
- Use specific USE_BARO_BMP580/BMP581 defines instead of BMP5XX
- Change unknown chip fallback to BARO_NONE instead of BARO_BMP5XX
- Keep PG version at 4 (BMP580=13, BMP581=14 as new high values)
- Keep BARO_BMP5XX=11 in enum for backward compat (deprecated)

@haslinghuis haslinghuis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for patience.

Comment thread src/main/sensors/barometer.c Outdated
Comment thread src/main/sensors/barometer.c Outdated
Comment thread src/main/sensors/barometer.c Outdated
Comment thread src/main/sensors/barometer.h Outdated
- Remove deprecated BARO_BMP5XX from enum (use BMP580/BMP581 directly)
- BMP580=11, BMP581=12, VIRTUAL=13 (VIRTUAL always last per haslinghuis)
- Update all USE_BARO_BMP5XX references to USE_BARO_BMP580/BMP581
- Keep PG version 4 (old VIRTUAL=11 configs reset to auto-detect)
@haslinghuis

haslinghuis commented Feb 16, 2026 •

Copy link
Copy Markdown
Member

@blckmn how to recover from https://github.com/betaflight/betaflight/actions/runs/22068643616/job/63768883254?pr=14925 ?

@gintaris try to update submodule(s) and push again.

image

@haslinghuis

Copy link
Copy Markdown
Member

@gintaris not sure if this works (out of office)

https://www.betaflight.com/docs/development/Git#update-submodules-config

@gintaris

Copy link
Copy Markdown
Contributor Author
  • blckmn

Let's try I have updated

Comment thread src/main/sensors/barometer.c Outdated
gintaris added a commit to gintaris/betaflight that referenced this pull request Feb 18, 2026
- Add link to config PR betaflight#1030
- Document INA226 sensor defines added
- Add dependency table for firmware PRs betaflight#14924, betaflight#14925, betaflight#14927
- Add merge coordination notes
- Address reviewer comment about CURRENT_METER_INA226
@senjabl

senjabl commented Feb 22, 2026

Copy link
Copy Markdown

Just my 2 cents.
I tested BMP580 drivers on 2 boards and they kind of works. Had some BMP580 modules from aliexpress so I wanted to test them.
Screenshot_20260222_215323

On both boards I use fully functional combo of QMC5883P magnetometer and BMP280 or BMP390 baro.

So I tried QMC5883P and BMP580 on same i2c and all combinations.

JHEMCU F435 NEO - AT32F435 MCU

  • When powered over USB everything works (QMC5883P + BMP580)
  • If powered from battery, neither QMC5883P or BMP580 are detected.
  • If powered from battery and BMP580 is disabled, QMC5883P works
  • If powered from battery and QMC5883P is disabled, BMP580 don't work
  • If powered from battery and QMC5883P is physically removed, BMP580 works

JHEMCU G474ELRS - STM32G474CE MCU

  • If powered from USB,neither QMC5883P or BMP580 are detected.
  • If powered from battery, neither QMC5883P or BMP580 are detected.
  • If QMC5883P is disabled, BMP580 don't work
  • If BMP580 is disabled, QMC5883P works
  • If powered from USB and QMC5883P is phisicaly removed, BMP580 works
  • If powered from battery and QMC5883P is phisicaly removed, BMP580 works

I will use it on my quad builds, when I don't need compass.

@gintaris

Copy link
Copy Markdown
Contributor Author

JHEMCU F435 NEO

One thing is clear, they block each other under certain conditions. Your tests confirm this.
Several options are possible:

  1. Bad cable connections.
  2. Bad power supply circuit design in either the BMP580 or QMC5883P module.
  3. Noisy power supply circuit in the FC itself, so in one case both work when connected via USB.
  4. Pull-up resistors on the I2C line are too weak

In my case, the BMP580 driver I tested was also connected to the same I2C bus with INA226 and MMC5603, both when connected via USB and/or from the battery, all sensors work perfectly.
Tested with Madflight FC3 v2

@senjabl

senjabl commented Feb 23, 2026 •

Copy link
Copy Markdown

You were right.
QMC5883P have 2.2 K pullups and BMP580 have 4.7K.
Wired to FC I measured around 1.3K on SCL and SDA.

I removed two pullup resistors from QMC5883 and everything works on USB and battery on both FCs.
20260223_183258

Thank you for hint. I learned something today.

BTW. My BMP280 modules have 10K pullups. That was why they worked.

@haslinghuis
haslinghuis merged commit a433da0 into betaflight:master Feb 27, 2026
34 checks passed
@github-project-automation github-project-automation Bot moved this from Hardware to Done in 2026.6.0 Feb 27, 2026
x4FF3 pushed a commit to openwch/betaflight that referenced this pull request Apr 7, 2026
* feat(driver): add BMP580/BMP581 barometer driver

Add support for Bosch BMP580/BMP581 next-gen barometer:
- New driver barometer_bmp580.c/h with I2C protocol
- 128X oversampling for pressure (lowest noise)
- 4X oversampling for temperature
- IIR filter coefficient 4
- Normal power mode continuous measurement
- Compatible with BMP580 and BMP581 variants

Specifications:
- Pressure range: 300-1250 hPa
- Relative accuracy: ±0.06 hPa (±0.5m)
- Temperature range: -40 to +85°C
- I2C address: 0x46 or 0x47

Tested on RP2350B (Raspberry Pi Pico 2) at I2C address 0x47.

* Rename BMP580 driver to BMP5xx for sensor family support

Refactor naming to support future BMP5xx series devices (BMP580, BMP581,
BMP582, etc.) similar to existing ICM426xx and QMC5883 driver naming
conventions.

Changes:
- Rename barometer_bmp580.c/h → barometer_bmp5xx.c/h
- Rename USE_BARO_BMP580 → USE_BARO_BMP5XX
- Rename USE_BARO_SPI_BMP580 → USE_BARO_SPI_BMP5XX
- Rename BARO_BMP580 enum → BARO_BMP5XX
- Update CLI baro_hardware setting from BMP580 to BMP5XX
- Preserve specific chip ID detection (BMP580_CHIP_ID, BMP581_CHIP_ID)

Suggested-by: haslinghuis

* Add BMP580 and BMP581 as separate barometer types

- Add BARO_BMP580 (12) and BARO_BMP581 (13) to baroSensor_e enum
- Add BMP580, BMP581 entries to lookupTableBaroHardware
- Modify bmp5xxDetect() to return detected chip ID via parameter
- Barometer detection now reports specific model (BMP580/BMP581)
- Bump PG version to 5 for enum changes (BARO_VIRTUAL now 14)

This allows users to see the exact sensor model in status/setup tabs.
Auto-detection with BMP5XX still works and resolves to specific type.

Requested-by: haslinghuis

* BMP5xx: Address haslinghuis review comments

- Remove BMP5XX from settings.c lookup table (keep BMP580/BMP581)
- Use specific USE_BARO_BMP580/BMP581 defines instead of BMP5XX
- Change unknown chip fallback to BARO_NONE instead of BARO_BMP5XX
- Keep PG version at 4 (BMP580=13, BMP581=14 as new high values)
- Keep BARO_BMP5XX=11 in enum for backward compat (deprecated)

* BMP5xx: Remove BARO_BMP5XX enum, keep VIRTUAL last

- Remove deprecated BARO_BMP5XX from enum (use BMP580/BMP581 directly)
- BMP580=11, BMP581=12, VIRTUAL=13 (VIRTUAL always last per haslinghuis)
- Update all USE_BARO_BMP5XX references to USE_BARO_BMP580/BMP581
- Keep PG version 4 (old VIRTUAL=11 configs reset to auto-detect)

* Temporarily use official config submodule for CI

Config PR pending: https://github.com/betaflight/config (MADFLIGHT_FC3 sensors)

* BMP5xx: Keep PG version 3 (no version bump needed)
holydust added a commit to holydust/betaflight that referenced this pull request Jun 10, 2026
Adds BMP581 (also BMP580) support for the CORVON 743V2 board.

Source: a433da0 'Feature/bmp580 barometer (betaflight#14925)' (gintaris) on master.
Manually adapted to apply on tag 2025.12.2 — the upstream patch's
barometer.h / settings.c context lines depend on a later
BARO_HARDWARE_COUNT enum addition and a settings.c reorganisation
that aren't in this maintenance line, so the patch was reduced to
the BMP5xx-specific changes and applied by hand.

Deviation from upstream PR betaflight#14925: Bosch BMP581 silicon ships with
chip ID 0x50 (primary rev) or 0x51 (secondary rev) — both are the
same BMP581 product (PX4's bmp581.h documents this as
BMP581_CHIP_ID_PRIM and _SEC, both treated as BMP581). The upstream
case block split 0x50 into BARO_BMP580 and 0x51 into BARO_BMP581
as if they were distinct products, which misidentifies common
BMP581 silicon as BMP580. Aligned with PX4: both detected IDs
report as BARO_BMP581.

Files:
  - src/main/drivers/barometer/barometer_bmp5xx.{c,h}: new driver
  - src/main/sensors/barometer.h: add BARO_BMP580=11 / BMP581=12,
    renumber BARO_VIRTUAL=13
  - src/main/cli/settings.c: extend lookupTableBaroHardware with
    BMP580 / BMP581 entries
  - src/main/sensors/barometer.c: add include, extend pgReset elif
    chain and the no-baro UNUSED guard, and add a BARO_BMP580 /
    BARO_BMP581 case that calls bmp5xxDetect and reports both
    0x50 and 0x51 chip IDs as BMP581 (per PX4)
  - mk/source.mk: include barometer_bmp5xx.c in COMMON_SRC

Original SPI_BMP388 fix from the upstream PR is intentionally
dropped — out of scope for this backport.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants