F439_CPP_BMP390_Barometric_Pressure_and_Altimeter_01 1.0
STM32F439 BMP390 barometric pressure and altimeter tutorial
Loading...
Searching...
No Matches
F439 BMP390 Barometric Pressure and Altimeter

A bare-metal (no RTOS) firmware for an STM32F439ZI that reads pressure and temperature from an Adafruit BMP390 breakout over I2C, using Bosch Sensortec's own BMP3 driver, and streams temperature, pressure, and a computed altitude over a debug UART.

Status: tabletop/breadboard prototype. No enclosure has been built, and distance/threshold-style tuning has not been attempted – see the "Altitude calibration" note below for the one location-dependent value that does need attention.

How it works

After clock and peripheral init, the main loop:

  1. Configures the BMP390 for continuous pressure + temperature sampling (2x oversampling on both, 25 Hz ODR, normal mode).
  2. Polls the sensor's data-ready status flag, and on ready reads compensated pressure (Pa) and temperature (degC) via bmp3_get_sensor_data().
  3. Converts temperature to degF, pressure to inHg, and computes altitude (ft) from pressure using the International Standard Atmosphere barometric formula.
  4. Prints all four values to the debug UART once per second – decoupled from the sensor's 25 Hz ODR via HAL_Delay() so the terminal output is readable without a screen capture – positioning the cursor so each reading overwrites the same line instead of scrolling.

Altitude calibration

Altitude is only as accurate as its sea-level pressure reference. By default SEA_LEVEL_PRESSURE_PA uses the fixed standard-atmosphere value (101325 Pa), which reads altitude relative to the standard atmosphere, not true elevation, since actual sea-level pressure drifts with the weather. Defining LOCAL_QNH_CALIBRATION (in Core/Src/main.c, inside USER CODE BEGIN PD so it survives .ioc regen) swaps in a value derived from a known reference elevation against this sensor's own readings on a given day – accurate at calibration time, but it will drift and need re-deriving the same way later.

Hardware

Peripheral Interface Pins Notes
BMP390 (Adafruit breakout) I2C1 PB8 (SCL) / PB9 (SDA) I2C address 0x77 (secondary, 7-bit); VIN powered at 5V via the breakout's onboard regulator
Debug console USART1 PA9 (TX) / PA10 (RX) 19200 baud, 8N1
Microsecond timer TIM1 1 MHz free-running counter; backs delayUS(), wired to the BMP3 driver's delay_us callback

MCU: STM32F439ZITx (LQFP144).

Firmware architecture

No RTOS – a single superloop in Core/Src/main.c:

  • BMP3 driver (BMP3/) – Bosch Sensortec's own vendored driver (bmp3.c/bmp3.h/bmp3_defs.h), BSD-3-Clause licensed, unmodified.
  • HAL glue layer (BMP3/common/) – maps the driver's I2C read/write/delay-us callbacks onto STM32 HAL calls (HAL_I2C_Mem_Read/Write, delayUS()).
  • Application code (Core/Src/main.c) – clock/peripheral init, BMP390 sensor configuration, and the read/convert/print loop.

Building

This is an STM32CubeIDE project, but it can also be built headlessly from the command line using CubeIDE's bundled ARM GCC toolchain:

cd Debug
TOOLCHAIN_BIN="/opt/st/stm32cubeide_1.18.1/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.13.3.rel1.linux64_1.0.0.202410170706/tools/bin"
export PATH="$TOOLCHAIN_BIN:$PATH"
make -j4 all

This produces F439_CPP_BMP390_Barometric_Pressure_and_Altimeter_01.elf. Grep the make output for warning:/error: to check a change compiles cleanly.

Debug output

Connect a serial terminal to USART1 at 19200 baud, 8N1. On boot, a successful BMP390 init prints its chip ID (0x60 for the BMP390), then each reading prints as:

T: 75.68 degF, P: 99862.10 Pa, 29.48 inHg, Alt: 401.32 ft

Contributing

No direct commits to master – branch, open a PR, and merge. Test changes on real hardware before committing; a clean compile alone isn't sufficient sign-off for this project.