Skip to content

Commit

Permalink
Merge pull request #1 from vaxxi/bmp180
Browse files Browse the repository at this point in the history
Add support for BMP180 sensor
  • Loading branch information
vaxxi authored Oct 15, 2023
2 parents b1f597c + 8b4fca4 commit cdb0e88
Showing 1 changed file with 124 additions and 7 deletions.
131 changes: 124 additions & 7 deletions klippy/extras/bme280.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
#
# Copyright (C) 2020 Eric Callahan <[email protected]>
#
# BMP180 sensor support by VAXXi <[email protected]>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
import time
from . import bus

REPORT_TIME = .8
BME280_CHIP_ADDR = 0x76
BMP180_CHIP_ADDR = 0x77

BME280_REGS = {
'RESET': 0xE0, 'CTRL_HUM': 0xF2,
'STATUS': 0xF3, 'CTRL_MEAS': 0xF4, 'CONFIG': 0xF5,
Expand Down Expand Up @@ -46,6 +51,16 @@
15: (1., 244.140625)
}

BMP180_REGS = {
'RESET': 0xE0,
'CAL_1': 0xAA,
'CTRL_MEAS': 0xF4,
'REG_MSB': 0xF6,
'REG_LSB': 0xF7,
'CRV_TEMP': 0x2E,
'CRV_PRES': 0x34
}

STATUS_MEASURING = 1 << 3
STATUS_IM_UPDATE = 1
MODE = 1
Expand All @@ -57,7 +72,7 @@
RESET_CHIP_VALUE = 0xB6

BME_CHIPS = {
0x58: 'BMP280', 0x60: 'BME280', 0x61: 'BME680'
0x58: 'BMP280', 0x60: 'BME280', 0x61: 'BME680', 0x55: 'BMP180'
}
BME_CHIP_ID_REG = 0xD0

Expand All @@ -81,6 +96,14 @@ def get_signed_byte(bits):
return get_twos_complement(bits, 8)


def get_unsigned_short_msb(bits):
return bits[0] << 8 | bits[1]


def get_signed_short_msb(bits):
val = get_unsigned_short_msb(bits)
return get_twos_complement(val, 16)

class BME280:
def __init__(self, config):
self.printer = config.get_printer()
Expand Down Expand Up @@ -188,6 +211,23 @@ def read_calibration_data_bme680(calib_data_1, calib_data_2):
dig['G3'] = get_signed_byte(calib_data_2[13])
return dig

def read_calibration_data_bmp180(calib_data_1):
dig = {}
dig['AC1'] = get_signed_short_msb(calib_data_1[0:2])
dig['AC2'] = get_signed_short_msb(calib_data_1[2:4])
dig['AC3'] = get_signed_short_msb(calib_data_1[4:6])
dig['AC4'] = get_unsigned_short_msb(calib_data_1[6:8])
dig['AC5'] = get_unsigned_short_msb(calib_data_1[8:10])
dig['AC6'] = get_unsigned_short_msb(calib_data_1[10:12])

dig['B1'] = get_signed_short_msb(calib_data_1[12:14])
dig['B2'] = get_signed_short_msb(calib_data_1[14:16])

dig['MB'] = get_signed_short_msb(calib_data_1[16:18])
dig['MC'] = get_signed_short_msb(calib_data_1[18:20])
dig['MD'] = get_signed_short_msb(calib_data_1[20:22])
return dig

chip_id = self.read_id()
if chip_id not in BME_CHIPS.keys():
logging.info("bme280: Unknown Chip ID received %#x" % chip_id)
Expand All @@ -200,16 +240,21 @@ def read_calibration_data_bme680(calib_data_1, calib_data_2):
self.write_register('RESET', [RESET_CHIP_VALUE])
self.reactor.pause(self.reactor.monotonic() + .5)

# Make sure non-volatile memory has been copied to registers
status = self.read_register('STATUS', 1)[0]
while status & STATUS_IM_UPDATE:
self.reactor.pause(self.reactor.monotonic() + .01)
# Make sure non-volatile memory has been copied to registers, except BMP180 which has no status
if self.chip_type != 'BMP180':
status = self.read_register('STATUS', 1)[0]
while status & STATUS_IM_UPDATE:
self.reactor.pause(self.reactor.monotonic() + .01)
status = self.read_register('STATUS', 1)[0]

if self.chip_type == 'BME680':
self.max_sample_time = 0.5
self.sample_timer = self.reactor.register_timer(self._sample_bme680)
self.chip_registers = BME680_REGS
elif self.chip_type == 'BMP180':
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
else:
self.max_sample_time = \
(1.25 + (2.3 * self.os_temp) + ((2.3 * self.os_pres) + .575)
Expand All @@ -221,14 +266,19 @@ def read_calibration_data_bme680(calib_data_1, calib_data_2):
self.write_register('CONFIG', (self.iir_filter & 0x07) << 2)

# Read out and calculate the trimming parameters
cal_1 = self.read_register('CAL_1', 26)
cal_2 = self.read_register('CAL_2', 16)
if self.chip_type == 'BMP180':
cal_1 = self.read_register('CAL_1', 22)
else:
cal_1 = self.read_register('CAL_1', 26)
cal_2 = self.read_register('CAL_2', 16)
if self.chip_type == 'BME280':
self.dig = read_calibration_data_bme280(cal_1, cal_2)
elif self.chip_type == 'BMP280':
self.dig = read_calibration_data_bmp280(cal_1)
elif self.chip_type == 'BME680':
self.dig = read_calibration_data_bme680(cal_1, cal_2)
elif self.chip_type == 'BMP180':
self.dig = read_calibration_data_bmp180(cal_1)

def _sample_bme280(self, eventtime):
# Enter forced mode
Expand Down Expand Up @@ -334,6 +384,42 @@ def data_ready(stat):
self._callback(self.mcu.estimated_print_time(measured_time), self.temp)
return measured_time + REPORT_TIME

def _sample_bmp180(self, eventtime):
meas = self.chip_registers['CRV_TEMP']
self.write_register('CTRL_MEAS', meas)

try:
time.sleep(0.005)
data = self.read_register('REG_MSB', 2)
UT = (data[0] << 8) | data[1]
except Exception:
logging.exception("BMP180: Error reading temperature")
self.temp = self.pressure = .0
return self.reactor.NEVER

meas = self.chip_registers['CRV_PRES'] | (self.os_pres << 6)
self.write_register('CTRL_MEAS', meas)

try:
time.sleep(0.005)
data = self.read_register('REG_MSB', 3)
UP = ( (data[0] << 16) | (data[1] << 8) | data[2] ) >> (8 - self.os_pres)
except Exception:
logging.exception("BMP180: Error reading pressure")
self.temp = self.pressure = .0
return self.reactor.NEVER

self.temp = self._compensate_temp_bmp180(UT)
self.pressure = self._compensate_pressure_bmp180(UP) / 100.
if self.temp < self.min_temp or self.temp > self.max_temp:
self.printer.invoke_shutdown(
"BMP180 temperature %0.1f outside range of %0.1f:%.01f"
% (self.temp, self.min_temp, self.max_temp))
measured_time = self.reactor.monotonic()
self._callback(self.mcu.estimated_print_time(measured_time), self.temp)
return measured_time + REPORT_TIME


def _compensate_temp(self, raw_temp):
dig = self.dig
var1 = ((raw_temp / 16384. - (dig['T1'] / 1024.)) * dig['T2'])
Expand Down Expand Up @@ -443,6 +529,37 @@ def _calculate_gas_heater_duration(self, duration_ms):

return duration_reg

def _compensate_temp_bmp180(self, raw_temp):
dig = self.dig
X1 = (raw_temp - dig['AC6']) * dig['AC5'] / 32768.
X2 = dig['MC'] * 2048 / (X1 + dig['MD'])
B5 = X1 + X2
self.t_fine = B5
return (B5 + 8)/16./10.

def _compensate_pressure_bmp180(self, raw_pressure):
dig = self.dig
B5 = self.t_fine
B6 = B5 - 4000
X1 = (dig['B2'] * (B6 * B6 / 4096)) / 2048
X2 = dig['AC2'] * B6 / 2048
X3 = X1 + X2
B3 = ((int(dig['AC1'] * 4 + X3) << self.os_pres) + 2) / 4
X1 = dig['AC3'] * B6 / 8192
X2 = (dig['B1'] * (B6 * B6 / 4096)) / 65536
X3 = ((X1 + X2) + 2) / 4
B4 = dig['AC4'] * (X3 + 32768) / 32768
B7 = (raw_pressure - B3) * (50000 >> self.os_pres)
if (B7 < 0x80000000):
p = (B7 * 2) / B4
else:
p = (B7 / B4) * 2
X1 = (p / 256) * (p / 256)
X1 = (X1 * 3038) / 65536
X2 = (-7357 * p) / 65536
p = p + (X1 + X2 + 3791) / 16.
return p

def read_id(self):
# read chip id register
regs = [BME_CHIP_ID_REG]
Expand Down

0 comments on commit cdb0e88

Please sign in to comment.