-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extends the BMxx80 category with support for the older BMP180 sensor, providing temperature and humidity output.
- Loading branch information
Showing
1 changed file
with
124 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, | ||
|
@@ -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 | ||
|
@@ -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 | ||
|
||
|
@@ -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() | ||
|
@@ -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) | ||
|
@@ -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) | ||
|
@@ -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 | ||
|
@@ -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']) | ||
|
@@ -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] | ||
|