ESPHome  2024.3.2
bmp280.cpp
Go to the documentation of this file.
1 #include "bmp280.h"
2 #include "esphome/core/hal.h"
3 #include "esphome/core/log.h"
4 
5 namespace esphome {
6 namespace bmp280 {
7 
8 static const char *const TAG = "bmp280.sensor";
9 
10 static const uint8_t BMP280_REGISTER_STATUS = 0xF3;
11 static const uint8_t BMP280_REGISTER_CONTROL = 0xF4;
12 static const uint8_t BMP280_REGISTER_CONFIG = 0xF5;
13 static const uint8_t BMP280_REGISTER_PRESSUREDATA = 0xF7;
14 static const uint8_t BMP280_REGISTER_TEMPDATA = 0xFA;
15 static const uint8_t BMP280_REGISTER_RESET = 0xE0;
16 
17 static const uint8_t BMP280_MODE_FORCED = 0b01;
18 static const uint8_t BMP280_SOFT_RESET = 0xB6;
19 static const uint8_t BMP280_STATUS_IM_UPDATE = 0b01;
20 
21 inline uint16_t combine_bytes(uint8_t msb, uint8_t lsb) { return ((msb & 0xFF) << 8) | (lsb & 0xFF); }
22 
23 static 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 
42 static 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  if (!this->read_byte(0xD0, &chip_id)) {
63  this->error_code_ = COMMUNICATION_FAILED;
64  this->mark_failed();
65  return;
66  }
67  if (chip_id != 0x58) {
68  this->error_code_ = WRONG_CHIP_ID;
69  this->mark_failed();
70  return;
71  }
72 
73  // Send a soft reset.
74  if (!this->write_byte(BMP280_REGISTER_RESET, BMP280_SOFT_RESET)) {
75  this->mark_failed();
76  return;
77  }
78  // Wait until the NVM data has finished loading.
79  uint8_t status;
80  uint8_t retry = 5;
81  do {
82  delay(2);
83  if (!this->read_byte(BMP280_REGISTER_STATUS, &status)) {
84  ESP_LOGW(TAG, "Error reading status register.");
85  this->mark_failed();
86  return;
87  }
88  } while ((status & BMP280_STATUS_IM_UPDATE) && (--retry));
89  if (status & BMP280_STATUS_IM_UPDATE) {
90  ESP_LOGW(TAG, "Timeout loading NVM.");
91  this->mark_failed();
92  return;
93  }
94 
95  // Read calibration
96  this->calibration_.t1 = this->read_u16_le_(0x88);
97  this->calibration_.t2 = this->read_s16_le_(0x8A);
98  this->calibration_.t3 = this->read_s16_le_(0x8C);
99 
100  this->calibration_.p1 = this->read_u16_le_(0x8E);
101  this->calibration_.p2 = this->read_s16_le_(0x90);
102  this->calibration_.p3 = this->read_s16_le_(0x92);
103  this->calibration_.p4 = this->read_s16_le_(0x94);
104  this->calibration_.p5 = this->read_s16_le_(0x96);
105  this->calibration_.p6 = this->read_s16_le_(0x98);
106  this->calibration_.p7 = this->read_s16_le_(0x9A);
107  this->calibration_.p8 = this->read_s16_le_(0x9C);
108  this->calibration_.p9 = this->read_s16_le_(0x9E);
109 
110  uint8_t config_register = 0;
111  if (!this->read_byte(BMP280_REGISTER_CONFIG, &config_register)) {
112  this->mark_failed();
113  return;
114  }
115  config_register &= ~0b11111100;
116  config_register |= 0b000 << 5; // 0.5 ms standby time
117  config_register |= (this->iir_filter_ & 0b111) << 2;
118  if (!this->write_byte(BMP280_REGISTER_CONFIG, config_register)) {
119  this->mark_failed();
120  return;
121  }
122 }
124  ESP_LOGCONFIG(TAG, "BMP280:");
125  LOG_I2C_DEVICE(this);
126  switch (this->error_code_) {
128  ESP_LOGE(TAG, "Communication with BMP280 failed!");
129  break;
130  case WRONG_CHIP_ID:
131  ESP_LOGE(TAG, "BMP280 has wrong chip ID! Is it a BME280?");
132  break;
133  case NONE:
134  default:
135  break;
136  }
137  ESP_LOGCONFIG(TAG, " IIR Filter: %s", iir_filter_to_str(this->iir_filter_));
138  LOG_UPDATE_INTERVAL(this);
139 
140  LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
141  ESP_LOGCONFIG(TAG, " Oversampling: %s", oversampling_to_str(this->temperature_oversampling_));
142  LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
143  ESP_LOGCONFIG(TAG, " Oversampling: %s", oversampling_to_str(this->pressure_oversampling_));
144 }
146 
147 inline uint8_t oversampling_to_time(BMP280Oversampling over_sampling) { return (1 << uint8_t(over_sampling)) >> 1; }
148 
150  // Enable sensor
151  ESP_LOGV(TAG, "Sending conversion request...");
152  uint8_t meas_value = 0;
153  meas_value |= (this->temperature_oversampling_ & 0b111) << 5;
154  meas_value |= (this->pressure_oversampling_ & 0b111) << 2;
155  meas_value |= 0b01; // Forced mode
156  if (!this->write_byte(BMP280_REGISTER_CONTROL, meas_value)) {
157  this->status_set_warning();
158  return;
159  }
160 
161  float meas_time = 1;
162  meas_time += 2.3f * oversampling_to_time(this->temperature_oversampling_);
163  meas_time += 2.3f * oversampling_to_time(this->pressure_oversampling_) + 0.575f;
164 
165  this->set_timeout("data", uint32_t(ceilf(meas_time)), [this]() {
166  int32_t t_fine = 0;
167  float temperature = this->read_temperature_(&t_fine);
168  if (std::isnan(temperature)) {
169  ESP_LOGW(TAG, "Invalid temperature, cannot read pressure values.");
170  this->status_set_warning();
171  return;
172  }
173  float pressure = this->read_pressure_(t_fine);
174 
175  ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa", temperature, pressure);
176  if (this->temperature_sensor_ != nullptr)
177  this->temperature_sensor_->publish_state(temperature);
178  if (this->pressure_sensor_ != nullptr)
179  this->pressure_sensor_->publish_state(pressure);
180  this->status_clear_warning();
181  });
182 }
183 
184 float BMP280Component::read_temperature_(int32_t *t_fine) {
185  uint8_t data[3];
186  if (!this->read_bytes(BMP280_REGISTER_TEMPDATA, data, 3))
187  return NAN;
188  int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
189  adc >>= 4;
190  if (adc == 0x80000) {
191  // temperature was disabled
192  return NAN;
193  }
194 
195  const int32_t t1 = this->calibration_.t1;
196  const int32_t t2 = this->calibration_.t2;
197  const int32_t t3 = this->calibration_.t3;
198 
199  int32_t var1 = (((adc >> 3) - (t1 << 1)) * t2) >> 11;
200  int32_t var2 = (((((adc >> 4) - t1) * ((adc >> 4) - t1)) >> 12) * t3) >> 14;
201  *t_fine = var1 + var2;
202 
203  float temperature = (*t_fine * 5 + 128);
204  return temperature / 25600.0f;
205 }
206 
207 float BMP280Component::read_pressure_(int32_t t_fine) {
208  uint8_t data[3];
209  if (!this->read_bytes(BMP280_REGISTER_PRESSUREDATA, data, 3))
210  return NAN;
211  int32_t adc = ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
212  adc >>= 4;
213  if (adc == 0x80000) {
214  // pressure was disabled
215  return NAN;
216  }
217  const int64_t p1 = this->calibration_.p1;
218  const int64_t p2 = this->calibration_.p2;
219  const int64_t p3 = this->calibration_.p3;
220  const int64_t p4 = this->calibration_.p4;
221  const int64_t p5 = this->calibration_.p5;
222  const int64_t p6 = this->calibration_.p6;
223  const int64_t p7 = this->calibration_.p7;
224  const int64_t p8 = this->calibration_.p8;
225  const int64_t p9 = this->calibration_.p9;
226 
227  int64_t var1, var2, p;
228  var1 = int64_t(t_fine) - 128000;
229  var2 = var1 * var1 * p6;
230  var2 = var2 + ((var1 * p5) << 17);
231  var2 = var2 + (p4 << 35);
232  var1 = ((var1 * var1 * p3) >> 8) + ((var1 * p2) << 12);
233  var1 = ((int64_t(1) << 47) + var1) * p1 >> 33;
234 
235  if (var1 == 0)
236  return NAN;
237 
238  p = 1048576 - adc;
239  p = (((p << 31) - var2) * 3125) / var1;
240  var1 = (p9 * (p >> 13) * (p >> 13)) >> 25;
241  var2 = (p8 * p) >> 19;
242 
243  p = ((p + var1 + var2) >> 8) + (p7 << 4);
244  return (p / 256.0f) / 100.0f;
245 }
247  this->temperature_oversampling_ = temperature_over_sampling;
248 }
250  this->pressure_oversampling_ = pressure_over_sampling;
251 }
252 void BMP280Component::set_iir_filter(BMP280IIRFilter iir_filter) { this->iir_filter_ = iir_filter; }
253 uint8_t BMP280Component::read_u8_(uint8_t a_register) {
254  uint8_t data = 0;
255  this->read_byte(a_register, &data);
256  return data;
257 }
258 uint16_t BMP280Component::read_u16_le_(uint8_t a_register) {
259  uint16_t data = 0;
260  this->read_byte_16(a_register, &data);
261  return (data >> 8) | (data << 8);
262 }
263 int16_t BMP280Component::read_s16_le_(uint8_t a_register) { return this->read_u16_le_(a_register); }
264 
265 } // namespace bmp280
266 } // namespace esphome
bool read_byte(uint8_t a_register, uint8_t *data, bool stop=true)
Definition: i2c.h:235
bool read_byte_16(uint8_t a_register, uint16_t *data)
Definition: i2c.h:246
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
float read_temperature_(int32_t *t_fine)
Read the temperature value and store the calculated ambient temperature in t_fine.
Definition: bmp280.cpp:184
void set_iir_filter(BMP280IIRFilter iir_filter)
Set the IIR Filter used to increase accuracy, defaults to no IIR Filter.
Definition: bmp280.cpp:252
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:146
sensor::Sensor * pressure_sensor_
Definition: bmp280.h:85
uint8_t pressure
Definition: tt21100.cpp:19
uint8_t read_u8_(uint8_t a_register)
Definition: bmp280.cpp:253
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:69
bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len)
Compat APIs All methods below have been added for compatibility reasons.
Definition: i2c.h:212
float temperature
Definition: qmp6988.h:71
uint16_t combine_bytes(uint8_t msb, uint8_t lsb)
Definition: bmp280.cpp:21
BMP280Oversampling pressure_oversampling_
Definition: bmp280.h:82
float get_setup_priority() const override
Definition: bmp280.cpp:145
void set_pressure_oversampling(BMP280Oversampling pressure_over_sampling)
Set the oversampling value for the pressure sensor. Default is 16x.
Definition: bmp280.cpp:249
int16_t read_s16_le_(uint8_t a_register)
Definition: bmp280.cpp:263
void status_clear_warning()
Definition: component.cpp:161
sensor::Sensor * temperature_sensor_
Definition: bmp280.h:84
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
BMP280CalibrationData calibration_
Definition: bmp280.h:80
uint16_t read_u16_le_(uint8_t a_register)
Definition: bmp280.cpp:258
enum esphome::bmp280::BMP280Component::ErrorCode NONE
BMP280IIRFilter
Enum listing all Infinite Impulse Filter values for the BMP280.
Definition: bmp280.h:45
uint8_t status
Definition: bl0942.h:23
void set_temperature_oversampling(BMP280Oversampling temperature_over_sampling)
Set the oversampling value for the temperature sensor. Default is 16x.
Definition: bmp280.cpp:246
uint8_t oversampling_to_time(BMP280Oversampling over_sampling)
Definition: bmp280.cpp:147
bool write_byte(uint8_t a_register, uint8_t data, bool stop=true)
Definition: i2c.h:262
BMP280Oversampling
Enum listing all Oversampling values for the BMP280.
Definition: bmp280.h:32
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:113
float read_pressure_(int32_t t_fine)
Read the pressure value in hPa using the provided t_fine value.
Definition: bmp280.cpp:207
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
BMP280IIRFilter iir_filter_
Definition: bmp280.h:83
BMP280Oversampling temperature_oversampling_
Definition: bmp280.h:81
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26