ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
bmp3xx_base.cpp
Go to the documentation of this file.
1/*
2 based on BMP388_DEV by Martin Lindupp
3 under MIT License (MIT)
4 Copyright (C) Martin Lindupp 2020
5 http://github.com/MartinL1/BMP388_DEV
6*/
7
8#include "bmp3xx_base.h"
9#include "esphome/core/hal.h"
11#include "esphome/core/log.h"
13#include <cinttypes>
14
16
17ESPHOME_LOG_TAG(TAG, "bmp3xx.sensor");
18
19static constexpr uint32_t DATA_TIMEOUT_ID = 0;
20
21static const LogString *chip_type_to_str(uint8_t chip_type) {
22 switch (chip_type) {
23 case BMP388_ID:
24 return LOG_STR("BMP 388");
25 case BMP390_ID:
26 return LOG_STR("BMP 390");
27 default:
28 return LOG_STR("Unknown Chip Type");
29 }
30}
31
32// Oversampling strings indexed by Oversampling enum (0-5): NONE, X2, X4, X8, X16, X32
33PROGMEM_STRING_TABLE(OversamplingStrings, "None", "2x", "4x", "8x", "16x", "32x", "");
34
35static const LogString *oversampling_to_str(Oversampling oversampling) {
36 return OversamplingStrings::get_log_str(static_cast<uint8_t>(oversampling), OversamplingStrings::LAST_INDEX);
37}
38
39// IIR filter strings indexed by IIRFilter enum (0-7): OFF, 2, 4, 8, 16, 32, 64, 128
40PROGMEM_STRING_TABLE(IIRFilterStrings, "OFF", "2x", "4x", "8x", "16x", "32x", "64x", "128x", "");
41
42static const LogString *iir_filter_to_str(IIRFilter filter) {
43 return IIRFilterStrings::get_log_str(static_cast<uint8_t>(filter), IIRFilterStrings::LAST_INDEX);
44}
45
47 // Call the Device base class "initialise" function
48 if (!reset()) {
49 this->mark_failed(LOG_STR("Failed to reset"));
50 return;
51 }
52
53 if (!read_byte(BMP388_CHIP_ID, &this->chip_id_.reg)) {
54 this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
55 return;
56 }
57 ESP_LOGCONFIG(TAG, "Chip %s Id 0x%X", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg);
58
59 if (chip_id_.reg != BMP388_ID && chip_id_.reg != BMP390_ID) {
60 this->mark_failed(LOG_STR("Wrong chip ID - please check if you are really using a BMP 388 or BMP 390"));
61 return;
62 }
63 // set sensor in sleep mode
65 // Read the calibration parameters into the params structure
66 if (!read_bytes(BMP388_TRIM_PARAMS, (uint8_t *) &compensation_params_, sizeof(compensation_params_))) {
67 this->mark_failed(LOG_STR("Can't read calibration data"));
68 return;
69 }
71 (float) compensation_params_.param_T1 / powf(2.0f, -8.0f); // Calculate the floating point trim parameters
72 compensation_float_params_.param_T2 = (float) compensation_params_.param_T2 / powf(2.0f, 30.0f);
73 compensation_float_params_.param_T3 = (float) compensation_params_.param_T3 / powf(2.0f, 48.0f);
74 compensation_float_params_.param_P1 = ((float) compensation_params_.param_P1 - powf(2.0f, 14.0f)) / powf(2.0f, 20.0f);
75 compensation_float_params_.param_P2 = ((float) compensation_params_.param_P2 - powf(2.0f, 14.0f)) / powf(2.0f, 29.0f);
76 compensation_float_params_.param_P3 = (float) compensation_params_.param_P3 / powf(2.0f, 32.0f);
77 compensation_float_params_.param_P4 = (float) compensation_params_.param_P4 / powf(2.0f, 37.0f);
78 compensation_float_params_.param_P5 = (float) compensation_params_.param_P5 / powf(2.0f, -3.0f);
79 compensation_float_params_.param_P6 = (float) compensation_params_.param_P6 / powf(2.0f, 6.0f);
80 compensation_float_params_.param_P7 = (float) compensation_params_.param_P7 / powf(2.0f, 8.0f);
81 compensation_float_params_.param_P8 = (float) compensation_params_.param_P8 / powf(2.0f, 15.0f);
82 compensation_float_params_.param_P9 = (float) compensation_params_.param_P9 / powf(2.0f, 48.0f);
83 compensation_float_params_.param_P10 = (float) compensation_params_.param_P10 / powf(2.0f, 48.0f);
84 compensation_float_params_.param_P11 = (float) compensation_params_.param_P11 / powf(2.0f, 65.0f);
85
86 // Initialise the BMP388 IIR filter register
87 if (!set_iir_filter(this->iir_filter_)) {
88 this->mark_failed(LOG_STR("Failed to set IIR filter"));
89 return;
90 }
91
92 // Set power control registers
93 pwr_ctrl_.bit.press_en = 1;
94 pwr_ctrl_.bit.temp_en = 1;
95 // Disable pressure if no sensor defined
96 // keep temperature enabled since it's needed for compensation
97 if (this->pressure_sensor_ == nullptr) {
98 pwr_ctrl_.bit.press_en = 0;
100 }
101 // just disable oeversampling for temp if not used
102 if (this->temperature_sensor_ == nullptr) {
104 }
105 // Initialise the BMP388 oversampling register
107 this->mark_failed(LOG_STR("Failed to set oversampling register"));
108 return;
109 }
110}
111
113 ESP_LOGCONFIG(TAG,
114 "BMP3XX:\n"
115 " Type: %s (0x%X)",
116 LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg);
117 ESP_LOGCONFIG(TAG, " IIR Filter: %s", LOG_STR_ARG(iir_filter_to_str(this->iir_filter_)));
118 LOG_UPDATE_INTERVAL(this);
119 if (this->temperature_sensor_) {
120 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
121 ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->temperature_oversampling_)));
122 }
123 if (this->pressure_sensor_) {
124 LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
125 ESP_LOGCONFIG(TAG, " Oversampling: %s", LOG_STR_ARG(oversampling_to_str(this->pressure_oversampling_)));
126 }
127}
128
129inline uint8_t oversampling_to_time(Oversampling over_sampling) { return (1 << uint8_t(over_sampling)); }
130
132 // Enable sensor
133 ESP_LOGV(TAG, "Sending conversion request");
134 float meas_time = 1.0f;
135 // Ref: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp390-ds002.pdf 3.9.2
136 meas_time += 2.02f * oversampling_to_time(this->temperature_oversampling_) + 0.163f;
137 meas_time += 2.02f * oversampling_to_time(this->pressure_oversampling_) + 0.392f;
138 meas_time += 0.234f;
139 if (!set_mode(FORCED_MODE)) {
140 this->mark_failed(LOG_STR("Failed start forced mode"));
141 return;
142 }
143
144 const uint32_t meas_timeout = uint32_t(ceilf(meas_time));
145 ESP_LOGVV(TAG, "measurement time %" PRIu32, meas_timeout);
146 this->set_timeout(DATA_TIMEOUT_ID, meas_timeout, [this]() {
147 float temperature = 0.0f;
148 float pressure = 0.0f;
149 if (this->pressure_sensor_ != nullptr) {
150 if (!get_measurements(temperature, pressure)) {
151 ESP_LOGW(TAG, "Failed to read pressure and temperature - skipping update");
152 this->status_set_warning();
153 return;
154 }
155 ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa", temperature, pressure);
156 } else {
158 ESP_LOGW(TAG, "Failed to read temperature - skipping update");
159 this->status_set_warning();
160 return;
161 }
162 ESP_LOGD(TAG, "Got temperature=%.1f°C", temperature);
163 }
164
165 if (this->temperature_sensor_ != nullptr)
166 this->temperature_sensor_->publish_state(temperature);
167 if (this->pressure_sensor_ != nullptr)
168 this->pressure_sensor_->publish_state(pressure);
169 this->status_clear_warning();
171 });
172}
173
174// Reset the BMP3XX
176 write_byte(BMP388_CMD, RESET_CODE); // Write the reset code to the command register
177 // Wait for 10ms
178 delay(10);
179 this->read_byte(BMP388_EVENT, &event_.reg); // Read the BMP388's event register
180 return event_.bit.por_detected; // Return if device reset is complete
181}
182
183// Start a one shot measurement in FORCED_MODE
185 // Only set FORCED_MODE if we're already in SLEEP_MODE
186 if (pwr_ctrl_.bit.mode == SLEEP_MODE) {
187 return set_mode(FORCED_MODE);
188 }
189 return true;
190}
191
192// Stop the conversion and return to SLEEP_MODE
194
195// Set the pressure oversampling rate
197 osr_.bit.osr_p = oversampling;
198 return this->write_byte(BMP388_OSR, osr_.reg);
199}
200
201// Set the temperature oversampling rate
203 osr_.bit.osr_t = oversampling;
204 return this->write_byte(BMP388_OSR, osr_.reg);
205}
206
207// Set the IIR filter setting
209 config_.bit.iir_filter = iir_filter;
210 return this->write_byte(BMP388_CONFIG, config_.reg);
211}
212
213// Get temperature
215 // Check if a measurement is ready
216 if (!data_ready()) {
217 return false;
218 }
219 uint8_t data[3];
220 // Read the temperature
221 if (!this->read_bytes(BMP388_DATA_3, &data[0], 3)) {
222 ESP_LOGE(TAG, "Failed to read temperature");
223 return false;
224 }
225 // Copy the temperature data into the adc variables
226 int32_t adc_temp = encode_uint24(data[2], data[1], data[0]);
227 // Temperature compensation (function from BMP388 datasheet)
229 return true;
230}
231
232// Get the pressure
237
238// Get temperature and pressure
240 // Check if a measurement is ready
241 if (!data_ready()) {
242 ESP_LOGD(TAG, "Get measurement - data not ready skipping update");
243 return false;
244 }
245
246 uint8_t data[6];
247 // Read the temperature and pressure data
248 if (!this->read_bytes(BMP388_DATA_0, &data[0], 6)) {
249 ESP_LOGE(TAG, "Failed to read measurements");
250 return false;
251 }
252 // Copy the temperature and pressure data into the adc variables
253 int32_t adc_pres = encode_uint24(data[2], data[1], data[0]);
254 int32_t adc_temp = encode_uint24(data[5], data[4], data[3]);
255
256 // Temperature compensation (function from BMP388 datasheet)
258 // Pressure compensation (function from BMP388 datasheet)
260 // Calculate the pressure in millibar/hPa
261 pressure /= 100.0f;
262 return true;
263}
264
265// Set the BMP388's mode in the power control register
270
271// Set the BMP388 oversampling register
273 Oversampling temperature_oversampling) {
274 osr_.reg = temperature_oversampling << 3 | pressure_oversampling;
275 return this->write_byte(BMP388_OSR, osr_.reg);
276}
277
278// Check if measurement data is ready
280 // If we're in SLEEP_MODE return immediately
281 if (pwr_ctrl_.bit.mode == SLEEP_MODE) {
282 ESP_LOGD(TAG, "Not ready - sensor is in sleep mode");
283 return false;
284 }
285 // Read the interrupt status register
286 uint8_t status;
287 if (!this->read_byte(BMP388_INT_STATUS, &status)) {
288 ESP_LOGE(TAG, "Failed to read status register");
289 return false;
290 }
291 int_status_.reg = status;
292 ESP_LOGVV(TAG, "data ready status %d", status);
293 // If we're in FORCED_MODE switch back to SLEEP_MODE
294 if (int_status_.bit.drdy) {
295 if (pwr_ctrl_.bit.mode == FORCED_MODE) {
296 pwr_ctrl_.bit.mode = SLEEP_MODE;
297 }
298 return true; // The measurement is ready
299 }
300 return false; // The measurement is still pending
301}
302
304// Bosch BMP3XXComponent (Private) Member Functions
306
308 float partial_data1 = uncomp_temp - compensation_float_params_.param_T1;
309 float partial_data2 = partial_data1 * compensation_float_params_.param_T2;
310 return partial_data2 + partial_data1 * partial_data1 * compensation_float_params_.param_T3;
311}
312
313float BMP3XXComponent::bmp388_compensate_pressure_(float uncomp_press, float t_lin) {
314 float partial_data1 = compensation_float_params_.param_P6 * t_lin;
315 float partial_data2 = compensation_float_params_.param_P7 * t_lin * t_lin;
316 float partial_data3 = compensation_float_params_.param_P8 * t_lin * t_lin * t_lin;
317 float partial_out1 = compensation_float_params_.param_P5 + partial_data1 + partial_data2 + partial_data3;
318 partial_data1 = compensation_float_params_.param_P2 * t_lin;
319 partial_data2 = compensation_float_params_.param_P3 * t_lin * t_lin;
320 partial_data3 = compensation_float_params_.param_P4 * t_lin * t_lin * t_lin;
321 float partial_out2 =
322 uncomp_press * (compensation_float_params_.param_P1 + partial_data1 + partial_data2 + partial_data3);
323 partial_data1 = uncomp_press * uncomp_press;
325 partial_data3 = partial_data1 * partial_data2;
326 float partial_data4 =
327 partial_data3 + uncomp_press * uncomp_press * uncomp_press * compensation_float_params_.param_P11;
328 return partial_out1 + partial_out2 + partial_data4;
329}
330
331} // namespace esphome::bmp3xx_base
BedjetMode mode
BedJet operating mode.
uint8_t status
Definition bl0942.h:8
void mark_failed()
Mark this component as failed.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
Definition component.cpp:96
void status_clear_warning()
Definition component.h:296
union esphome::bmp3xx_base::BMP3XXComponent::@24 chip_id_
union esphome::bmp3xx_base::BMP3XXComponent::@28 osr_
struct esphome::bmp3xx_base::BMP3XXComponent::FloatParams compensation_float_params_
bool get_pressure(float &pressure)
Get a pressure measurement.
bool get_measurements(float &temperature, float &pressure)
Get a temperature and pressure measurement.
union esphome::bmp3xx_base::BMP3XXComponent::@26 int_status_
bool start_forced_conversion()
Start a one shot measurement in FORCED_MODE.
bool set_iir_filter(IIRFilter iir_filter)
Set the IIR filter setting: OFF, 2, 3, 8, 16, 32.
union esphome::bmp3xx_base::BMP3XXComponent::@27 pwr_ctrl_
bool set_pressure_oversampling(Oversampling pressure_oversampling)
Set the pressure oversampling: OFF, X1, X2, X4, X8, X16, X32.
bool get_temperature(float &temperature)
Get a temperature measurement.
bool stop_conversion()
Stop the conversion and return to SLEEP_MODE.
float bmp388_compensate_temperature_(float uncomp_temp)
virtual bool write_byte(uint8_t a_register, uint8_t data)=0
virtual bool read_bytes(uint8_t a_register, uint8_t *data, size_t len)=0
union esphome::bmp3xx_base::BMP3XXComponent::@30 config_
uint8_t reset()
Soft reset the sensor.
union esphome::bmp3xx_base::BMP3XXComponent::@25 event_
bool set_oversampling_register(Oversampling pressure_oversampling, Oversampling temperature_oversampling)
Set the BMP388 oversampling register.
bool data_ready()
Checks if a measurement is ready.
virtual bool read_byte(uint8_t a_register, uint8_t *data)=0
bool set_mode(OperationMode mode)
Set the barometer mode.
float bmp388_compensate_pressure_(float uncomp_press, float t_lin)
bool set_temperature_oversampling(Oversampling temperature_oversampling)
Set the temperature oversampling: OFF, X1, X2, X4, X8, X16, X32.
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:65
uint8_t oversampling_to_time(Oversampling over_sampling)
Oversampling
Oversampling bit fields in the control and measurement register.
Definition bmp3xx_base.h:49
ESPHOME_LOG_TAG(TAG, "bmp3xx.sensor")
OperationMode
Device mode bitfield in the control and measurement register.
Definition bmp3xx_base.h:46
PROGMEM_STRING_TABLE(OversamplingStrings, "None", "2x", "4x", "8x", "16x", "32x", "")
IIRFilter
Infinite Impulse Response (IIR) filter bit field in the configuration register.
Definition bmp3xx_base.h:59
constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3)
Encode a 24-bit value given three bytes in most to least significant byte order.
Definition helpers.h:1002
void HOT delay(uint32_t ms)
Definition hal.cpp:85
static void uint32_t
uint16_t temperature
Definition sun_gtil2.cpp:12
uint8_t pressure
Definition tt21100.cpp:7