// BMP280 compensation maths — pure logic. See bmp280_compensate.h. #include "bmp280_compensate.h" static int16_t s16(uint8_t lsb, uint8_t msb) { return (int16_t)((uint16_t)msb << 8 | lsb); } static uint16_t u16(uint8_t lsb, uint8_t msb) { return (uint16_t)((uint16_t)msb << 8 | lsb); } void bmp280_calib_from_regs(const uint8_t buf[BMP280_CALIB_LEN], bmp280_calib_t *out) { if (buf == NULL || out == NULL) { return; } out->dig_T1 = u16(buf[0], buf[1]); out->dig_T2 = s16(buf[2], buf[3]); out->dig_T3 = s16(buf[4], buf[5]); out->dig_P1 = u16(buf[6], buf[7]); out->dig_P2 = s16(buf[8], buf[9]); out->dig_P3 = s16(buf[10], buf[11]); out->dig_P4 = s16(buf[12], buf[13]); out->dig_P5 = s16(buf[14], buf[15]); out->dig_P6 = s16(buf[16], buf[17]); out->dig_P7 = s16(buf[18], buf[19]); out->dig_P8 = s16(buf[20], buf[21]); out->dig_P9 = s16(buf[22], buf[23]); } void bmp280_adc_from_regs(const uint8_t raw[BMP280_RAW_LEN], int32_t *out_adc_P, int32_t *out_adc_T) { if (raw == NULL || out_adc_P == NULL || out_adc_T == NULL) { return; } *out_adc_P = ((int32_t)raw[0] << 12) | ((int32_t)raw[1] << 4) | (raw[2] >> 4); *out_adc_T = ((int32_t)raw[3] << 12) | ((int32_t)raw[4] << 4) | (raw[5] >> 4); } // Bosch datasheet 3.11.3 double-precision reference compensation formulas, // transcribed near-verbatim (variable names kept close to the original so // it's checkable against the datasheet PDF side-by-side). double bmp280_compensate_temperature(const bmp280_calib_t *c, int32_t adc_T, double *out_t_fine) { double var1 = (((double)adc_T) / 16384.0 - ((double)c->dig_T1) / 1024.0) * ((double)c->dig_T2); double var2 = ((((double)adc_T) / 131072.0 - ((double)c->dig_T1) / 8192.0) * (((double)adc_T) / 131072.0 - ((double)c->dig_T1) / 8192.0)) * ((double)c->dig_T3); *out_t_fine = var1 + var2; return (var1 + var2) / 5120.0; // degrees C } double bmp280_compensate_pressure(const bmp280_calib_t *c, int32_t adc_P, double t_fine) { double var1 = (t_fine / 2.0) - 64000.0; double var2 = var1 * var1 * ((double)c->dig_P6) / 32768.0; var2 = var2 + var1 * ((double)c->dig_P5) * 2.0; var2 = (var2 / 4.0) + (((double)c->dig_P4) * 65536.0); var1 = (((double)c->dig_P3) * var1 * var1 / 524288.0 + ((double)c->dig_P2) * var1) / 524288.0; var1 = (1.0 + var1 / 32768.0) * ((double)c->dig_P1); if (var1 == 0.0) { return 0.0; // avoid divide-by-zero per datasheet's own guard } double p = 1048576.0 - (double)adc_P; p = (p - (var2 / 4096.0)) * 6250.0 / var1; var1 = ((double)c->dig_P9) * p * p / 2147483648.0; var2 = p * ((double)c->dig_P8) / 32768.0; p = p + (var1 + var2 + ((double)c->dig_P7)) / 16.0; return p; // Pa }