ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
bmp280_base.cpp
Go to the documentation of this file.
1#include "bmp280_base.h"
2#include "esphome/core/hal.h"
3#include "esphome/core/log.h"
4
5#define BMP280_ERROR_WRONG_CHIP_ID "Wrong chip ID or no response"
6
8
9static const char *const TAG = "bmp280.sensor";
10
11static const uint8_t BMP280_REGISTER_STATUS = 0xF3;
12static const uint8_t BMP280_REGISTER_CONTROL = 0xF4;
13static const uint8_t BMP280_REGISTER_CONFIG = 0xF5;
14static const uint8_t BMP280_REGISTER_PRESSUREDATA = 0xF7;
15static const uint8_t BMP280_REGISTER_TEMPDATA = 0xFA;
16static const uint8_t BMP280_REGISTER_RESET = 0xE0;
17
18static const uint8_t BMP280_MODE_FORCED = 0b01;
19static const uint8_t BMP280_SOFT_RESET = 0xB6;
20static const uint8_t BMP280_STATUS_IM_UPDATE = 0b01;
21
22inline uint16_t combine_bytes(uint8_t msb, uint8_t lsb) { return ((msb & 0xFF) << 8) | (lsb & 0xFF); }
23
24static const char *oversampling_to_str(BMP280Oversampling oversampling) {
25 switch (oversampling) {
27 return "None";
29 return "1x";
31 return "2x";
33 return "4x";
35 return "8x";
37 return "16x";
38 default:
39 return "UNKNOWN";
40 }
41}
42
43static const char *iir_filter_to_str(BMP280IIRFilter filter) {
44 switch (filter) {
46 return "OFF";
48 return "2x";
50 return "4x";
52 return "8x";
54 return "16x";
55 default:
56 return "UNKNOWN";
57 }
58}
59
61 uint8_t chip_id = 0;
62
63 // Read the chip id twice, to work around a bug where the first read is 0.
64 // https://community.st.com/t5/stm32-mcus-products/issue-with-reading-bmp280-chip-id-using-spi/td-p/691855
65 if (!this->bmp_read_byte(0xD0, &chip_id)) {
66 this->error_code_ = COMMUNICATION_FAILED;
67 this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
68 return;
69 }
70 if (!this->bmp_read_byte(0xD0, &chip_id)) {
71 this->error_code_ = COMMUNICATION_FAILED;
72 this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
73 return;
74 }
75 if (chip_id != 0x58) {
76 this->error_code_ = WRONG_CHIP_ID;
77 this->mark_failed(LOG_STR(BMP280_ERROR_WRONG_CHIP_ID));
78 return;
79 }
80
81 // Send a soft reset.
82 if (!this->bmp_write_byte(BMP280_REGISTER_RESET, BMP280_SOFT_RESET)) {
83 this->mark_failed(LOG_STR("Reset failed"));
84 return;
85 }
86 // Wait until the NVM data has finished loading.
87 uint8_t status;
88 uint8_t retry = 5;
89 do {
90 delay(2);
91 if (!this->bmp_read_byte(BMP280_REGISTER_STATUS, &status)) {
92 this->mark_failed(LOG_STR("Error reading status register"));
93 return;
94 }
95 } while ((status & BMP280_STATUS_IM_UPDATE) && (--retry));
96 if (status & BMP280_STATUS_IM_UPDATE) {
97 this->mark_failed(LOG_STR("Timeout loading NVM"));
98 return;
99 }
100
101 // Read calibration
102 this->calibration_.t1 = this->read_u16_le_(0x88);
103 this->calibration_.t2 = this->read_s16_le_(0x8A);
104 this->calibration_.t3 = this->read_s16_le_(0x8C);
105
106 this->calibration_.p1 = this->read_u16_le_(0x8E);
107 this->calibration_.p2 = this->read_s16_le_(0x90);
108 this->calibration_.p3 = this->read_s16_le_(0x92);
109 this->calibration_.p4 = this->read_s16_le_(0x94);
110 this->calibration_.p5 = this->read_s16_le_(0x96);
111 this->calibration_.p6 = this->read_s16_le_(0x98);
112 this->calibration_.p7 = this->read_s16_le_(0x9A);
113 this->calibration_.p8 = this->read_s16_le_(0x9C);
114 this->calibration_.p9 = this->read_s16_le_(0x9E);
115
116 uint8_t config_register = 0;
117 if (!this->bmp_read_byte(BMP280_REGISTER_CONFIG, &config_register)) {
118 this->mark_failed(LOG_STR("Read config"));
119 return;
120 }
121 config_register &= ~0b11111100;
122 config_register |= 0b000 << 5; // 0.5 ms standby time
123 config_register |= (this->iir_filter_ & 0b111) << 2;
124 if (!this->bmp_write_byte(BMP280_REGISTER_CONFIG, config_register)) {
125 this->mark_failed(LOG_STR("Write config"));
126 return;
127 }
128}
130 ESP_LOGCONFIG(TAG, "BMP280:");
131 switch (this->error_code_) {
133 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
134 break;
135 case WRONG_CHIP_ID:
136 ESP_LOGE(TAG, BMP280_ERROR_WRONG_CHIP_ID);
137 break;
138 case NONE:
139 default:
140 break;
141 }
142 ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_));
143 LOG_UPDATE_INTERVAL(this);
144
145 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
146 ESP_LOGCONFIG(TAG, " Oversampling: %s", oversampling_to_str(this->temperature_oversampling_));
147 LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
148 ESP_LOGCONFIG(TAG, " Oversampling: %s", oversampling_to_str(this->pressure_oversampling_));
149}
150
151inline uint8_t oversampling_to_time(BMP280Oversampling over_sampling) { return (1 << uint8_t(over_sampling)) >> 1; }
152
154 // Enable sensor
155 ESP_LOGV(TAG, "Sending conversion request");
156 uint8_t meas_value = 0;
157 meas_value |= (this->temperature_oversampling_ & 0b111) << 5;
158 meas_value |= (this->pressure_oversampling_ & 0b111) << 2;
159 meas_value |= 0b01; // Forced mode
160 if (!this->bmp_write_byte(BMP280_REGISTER_CONTROL, meas_value)) {
161 this->status_set_warning();
162 return;
163 }
164
165 float meas_time = 1;
166 meas_time += 2.3f * oversampling_to_time(this->temperature_oversampling_);
167 meas_time += 2.3f * oversampling_to_time(this->pressure_oversampling_) + 0.575f;
168
169 this->set_timeout("data", uint32_t(ceilf(meas_time)), [this]() {
170 int32_t t_fine = 0;
171 float temperature = this->read_temperature_(&t_fine);
172 if (std::isnan(temperature)) {
173 ESP_LOGW(TAG, "Invalid temperature");
174 this->status_set_warning();
175 return;
176 }
177 float pressure = this->read_pressure_(t_fine);
178
179 ESP_LOGV(TAG, "Temperature=%.1f°C Pressure=%.1fhPa", temperature, pressure);
180 if (this->temperature_sensor_ != nullptr)
181 this->temperature_sensor_->publish_state(temperature);
182 if (this->pressure_sensor_ != nullptr)
183 this->pressure_sensor_->publish_state(pressure);
184 this->status_clear_warning();
185 });
186}
187
189 uint8_t data[3]{};
190 if (!this->bmp_read_bytes(BMP280_REGISTER_TEMPDATA, data, 3))
191 return NAN;
192 ESP_LOGV(TAG, "Read temperature data, raw: %02X %02X %02X", data[0], data[1], data[2]);
193 int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
194 adc >>= 4;
195 if (adc == 0x80000) {
196 // temperature was disabled
197 return NAN;
198 }
199
200 const int32_t t1 = this->calibration_.t1;
201 const int32_t t2 = this->calibration_.t2;
202 const int32_t t3 = this->calibration_.t3;
203
204 int32_t var1 = (((adc >> 3) - (t1 << 1)) * t2) >> 11;
205 int32_t var2 = (((((adc >> 4) - t1) * ((adc >> 4) - t1)) >> 12) * t3) >> 14;
206 *t_fine = var1 + var2;
207
208 float temperature = (*t_fine * 5 + 128);
209 return temperature / 25600.0f;
210}
211
212float BMP280Component::read_pressure_(int32_t t_fine) {
213 uint8_t data[3];
214 if (!this->bmp_read_bytes(BMP280_REGISTER_PRESSUREDATA, data, 3))
215 return NAN;
216 int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
217 adc >>= 4;
218 if (adc == 0x80000) {
219 // pressure was disabled
220 return NAN;
221 }
222 const int64_t p1 = this->calibration_.p1;
223 const int64_t p2 = this->calibration_.p2;
224 const int64_t p3 = this->calibration_.p3;
225 const int64_t p4 = this->calibration_.p4;
226 const int64_t p5 = this->calibration_.p5;
227 const int64_t p6 = this->calibration_.p6;
228 const int64_t p7 = this->calibration_.p7;
229 const int64_t p8 = this->calibration_.p8;
230 const int64_t p9 = this->calibration_.p9;
231
232 int64_t var1, var2, p;
233 var1 = int64_t(t_fine) - 128000;
234 var2 = var1 * var1 * p6;
235 var2 = var2 + ((var1 * p5) << 17);
236 var2 = var2 + (p4 << 35);
237 var1 = ((var1 * var1 * p3) >> 8) + ((var1 * p2) << 12);
238 var1 = ((int64_t(1) << 47) + var1) * p1 >> 33;
239
240 if (var1 == 0)
241 return NAN;
242
243 p = 1048576 - adc;
244 p = (((p << 31) - var2) * 3125) / var1;
245 var1 = (p9 * (p >> 13) * (p >> 13)) >> 25;
246 var2 = (p8 * p) >> 19;
247
248 p = ((p + var1 + var2) >> 8) + (p7 << 4);
249 return (p / 256.0f) / 100.0f;
250}
252 this->temperature_oversampling_ = temperature_over_sampling;
253}
255 this->pressure_oversampling_ = pressure_over_sampling;
256}
257void BMP280Component::set_iir_filter(BMP280IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
258uint8_t BMP280Component::read_u8_(uint8_t a_register) {
259 uint8_t data = 0;
260 this->bmp_read_byte(a_register, &data);
261 return data;
262}
263uint16_t BMP280Component::read_u16_le_(uint8_t a_register) {
264 uint16_t data = 0;
265 this->bmp_read_byte_16(a_register, &data);
266 return (data >> 8) | (data << 8);
267}
268int16_t BMP280Component::read_s16_le_(uint8_t a_register) { return this->read_u16_le_(a_register); }
269
270} // namespace esphome::bmp280_base
uint8_t status
Definition bl0942.h:8
void mark_failed()
Mark this component as failed.
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.h:493
void status_clear_warning()
Definition component.h:289
virtual bool bmp_write_byte(uint8_t a_register, uint8_t data)=0
enum esphome::bmp280_base::BMP280Component::ErrorCode NONE
uint8_t read_u8_(uint8_t a_register)
virtual bool bmp_read_bytes(uint8_t a_register, uint8_t *data, size_t len)=0
uint16_t read_u16_le_(uint8_t a_register)
virtual bool bmp_read_byte_16(uint8_t a_register, uint16_t *data)=0
int16_t read_s16_le_(uint8_t a_register)
float read_pressure_(int32_t t_fine)
Read the pressure value in hPa using the provided t_fine value.
BMP280Oversampling pressure_oversampling_
Definition bmp280_base.h:84
virtual bool bmp_read_byte(uint8_t a_register, uint8_t *data)=0
float read_temperature_(int32_t *t_fine)
Read the temperature value and store the calculated ambient temperature in t_fine.
void set_pressure_oversampling(BMP280Oversampling pressure_over_sampling)
Set the oversampling value for the pressure sensor. Default is 16x.
BMP280Oversampling temperature_oversampling_
Definition bmp280_base.h:83
void set_temperature_oversampling(BMP280Oversampling temperature_over_sampling)
Set the oversampling value for the temperature sensor. Default is 16x.
BMP280CalibrationData calibration_
Definition bmp280_base.h:82
void set_iir_filter(BMP280IIRFilter iir_filter)
Set the IIR Filter used to increase accuracy, defaults to no IIR Filter.
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:68
const char * iir_filter_to_str(BME280IIRFilter filter)
uint16_t combine_bytes(uint8_t msb, uint8_t lsb)
BMP280IIRFilter
Enum listing all Infinite Impulse Filter values for the BMP280.
Definition bmp280_base.h:43
BMP280Oversampling
Enum listing all Oversampling values for the BMP280.
Definition bmp280_base.h:30
uint8_t oversampling_to_time(BMP280Oversampling over_sampling)
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