ESPHome 2025.5.0
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
5namespace esphome {
6namespace bmp280_base {
7
8static const char *const TAG = "bmp280.sensor";
9
10static const uint8_t BMP280_REGISTER_STATUS = 0xF3;
11static const uint8_t BMP280_REGISTER_CONTROL = 0xF4;
12static const uint8_t BMP280_REGISTER_CONFIG = 0xF5;
13static const uint8_t BMP280_REGISTER_PRESSUREDATA = 0xF7;
14static const uint8_t BMP280_REGISTER_TEMPDATA = 0xFA;
15static const uint8_t BMP280_REGISTER_RESET = 0xE0;
16
17static const uint8_t BMP280_MODE_FORCED = 0b01;
18static const uint8_t BMP280_SOFT_RESET = 0xB6;
19static const uint8_t BMP280_STATUS_IM_UPDATE = 0b01;
20
21inline uint16_t combine_bytes(uint8_t msb, uint8_t lsb) { return ((msb & 0xFF) << 8) | (lsb & 0xFF); }
22
23static const char *oversampling_to_str(BMP280Oversampling oversampling) {
24 switch (oversampling) {
26 return "None";
28 return "1x";
30 return "2x";
32 return "4x";
34 return "8x";
36 return "16x";
37 default:
38 return "UNKNOWN";
39 }
40}
41
42static const char *iir_filter_to_str(BMP280IIRFilter filter) {
43 switch (filter) {
45 return "OFF";
47 return "2x";
49 return "4x";
51 return "8x";
53 return "16x";
54 default:
55 return "UNKNOWN";
56 }
57}
58
60 ESP_LOGCONFIG(TAG, "Setting up BMP280...");
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->read_byte(0xD0, &chip_id)) {
66 this->error_code_ = COMMUNICATION_FAILED;
67 this->mark_failed();
68 return;
69 }
70 if (!this->read_byte(0xD0, &chip_id)) {
71 this->error_code_ = COMMUNICATION_FAILED;
72 this->mark_failed();
73 return;
74 }
75 if (chip_id != 0x58) {
76 this->error_code_ = WRONG_CHIP_ID;
77 this->mark_failed();
78 return;
79 }
80
81 // Send a soft reset.
82 if (!this->write_byte(BMP280_REGISTER_RESET, BMP280_SOFT_RESET)) {
83 this->mark_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->read_byte(BMP280_REGISTER_STATUS, &status)) {
92 ESP_LOGW(TAG, "Error reading status register.");
93 this->mark_failed();
94 return;
95 }
96 } while ((status & BMP280_STATUS_IM_UPDATE) && (--retry));
97 if (status & BMP280_STATUS_IM_UPDATE) {
98 ESP_LOGW(TAG, "Timeout loading NVM.");
99 this->mark_failed();
100 return;
101 }
102
103 // Read calibration
104 this->calibration_.t1 = this->read_u16_le_(0x88);
105 this->calibration_.t2 = this->read_s16_le_(0x8A);
106 this->calibration_.t3 = this->read_s16_le_(0x8C);
107
108 this->calibration_.p1 = this->read_u16_le_(0x8E);
109 this->calibration_.p2 = this->read_s16_le_(0x90);
110 this->calibration_.p3 = this->read_s16_le_(0x92);
111 this->calibration_.p4 = this->read_s16_le_(0x94);
112 this->calibration_.p5 = this->read_s16_le_(0x96);
113 this->calibration_.p6 = this->read_s16_le_(0x98);
114 this->calibration_.p7 = this->read_s16_le_(0x9A);
115 this->calibration_.p8 = this->read_s16_le_(0x9C);
116 this->calibration_.p9 = this->read_s16_le_(0x9E);
117
118 uint8_t config_register = 0;
119 if (!this->read_byte(BMP280_REGISTER_CONFIG, &config_register)) {
120 this->mark_failed();
121 return;
122 }
123 config_register &= ~0b11111100;
124 config_register |= 0b000 << 5; // 0.5 ms standby time
125 config_register |= (this->iir_filter_ & 0b111) << 2;
126 if (!this->write_byte(BMP280_REGISTER_CONFIG, config_register)) {
127 this->mark_failed();
128 return;
129 }
130}
132 ESP_LOGCONFIG(TAG, "BMP280:");
133 switch (this->error_code_) {
135 ESP_LOGE(TAG, "Communication with BMP280 failed!");
136 break;
137 case WRONG_CHIP_ID:
138 ESP_LOGE(TAG, "BMP280 has wrong chip ID! Is it a BME280?");
139 break;
140 case NONE:
141 default:
142 break;
143 }
144 ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_));
145 LOG_UPDATE_INTERVAL(this);
146
147 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
148 ESP_LOGCONFIG(TAG, " Oversampling: %s", oversampling_to_str(this->temperature_oversampling_));
149 LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
150 ESP_LOGCONFIG(TAG, " Oversampling: %s", oversampling_to_str(this->pressure_oversampling_));
151}
153
154inline uint8_t oversampling_to_time(BMP280Oversampling over_sampling) { return (1 << uint8_t(over_sampling)) >> 1; }
155
157 // Enable sensor
158 ESP_LOGV(TAG, "Sending conversion request...");
159 uint8_t meas_value = 0;
160 meas_value |= (this->temperature_oversampling_ & 0b111) << 5;
161 meas_value |= (this->pressure_oversampling_ & 0b111) << 2;
162 meas_value |= 0b01; // Forced mode
163 if (!this->write_byte(BMP280_REGISTER_CONTROL, meas_value)) {
164 this->status_set_warning();
165 return;
166 }
167
168 float meas_time = 1;
169 meas_time += 2.3f * oversampling_to_time(this->temperature_oversampling_);
170 meas_time += 2.3f * oversampling_to_time(this->pressure_oversampling_) + 0.575f;
171
172 this->set_timeout("data", uint32_t(ceilf(meas_time)), [this]() {
173 int32_t t_fine = 0;
174 float temperature = this->read_temperature_(&t_fine);
175 if (std::isnan(temperature)) {
176 ESP_LOGW(TAG, "Invalid temperature, cannot read pressure values.");
177 this->status_set_warning();
178 return;
179 }
180 float pressure = this->read_pressure_(t_fine);
181
182 ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa", temperature, pressure);
183 if (this->temperature_sensor_ != nullptr)
184 this->temperature_sensor_->publish_state(temperature);
185 if (this->pressure_sensor_ != nullptr)
186 this->pressure_sensor_->publish_state(pressure);
187 this->status_clear_warning();
188 });
189}
190
192 uint8_t data[3];
193 if (!this->read_bytes(BMP280_REGISTER_TEMPDATA, data, 3))
194 return NAN;
195 int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
196 adc >>= 4;
197 if (adc == 0x80000) {
198 // temperature was disabled
199 return NAN;
200 }
201
202 const int32_t t1 = this->calibration_.t1;
203 const int32_t t2 = this->calibration_.t2;
204 const int32_t t3 = this->calibration_.t3;
205
206 int32_t var1 = (((adc >> 3) - (t1 << 1)) * t2) >> 11;
207 int32_t var2 = (((((adc >> 4) - t1) * ((adc >> 4) - t1)) >> 12) * t3) >> 14;
208 *t_fine = var1 + var2;
209
210 float temperature = (*t_fine * 5 + 128);
211 return temperature / 25600.0f;
212}
213
214float BMP280Component::read_pressure_(int32_t t_fine) {
215 uint8_t data[3];
216 if (!this->read_bytes(BMP280_REGISTER_PRESSUREDATA, data, 3))
217 return NAN;
218 int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
219 adc >>= 4;
220 if (adc == 0x80000) {
221 // pressure was disabled
222 return NAN;
223 }
224 const int64_t p1 = this->calibration_.p1;
225 const int64_t p2 = this->calibration_.p2;
226 const int64_t p3 = this->calibration_.p3;
227 const int64_t p4 = this->calibration_.p4;
228 const int64_t p5 = this->calibration_.p5;
229 const int64_t p6 = this->calibration_.p6;
230 const int64_t p7 = this->calibration_.p7;
231 const int64_t p8 = this->calibration_.p8;
232 const int64_t p9 = this->calibration_.p9;
233
234 int64_t var1, var2, p;
235 var1 = int64_t(t_fine) - 128000;
236 var2 = var1 * var1 * p6;
237 var2 = var2 + ((var1 * p5) << 17);
238 var2 = var2 + (p4 << 35);
239 var1 = ((var1 * var1 * p3) >> 8) + ((var1 * p2) << 12);
240 var1 = ((int64_t(1) << 47) + var1) * p1 >> 33;
241
242 if (var1 == 0)
243 return NAN;
244
245 p = 1048576 - adc;
246 p = (((p << 31) - var2) * 3125) / var1;
247 var1 = (p9 * (p >> 13) * (p >> 13)) >> 25;
248 var2 = (p8 * p) >> 19;
249
250 p = ((p + var1 + var2) >> 8) + (p7 << 4);
251 return (p / 256.0f) / 100.0f;
252}
254 this->temperature_oversampling_ = temperature_over_sampling;
255}
257 this->pressure_oversampling_ = pressure_over_sampling;
258}
259void BMP280Component::set_iir_filter(BMP280IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
260uint8_t BMP280Component::read_u8_(uint8_t a_register) {
261 uint8_t data = 0;
262 this->read_byte(a_register, &data);
263 return data;
264}
265uint16_t BMP280Component::read_u16_le_(uint8_t a_register) {
266 uint16_t data = 0;
267 this->read_byte_16(a_register, &data);
268 return (data >> 8) | (data << 8);
269}
270int16_t BMP280Component::read_s16_le_(uint8_t a_register) { return this->read_u16_le_(a_register); }
271
272} // namespace bmp280_base
273} // namespace esphome
uint8_t status
Definition bl0942.h:8
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.cpp:72
enum esphome::bmp280_base::BMP280Component::ErrorCode NONE
uint8_t read_u8_(uint8_t a_register)
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:86
virtual bool read_bytes(uint8_t a_register, uint8_t *data, size_t len)=0
virtual bool read_byte_16(uint8_t a_register, uint16_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.
virtual bool write_byte(uint8_t a_register, uint8_t data)=0
BMP280Oversampling temperature_oversampling_
Definition bmp280_base.h:85
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:84
virtual bool read_byte(uint8_t a_register, uint8_t *data)=0
void set_iir_filter(BMP280IIRFilter iir_filter)
Set the IIR Filter used to increase accuracy, defaults to no IIR Filter.
float get_setup_priority() const override
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
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:44
BMP280Oversampling
Enum listing all Oversampling values for the BMP280.
Definition bmp280_base.h:31
uint8_t oversampling_to_time(BMP280Oversampling over_sampling)
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:19
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
uint16_t temperature
Definition sun_gtil2.cpp:12
uint8_t pressure
Definition tt21100.cpp:7