From 87778d8c2b43eb564af60b680202cb54574da413 Mon Sep 17 00:00:00 2001 From: Andrew Malota <2bitoperations@gmail.com> Date: Thu, 30 Nov 2017 18:48:39 -0600 Subject: [PATCH 1/6] support for kernel spi (not bitbang) MAX38155 interface --- .gitignore | 1 + config.py.EXAMPLE | 13 ++++++++++--- lib/max31855spi.py | 32 ++++++++++++++++++++++++++++++++ lib/oven.py | 34 +++++++++++++++++++++------------- requirements.txt | 1 + 5 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 lib/max31855spi.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index e2e9708..53b63f4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ thumbs.db storage/profiles config.py +.idea/* diff --git a/config.py.EXAMPLE b/config.py.EXAMPLE index 2dbf4c0..8c771bd 100644 --- a/config.py.EXAMPLE +++ b/config.py.EXAMPLE @@ -35,15 +35,22 @@ heater_invert = 0 # switches the polarity of the heater control ### Inputs gpio_door = 18 -### Thermocouple Adapter selection (MAX31855 or MAX6675) -max31855 = 1 +### Thermocouple Adapter selection: +# max31855 - bitbang SPI interface +# max31855spi - kernel SPI interface +# max6675 - bitbang SPI interface +max31855 = 0 max6675 = 0 +max31855spi = 1 -### Thermocouple I2C Connection +### Thermocouple Connection (using bitbang interfaces) gpio_sensor_cs = 27 gpio_sensor_clock = 22 gpio_sensor_data = 17 +### Thermocouple SPI Connection (using adafrut drivers + kernel SPI interface) +spi_sensor_chip_id = 0 + ######################################################################## # diff --git a/lib/max31855spi.py b/lib/max31855spi.py new file mode 100644 index 0000000..89182de --- /dev/null +++ b/lib/max31855spi.py @@ -0,0 +1,32 @@ +#!/usr/bin/python +from Adafruit_MAX31855 import MAX31855 + +class MAX31855SPI(object): + '''Python driver for [MAX38155 Cold-Junction Compensated Thermocouple-to-Digital Converter](http://www.maximintegrated.com/datasheet/index.mvp/id/7273) + Requires: + - adafruit's MAX31855 SPI-only device library + + ''' + def __init__(self, spi_dev): + self.max31855 = MAX31855.MAX31855(spi=spi_dev) + + def get(self): + '''Reads SPI bus and returns current value of thermocouple.''' + state = self.max31855.readState() + if state['openCircuit']: + raise MAX31855Error('Not Connected') + elif state['shortGND']: + raise MAX31855Error('Short to Ground') + elif state['shortVCC']: + raise MAX31855Error('Short to VCC') + elif state['fault']: + raise MAX31855Error('Unknown Error') + return self.max31855.readLinearizedTempC() + + +class MAX31855SPIError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) diff --git a/lib/oven.py b/lib/oven.py index 74059cb..c8d7be4 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -10,15 +10,19 @@ import config log = logging.getLogger(__name__) try: - if (config.max31855 == config.max6675): - log.error("choose (only) one converter IC") - exit() + if config.max31855 + config.max6675 + config.max31855spi > 1: + log.error("choose (only) one converter IC") + exit() if config.max31855: - from max31855 import MAX31855, MAX31855Error - log.info("import MAX31855") + from max31855 import MAX31855, MAX31855Error + log.info("import MAX31855") + if config.max31855spi: + import Adafruit_GPIO.SPI as SPI + from max6675 import MAX31855SPI, MAX31855SPIError + log.info("import MAX31855SPI") if config.max6675: - from max6675 import MAX6675, MAX6675Error - log.info("import MAX6675") + from max6675 import MAX6675, MAX6675Error + log.info("import MAX6675") sensor_available = True except ImportError: log.warning("Could not initialize temperature sensor, using dummy values!") @@ -147,14 +151,14 @@ class Oven (threading.Thread): self.heat = 1.0 if gpio_available: if config.heater_invert: - GPIO.output(config.gpio_heat, GPIO.LOW) + GPIO.output(config.gpio_heat, GPIO.LOW) else: GPIO.output(config.gpio_heat, GPIO.HIGH) else: self.heat = 0.0 if gpio_available: if config.heater_invert: - GPIO.output(config.gpio_heat, GPIO.HIGH) + GPIO.output(config.gpio_heat, GPIO.HIGH) else: GPIO.output(config.gpio_heat, GPIO.LOW) @@ -211,19 +215,23 @@ class TempSensorReal(TempSensor): def __init__(self, time_step): TempSensor.__init__(self, time_step) if config.max6675: - log.info("init MAX6675") - self.thermocouple = MAX6675(config.gpio_sensor_cs, + log.info("init MAX6675") + self.thermocouple = MAX6675(config.gpio_sensor_cs, config.gpio_sensor_clock, config.gpio_sensor_data, config.temp_scale) if config.max31855: - log.info("init MAX31855") - self.thermocouple = MAX31855(config.gpio_sensor_cs, + log.info("init MAX31855") + self.thermocouple = MAX31855(config.gpio_sensor_cs, config.gpio_sensor_clock, config.gpio_sensor_data, config.temp_scale) + if config.max31855spi: + log.info("init MAX31855-spi") + self.thermocouple = MAX31855SPI(spi_dev=SPI.SpiDev(port=0, device=config.spi_sensor_chip_id)) + def run(self): while True: self.temperature = self.thermocouple.get() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..215aad3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +Adafruit-MAX31855>=1.6.1 \ No newline at end of file From e95a61fe3e7d25bb4bc6a987516ef4608063eb3b Mon Sep 17 00:00:00 2001 From: Andrew Malota <2bitoperations@gmail.com> Date: Thu, 30 Nov 2017 18:58:47 -0600 Subject: [PATCH 2/6] fix a bug or two --- config.py.EXAMPLE | 7 +++++-- lib/oven.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/config.py.EXAMPLE b/config.py.EXAMPLE index 8c771bd..19e9b0f 100644 --- a/config.py.EXAMPLE +++ b/config.py.EXAMPLE @@ -39,9 +39,9 @@ gpio_door = 18 # max31855 - bitbang SPI interface # max31855spi - kernel SPI interface # max6675 - bitbang SPI interface -max31855 = 0 +max31855 = 1 max6675 = 0 -max31855spi = 1 +max31855spi = 0 ### Thermocouple Connection (using bitbang interfaces) gpio_sensor_cs = 27 @@ -51,6 +51,9 @@ gpio_sensor_data = 17 ### Thermocouple SPI Connection (using adafrut drivers + kernel SPI interface) spi_sensor_chip_id = 0 +### amount of time, in seconds, to wait between reads of the thermocouple +sensor_time_wait = .5 + ######################################################################## # diff --git a/lib/oven.py b/lib/oven.py index c8d7be4..06c6c9d 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -48,7 +48,7 @@ class Oven (threading.Thread): STATE_IDLE = "IDLE" STATE_RUNNING = "RUNNING" - def __init__(self, simulate=False, time_step=0.5): + def __init__(self, simulate=False, time_step=config.sensor_time_wait): threading.Thread.__init__(self) self.daemon = True self.simulate = simulate From 0673f9ea9d65b428ffd818009e337277716e6fc7 Mon Sep 17 00:00:00 2001 From: Andrew Malota <2bitoperations@gmail.com> Date: Thu, 30 Nov 2017 19:03:16 -0600 Subject: [PATCH 3/6] add stanza to readme, lose the requirements file --- README.md | 4 ++++ requirements.txt | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) delete mode 100644 requirements.txt diff --git a/README.md b/README.md index 038b167..d9497dd 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,10 @@ If you want to deploy the code on a PI for production: This **only applies to non-Raspbian installations**, since Raspbian ships RPi.GPIO with the default installation. +If you also want to use the in-kernel SPI drivers with a MAX31855 sensor: + + $ sudo pip install Adafruit-MAX31855 + ### Clone repo $ git clone https://github.com/apollo-ng/picoReflow.git diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 215aad3..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -Adafruit-MAX31855>=1.6.1 \ No newline at end of file From 40bb54e521adda729139408f1b88535bf0a776cb Mon Sep 17 00:00:00 2001 From: Andrew Malota <2bitoperations@gmail.com> Date: Thu, 30 Nov 2017 19:09:29 -0600 Subject: [PATCH 4/6] be a little 'softer' with errors --- lib/oven.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/oven.py b/lib/oven.py index 06c6c9d..8aca88d 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -234,7 +234,10 @@ class TempSensorReal(TempSensor): def run(self): while True: - self.temperature = self.thermocouple.get() + try: + self.temperature = self.thermocouple.get() + except Exception as ex: + log.error(ex, "problem reading temp") time.sleep(self.time_step) From 9874aeb1d8c8ac01efe9ab134f717367a6dd7b68 Mon Sep 17 00:00:00 2001 From: Andrew Malota <2bitoperations@gmail.com> Date: Thu, 30 Nov 2017 20:05:16 -0600 Subject: [PATCH 5/6] another stupid oops --- lib/max31855spi.py | 4 ++++ lib/oven.py | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/max31855spi.py b/lib/max31855spi.py index 89182de..b3eb362 100644 --- a/lib/max31855spi.py +++ b/lib/max31855spi.py @@ -1,4 +1,6 @@ #!/usr/bin/python +import logging + from Adafruit_MAX31855 import MAX31855 class MAX31855SPI(object): @@ -9,10 +11,12 @@ class MAX31855SPI(object): ''' def __init__(self, spi_dev): self.max31855 = MAX31855.MAX31855(spi=spi_dev) + self.log = logging.getLogger(__name__) def get(self): '''Reads SPI bus and returns current value of thermocouple.''' state = self.max31855.readState() + self.log.debug("status %s" % state) if state['openCircuit']: raise MAX31855Error('Not Connected') elif state['shortGND']: diff --git a/lib/oven.py b/lib/oven.py index 8aca88d..23e4582 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -18,14 +18,14 @@ try: log.info("import MAX31855") if config.max31855spi: import Adafruit_GPIO.SPI as SPI - from max6675 import MAX31855SPI, MAX31855SPIError + from max31855spi import MAX31855SPI, MAX31855SPIError log.info("import MAX31855SPI") if config.max6675: from max6675 import MAX6675, MAX6675Error log.info("import MAX6675") sensor_available = True except ImportError: - log.warning("Could not initialize temperature sensor, using dummy values!") + log.exception("Could not initialize temperature sensor, using dummy values!") sensor_available = False try: @@ -236,8 +236,8 @@ class TempSensorReal(TempSensor): while True: try: self.temperature = self.thermocouple.get() - except Exception as ex: - log.error(ex, "problem reading temp") + except Exception: + log.exception("problem reading temp") time.sleep(self.time_step) From de0d3baadba045708172d2cde83781b02a813137 Mon Sep 17 00:00:00 2001 From: Andrew Malota <2bitoperations@gmail.com> Date: Fri, 1 Dec 2017 18:59:07 -0600 Subject: [PATCH 6/6] add a note about GPIO collisions with system SPI --- config.py.EXAMPLE | 2 +- lib/oven.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/config.py.EXAMPLE b/config.py.EXAMPLE index 19e9b0f..f002627 100644 --- a/config.py.EXAMPLE +++ b/config.py.EXAMPLE @@ -41,7 +41,7 @@ gpio_door = 18 # max6675 - bitbang SPI interface max31855 = 1 max6675 = 0 -max31855spi = 0 +max31855spi = 0 # if you use this one, you MUST reassign the default GPIO pins ### Thermocouple Connection (using bitbang interfaces) gpio_sensor_cs = 27 diff --git a/lib/oven.py b/lib/oven.py index 23e4582..fadd42d 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -20,6 +20,15 @@ try: import Adafruit_GPIO.SPI as SPI from max31855spi import MAX31855SPI, MAX31855SPIError log.info("import MAX31855SPI") + spi_reserved_gpio = [7, 8, 9, 10, 11] + if config.gpio_air in spi_reserved_gpio: + raise Exception("gpio_air pin %s collides with SPI pins %s" % (config.gpio_air, spi_reserved_gpio)) + if config.gpio_cool in spi_reserved_gpio: + raise Exception("gpio_cool pin %s collides with SPI pins %s" % (config.gpio_cool, spi_reserved_gpio)) + if config.gpio_door in spi_reserved_gpio: + raise Exception("gpio_door pin %s collides with SPI pins %s" % (config.gpio_door, spi_reserved_gpio)) + if config.gpio_heat in spi_reserved_gpio: + raise Exception("gpio_heat pin %s collides with SPI pins %s" % (config.gpio_heat, spi_reserved_gpio)) if config.max6675: from max6675 import MAX6675, MAX6675Error log.info("import MAX6675")