diff --git a/apps/barometer/CMakeLists.txt b/apps/barometer/CMakeLists.txt index e5c50a9..8cb5a93 100644 --- a/apps/barometer/CMakeLists.txt +++ b/apps/barometer/CMakeLists.txt @@ -4,7 +4,7 @@ project(pico-barometer) add_executable(barometer test.c) -target_link_libraries(barometer LINK_PUBLIC bmp180) +target_link_libraries(barometer LINK_PUBLIC bmp390) pico_add_extra_outputs(barometer) diff --git a/apps/barometer/test.c b/apps/barometer/test.c index 7a5b366..af8b388 100644 --- a/apps/barometer/test.c +++ b/apps/barometer/test.c @@ -1,21 +1,20 @@ #include #define DEBUG -#include "bmp180.h" +#include "bmp390.h" int main() { stdio_init_all(); - - getchar(); + sleep_ms(5000); printf("Hello from Pi Pico!\n"); bmp_t bmp; - bmp.oss = 0; + bmp.oss = 5; bmp.i2c.addr = 0x77; bmp.i2c.inst = i2c1; bmp.i2c.rate = 400000; - bmp.i2c.scl = 27; - bmp.i2c.sda = 26; + bmp.i2c.scl = 3; + bmp.i2c.sda = 2; if (!bmp_init(&bmp)) return 1; @@ -23,9 +22,10 @@ int main() { while (true) { if (!bmp_get_pressure_temperature(&bmp)) return 1; - printf("BMP180 Temperature (C): %f\n", bmp.temperature); - printf("BMP180 Pressure (hPa): %f\n", (float)bmp.pressure / 100.0); - sleep_ms(250); + printf("---------------------------------------------\n"); + printf("Temperature (ÂșC): %f\n", bmp.temperature); + printf("Pressure (hPa): %f\n", bmp.pressure); + printf("Altitude (m): %f\n", bmp.altitude); } printf("Bye from pico!\n\n"); diff --git a/lib/bmp180/bmp180.h b/lib/bmp180/bmp180.h index 3cf62e3..141045a 100644 --- a/lib/bmp180/bmp180.h +++ b/lib/bmp180/bmp180.h @@ -49,6 +49,7 @@ typedef struct { uint8_t oss; float temperature; int32_t pressure; + float altitude; bmp_calib_param_t calib; int32_t B5; } bmp_t; diff --git a/lib/bmp390/bmp390.h b/lib/bmp390/bmp390.h index 6926a8b..fb189fb 100644 --- a/lib/bmp390/bmp390.h +++ b/lib/bmp390/bmp390.h @@ -1,6 +1,7 @@ #ifndef BMP390_H #define BMP390_H +#include #include #include @@ -8,34 +9,55 @@ #include "pico/stdlib.h" #include "hardware/i2c.h" -#define BMP_REG_CONTROL 0xF4 -#define BMP_REG_RESULT 0xF6 -#define BMP_COM_TEMP 0x2E -#define BMP_COM_PRES 0x34 -#define BMP_CALIB_COEFF_LEN 0x16 -#define BMP_CALIB_COEFF_REG 0xAA -#define BMP_CHIP_ID_REG 0xD0 -#define BMP_CHIP_ID_VAL 0x55 -#define BMP_MIN_TEMP_THRESHOLD -40 -#define BMP_MAX_TEMP_THRESHOLD +85 -#define BMP_TEMP_DELAY 5 +#define BMP_RESET_REG 0x7E +#define BMP_RESET_VAL 0xB6 +#define BMP_SENSOR_ID_REG 0x00 +#define BMP_SENSOR_ID_VAL 0x60 +#define BMP_OSR_REG 0x1C +#define BMP_CAL_REG 0x31 +#define BMP_CAL_LEN 0x15 +#define BMP_TEMPERATURE_REG 0x07 +#define BMP_PRESSURE_REG 0x04 +#define BMP_MODE_REG 0x1B +#define BMP_MODE_VAL 0x13 // Forced Mode, Temp Enable, Pressure Enable +#define BMP_STATUS_REG 0x03 #define ASSERT_OK(X) { if (X == false) return false; }; typedef struct { - int16_t AC1; - int16_t AC2; - int16_t AC3; - uint16_t AC4; - uint16_t AC5; - uint16_t AC6; - int16_t B1; - int16_t B2; - int16_t MB; - int16_t MC; - int16_t MD; + uint16_t T1; + uint16_t T2; + int8_t T3; + int16_t P1; + int16_t P2; + int8_t P3; + int8_t P4; + uint16_t P5; + uint16_t P6; + int8_t P7; + int8_t P8; + int16_t P9; + int8_t P10; + int8_t P11; } bmp_calib_param_t; +typedef struct { + double T1; + double T2; + double T3; + double P1; + double P2; + double P3; + double P4; + double P5; + double P6; + double P7; + double P8; + double P9; + double P10; + double P11; +} bmp_calib_part_param_t; + typedef struct { int addr; int rate; @@ -48,21 +70,37 @@ typedef struct { i2c_t i2c; uint8_t oss; float temperature; - int32_t pressure; + float pressure; + float altitude; bmp_calib_param_t calib; - int32_t B5; + bmp_calib_part_param_t calib_part; } bmp_t; -const uint32_t oss_delay[] = {5, 8, 14, 26}; +bool bmp_reset(bmp_t* bmp) { + uint8_t data_buffer[] = { + BMP_RESET_REG, + BMP_RESET_VAL + }; + + i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, data_buffer, 2, false); + +#ifdef DEBUG + printf("INFO: Successfully reset sensor.\n"); +#endif + + sleep_ms(10); + + return true; +} bool bmp_check_chip_id(bmp_t* bmp) { - uint8_t chip_id_reg = BMP_CHIP_ID_REG; + uint8_t chip_id_reg = BMP_SENSOR_ID_REG; uint8_t chip_id_val[1]; i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &chip_id_reg, 1, true); i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, chip_id_val, 1, false); - if (chip_id_val[0] != BMP_CHIP_ID_VAL) { + if (chip_id_val[0] != BMP_SENSOR_ID_VAL) { #ifdef DEBUG printf("Returned Chip ID: 0x%02x\n", chip_id_val[0]); printf("Check your I2C configuration and connection.\n"); @@ -70,171 +108,192 @@ bool bmp_check_chip_id(bmp_t* bmp) { return false; } +#ifdef DEBUG + printf("INFO: Successfully checked the Chip ID.\n"); +#endif + return true; } +bool bmp_set_oversampling_rate(bmp_t* bmp) { + uint8_t data_buffer[] = { + BMP_OSR_REG, + (bmp->oss << 3) | (bmp->oss << 0) + }; + + i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, data_buffer, 2, false); + +#ifdef DEBUG + printf("INFO: Successfully configured oversampling rate.\n"); +#endif + + return true; +} bool bmp_get_calib_coeffs(bmp_t* bmp) { - uint8_t calib_coeffs_reg = BMP_CALIB_COEFF_REG; - uint8_t calib_coeffs_val[BMP_CALIB_COEFF_LEN]; + uint8_t calib_coeffs_reg = BMP_CAL_REG; + uint8_t calib_coeffs_val[BMP_CAL_LEN]; i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &calib_coeffs_reg, 1, true); - i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, calib_coeffs_val, BMP_CALIB_COEFF_LEN, false); + i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, calib_coeffs_val, BMP_CAL_LEN, false); - int16_t* data = (int16_t*)&bmp->calib; - for (int i = 0, j = 1; i < BMP_CALIB_COEFF_LEN / 2; i++, j += 2) { - data[i] = (calib_coeffs_val[i * 2] << 8) | calib_coeffs_val[j]; + bmp->calib.T1 = (calib_coeffs_val[1] << 8) | calib_coeffs_val[0]; + bmp->calib.T2 = (calib_coeffs_val[3] << 8) | calib_coeffs_val[2]; + bmp->calib.T3 = calib_coeffs_val[4]; + bmp->calib.P1 = (calib_coeffs_val[6] << 8) | calib_coeffs_val[5]; + bmp->calib.P2 = (calib_coeffs_val[8] << 8) | calib_coeffs_val[7]; + bmp->calib.P3 = calib_coeffs_val[9]; + bmp->calib.P4 = calib_coeffs_val[10]; + bmp->calib.P5 = (calib_coeffs_val[12] << 8) | calib_coeffs_val[11]; + bmp->calib.P6 = (calib_coeffs_val[14] << 8) | calib_coeffs_val[13]; + bmp->calib.P7 = calib_coeffs_val[15]; + bmp->calib.P8 = calib_coeffs_val[16]; + bmp->calib.P9 = (calib_coeffs_val[18] << 8) | calib_coeffs_val[17]; + bmp->calib.P10 = calib_coeffs_val[19]; + bmp->calib.P11 = calib_coeffs_val[20]; - if ((data[i] == 0) | (data[i] == -1)) { -#ifdef DEBUG - printf("Calibation data invalid.\n"); -#endif - return false; - } - } + bmp->calib_part.T1 = (double)bmp->calib.T1 / pow(2, -8.0); + bmp->calib_part.T2 = (double)bmp->calib.T2 / pow(2, 30.0); + bmp->calib_part.T3 = (double)bmp->calib.T3 / pow(2, 48.0); + + bmp->calib_part.P1 = ((double)bmp->calib.P1 - pow(2, 14.0)) / pow(2, 20.0); + bmp->calib_part.P2 = ((double)bmp->calib.P2 - pow(2, 14.0)) / pow(2, 29.0); + bmp->calib_part.P3 = (double)bmp->calib.P3 / pow(2, 32.0); + bmp->calib_part.P4 = (double)bmp->calib.P4 / pow(2, 37.0); + bmp->calib_part.P5 = (double)bmp->calib.P5 / pow(2, -3.0); + bmp->calib_part.P6 = (double)bmp->calib.P6 / pow(2, 6.0); + bmp->calib_part.P7 = (double)bmp->calib.P7 / pow(2, 8.0); + bmp->calib_part.P8 = (double)bmp->calib.P8 / pow(2, 15.0); + bmp->calib_part.P9 = (double)bmp->calib.P9 / pow(2, 48.0); + bmp->calib_part.P10 = (double)bmp->calib.P10 / pow(2, 48.0); + bmp->calib_part.P11 = (double)bmp->calib.P11 / pow(2.0, 65.0); #ifdef DEBUG printf("==== CALIBRATION COEFFS ====\n"); - printf("AC1: %d\n", bmp->calib.AC1); - printf("AC2: %d\n", bmp->calib.AC2); - printf("AC3: %d\n", bmp->calib.AC3); - printf("AC4: %d\n", bmp->calib.AC4); - printf("AC5: %d\n", bmp->calib.AC5); - printf("AC6: %d\n", bmp->calib.AC6); - printf("B1: %d\n", bmp->calib.B1); - printf("B2: %d\n", bmp->calib.B2); - printf("MB: %d\n", bmp->calib.MB); - printf("MC: %d\n", bmp->calib.MC); - printf("MD: %d\n", bmp->calib.MD); + printf("T1: %lf\n", bmp->calib_part.T1); + printf("T2: %lf\n", bmp->calib_part.T2); + printf("T3: %lf\n", bmp->calib_part.T3); + printf("P1: %lf\n", bmp->calib_part.P1); + printf("P2: %lf\n", bmp->calib_part.P2); + printf("P3: %lf\n", bmp->calib_part.P3); + printf("P4: %lf\n", bmp->calib_part.P4); + printf("P5: %lf\n", bmp->calib_part.P5); + printf("P6: %lf\n", bmp->calib_part.P6); + printf("P7: %lf\n", bmp->calib_part.P7); + printf("P8: %lf\n", bmp->calib_part.P8); + printf("P9: %lf\n", bmp->calib_part.P9); + printf("P10: %lf\n", bmp->calib_part.P10); + printf("P11: %lf\n", bmp->calib_part.P11); printf("============================\n"); #endif return true; } -uint32_t bmp_start_temperature(bmp_t* bmp) { - uint8_t temp_reg[] = { - BMP_REG_CONTROL, - BMP_COM_TEMP - }; - i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, temp_reg, 2, false); - return BMP_TEMP_DELAY; -} - -bool bmp_read_temperature(bmp_t* bmp) { - uint8_t temp_reg = BMP_REG_RESULT; - uint8_t temp_val[2]; +bool bmp_read_uncalibrated_temperature(bmp_t* bmp) { + uint8_t temp_reg = BMP_TEMPERATURE_REG; + uint8_t temp_val[3]; i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &temp_reg, 1, true); - if (i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, temp_val, 2, false) != 2) { -#ifdef DEBUG - printf("Wrong read length.\n"); -#endif - return false; - } + i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, temp_val, 3, false); - int16_t UT = (temp_val[0] << 8) + temp_val[1]; - - if (UT == (int16_t)0x8000) { -#ifdef DEBUG - printf("Non-initialized register detected.\n"); -#endif - return false; - } - - int32_t X1 = (((int32_t)UT - bmp->calib.AC6) * bmp->calib.AC5) >> 15; - int32_t X2 = (bmp->calib.MC << 11) / (X1 + bmp->calib.MD); - bmp->B5 = X1 + X2; - float temp = ((bmp->B5 + 8) >> 4) * 0.1f; - - if ((temp <= BMP_MIN_TEMP_THRESHOLD) || (temp >= BMP_MAX_TEMP_THRESHOLD)) { -#ifdef DEBUG - printf("Temperature beyond threshold: %f\n", temp); -#endif - return false; - } - - bmp->temperature = temp; + bmp->temperature = (temp_val[2] << 16) | (temp_val[1] << 8) | temp_val[0]; return true; } -uint32_t bmp_start_pressure(bmp_t* bmp) { - uint8_t pres_reg[] = { - BMP_REG_CONTROL, - BMP_COM_PRES + (bmp->oss << 6) - }; - i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, pres_reg, 2, false); - return oss_delay[bmp->oss]; -} - -bool bmp_read_pressure(bmp_t* bmp) { - uint8_t pres_reg = BMP_REG_RESULT; +bool bmp_read_uncalibrated_pressure(bmp_t* bmp) { + uint8_t pres_reg = BMP_PRESSURE_REG; uint8_t pres_val[3]; i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &pres_reg, 1, true); - if (i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, pres_val, 3, false) != 3) { -#ifdef DEBUG - printf("Wrong read length.\n"); -#endif - return false; - } + i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, pres_val, 3, false); - int32_t UP = ((pres_val[0] << 16) + (pres_val[1] << 8) + pres_val[2]) >> (8 - bmp->oss); + bmp->pressure = (pres_val[2] << 16) | (pres_val[1] << 8) | pres_val[0]; - int32_t X1, X2, X3, B3, B6, p = 0; - uint32_t B4, B7 = 0; + return true; - B6 = bmp->B5 - 4000; - X1 = (bmp->calib.B2 * ((B6 * B6) >> 12)) >> 11; - X2 = (bmp->calib.AC2 * B6) >> 11; - X3 = X1 + X2; - B3 = (((bmp->calib.AC1 * 4 + X3) << bmp->oss) + 2) / 4; - X1 = (bmp->calib.AC3 * B6) >> 13; - X2 = (bmp->calib.B1 * ((B6 * B6) >> 12)) >> 16; - X3 = ((X1 + X2) + 2) >> 2; - B4 = (bmp->calib.AC4 * (uint32_t)(X3 + 32768)) >> 15; - B7 = ((uint32_t)(UP) - B3) * (50000 >> bmp->oss); +} - if (B7 < 0x80000000) { - p = (B7 * 2) / B4; - } else { - p = (B7 / B4) * 2; - } - - X1 = (p >> 8) * (p >> 8); - X1 = (X1 * 3038) >> 16; - X2 = (-7357 * p) >> 16; - - bmp->pressure = p + ((X1 + X2 + 3791) >> 4); +bool bmp_calibrate_temperature(bmp_t* bmp) { + double par1 = bmp->temperature - bmp->calib_part.T1; + double par2 = par1 * bmp->calib_part.T2; + bmp->temperature = par2 + (par1 * par1) * bmp->calib_part.T3; return true; } -bool bmp_get_temperature(bmp_t* bmp) { - sleep_ms(bmp_start_temperature(bmp)); - return bmp_read_temperature(bmp); +bool bmp_calibrate_pressure(bmp_t* bmp) { + double out1, out2, out3; + + { + double par1 = bmp->calib_part.P6 * bmp->temperature; + double par2 = bmp->calib_part.P7 * pow(bmp->temperature, 2.0); + double par3 = bmp->calib_part.P8 * pow(bmp->temperature, 3.0); + out1 = bmp->calib_part.P5 + par1 + par2 + par3; + } + + { + double par1 = bmp->calib_part.P2 * bmp->temperature; + double par2 = bmp->calib_part.P3 * pow(bmp->temperature, 2.0); + double par3 = bmp->calib_part.P4 * pow(bmp->temperature, 3.0); + out2 = bmp->pressure * (bmp->calib_part.P1 + par1 + par2 + par3); + } + + { + double par1 = pow(bmp->pressure, 2.0); + double par2 = bmp->calib_part.P9 + bmp->calib_part.P10 * bmp->temperature; + double par3 = par1 * par2; + out3 = par3 + bmp->calib_part.P11 * pow(bmp->pressure, 3); + } + + bmp->pressure = (out1 + out2 + out3) / 100.0; + + return true; } -// User must call bmp_get_temperature() before calling this method. -// Or use the combo bmp_get_pressure_temperature(). -bool bmp_get_pressure(bmp_t* bmp) { - sleep_ms(bmp_start_pressure(bmp)); - return bmp_read_pressure(bmp); +bool bmp_calculate_altitude(bmp_t* bmp) { + bmp->altitude = ((pow((1013.25 / bmp->pressure), (1/5.257)) - 1) * (bmp->temperature + 273.15)) / 0.0065; + + return true; } bool bmp_get_pressure_temperature(bmp_t* bmp) { bool res = true; - res &= bmp_get_temperature(bmp); - res &= bmp_get_pressure(bmp); + + { + uint8_t data_buffer[] = { + BMP_MODE_REG, + BMP_MODE_VAL + }; + + i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, data_buffer, 2, false); + } + + { + uint8_t status = 0x00; + while ((status & 0x60) != 0x60) { + uint8_t status_reg = BMP_STATUS_REG; + i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &status_reg, 1, true); + i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, &status, 1, false); + sleep_ms(1); + } + } + + res &= bmp_read_uncalibrated_temperature(bmp); + res &= bmp_read_uncalibrated_pressure(bmp); + res &= bmp_calibrate_temperature(bmp); + res &= bmp_calibrate_pressure(bmp); + res &= bmp_calculate_altitude(bmp); + return res; } bool bmp_init(bmp_t* bmp) { i2c_init(bmp->i2c.inst, bmp->i2c.rate); - if (bmp->oss < 0 || bmp->oss > 3) { + if (bmp->oss < 0 || bmp->oss > 5) { #ifdef DEBUG - printf("Invalid over-sampling rate (%d). Valid 0 to 3.\n", bmp->oss); + printf("Invalid over-sampling rate (%d). Valid 0 to 5.\n", bmp->oss); #endif return false; } @@ -246,10 +305,20 @@ bool bmp_init(bmp_t* bmp) { sleep_ms(100); + ASSERT_OK(bmp_reset(bmp)); ASSERT_OK(bmp_check_chip_id(bmp)); + ASSERT_OK(bmp_set_oversampling_rate(bmp)); ASSERT_OK(bmp_get_calib_coeffs(bmp)); return true; } +bool bmp_get_temperature(bmp_t* bmp) { + return false; +} + +bool bmp_get_pressure(bmp_t* bmp) { + return false; +} + #endif