Skip to content

Commit

Permalink
bme280: Add BMP388 sensor support to BMxx80 (Klipper3d#6576) (Klipper…
Browse files Browse the repository at this point in the history
…3d#242)

Extends the BMxx80 category with support for the BMP388 sensor,
providing temperature and pressure output similar to the existing BMxx80 class of sensors.

Signed-off-by: 林玮 (Jade Lin) <[email protected]>
Co-authored-by: 林玮 (Jade Lin) <[email protected]>
  • Loading branch information
rogerlz and linw1995 authored May 15, 2024
1 parent 7f793c6 commit 9de3f85
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 6 deletions.
8 changes: 4 additions & 4 deletions docs/Config_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2911,9 +2911,9 @@ sensor_pin:
# name in the above list.
```

### BMP180/BMP280/BME280/BME680 temperature sensor
### BMP180/BMP280/BME280/BMP388/BME680 temperature sensor

BMP180/BMP280/BME280/BME680 two wire interface (I2C) environmental sensors.
BMP180/BMP280/BME280/BMP388/BME680 two wire interface (I2C) environmental sensors.
Note that these sensors are not intended for use with extruders and
heater beds, but rather for monitoring ambient temperature (C),
pressure (hPa), relative humidity and in case of the BME680 gas level.
Expand All @@ -2924,8 +2924,8 @@ temperature.
```
sensor_type: BME280
#i2c_address:
# Default is 118 (0x76). The BMP180 and some BME280 sensors have an address of 119
# (0x77).
# Default is 118 (0x76). The BMP180, BMP388 and some BME280 sensors
# have an address of 119 (0x77).
#i2c_mcu:
#i2c_bus:
#i2c_software_scl_pin:
Expand Down
158 changes: 156 additions & 2 deletions klippy/extras/bme280.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,29 @@
"CAL_2": 0xE1,
}

BMP388_REGS = {
"CMD": 0x7E,
"STATUS": 0x03,
"PWR_CTRL": 0x1B,
"OSR": 0x1C,
"ORD": 0x1D,
"INT_CTRL": 0x19,
"CAL_1": 0x31,
"TEMP_MSB": 0x09,
"TEMP_LSB": 0x08,
"TEMP_XLSB": 0x07,
"PRESS_MSB": 0x06,
"PRESS_LSB": 0x05,
"PRESS_XLSB": 0x04,
}
BMP388_REG_VAL_PRESS_EN = 0x01
BMP388_REG_VAL_TEMP_EN = 0x02
BMP388_REG_VAL_PRESS_OS_NO = 0b000
BMP388_REG_VAL_TEMP_OS_NO = 0b000000
BMP388_REG_VAL_ODR_50_HZ = 0x02
BMP388_REG_VAL_DRDY_EN = 0b100000
BMP388_REG_VAL_NORMAL_MODE = 0x30

BME680_REGS = {
"RESET": 0xE0,
"CTRL_HUM": 0x72,
Expand Down Expand Up @@ -95,8 +118,15 @@
MEASURE_DONE = 1 << 5
RESET_CHIP_VALUE = 0xB6

BME_CHIPS = {0x58: "BMP280", 0x60: "BME280", 0x61: "BME680", 0x55: "BMP180"}
BME_CHIPS = {
0x58: "BMP280",
0x60: "BME280",
0x61: "BME680",
0x55: "BMP180",
0x50: "BMP388",
}
BME_CHIP_ID_REG = 0xD0
BMP3_CHIP_ID_REG = 0x00


def get_twos_complement(val, bit_size):
Expand Down Expand Up @@ -197,6 +227,29 @@ def read_calibration_data_bmp280(calib_data_1):
dig["P9"] = get_signed_short(calib_data_1[22:24])
return dig

def read_calibration_data_bmp388(calib_data_1):
dig = {}
dig["T1"] = get_unsigned_short(calib_data_1[0:2]) / 0.00390625
dig["T2"] = get_unsigned_short(calib_data_1[2:4]) / 1073741824.0
dig["T3"] = get_signed_byte(calib_data_1[4]) / 281474976710656.0

dig["P1"] = get_signed_short(calib_data_1[5:7]) - 16384
dig["P1"] /= 1048576.0
dig["P2"] = get_signed_short(calib_data_1[7:9]) - 16384
dig["P2"] /= 536870912.0
dig["P3"] = get_signed_byte(calib_data_1[9]) / 4294967296.0
dig["P4"] = get_signed_byte(calib_data_1[10]) / 137438953472.0
dig["P5"] = get_unsigned_short(calib_data_1[11:13]) / 0.125
dig["P6"] = get_unsigned_short(calib_data_1[13:15]) / 64.0
dig["P7"] = get_signed_byte(calib_data_1[15]) / 256.0
dig["P8"] = get_signed_byte(calib_data_1[16]) / 32768.0
dig["P9"] = get_signed_short(calib_data_1[17:19])
dig["P9"] /= 281474976710656.0
dig["P10"] = get_signed_byte(calib_data_1[19]) / 281474976710656.0
dig["P11"] = get_signed_byte(calib_data_1[20])
dig["P11"] /= 36893488147419103232.0
return dig

def read_calibration_data_bme280(calib_data_1, calib_data_2):
dig = read_calibration_data_bmp280(calib_data_1)
dig["H1"] = calib_data_1[25] & 0xFF
Expand Down Expand Up @@ -262,7 +315,7 @@ def read_calibration_data_bmp180(calib_data_1):
dig["MD"] = get_signed_short_msb(calib_data_1[20:22])
return dig

chip_id = self.read_id()
chip_id = self.read_id() or self.read_bmp3_id()
if chip_id not in BME_CHIPS.keys():
logging.info("bme280: Unknown Chip ID received %#x" % chip_id)
else:
Expand Down Expand Up @@ -294,6 +347,24 @@ def read_calibration_data_bmp180(calib_data_1):
) / 1000
self.sample_timer = self.reactor.register_timer(self._sample_bmp180)
self.chip_registers = BMP180_REGS
elif self.chip_type == "BMP388":
self.max_sample_time = 0.5
self.chip_registers = BMP388_REGS
self.write_register(
"PWR_CTRL",
[
BMP388_REG_VAL_PRESS_EN
| BMP388_REG_VAL_TEMP_EN
| BMP388_REG_VAL_NORMAL_MODE
],
)
self.write_register(
"OSR", [BMP388_REG_VAL_PRESS_OS_NO | BMP388_REG_VAL_TEMP_OS_NO]
)
self.write_register("ORD", [BMP388_REG_VAL_ODR_50_HZ])
self.write_register("INT_CTRL", [BMP388_REG_VAL_DRDY_EN])

self.sample_timer = self.reactor.register_timer(self._sample_bmp388)
else:
self.max_sample_time = (
1.25
Expand All @@ -310,6 +381,8 @@ def read_calibration_data_bmp180(calib_data_1):
# Read out and calculate the trimming parameters
if self.chip_type == "BMP180":
cal_1 = self.read_register("CAL_1", 22)
elif self.chip_type == "BMP388":
cal_1 = self.read_register("CAL_1", 21)
else:
cal_1 = self.read_register("CAL_1", 26)
cal_2 = self.read_register("CAL_2", 16)
Expand All @@ -321,6 +394,8 @@ def read_calibration_data_bmp180(calib_data_1):
self.dig = read_calibration_data_bme680(cal_1, cal_2)
elif self.chip_type == "BMP180":
self.dig = read_calibration_data_bmp180(cal_1)
elif self.chip_type == "BMP388":
self.dig = read_calibration_data_bmp388(cal_1)

def _sample_bme280(self, eventtime):
# Enter forced mode
Expand Down Expand Up @@ -365,6 +440,79 @@ def _sample_bme280(self, eventtime):
self._callback(self.mcu.estimated_print_time(measured_time), self.temp)
return measured_time + REPORT_TIME

def _sample_bmp388(self, eventtime):
status = self.read_register("STATUS", 1)
if status[0] & 0b100000:
self.temp = self._sample_bmp388_temp()
if self.temp < self.min_temp or self.temp > self.max_temp:
self.printer.invoke_shutdown(
"BME280 temperature %0.1f outside range of %0.1f:%.01f"
% (self.temp, self.min_temp, self.max_temp)
)

if status[0] & 0b010000:
self.pressure = self._sample_bmp388_press() / 100.0

measured_time = self.reactor.monotonic()
self._callback(self.mcu.estimated_print_time(measured_time), self.temp)
return measured_time + REPORT_TIME

def _sample_bmp388_temp(self):
xlsb = self.read_register("TEMP_XLSB", 1)
lsb = self.read_register("TEMP_LSB", 1)
msb = self.read_register("TEMP_MSB", 1)
adc_T = (msb[0] << 16) + (lsb[0] << 8) + (xlsb[0])

partial_data1 = adc_T - self.dig["T1"]
partial_data2 = self.dig["T2"] * partial_data1

self.t_fine = partial_data2
self.t_fine += (partial_data1 * partial_data1) * self.dig["T3"]

if self.t_fine < -40.0:
self.t_fine = -40.0

if self.t_fine > 85.0:
self.t_fine = 85.0

return self.t_fine

def _sample_bmp388_press(self):
xlsb = self.read_register("PRESS_XLSB", 1)
lsb = self.read_register("PRESS_LSB", 1)
msb = self.read_register("PRESS_MSB", 1)
adc_P = (msb[0] << 16) + (lsb[0] << 8) + (xlsb[0])

partial_data1 = self.dig["P6"] * self.t_fine
partial_data2 = self.dig["P7"] * (self.t_fine * self.t_fine)
partial_data3 = self.dig["P8"]
partial_data3 *= self.t_fine * self.t_fine * self.t_fine
partial_out1 = self.dig["P5"]
partial_out1 += partial_data1 + partial_data2 + partial_data3

partial_data1 = self.dig["P2"] * self.t_fine
partial_data2 = self.dig["P3"] * (self.t_fine * self.t_fine)
partial_data3 = self.dig["P4"]
partial_data3 *= self.t_fine * self.t_fine * self.t_fine
partial_out2 = adc_P * (
self.dig["P1"] + partial_data1 + partial_data2 + partial_data3
)

partial_data1 = adc_P * adc_P
partial_data2 = self.dig["P9"] + (self.dig["P10"] * self.t_fine)
partial_data3 = partial_data1 * partial_data2
partial_data4 = partial_data3 + adc_P * adc_P * adc_P * self.dig["P11"]

comp_press = partial_out1 + partial_out2 + partial_data4

if comp_press < 30000:
comp_press = 30000

if comp_press > 125000:
comp_press = 125000

return comp_press

def _sample_bme680(self, eventtime):
self.write_register("CTRL_HUM", self.os_hum & 0x07)
meas = self.os_temp << 5 | self.os_pres << 2
Expand Down Expand Up @@ -644,6 +792,12 @@ def read_id(self):
params = self.i2c.i2c_read(regs, 1)
return bytearray(params["response"])[0]

def read_bmp3_id(self):
# read chip id register
regs = [BMP3_CHIP_ID_REG]
params = self.i2c.i2c_read(regs, 1)
return bytearray(params["response"])[0]

def read_register(self, reg_name, read_len):
# read a single register
regs = [self.chip_registers[reg_name]]
Expand Down

0 comments on commit 9de3f85

Please sign in to comment.