From 2147ddab30b9b9604a7fd496198cb7493f6e0d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E7=8E=AE=20=28Jade=20Lin=29?= Date: Tue, 23 Apr 2024 21:02:24 +0800 Subject: [PATCH 1/2] bme280: Add BMP388 sensor support to BMxx80 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- docs/Config_Reference.md | 8 +-- klippy/extras/bme280.py | 144 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 6 deletions(-) diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index 71cdfed872f1..b66140552938 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 3bc3c471cb1b..6dff541afaf5 100644 --- a/klippy/extras/bme280.py +++ b/klippy/extras/bme280.py @@ -17,6 +17,29 @@ '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,10 @@ 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): @@ -162,6 +186,25 @@ def read_calibration_data_bmp280(calib_data_1): dig['P8'] = get_signed_short(calib_data_1[20:22]) 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) / 1048576.0 + dig["P2"] = (get_signed_short(calib_data_1[7:9]) - 16384) / 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]) / 281474976710656.0 + dig["P10"] = get_signed_byte(calib_data_1[19]) / 281474976710656.0 + dig["P11"] = get_signed_byte(calib_data_1[20]) / 36893488147419103232.0 + return dig def read_calibration_data_bme280(calib_data_1, calib_data_2): dig = read_calibration_data_bmp280(calib_data_1) @@ -224,7 +267,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: @@ -252,6 +295,24 @@ def read_calibration_data_bmp180(calib_data_1): 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 +326,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) @@ -276,6 +339,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 @@ -318,6 +383,75 @@ 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 + (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"] * (self.t_fine * self.t_fine * self.t_fine) + partial_out1 = self.dig["P5"] + 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"] * (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 +698,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]] From 15d36f2d7544d21650523becc428d05627df71fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E7=8E=AE=20=28Jade=20Lin=29?= Date: Tue, 23 Apr 2024 22:08:16 +0800 Subject: [PATCH 2/2] fix lint errors --- klippy/extras/bme280.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/klippy/extras/bme280.py b/klippy/extras/bme280.py index 6dff541afaf5..262dc130f417 100644 --- a/klippy/extras/bme280.py +++ b/klippy/extras/bme280.py @@ -91,7 +91,8 @@ RESET_CHIP_VALUE = 0xB6 BME_CHIPS = { - 0x58: 'BMP280', 0x60: 'BME280', 0x61: 'BME680', 0x55: 'BMP180', 0x50: 'BMP388' + 0x58: 'BMP280', 0x60: 'BME280', 0x61: 'BME680', 0x55: 'BMP180', + 0x50: 'BMP388' } BME_CHIP_ID_REG = 0xD0 BMP3_CHIP_ID_REG = 0x00 @@ -186,24 +187,28 @@ def read_calibration_data_bmp280(calib_data_1): dig['P8'] = get_signed_short(calib_data_1[20:22]) 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) / 1048576.0 - dig["P2"] = (get_signed_short(calib_data_1[7:9]) - 16384) / 536870912.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]) / 281474976710656.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]) / 36893488147419103232.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): @@ -409,7 +414,8 @@ def _sample_bmp388_temp(self): partial_data1 = adc_T - self.dig["T1"] partial_data2 = self.dig["T2"] * partial_data1 - self.t_fine = partial_data2 + (partial_data1 * partial_data1) * self.dig["T3"] + 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 @@ -427,12 +433,15 @@ def _sample_bmp388_press(self): partial_data1 = self.dig["P6"] * self.t_fine partial_data2 = self.dig["P7"] * (self.t_fine * self.t_fine) - partial_data3 = self.dig["P8"] * (self.t_fine * self.t_fine * self.t_fine) - partial_out1 = self.dig["P5"] + partial_data1 + partial_data2 + partial_data3 + 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"] * (self.t_fine * 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 )