aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/Config_Reference.md8
-rw-r--r--klippy/extras/bme280.py153
2 files changed, 155 insertions, 6 deletions
diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md
index 71cdfed8..b6614055 100644
--- a/docs/Config_Reference.md
+++ b/docs/Config_Reference.md
@@ -2490,9 +2490,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.
@@ -2503,8 +2503,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:
diff --git a/klippy/extras/bme280.py b/klippy/extras/bme280.py
index 3bc3c471..262dc130 100644
--- a/klippy/extras/bme280.py
+++ b/klippy/extras/bme280.py
@@ -17,6 +17,29 @@ BME280_REGS = {
'HUM_MSB': 0xFD, 'HUM_LSB': 0xFE, 'CAL_1': 0x88, '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, 'CTRL_GAS_1': 0x71, 'CTRL_GAS_0': 0x70,
'GAS_WAIT_0': 0x64, 'RES_HEAT_0': 0x5A, 'IDAC_HEAT_0': 0x50,
@@ -68,9 +91,11 @@ MEASURE_DONE = 1 << 5
RESET_CHIP_VALUE = 0xB6
BME_CHIPS = {
- 0x58: 'BMP280', 0x60: 'BME280', 0x61: 'BME680', 0x55: 'BMP180'
+ 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):
@@ -163,6 +188,29 @@ class BME280:
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
@@ -224,7 +272,7 @@ class BME280:
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:
@@ -252,6 +300,24 @@ class BME280:
self.max_sample_time = (1.25 + ((2.3 * self.os_pres) + .575)) / 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 + (2.3 * self.os_temp) + ((2.3 * self.os_pres) + .575)
@@ -265,6 +331,8 @@ class BME280:
# 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)
@@ -276,6 +344,8 @@ class BME280:
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
@@ -318,6 +388,79 @@ class BME280:
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
@@ -564,6 +707,12 @@ class BME280:
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]]