1#![no_std]
24#![forbid(unsafe_code)]
25
26pub mod calibration;
27pub mod error;
28pub mod signals;
29
30use calibration::CalibrationData;
31pub use error::Bmp280Error;
32
33use embassy_time::Timer;
34use embedded_hal_async::i2c::I2c;
35
36const REG_CALIB_START: u8 = 0x88;
38const REG_CHIP_ID: u8 = 0xD0;
39const REG_RESET: u8 = 0xE0;
40const REG_CTRL_MEAS: u8 = 0xF4;
41const REG_CONFIG: u8 = 0xF5;
42const REG_PRESS_MSB: u8 = 0xF7;
43
44const CHIP_ID_BMP280: u8 = 0x58;
45const CHIP_ID_BME280: u8 = 0x60; const RESET_WORD: u8 = 0xB6;
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub enum Bmp280Address {
53 Default,
55 Secondary,
57 Custom(u8),
59}
60
61impl From<Bmp280Address> for u8 {
62 fn from(a: Bmp280Address) -> u8 {
63 match a {
64 Bmp280Address::Default => 0x76,
65 Bmp280Address::Secondary => 0x77,
66 Bmp280Address::Custom(v) => v,
67 }
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74#[repr(u8)]
75pub enum OversamplingTemp {
76 Skip = 0b000,
77 X1 = 0b001,
78 X2 = 0b010,
79 X4 = 0b011,
80 X8 = 0b100,
81 X16 = 0b101,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86#[repr(u8)]
87pub enum OversamplingPress {
88 Skip = 0b000,
89 X1 = 0b001,
90 X2 = 0b010,
91 X4 = 0b011,
92 X8 = 0b100,
93 X16 = 0b101,
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98#[repr(u8)]
99pub enum PowerMode {
100 Sleep = 0b00,
102 Forced = 0b01,
104 Normal = 0b11,
106}
107
108#[derive(Debug, Clone, Copy)]
110pub struct Bmp280Config {
111 pub temp_os: OversamplingTemp,
112 pub press_os: OversamplingPress,
113 pub mode: PowerMode,
114}
115
116impl Default for Bmp280Config {
117 fn default() -> Self {
119 Self {
120 temp_os: OversamplingTemp::X1,
121 press_os: OversamplingPress::X1,
122 mode: PowerMode::Normal,
123 }
124 }
125}
126
127#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
131pub struct Bmp280Data {
132 pub temperature_cdeg: i32,
134 pub pressure_pa256: u32,
137}
138
139impl Bmp280Data {
140 #[cfg(feature = "float")]
145 pub fn temperature_celsius(&self) -> f32 {
146 self.temperature_cdeg as f32 / 100.0
147 }
148
149 #[cfg(feature = "float")]
151 pub fn pressure_hpa(&self) -> f32 {
152 (self.pressure_pa256 as f32) / (256.0 * 100.0)
153 }
154}
155
156pub struct Bmp280<I2C> {
158 i2c: I2C,
159 addr: u8,
160 calib: CalibrationData,
161}
162
163impl<I2C: I2c> Bmp280<I2C> {
164 pub async fn new(
177 i2c: I2C,
178 addr: Bmp280Address,
179 config: Bmp280Config,
180 ) -> Result<Self, Bmp280Error<I2C::Error>> {
181 let mut driver = Self {
182 i2c,
183 addr: addr.into(),
184 calib: CalibrationData::default(),
185 };
186
187 driver.soft_reset().await?;
188 driver.verify_chip_id().await?;
189 driver.read_calibration().await?;
190 driver.apply_config(config).await?;
191
192 Ok(driver)
193 }
194
195 async fn write_reg(
197 &mut self,
198 reg: u8,
199 val: u8,
200 ) -> Result<(), Bmp280Error<I2C::Error>> {
201 self.i2c
202 .write(self.addr, &[reg, val])
203 .await
204 .map_err(Bmp280Error::I2c)
205 }
206
207 async fn read_reg(
208 &mut self,
209 reg: u8,
210 ) -> Result<u8, Bmp280Error<I2C::Error>> {
211 let mut buf = [0u8; 1];
212 self.i2c
213 .write_read(self.addr, &[reg], &mut buf)
214 .await
215 .map_err(Bmp280Error::I2c)?;
216 Ok(buf[0])
217 }
218
219 async fn read_bytes<const N: usize>(
220 &mut self,
221 reg: u8,
222 ) -> Result<[u8; N], Bmp280Error<I2C::Error>> {
223 let mut buf = [0u8; N];
224 self.i2c
225 .write_read(self.addr, &[reg], &mut buf)
226 .await
227 .map_err(Bmp280Error::I2c)?;
228 Ok(buf)
229 }
230
231 async fn soft_reset(&mut self) -> Result<(), Bmp280Error<I2C::Error>> {
232 self.write_reg(REG_RESET, RESET_WORD).await?;
233 Timer::after_millis(3).await;
235 Ok(())
236 }
237
238 async fn verify_chip_id(&mut self) -> Result<(), Bmp280Error<I2C::Error>> {
239 let id = self.read_reg(REG_CHIP_ID).await?;
240 if id != CHIP_ID_BMP280 && id != CHIP_ID_BME280 {
241 return Err(Bmp280Error::InvalidChipId(id));
242 }
243 Ok(())
244 }
245
246 async fn read_calibration(&mut self) -> Result<(), Bmp280Error<I2C::Error>> {
247 let raw: [u8; 24] = self.read_bytes::<24>(REG_CALIB_START).await?;
248 let calib = CalibrationData::from_raw(&raw);
249
250 if calib.dig_t1 == 0 {
252 return Err(Bmp280Error::InvalidCalibration);
253 }
254
255 self.calib = calib;
256 Ok(())
257 }
258
259 async fn apply_config(
260 &mut self,
261 cfg: Bmp280Config,
262 ) -> Result<(), Bmp280Error<I2C::Error>> {
263 let ctrl = ((cfg.temp_os as u8) << 5)
265 | ((cfg.press_os as u8) << 2)
266 | (cfg.mode as u8);
267 self.write_reg(REG_CTRL_MEAS, ctrl).await?;
268
269 self.write_reg(REG_CONFIG, 0x00).await?;
271 Ok(())
272 }
273
274 pub async fn read(&mut self) -> Result<Bmp280Data, Bmp280Error<I2C::Error>> {
284 let raw: [u8; 6] = self.read_bytes::<6>(REG_PRESS_MSB).await?;
286
287 let raw_p = ((raw[0] as u32) << 12)
288 | ((raw[1] as u32) << 4)
289 | ((raw[2] as u32) >> 4);
290
291 let raw_t = ((raw[3] as u32) << 12)
292 | ((raw[4] as u32) << 4)
293 | ((raw[5] as u32) >> 4);
294
295 let (temperature_cdeg, t_fine) = self.calib.compensate_temperature(raw_t);
296 let pressure_pa256 = self.calib
297 .compensate_pressure(raw_p, t_fine)
298 .unwrap_or(0);
299
300 Ok(Bmp280Data { temperature_cdeg, pressure_pa256 })
301 }
302
303 pub fn set_address(&mut self, addr: Bmp280Address) {
305 self.addr = addr.into();
306 }
307
308 pub async fn set_mode(
312 &mut self,
313 mode: PowerMode,
314 ) -> Result<(), Bmp280Error<I2C::Error>> {
315 let current = self.read_reg(REG_CTRL_MEAS).await?;
316 let updated = (current & 0b1111_1100) | (mode as u8);
317 self.write_reg(REG_CTRL_MEAS, updated).await
318 }
319}