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