Skip to content

Commit

Permalink
Support for low/high gas variants
Browse files Browse the repository at this point in the history
The BME688 is a "high" gas resistance variant of the BME680 and requires a slightly different init and gas compensation formula.

This change attempts to auto-detect the chip variant ID and do the right thing.

The constant ENABLE_GAS_MEAS is now set to -1 for back-compat, and passing this into set_gas_status will use the detected variant.
  • Loading branch information
Gadgetoid committed May 10, 2021
1 parent f1d671e commit d1856c5
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 10 deletions.
63 changes: 56 additions & 7 deletions library/bme680/__init__.py
Expand Up @@ -49,6 +49,8 @@ def __init__(self, i2c_addr=constants.I2C_ADDR_PRIMARY, i2c_device=None):
except IOError:
raise RuntimeError("Unable to identify BME680 at 0x{:02x} (IOError)".format(self.i2c_addr))

self._variant = self._get_regs(constants.CHIP_VARIANT_ADDR, 1)

self.soft_reset()
self.set_power_mode(constants.SLEEP_MODE)

Expand All @@ -58,7 +60,10 @@ def __init__(self, i2c_addr=constants.I2C_ADDR_PRIMARY, i2c_device=None):
self.set_pressure_oversample(constants.OS_4X)
self.set_temperature_oversample(constants.OS_8X)
self.set_filter(constants.FILTER_SIZE_3)
self.set_gas_status(constants.ENABLE_GAS_MEAS)
if self._variant == constants.VARIANT_HIGH:
self.set_gas_status(constants.ENABLE_GAS_MEAS_HIGH)
else:
self.set_gas_status(constants.ENABLE_GAS_MEAS_LOW)
self.set_temp_offset(0)
self.get_sensor_data()

Expand Down Expand Up @@ -197,6 +202,11 @@ def get_gas_heater_status(self):

def set_gas_status(self, value):
"""Enable/disable gas sensor."""
if value == -1:
if self._variant == constants.VARIANT_HIGH:
value = constants.ENABLE_GAS_MEAS_HIGH
else:
value = constants.ENABLE_GAS_MEAS_LOW
self.gas_settings.run_gas = value
self._set_bits(constants.CONF_ODR_RUN_GAS_NBC_ADDR, constants.RUN_GAS_MSK, constants.RUN_GAS_POS, value)

Expand Down Expand Up @@ -292,11 +302,17 @@ def get_sensor_data(self):
adc_pres = (regs[2] << 12) | (regs[3] << 4) | (regs[4] >> 4)
adc_temp = (regs[5] << 12) | (regs[6] << 4) | (regs[7] >> 4)
adc_hum = (regs[8] << 8) | regs[9]
adc_gas_res = (regs[13] << 2) | (regs[14] >> 6)
gas_range = regs[14] & constants.GAS_RANGE_MSK

self.data.status |= regs[14] & constants.GASM_VALID_MSK
self.data.status |= regs[14] & constants.HEAT_STAB_MSK
adc_gas_res_low = (regs[13] << 2) | (regs[14] >> 6)
adc_gas_res_high = (regs[15] << 2) | (regs[16] >> 6)
gas_range_l = regs[14] & constants.GAS_RANGE_MSK
gas_range_h = regs[16] & constants.GAS_RANGE_MSK

if self._variant == constants.VARIANT_HIGH:
self.data.status |= regs[16] & constants.GASM_VALID_MSK
self.data.status |= regs[16] & constants.HEAT_STAB_MSK
else:
self.data.status |= regs[14] & constants.GASM_VALID_MSK
self.data.status |= regs[14] & constants.HEAT_STAB_MSK

self.data.heat_stable = (self.data.status & constants.HEAT_STAB_MSK) > 0

Expand All @@ -306,7 +322,12 @@ def get_sensor_data(self):

self.data.pressure = self._calc_pressure(adc_pres) / 100.0
self.data.humidity = self._calc_humidity(adc_hum) / 1000.0
self.data.gas_resistance = self._calc_gas_resistance(adc_gas_res, gas_range)

if self._variant == constants.VARIANT_HIGH:
self.data.gas_resistance = self._calc_gas_resistance_high(adc_gas_res_high, gas_range_h)
else:
self.data.gas_resistance = self._calc_gas_resistance_low(adc_gas_res_low, gas_range_l)

return True

return False
Expand Down Expand Up @@ -399,6 +420,34 @@ def _calc_humidity(self, humidity_adc):

def _calc_gas_resistance(self, gas_res_adc, gas_range):
"""Convert the raw gas resistance using calibration data."""
if self._variant == constants.VARIANT_HIGH:
return self._calc_gas_resistance_high(gas_res_adc, gas_range)
else:
return self._calc_gas_resistance_low(gas_res_adc, gas_range)

def _calc_gas_resistance_high(self, gas_res_adc, gas_range):
"""Convert the raw gas resistance using calibration data.
Applies to Variant ID == 0x01 only.
"""
var1 = 262144 >> gas_range
var2 = gas_res_adc - 512

var2 *= 3
var2 = 4096 + var2

calc_gas_res = (10000 * var1) / var2
calc_gas_res *= 100

return calc_gas_res

def _calc_gas_resistance_low(self, gas_res_adc, gas_range):
"""Convert the raw gas resistance using calibration data.
Applies to Variant ID == 0x00 only.
"""
var1 = ((1340 + (5 * self.calibration_data.range_sw_err)) * (lookupTable1[gas_range])) >> 16
var2 = (((gas_res_adc << 15) - (16777216)) + var1)
var3 = ((lookupTable2[gas_range] * var1) >> 9)
Expand Down
12 changes: 9 additions & 3 deletions library/bme680/constants.py
Expand Up @@ -16,7 +16,7 @@
COEFF_ADDR2_LEN = 16

# BME680 field_x related defines
FIELD_LENGTH = 15
FIELD_LENGTH = 17
FIELD_ADDR_OFFSET = 17

# Soft reset command
Expand Down Expand Up @@ -67,6 +67,10 @@

# Chip identifier
CHIP_ID_ADDR = 0xd0
CHIP_VARIANT_ADDR = 0xf0

VARIANT_LOW = 0x00
VARIANT_HIGH = 0x01

# Soft reset register
SOFT_RESET_ADDR = 0xe0
Expand All @@ -77,7 +81,9 @@

# Gas measurement settings
DISABLE_GAS_MEAS = 0x00
ENABLE_GAS_MEAS = 0x01
ENABLE_GAS_MEAS = -1 # Now used as auto-select
ENABLE_GAS_MEAS_LOW = 0x01
ENABLE_GAS_MEAS_HIGH = 0x02

# Over-sampling settings
OS_NONE = 0
Expand Down Expand Up @@ -145,7 +151,7 @@
OSP_MSK = 0X1C
OSH_MSK = 0X07
HCTRL_MSK = 0x08
RUN_GAS_MSK = 0x10
RUN_GAS_MSK = 0x30
MODE_MSK = 0x03
RHRANGE_MSK = 0x30
RSERROR_MSK = 0xf0
Expand Down

0 comments on commit d1856c5

Please sign in to comment.