| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  | # Support for common SPI based thermocouple and RTD temperature sensors | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Copyright (C) 2018  Petri Honkala <cruwaller@gmail.com> | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  | # Copyright (C) 2018  Kevin O'Connor <kevin@koconnor.net> | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  | # | 
					
						
							|  |  |  | # This file may be distributed under the terms of the GNU GPLv3 license. | 
					
						
							|  |  |  | import math | 
					
						
							| 
									
										
										
										
											2018-11-18 17:17:51 -05:00
										 |  |  | import bus | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | # SensorBase | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-24 14:05:35 -04:00
										 |  |  | REPORT_TIME = 0.300 | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-24 14:05:35 -04:00
										 |  |  | class SensorBase: | 
					
						
							| 
									
										
										
										
											2019-05-22 11:40:53 -04:00
										 |  |  |     def __init__(self, config, chip_type, config_cmd=None, spi_mode=1): | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |         self.printer = config.get_printer() | 
					
						
							| 
									
										
										
										
											2019-02-04 09:30:26 -05:00
										 |  |  |         self.chip_type = chip_type | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         self._callback = None | 
					
						
							| 
									
										
										
										
											2018-07-24 14:12:00 -04:00
										 |  |  |         self.min_sample_value = self.max_sample_value = 0 | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         self._report_clock = 0 | 
					
						
							| 
									
										
										
										
											2018-11-18 17:17:51 -05:00
										 |  |  |         self.spi = bus.MCU_SPI_from_config( | 
					
						
							| 
									
										
										
										
											2019-05-22 11:40:53 -04:00
										 |  |  |             config, spi_mode, pin_option="sensor_pin", default_speed=4000000) | 
					
						
							| 
									
										
										
										
											2018-07-24 15:10:10 -04:00
										 |  |  |         if config_cmd is not None: | 
					
						
							| 
									
										
										
										
											2018-11-18 17:17:51 -05:00
										 |  |  |             self.spi.spi_send(config_cmd) | 
					
						
							|  |  |  |         self.mcu = mcu = self.spi.get_mcu() | 
					
						
							| 
									
										
										
										
											2018-07-24 14:05:35 -04:00
										 |  |  |         # Reader chip configuration | 
					
						
							|  |  |  |         self.oid = oid = mcu.create_oid() | 
					
						
							| 
									
										
										
										
											2019-06-20 17:36:46 -04:00
										 |  |  |         mcu.register_response(self._handle_spi_response, | 
					
						
							|  |  |  |                               "thermocouple_result", oid) | 
					
						
							| 
									
										
										
										
											2018-09-03 11:48:22 -04:00
										 |  |  |         mcu.register_config_callback(self._build_config) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |     def setup_minmax(self, min_temp, max_temp): | 
					
						
							| 
									
										
										
										
											2018-07-24 14:12:00 -04:00
										 |  |  |         adc_range = [self.calc_adc(min_temp), self.calc_adc(max_temp)] | 
					
						
							|  |  |  |         self.min_sample_value = min(adc_range) | 
					
						
							|  |  |  |         self.max_sample_value = max(adc_range) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |     def setup_callback(self, cb): | 
					
						
							| 
									
										
										
										
											2018-07-24 14:05:35 -04:00
										 |  |  |         self._callback = cb | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |     def get_report_time_delta(self): | 
					
						
							| 
									
										
										
										
											2018-07-24 14:05:35 -04:00
										 |  |  |         return REPORT_TIME | 
					
						
							| 
									
										
										
										
											2018-09-03 11:48:22 -04:00
										 |  |  |     def _build_config(self): | 
					
						
							| 
									
										
										
										
											2019-02-04 09:30:26 -05:00
										 |  |  |         self.mcu.add_config_cmd( | 
					
						
							| 
									
										
										
										
											2019-03-12 12:58:04 -04:00
										 |  |  |             "config_thermocouple oid=%u spi_oid=%u thermocouple_type=%s" % ( | 
					
						
							| 
									
										
										
										
											2019-02-04 09:30:26 -05:00
										 |  |  |                 self.oid, self.spi.get_oid(), self.chip_type)) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         clock = self.mcu.get_query_slot(self.oid) | 
					
						
							| 
									
										
										
										
											2018-07-24 14:05:35 -04:00
										 |  |  |         self._report_clock = self.mcu.seconds_to_clock(REPORT_TIME) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         self.mcu.add_config_cmd( | 
					
						
							|  |  |  |             "query_thermocouple oid=%u clock=%u rest_ticks=%u" | 
					
						
							|  |  |  |             " min_value=%u max_value=%u" % ( | 
					
						
							|  |  |  |                 self.oid, clock, self._report_clock, | 
					
						
							| 
									
										
										
										
											2018-07-24 19:50:11 -04:00
										 |  |  |                 self.min_sample_value, self.max_sample_value), is_init=True) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |     def _handle_spi_response(self, params): | 
					
						
							| 
									
										
										
										
											2018-07-24 14:50:47 -04:00
										 |  |  |         temp = self.calc_temp(params['value'], params['fault']) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         next_clock      = self.mcu.clock32_to_clock64(params['next_clock']) | 
					
						
							|  |  |  |         last_read_clock = next_clock - self._report_clock | 
					
						
							|  |  |  |         last_read_time  = self.mcu.clock_to_print_time(last_read_clock) | 
					
						
							| 
									
										
										
										
											2018-07-24 14:50:47 -04:00
										 |  |  |         self._callback(last_read_time, temp) | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |     def fault(self, msg): | 
					
						
							|  |  |  |         self.printer.invoke_async_shutdown(msg) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  | # MAX31856 thermocouple | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  | ###################################################################### | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX31856_CR0_REG           = 0x00 | 
					
						
							|  |  |  | MAX31856_CR0_AUTOCONVERT   = 0x80 | 
					
						
							|  |  |  | MAX31856_CR0_1SHOT         = 0x40 | 
					
						
							|  |  |  | MAX31856_CR0_OCFAULT1      = 0x20 | 
					
						
							|  |  |  | MAX31856_CR0_OCFAULT0      = 0x10 | 
					
						
							|  |  |  | MAX31856_CR0_CJ            = 0x08 | 
					
						
							|  |  |  | MAX31856_CR0_FAULT         = 0x04 | 
					
						
							|  |  |  | MAX31856_CR0_FAULTCLR      = 0x02 | 
					
						
							|  |  |  | MAX31856_CR0_FILT50HZ      = 0x01 | 
					
						
							|  |  |  | MAX31856_CR0_FILT60HZ      = 0x00 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX31856_CR1_REG           = 0x01 | 
					
						
							|  |  |  | MAX31856_CR1_AVGSEL1       = 0x00 | 
					
						
							|  |  |  | MAX31856_CR1_AVGSEL2       = 0x10 | 
					
						
							|  |  |  | MAX31856_CR1_AVGSEL4       = 0x20 | 
					
						
							|  |  |  | MAX31856_CR1_AVGSEL8       = 0x30 | 
					
						
							|  |  |  | MAX31856_CR1_AVGSEL16      = 0x70 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX31856_MASK_REG                          = 0x02 | 
					
						
							|  |  |  | MAX31856_MASK_COLD_JUNCTION_HIGH_FAULT     = 0x20 | 
					
						
							|  |  |  | MAX31856_MASK_COLD_JUNCTION_LOW_FAULT      = 0x10 | 
					
						
							|  |  |  | MAX31856_MASK_THERMOCOUPLE_HIGH_FAULT      = 0x08 | 
					
						
							|  |  |  | MAX31856_MASK_THERMOCOUPLE_LOW_FAULT       = 0x04 | 
					
						
							|  |  |  | MAX31856_MASK_VOLTAGE_UNDER_OVER_FAULT     = 0x02 | 
					
						
							|  |  |  | MAX31856_MASK_THERMOCOUPLE_OPEN_FAULT      = 0x01 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX31856_CJHF_REG          = 0x03 | 
					
						
							|  |  |  | MAX31856_CJLF_REG          = 0x04 | 
					
						
							|  |  |  | MAX31856_LTHFTH_REG        = 0x05 | 
					
						
							|  |  |  | MAX31856_LTHFTL_REG        = 0x06 | 
					
						
							|  |  |  | MAX31856_LTLFTH_REG        = 0x07 | 
					
						
							|  |  |  | MAX31856_LTLFTL_REG        = 0x08 | 
					
						
							|  |  |  | MAX31856_CJTO_REG          = 0x09 | 
					
						
							|  |  |  | MAX31856_CJTH_REG          = 0x0A | 
					
						
							|  |  |  | MAX31856_CJTL_REG          = 0x0B | 
					
						
							|  |  |  | MAX31856_LTCBH_REG         = 0x0C | 
					
						
							|  |  |  | MAX31856_LTCBM_REG         = 0x0D | 
					
						
							|  |  |  | MAX31856_LTCBL_REG         = 0x0E | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX31856_SR_REG            = 0x0F | 
					
						
							|  |  |  | MAX31856_FAULT_CJRANGE     = 0x80  # Cold Junction out of range | 
					
						
							|  |  |  | MAX31856_FAULT_TCRANGE     = 0x40  # Thermocouple out of range | 
					
						
							|  |  |  | MAX31856_FAULT_CJHIGH      = 0x20  # Cold Junction High | 
					
						
							|  |  |  | MAX31856_FAULT_CJLOW       = 0x10  # Cold Junction Low | 
					
						
							|  |  |  | MAX31856_FAULT_TCHIGH      = 0x08  # Thermocouple Low | 
					
						
							|  |  |  | MAX31856_FAULT_TCLOW       = 0x04  # Thermocouple Low | 
					
						
							|  |  |  | MAX31856_FAULT_OVUV        = 0x02  # Under Over Voltage | 
					
						
							|  |  |  | MAX31856_FAULT_OPEN        = 0x01 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  | MAX31856_SCALE = 5 | 
					
						
							|  |  |  | MAX31856_MULT = 0.0078125 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MAX31856(SensorBase): | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |     def __init__(self, config): | 
					
						
							| 
									
										
										
										
											2019-03-12 12:58:04 -04:00
										 |  |  |         SensorBase.__init__(self, config, "MAX31856", | 
					
						
							| 
									
										
										
										
											2018-07-24 15:10:10 -04:00
										 |  |  |                             self.build_spi_init(config)) | 
					
						
							| 
									
										
										
										
											2018-07-24 14:50:47 -04:00
										 |  |  |     def calc_temp(self, adc, fault): | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if fault & MAX31856_FAULT_CJRANGE: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31856: Cold Junction Range Fault") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if fault & MAX31856_FAULT_TCRANGE: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31856: Thermocouple Range Fault") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if fault & MAX31856_FAULT_CJHIGH: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31856: Cold Junction High Fault") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if fault & MAX31856_FAULT_CJLOW: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31856: Cold Junction Low Fault") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if fault & MAX31856_FAULT_TCHIGH: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31856: Thermocouple High Fault") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if fault & MAX31856_FAULT_TCLOW: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31856: Thermocouple Low Fault") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if fault & MAX31856_FAULT_OVUV: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31856: Over/Under Voltage Fault") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if fault & MAX31856_FAULT_OPEN: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31856: Thermocouple Open Fault") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         adc = adc >> MAX31856_SCALE | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         # Fix sign bit: | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if adc & 0x40000: | 
					
						
							|  |  |  |             adc = ((adc & 0x3FFFF) + 1) * -1 | 
					
						
							|  |  |  |         temp = MAX31856_MULT * adc | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         return temp | 
					
						
							|  |  |  |     def calc_adc(self, temp): | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         adc = int( ( temp / MAX31856_MULT ) + 0.5 ) # convert to ADC value | 
					
						
							|  |  |  |         adc = adc << MAX31856_SCALE | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         return adc | 
					
						
							| 
									
										
										
										
											2018-07-24 15:10:10 -04:00
										 |  |  |     def build_spi_init(self, config): | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         cmds = [] | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         value = MAX31856_CR0_AUTOCONVERT | 
					
						
							| 
									
										
										
										
											2018-07-24 15:10:10 -04:00
										 |  |  |         if config.getboolean('tc_use_50Hz_filter', False): | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |             value |= MAX31856_CR0_FILT50HZ | 
					
						
							|  |  |  |         cmds.append(0x80 + MAX31856_CR0_REG) | 
					
						
							|  |  |  |         cmds.append(value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-24 15:10:10 -04:00
										 |  |  |         types = { | 
					
						
							|  |  |  |             "B" : 0b0000, | 
					
						
							|  |  |  |             "E" : 0b0001, | 
					
						
							|  |  |  |             "J" : 0b0010, | 
					
						
							|  |  |  |             "K" : 0b0011, | 
					
						
							|  |  |  |             "N" : 0b0100, | 
					
						
							|  |  |  |             "R" : 0b0101, | 
					
						
							|  |  |  |             "S" : 0b0110, | 
					
						
							|  |  |  |             "T" : 0b0111, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         value = config.getchoice('tc_type', types, default="K") | 
					
						
							|  |  |  |         averages = { | 
					
						
							|  |  |  |             "1"  : MAX31856_CR1_AVGSEL1, | 
					
						
							|  |  |  |             "2"  : MAX31856_CR1_AVGSEL2, | 
					
						
							|  |  |  |             "4"  : MAX31856_CR1_AVGSEL4, | 
					
						
							|  |  |  |             "8"  : MAX31856_CR1_AVGSEL8, | 
					
						
							|  |  |  |             "16" : MAX31856_CR1_AVGSEL16 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         value |= config.getchoice('tc_averaging_count', averages, "1") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         cmds.append(0x80 + MAX31856_CR1_REG) | 
					
						
							|  |  |  |         cmds.append(value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         value = (MAX31856_MASK_VOLTAGE_UNDER_OVER_FAULT | | 
					
						
							|  |  |  |                  MAX31856_MASK_THERMOCOUPLE_OPEN_FAULT) | 
					
						
							|  |  |  |         cmds.append(0x80 + MAX31856_MASK_REG) | 
					
						
							|  |  |  |         cmds.append(value) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         return cmds | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  | ###################################################################### | 
					
						
							|  |  |  | # MAX31855 thermocouple | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX31855_SCALE = 18 | 
					
						
							|  |  |  | MAX31855_MULT = 0.25 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MAX31855(SensorBase): | 
					
						
							|  |  |  |     def __init__(self, config): | 
					
						
							| 
									
										
										
										
											2019-05-22 11:40:53 -04:00
										 |  |  |         SensorBase.__init__(self, config, "MAX31855", spi_mode=0) | 
					
						
							| 
									
										
										
										
											2018-07-24 14:50:47 -04:00
										 |  |  |     def calc_temp(self, adc, fault): | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if adc & 0x1: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("MAX31855 : Open Circuit") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if adc & 0x2: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("MAX31855 : Short to GND") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if adc & 0x4: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("MAX31855 : Short to Vcc") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         adc = adc >> MAX31855_SCALE | 
					
						
							|  |  |  |         # Fix sign bit: | 
					
						
							|  |  |  |         if adc & 0x2000: | 
					
						
							|  |  |  |             adc = ((adc & 0x1FFF) + 1) * -1 | 
					
						
							|  |  |  |         temp = MAX31855_MULT * adc | 
					
						
							|  |  |  |         return temp | 
					
						
							|  |  |  |     def calc_adc(self, temp): | 
					
						
							|  |  |  |         adc = int( ( temp / MAX31855_MULT ) + 0.5 ) # convert to ADC value | 
					
						
							|  |  |  |         adc = adc << MAX31855_SCALE | 
					
						
							|  |  |  |         return adc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | # MAX6675 thermocouple | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX6675_SCALE = 3 | 
					
						
							|  |  |  | MAX6675_MULT = 0.25 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MAX6675(SensorBase): | 
					
						
							|  |  |  |     def __init__(self, config): | 
					
						
							| 
									
										
										
										
											2019-05-22 11:40:53 -04:00
										 |  |  |         SensorBase.__init__(self, config, "MAX6675", spi_mode=0) | 
					
						
							| 
									
										
										
										
											2018-07-24 14:50:47 -04:00
										 |  |  |     def calc_temp(self, adc, fault): | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if adc & 0x02: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max6675 : Device ID error") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         if adc & 0x04: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max6675 : Thermocouple Open Fault") | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         adc = adc >> MAX6675_SCALE | 
					
						
							|  |  |  |         # Fix sign bit: | 
					
						
							|  |  |  |         if adc & 0x2000: | 
					
						
							|  |  |  |             adc = ((adc & 0x1FFF) + 1) * -1 | 
					
						
							|  |  |  |         temp = MAX6675_MULT * adc | 
					
						
							|  |  |  |         return temp | 
					
						
							|  |  |  |     def calc_adc(self, temp): | 
					
						
							|  |  |  |         adc = int( ( temp / MAX6675_MULT ) + 0.5 ) # convert to ADC value | 
					
						
							|  |  |  |         adc = adc << MAX6675_SCALE | 
					
						
							|  |  |  |         return adc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  | ###################################################################### | 
					
						
							|  |  |  | # MAX31865 (RTD sensor) | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX31865_CONFIG_REG            = 0x00 | 
					
						
							|  |  |  | MAX31865_RTDMSB_REG            = 0x01 | 
					
						
							|  |  |  | MAX31865_RTDLSB_REG            = 0x02 | 
					
						
							|  |  |  | MAX31865_HFAULTMSB_REG         = 0x03 | 
					
						
							|  |  |  | MAX31865_HFAULTLSB_REG         = 0x04 | 
					
						
							|  |  |  | MAX31865_LFAULTMSB_REG         = 0x05 | 
					
						
							|  |  |  | MAX31865_LFAULTLSB_REG         = 0x06 | 
					
						
							|  |  |  | MAX31865_FAULTSTAT_REG         = 0x07 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX31865_CONFIG_BIAS           = 0x80 | 
					
						
							|  |  |  | MAX31865_CONFIG_MODEAUTO       = 0x40 | 
					
						
							|  |  |  | MAX31865_CONFIG_1SHOT          = 0x20 | 
					
						
							|  |  |  | MAX31865_CONFIG_3WIRE          = 0x10 | 
					
						
							|  |  |  | MAX31865_CONFIG_FAULTCLEAR     = 0x02 | 
					
						
							|  |  |  | MAX31865_CONFIG_FILT50HZ       = 0x01 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MAX31865_FAULT_HIGHTHRESH      = 0x80 | 
					
						
							|  |  |  | MAX31865_FAULT_LOWTHRESH       = 0x40 | 
					
						
							|  |  |  | MAX31865_FAULT_REFINLOW        = 0x20 | 
					
						
							|  |  |  | MAX31865_FAULT_REFINHIGH       = 0x10 | 
					
						
							|  |  |  | MAX31865_FAULT_RTDINLOW        = 0x08 | 
					
						
							|  |  |  | MAX31865_FAULT_OVUV            = 0x04 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | VAL_A = 0.00390830 | 
					
						
							|  |  |  | VAL_B = 0.0000005775 | 
					
						
							|  |  |  | VAL_C = -0.00000000000418301 | 
					
						
							|  |  |  | VAL_ADC_MAX = 32768.0 # 2^15 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  | class MAX31865(SensorBase): | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |     def __init__(self, config): | 
					
						
							|  |  |  |         self.rtd_nominal_r = config.getint('rtd_nominal_r', 100) | 
					
						
							|  |  |  |         self.reference_r = config.getfloat('rtd_reference_r', 430., above=0.) | 
					
						
							| 
									
										
										
										
											2019-03-12 12:58:04 -04:00
										 |  |  |         SensorBase.__init__(self, config, "MAX31865", | 
					
						
							| 
									
										
										
										
											2018-07-24 15:10:10 -04:00
										 |  |  |                             self.build_spi_init(config)) | 
					
						
							| 
									
										
										
										
											2018-07-24 14:50:47 -04:00
										 |  |  |     def calc_temp(self, adc, fault): | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         if fault & 0x80: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31865 RTD input is disconnected") | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         if fault & 0x40: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31865 RTD input is shorted") | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         if fault & 0x20: | 
					
						
							| 
									
										
										
										
											2019-02-27 13:14:23 -05:00
										 |  |  |             self.fault( | 
					
						
							|  |  |  |                 "Max31865 VREF- is greater than 0.85 * VBIAS, FORCE- open") | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         if fault & 0x10: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31865 VREF- is less than 0.85 * VBIAS, FORCE- open") | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         if fault & 0x08: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31865 VRTD- is less than 0.85 * VBIAS, FORCE- open") | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         if fault & 0x04: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31865 Overvoltage or undervoltage fault") | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         if fault & 0x03: | 
					
						
							| 
									
										
										
										
											2018-07-24 15:17:56 -04:00
										 |  |  |             self.fault("Max31865 Unspecified error") | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         adc = adc >> 1 # remove fault bit | 
					
						
							|  |  |  |         R_rtd = (self.reference_r * adc) / VAL_ADC_MAX | 
					
						
							| 
									
										
										
										
											2019-02-27 13:14:23 -05:00
										 |  |  |         temp = ((( ( -1 * self.rtd_nominal_r ) * VAL_A ) | 
					
						
							|  |  |  |                  + math.sqrt( ( self.rtd_nominal_r**2 * VAL_A * VAL_A ) | 
					
						
							|  |  |  |                               - ( 4 * self.rtd_nominal_r * VAL_B | 
					
						
							|  |  |  |                                   * ( self.rtd_nominal_r - R_rtd ) ))) | 
					
						
							|  |  |  |                 / (2 * self.rtd_nominal_r * VAL_B)) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         return temp | 
					
						
							|  |  |  |     def calc_adc(self, temp): | 
					
						
							|  |  |  |         R_rtd = temp * ( 2 * self.rtd_nominal_r * VAL_B ) | 
					
						
							|  |  |  |         R_rtd = math.pow( ( R_rtd + ( self.rtd_nominal_r * VAL_A ) ), 2) | 
					
						
							| 
									
										
										
										
											2019-02-27 13:14:23 -05:00
										 |  |  |         R_rtd = -1 * ( R_rtd - (self.rtd_nominal_r**2 * VAL_A * VAL_A ) ) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         R_rtd = R_rtd / ( 4 * self.rtd_nominal_r * VAL_B ) | 
					
						
							|  |  |  |         R_rtd = ( -1 * R_rtd ) + self.rtd_nominal_r | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |         adc = int( ( ( R_rtd * VAL_ADC_MAX ) / self.reference_r) + 0.5 ) | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         adc = adc << 1 # Add fault bit | 
					
						
							|  |  |  |         return adc | 
					
						
							| 
									
										
										
										
											2018-07-24 15:10:10 -04:00
										 |  |  |     def build_spi_init(self, config): | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |         value = (MAX31865_CONFIG_BIAS | | 
					
						
							|  |  |  |                  MAX31865_CONFIG_MODEAUTO | | 
					
						
							|  |  |  |                  MAX31865_CONFIG_FAULTCLEAR) | 
					
						
							| 
									
										
										
										
											2018-07-24 15:10:10 -04:00
										 |  |  |         if config.getboolean('rtd_use_50Hz_filter', False): | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |             value |= MAX31865_CONFIG_FILT50HZ | 
					
						
							| 
									
										
										
										
											2018-07-24 15:10:10 -04:00
										 |  |  |         if config.getint('rtd_num_of_wires', 2) == 3: | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |             value |= MAX31865_CONFIG_3WIRE | 
					
						
							|  |  |  |         cmd = 0x80 + MAX31865_CONFIG_REG | 
					
						
							|  |  |  |         return [cmd, value] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | # Sensor registration | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Sensors = { | 
					
						
							| 
									
										
										
										
											2018-07-24 14:45:00 -04:00
										 |  |  |     "MAX6675": MAX6675, | 
					
						
							|  |  |  |     "MAX31855": MAX31855, | 
					
						
							|  |  |  |     "MAX31856": MAX31856, | 
					
						
							|  |  |  |     "MAX31865": MAX31865, | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def load_config(config): | 
					
						
							|  |  |  |     # Register sensors | 
					
						
							| 
									
										
										
										
											2020-04-25 13:27:41 -04:00
										 |  |  |     pheaters = config.get_printer().try_load_module(config, "heaters") | 
					
						
							| 
									
										
										
										
											2018-05-04 14:16:21 -04:00
										 |  |  |     for name, klass in Sensors.items(): | 
					
						
							| 
									
										
										
										
											2020-04-25 13:27:41 -04:00
										 |  |  |         pheaters.add_sensor_factory(name, klass) |