Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bme280: Add BMP388 sensor support to BMxx80 #6576

Merged
merged 2 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/Config_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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:
Expand Down
153 changes: 151 additions & 2 deletions klippy/extras/bme280.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -68,9 +91,11 @@
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):
Expand Down Expand Up @@ -163,6 +188,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 @@ -224,7 +272,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 @@ -252,6 +300,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)
Expand All @@ -265,6 +331,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 @@ -276,6 +344,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 @@ -318,6 +388,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 @@ -564,6 +707,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
Loading