Fix MAX31865 on SPI (PT100/1000) support (#20074)

This commit is contained in:
JoAnn Manges 2020-11-11 16:52:35 -05:00 committed by GitHub
parent 6ccb4b93b1
commit 40d442fde2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 100 deletions

View File

@ -436,11 +436,11 @@
#define DUMMY_THERMISTOR_998_VALUE 25
#define DUMMY_THERMISTOR_999_VALUE 100
// Resistor values when using a MAX31865 (sensor -5)
// Sensor value is typically 100 (PT100) or 1000 (PT1000)
// Calibration value is typically 430 ohm for AdaFruit PT100 modules and 4300 ohm for AdaFruit PT1000 modules.
//#define MAX31865_SENSOR_OHMS 100
//#define MAX31865_CALIBRATION_OHMS 430
// Resistor values when using MAX31865 sensors (-5) on TEMP_SENSOR_0 / 1
//#define MAX31865_SENSOR_OHMS_0 100 // (Ω) Typically 100 or 1000 (PT100 or PT1000)
//#define MAX31865_CALIBRATION_OHMS_0 430 // (Ω) Typically 430 for AdaFruit PT100; 4300 for AdaFruit PT1000
//#define MAX31865_SENSOR_OHMS_1 100
//#define MAX31865_CALIBRATION_OHMS_1 430
// Use temp sensor 1 as a redundant sensor with sensor 0. If the readings
// from the two sensors differ too much the print will be aborted.

View File

@ -445,9 +445,9 @@
#define HEATER_0_MAX6675_TMAX 1024
#endif
#if TEMP_SENSOR_0 == -5
#define MAX6675_IS_MAX31865 1
#define MAX6675_0_IS_MAX31865 1
#elif TEMP_SENSOR_0 == -3
#define MAX6675_IS_MAX31855 1
#define MAX6675_0_IS_MAX31855 1
#endif
#elif TEMP_SENSOR_0 == -4
#define HEATER_0_USES_AD8495 1
@ -473,6 +473,11 @@
#define HEATER_1_MAX6675_TMIN 0
#define HEATER_1_MAX6675_TMAX 1024
#endif
#if TEMP_SENSOR_1 == -5
#define MAX6675_1_IS_MAX31865 1
#elif TEMP_SENSOR_1 == -3
#define MAX6675_1_IS_MAX31855 1
#endif
#if TEMP_SENSOR_1 != TEMP_SENSOR_0
#if TEMP_SENSOR_1 == -5
#error "If MAX31865 Thermocouple (-5) is used for TEMP_SENSOR_1 then TEMP_SENSOR_0 must match."

View File

@ -405,6 +405,10 @@
#error "MAX6675_SS is now MAX6675_SS_PIN. Please update your configuration and/or pins."
#elif defined(MAX6675_SS2)
#error "MAX6675_SS2 is now MAX6675_SS2_PIN. Please update your configuration and/or pins."
#elif defined(MAX31865_SENSOR_OHMS)
#error "MAX31865_SENSOR_OHMS is now MAX31865_SENSOR_OHMS_0. Please update your configuration."
#elif defined(MAX31865_CALIBRATION_OHMS)
#error "MAX31865_CALIBRATION_OHMS is now MAX31865_CALIBRATION_OHMS_0. Please update your configuration."
#elif defined(SPINDLE_LASER_ENABLE)
#error "SPINDLE_LASER_ENABLE is now SPINDLE_FEATURE or LASER_FEATURE. Please update your Configuration_adv.h."
#elif defined(SPINDLE_LASER_ENABLE_PIN)
@ -1814,8 +1818,10 @@ static_assert(hbm[Z_AXIS] >= 0, "HOMING_BUMP_MM.Z must be greater than or equal
#error "TEMP_SENSOR_1 is required with TEMP_SENSOR_1_AS_REDUNDANT."
#endif
#if MAX6675_IS_MAX31865 && !(defined(MAX31865_SENSOR_OHMS) && defined(MAX31865_CALIBRATION_OHMS))
#error "MAX31865_SENSOR_OHMS and MAX31865_CALIBRATION_OHMS must be set in Configuration.h when using a MAX31865 temperature sensor."
#if MAX6675_0_IS_MAX31865 && !(defined(MAX31865_SENSOR_OHMS_0) && defined(MAX31865_CALIBRATION_OHMS_0))
#error "MAX31865_SENSOR_OHMS_0 and MAX31865_CALIBRATION_OHMS_0 must be set in Configuration.h if TEMP_SENSOR_0 is MAX31865."
#elif MAX6675_1_IS_MAX31865 && !(defined(MAX31865_SENSOR_OHMS_1) && defined(MAX31865_CALIBRATION_OHMS_1))
#error "MAX31865_SENSOR_OHMS_1 and MAX31865_CALIBRATION_OHMS_1 must be set in Configuration.h if TEMP_SENSOR_1 is MAX31865."
#endif
/**

View File

@ -44,30 +44,44 @@
#include "../lcd/extui/ui_api.h"
#endif
#if MAX6675_IS_MAX31865
#if MAX6675_0_IS_MAX31865 || MAX6675_1_IS_MAX31865
#include <Adafruit_MAX31865.h>
#ifndef MAX31865_CS_PIN
#define MAX31865_CS_PIN MAX6675_SS_PIN // HW:49 SW:65 for example
#if MAX6675_0_IS_MAX31865 && !defined(MAX31865_CS_PIN) && PIN_EXISTS(MAX6675_SS)
#define MAX31865_CS_PIN MAX6675_SS_PIN
#endif
#if MAX6675_1_IS_MAX31865 && !defined(MAX31865_CS2_PIN) && PIN_EXISTS(MAX6675_SS2)
#define MAX31865_CS2_PIN MAX6675_SS2_PIN
#endif
#ifndef MAX31865_MOSI_PIN
#define MAX31865_MOSI_PIN MOSI_PIN // 63
#define MAX31865_MOSI_PIN MOSI_PIN
#endif
#ifndef MAX31865_MISO_PIN
#define MAX31865_MISO_PIN MAX6675_DO_PIN // 42
#define MAX31865_MISO_PIN MAX6675_DO_PIN
#endif
#ifndef MAX31865_SCK_PIN
#define MAX31865_SCK_PIN MAX6675_SCK_PIN // 40
#define MAX31865_SCK_PIN MAX6675_SCK_PIN
#endif
Adafruit_MAX31865 max31865 = Adafruit_MAX31865(MAX31865_CS_PIN
#if MAX6675_0_IS_MAX31865 && PIN_EXISTS(MAX31865_CS)
#define HAS_MAX31865 1
Adafruit_MAX31865 max31865_0 = Adafruit_MAX31865(MAX31865_CS_PIN
#if MAX31865_CS_PIN != MAX6675_SS_PIN
, MAX31865_MOSI_PIN // For software SPI also set MOSI/MISO/SCK
, MAX31865_MISO_PIN
, MAX31865_SCK_PIN
, MAX31865_MOSI_PIN, MAX31865_MISO_PIN, MAX31865_SCK_PIN // For software SPI also set MOSI/MISO/SCK
#endif
);
#endif
#if MAX6675_1_IS_MAX31865 && PIN_EXISTS(MAX31865_CS2)
#define HAS_MAX31865 1
Adafruit_MAX31865 max31865_1 = Adafruit_MAX31865(MAX31865_CS2_PIN
#if MAX31865_CS2_PIN != MAX6675_SS2_PIN
, MAX31865_MOSI_PIN, MAX31865_MISO_PIN, MAX31865_SCK_PIN // For software SPI also set MOSI/MISO/SCK
#endif
);
#endif
#endif
#define MAX6675_SEPARATE_SPI (EITHER(HEATER_0_USES_MAX6675, HEATER_1_USES_MAX6675) && PINS_EXIST(MAX6675_SCK, MAX6675_DO))
#if EITHER(HEATER_0_USES_MAX6675, HEATER_1_USES_MAX6675) && PINS_EXIST(MAX6675_SCK, MAX6675_DO)
#define MAX6675_SEPARATE_SPI 1
#endif
#if MAX6675_SEPARATE_SPI
#include "../libs/private_spi.h"
@ -1471,13 +1485,7 @@ void Temperature::manage_heater() {
#if HEATER_0_USER_THERMISTOR
return user_thermistor_to_deg_c(CTI_HOTEND_0, raw);
#elif HEATER_0_USES_MAX6675
return (
#if MAX6675_IS_MAX31865
max31865.temperature(MAX31865_SENSOR_OHMS, MAX31865_CALIBRATION_OHMS)
#else
raw * 0.25
#endif
);
return TERN(MAX6675_0_IS_MAX31865, max31865_0.temperature(MAX31865_SENSOR_OHMS_0, MAX31865_CALIBRATION_OHMS_0), raw * 0.25);
#elif HEATER_0_USES_AD595
return TEMP_AD595(raw);
#elif HEATER_0_USES_AD8495
@ -1489,7 +1497,7 @@ void Temperature::manage_heater() {
#if HEATER_1_USER_THERMISTOR
return user_thermistor_to_deg_c(CTI_HOTEND_1, raw);
#elif HEATER_1_USES_MAX6675
return raw * 0.25;
return TERN(MAX6675_1_IS_MAX31865, max31865_1.temperature(MAX31865_SENSOR_OHMS_1, MAX31865_CALIBRATION_OHMS_1), raw * 0.25);
#elif HEATER_1_USES_AD595
return TEMP_AD595(raw);
#elif HEATER_1_USES_AD8495
@ -1691,7 +1699,8 @@ void Temperature::updateTemperaturesFromRawValues() {
*/
void Temperature::init() {
TERN_(MAX6675_IS_MAX31865, max31865.begin(MAX31865_2WIRE)); // MAX31865_2WIRE, MAX31865_3WIRE, MAX31865_4WIRE
TERN_(MAX6675_0_IS_MAX31865, max31865_0.begin(MAX31865_2WIRE)); // MAX31865_2WIRE, MAX31865_3WIRE, MAX31865_4WIRE
TERN_(MAX6675_1_IS_MAX31865, max31865_1.begin(MAX31865_2WIRE));
#if EARLY_WATCHDOG
// Flag that the thermalManager should be running
@ -2200,27 +2209,19 @@ void Temperature::disable_all_heaters() {
#define THERMOCOUPLE_MAX_ERRORS 15
#endif
int Temperature::read_max6675(
#if COUNT_6675 > 1
const uint8_t hindex
#endif
) {
#if COUNT_6675 == 1
constexpr uint8_t hindex = 0;
#else
// Needed to return the correct temp when this is called too soon
static uint16_t max6675_temp_previous[COUNT_6675] = { 0 };
#endif
static uint8_t max6675_errors[COUNT_6675] = { 0 };
int Temperature::read_max6675(TERN_(HAS_MULTI_6675, const uint8_t hindex/*=0*/)) {
#define MAX6675_HEAT_INTERVAL 250UL
#if MAX6675_IS_MAX31855
#if MAX6675_0_IS_MAX31855 || MAX6675_1_IS_MAX31855
static uint32_t max6675_temp = 2000;
#define MAX6675_ERROR_MASK 7
#define MAX6675_DISCARD_BITS 18
#define MAX6675_SPEED_BITS 3 // (_BV(SPR1)) // clock ÷ 64
#elif HAS_MAX31865
static uint16_t max6675_temp = 2000; // From datasheet 16 bits D15-D0
#define MAX6675_ERROR_MASK 1 // D0 Bit not used
#define MAX6675_DISCARD_BITS 1 // Data is in D15-D1
#define MAX6675_SPEED_BITS 3 // (_BV(SPR1)) // clock ÷ 64
#else
static uint16_t max6675_temp = 2000;
#define MAX6675_ERROR_MASK 4
@ -2228,22 +2229,44 @@ void Temperature::disable_all_heaters() {
#define MAX6675_SPEED_BITS 2 // (_BV(SPR0)) // clock ÷ 16
#endif
#if HAS_MULTI_6675
// Needed to return the correct temp when this is called between readings
static uint16_t max6675_temp_previous[COUNT_6675] = { 0 };
#define MAX6675_TEMP(I) max6675_temp_previous[I]
#define MAX6675_SEL(A,B) (hindex ? (B) : (A))
#define MAX6675_WRITE(V) do{ switch (hindex) { case 1: WRITE(MAX6675_SS2_PIN, V); break; default: WRITE(MAX6675_SS_PIN, V); } }while(0)
#define MAX6675_SET_OUTPUT() do{ switch (hindex) { case 1: SET_OUTPUT(MAX6675_SS2_PIN); break; default: SET_OUTPUT(MAX6675_SS_PIN); } }while(0)
#else
constexpr uint8_t hindex = 0;
#define MAX6675_TEMP(I) max6675_temp
#if MAX6675_1_IS_MAX31865
#define MAX6675_SEL(A,B) B
#else
#define MAX6675_SEL(A,B) A
#endif
#if HEATER_0_USES_MAX6675
#define MAX6675_WRITE(V) WRITE(MAX6675_SS_PIN, V)
#define MAX6675_SET_OUTPUT() SET_OUTPUT(MAX6675_SS_PIN)
#else
#define MAX6675_WRITE(V) WRITE(MAX6675_SS2_PIN, V)
#define MAX6675_SET_OUTPUT() SET_OUTPUT(MAX6675_SS2_PIN)
#endif
#endif
static uint8_t max6675_errors[COUNT_6675] = { 0 };
// Return last-read value between readings
static millis_t next_max6675_ms[COUNT_6675] = { 0 };
millis_t ms = millis();
if (PENDING(ms, next_max6675_ms[hindex]))
return int(
#if COUNT_6675 == 1
max6675_temp
#else
max6675_temp_previous[hindex] // Need to return the correct previous value
#endif
);
if (PENDING(ms, next_max6675_ms[hindex])) return int(MAX6675_TEMP(hindex));
next_max6675_ms[hindex] = ms + MAX6675_HEAT_INTERVAL;
#if MAX6675_IS_MAX31865
max6675_temp = int(max31865.temperature(MAX31865_SENSOR_OHMS, MAX31865_CALIBRATION_OHMS));
#if HAS_MAX31865
Adafruit_MAX31865 &maxref = MAX6675_SEL(max31865_0, max31865_1);
max6675_temp = int(maxref.temperature(
MAX6675_SEL(MAX31865_SENSOR_OHMS_0, MAX31865_SENSOR_OHMS_1),
MAX6675_SEL(MAX31865_CALIBRATION_OHMS_0, MAX31865_CALIBRATION_OHMS_1)
));
#endif
//
@ -2254,39 +2277,24 @@ void Temperature::disable_all_heaters() {
spiInit(MAX6675_SPEED_BITS);
#endif
#if COUNT_6675 > 1
#define WRITE_MAX6675(V) do{ switch (hindex) { case 1: WRITE(MAX6675_SS2_PIN, V); break; default: WRITE(MAX6675_SS_PIN, V); } }while(0)
#define SET_OUTPUT_MAX6675() do{ switch (hindex) { case 1: SET_OUTPUT(MAX6675_SS2_PIN); break; default: SET_OUTPUT(MAX6675_SS_PIN); } }while(0)
#elif HEATER_1_USES_MAX6675
#define WRITE_MAX6675(V) WRITE(MAX6675_SS2_PIN, V)
#define SET_OUTPUT_MAX6675() SET_OUTPUT(MAX6675_SS2_PIN)
#else
#define WRITE_MAX6675(V) WRITE(MAX6675_SS_PIN, V)
#define SET_OUTPUT_MAX6675() SET_OUTPUT(MAX6675_SS_PIN)
#endif
SET_OUTPUT_MAX6675();
WRITE_MAX6675(LOW); // enable TT_MAX6675
MAX6675_SET_OUTPUT();
MAX6675_WRITE(LOW); // enable TT_MAX6675
DELAY_NS(100); // Ensure 100ns delay
// Read a big-endian temperature value
max6675_temp = 0;
for (uint8_t i = sizeof(max6675_temp); i--;) {
max6675_temp |= (
#if MAX6675_SEPARATE_SPI
max6675_spi.receive()
#else
spiRec()
#endif
);
max6675_temp |= TERN(MAX6675_SEPARATE_SPI, max6675_spi.receive(), spiRec());
if (i > 0) max6675_temp <<= 8; // shift left if not the last byte
}
WRITE_MAX6675(HIGH); // disable TT_MAX6675
MAX6675_WRITE(HIGH); // disable TT_MAX6675
if (DISABLED(IGNORE_THERMOCOUPLE_ERRORS) && (max6675_temp & MAX6675_ERROR_MASK)) {
max6675_errors[hindex] += 1;
const uint8_t fault_31865 = TERN1(HAS_MAX31865, maxref.readFault());
if (DISABLED(IGNORE_THERMOCOUPLE_ERRORS) && (max6675_temp & MAX6675_ERROR_MASK) && fault_31865) {
max6675_errors[hindex]++;
if (max6675_errors[hindex] > THERMOCOUPLE_MAX_ERRORS) {
SERIAL_ERROR_START();
SERIAL_ECHOPGM("Temp measurement error! ");
@ -2298,18 +2306,29 @@ void Temperature::disable_all_heaters() {
SERIAL_ECHOLNPGM("Short to GND");
else if (max6675_temp & 4)
SERIAL_ECHOLNPGM("Short to VCC");
#elif HAS_MAX31865
if (fault_31865) {
maxref.clearFault();
SERIAL_ECHOPAIR("MAX31865 Fault :(", fault_31865, ") >>");
if (fault_31865 & MAX31865_FAULT_HIGHTHRESH)
SERIAL_ECHOLNPGM("RTD High Threshold");
else if (fault_31865 & MAX31865_FAULT_LOWTHRESH)
SERIAL_ECHOLNPGM("RTD Low Threshold");
else if (fault_31865 & MAX31865_FAULT_REFINLOW)
SERIAL_ECHOLNPGM("REFIN- > 0.85 x Bias");
else if (fault_31865 & MAX31865_FAULT_REFINHIGH)
SERIAL_ECHOLNPGM("REFIN- < 0.85 x Bias - FORCE- open");
else if (fault_31865 & MAX31865_FAULT_RTDINLOW)
SERIAL_ECHOLNPGM("REFIN- < 0.85 x Bias - FORCE- open");
else if (fault_31865 & MAX31865_FAULT_OVUV)
SERIAL_ECHOLNPGM("Under/Over voltage");
}
#else
SERIAL_ECHOLNPGM("MAX6675");
#endif
// Thermocouple open
max6675_temp = 4 * (
#if COUNT_6675 > 1
hindex ? HEATER_1_MAX6675_TMAX : HEATER_0_MAX6675_TMAX
#else
TERN(HEATER_1_USES_MAX6675, HEATER_1_MAX6675_TMAX, HEATER_0_MAX6675_TMAX)
#endif
);
max6675_temp = 4 * MAX6675_SEL(HEATER_0_MAX6675_TMAX, HEATER_1_MAX6675_TMAX);
}
else
max6675_temp >>= MAX6675_DISCARD_BITS;
@ -2319,13 +2338,11 @@ void Temperature::disable_all_heaters() {
max6675_errors[hindex] = 0;
}
#if ENABLED(MAX6675_IS_MAX31855)
#if MAX6675_0_IS_MAX31855 || MAX6675_1_IS_MAX31855
if (max6675_temp & 0x00002000) max6675_temp |= 0xFFFFC000; // Support negative temperature
#endif
#if COUNT_6675 > 1
max6675_temp_previous[hindex] = max6675_temp;
#endif
MAX6675_TEMP(hindex) = max6675_temp;
return int(max6675_temp);
}

View File

@ -811,7 +811,7 @@ class Temperature {
#if HAS_MAX6675
#define COUNT_6675 1 + BOTH(HEATER_0_USES_MAX6675, HEATER_1_USES_MAX6675)
#if COUNT_6675 > 1
#define HAS_MULTI_6675
#define HAS_MULTI_6675 1
#define READ_MAX6675(N) read_max6675(N)
#else
#define READ_MAX6675(N) read_max6675()

View File

@ -55,10 +55,10 @@ extern "C"{
*----------------------------------------------------------------------------*/
// Number of pins defined in PinDescription array
#define PINS_COUNT (79U)
#define NUM_DIGITAL_PINS (66U)
#define NUM_ANALOG_INPUTS (12U)
#define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1)
#define PINS_COUNT 79
#define NUM_DIGITAL_PINS 66
#define NUM_ANALOG_INPUTS 12
#define analogInputToDigitalPin(p) ((p < 12) ? (p) + 54 : -1)
#define digitalPinToPort(P) ( g_APinDescription[P].pPort )
#define digitalPinToBitMask(P) ( g_APinDescription[P].ulPin )

View File

@ -222,7 +222,7 @@ HAS_L64XX = Arduino-L6470@0.8.0
src_filter=+<src/libs/L64XX> +<src/module/stepper/L64xx.cpp> +<src/gcode/feature/L6470>
NEOPIXEL_LED = Adafruit NeoPixel@1.5.0
src_filter=+<src/feature/leds/neopixel.cpp>
MAX6675_IS_MAX31865 = Adafruit MAX31865 library@~1.1.0
MAX6675_._IS_MAX31865 = Adafruit MAX31865 library@~1.1.0
USES_LIQUIDCRYSTAL = LiquidCrystal@1.5.0
USES_LIQUIDCRYSTAL_I2C = marcoschwartz/LiquidCrystal_I2C@1.1.4
USES_LIQUIDTWI2 = LiquidTWI2@1.2.7