/* * bmp280.c — BMP280/BME280 barometer driver (I2C1, shared bus) * * Probes 0x76 first, then 0x77. Requires i2c1_init() before bmp280_init(). * Returns chip_id on success (0x58=BMP280, 0x60=BME280), negative if absent. */ #include "bmp280.h" #include "i2c1.h" #include /* Shift I2C address for HAL (7-bit left-shifted) */ static uint16_t s_addr; /* Calibration data */ static uint16_t dig_T1; static int16_t dig_T2, dig_T3; static uint16_t dig_P1; static int16_t dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9; static int32_t t_fine; static uint8_t i2c_read(uint8_t reg) { uint8_t val = 0; HAL_I2C_Mem_Read(&hi2c1, s_addr, reg, 1, &val, 1, 100); return val; } static void i2c_read_burst(uint8_t reg, uint8_t *buf, uint8_t len) { HAL_I2C_Mem_Read(&hi2c1, s_addr, reg, 1, buf, len, 100); } static void i2c_write(uint8_t reg, uint8_t val) { HAL_I2C_Mem_Write(&hi2c1, s_addr, reg, 1, &val, 1, 100); } static int try_init(uint16_t addr) { s_addr = addr; uint8_t id = i2c_read(0xD0); if (id != 0x58 && id != 0x60) return -(int)id; /* Read calibration */ uint8_t cal[26]; i2c_read_burst(0x88, cal, 26); dig_T1 = (uint16_t)(cal[1] << 8 | cal[0]); dig_T2 = (int16_t) (cal[3] << 8 | cal[2]); dig_T3 = (int16_t) (cal[5] << 8 | cal[4]); dig_P1 = (uint16_t)(cal[7] << 8 | cal[6]); dig_P2 = (int16_t) (cal[9] << 8 | cal[8]); dig_P3 = (int16_t) (cal[11] << 8 | cal[10]); dig_P4 = (int16_t) (cal[13] << 8 | cal[12]); dig_P5 = (int16_t) (cal[15] << 8 | cal[14]); dig_P6 = (int16_t) (cal[17] << 8 | cal[16]); dig_P7 = (int16_t) (cal[19] << 8 | cal[18]); dig_P8 = (int16_t) (cal[21] << 8 | cal[20]); dig_P9 = (int16_t) (cal[23] << 8 | cal[22]); /* Normal mode, ×16 oversampling temp+press, 0.5 ms standby */ i2c_write(0xF5, 0x00); /* config: standby=0.5ms, filter=off */ i2c_write(0xF4, 0xB7); /* ctrl_meas: osrs_t=×16, osrs_p=×16, normal mode */ return (int)id; } int bmp280_init(void) { int ret = try_init(0x76 << 1); if (ret > 0) return ret; return try_init(0x77 << 1); } void bmp280_read(int32_t *pressure_pa, int16_t *temp_x10) { uint8_t buf[6]; i2c_read_burst(0xF7, buf, 6); int32_t adc_P = (int32_t)((buf[0] << 12) | (buf[1] << 4) | (buf[2] >> 4)); int32_t adc_T = (int32_t)((buf[3] << 12) | (buf[4] << 4) | (buf[5] >> 4)); /* Temperature compensation (BMP280 datasheet Section 4.2.3) */ int32_t v1 = ((((adc_T >> 3) - ((int32_t)dig_T1 << 1))) * ((int32_t)dig_T2)) >> 11; int32_t v2 = (((((adc_T >> 4) - (int32_t)dig_T1) * ((adc_T >> 4) - (int32_t)dig_T1)) >> 12) * (int32_t)dig_T3) >> 14; t_fine = v1 + v2; *temp_x10 = (int16_t)((t_fine * 5 + 128) >> 8); /* 0.1 °C */ /* Pressure compensation */ int64_t p1 = ((int64_t)t_fine) - 128000; int64_t p2 = p1 * p1 * (int64_t)dig_P6; p2 += (p1 * (int64_t)dig_P5) << 17; p2 += ((int64_t)dig_P4) << 35; p1 = ((p1 * p1 * (int64_t)dig_P3) >> 8) + ((p1 * (int64_t)dig_P2) << 12); p1 = ((((int64_t)1 << 47) + p1)) * ((int64_t)dig_P1) >> 33; if (p1 == 0) { *pressure_pa = 0; return; } int64_t p = 1048576 - adc_P; p = (((p << 31) - p2) * 3125) / p1; p1 = ((int64_t)dig_P9 * (p >> 13) * (p >> 13)) >> 25; p2 = ((int64_t)dig_P8 * p) >> 19; *pressure_pa = (int32_t)(((p + p1 + p2) >> 8) + ((int64_t)dig_P7 << 4)) / 256; } int32_t bmp280_pressure_to_alt_cm(int32_t pressure_pa) { /* Barometric formula: h = 44330 * (1 - (p/p0)^(1/5.255)) metres */ float ratio = (float)pressure_pa / 101325.0f; float alt_m = 44330.0f * (1.0f - powf(ratio, 0.1902949f)); return (int32_t)(alt_m * 100.0f); /* cm */ }