// Bosch BMP280 compensation maths + calibration/ADC decoding — PURE LOGIC. // // ESP-IDF-free by design: no I2C, no esp_err_t, no FreeRTOS, no logging. // Only /, so it compiles and is testable on a host // with plain gcc (see ../test/). `bmp280.c` does the I2C traffic and calls // in here for every byte-order decision and every line of arithmetic. // // The formulas are Bosch datasheet (rev 1.23) §3.11.3's double-precision // reference implementation, transcribed near-verbatim, with the variable // names kept close to the original so it's checkable against the datasheet // PDF side-by-side. The register map decoded below is §3.11.1. // // What host tests can prove here: byte-order/packing of the calibration // block and the 20-bit ADC words, and that the arithmetic behaves // sanely and monotonically. What they CANNOT prove: that this exact // silicon returns the register contents we assume. #pragma once #include #include #ifdef __cplusplus extern "C" { #endif // Calibration block is 24 bytes at 0x88..0x9F (dig_T1..dig_P9). #define BMP280_CALIB_LEN 24 // Burst measurement read is 6 bytes from 0xF7: press(3) + temp(3). #define BMP280_RAW_LEN 6 typedef struct { uint16_t dig_T1; int16_t dig_T2; int16_t dig_T3; uint16_t dig_P1; int16_t dig_P2; int16_t dig_P3; int16_t dig_P4; int16_t dig_P5; int16_t dig_P6; int16_t dig_P7; int16_t dig_P8; int16_t dig_P9; } bmp280_calib_t; // Decode the 24-byte calibration block. Each coefficient is stored // little-endian (LSB first) in the register map. void bmp280_calib_from_regs(const uint8_t buf[BMP280_CALIB_LEN], bmp280_calib_t *out); // Decode the 6-byte burst read into the two 20-bit ADC words. Pressure // comes first (0xF7..0xF9), then temperature (0xFA..0xFC); each is // MSB/LSB/XLSB with the XLSB's top nibble carrying the low 4 bits. void bmp280_adc_from_regs(const uint8_t raw[BMP280_RAW_LEN], int32_t *out_adc_P, int32_t *out_adc_T); // Returns degrees C, and writes the shared `t_fine` intermediate that the // pressure compensation needs. double bmp280_compensate_temperature(const bmp280_calib_t *c, int32_t adc_T, double *out_t_fine); // Returns Pa. Returns exactly 0.0 when the datasheet's own divide-by-zero // guard trips (var1 == 0, i.e. an all-zero / unread calibration block). double bmp280_compensate_pressure(const bmp280_calib_t *c, int32_t adc_P, double t_fine); #ifdef __cplusplus } #endif