🐛 Fix dual MAX31865 initialization issues (#23496)
This commit is contained in:
		
				
					committed by
					
						
						Scott Lahteine
					
				
			
			
				
	
			
			
			
						parent
						
							a23ecf0d2f
						
					
				
				
					commit
					cdcf31453b
				
			@@ -138,24 +138,21 @@
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Configuration options for MAX Thermocouples (-2, -3, -5).
 | 
					 * Thermocouple Options — for MAX6675 (-2), MAX31855 (-3), and MAX31865 (-5).
 | 
				
			||||||
 *   FORCE_HW_SPI:   Ignore SCK/MOSI/MISO pins and just use the CS pin & default SPI bus.
 | 
					 | 
				
			||||||
 *   MAX31865_WIRES: Set the number of wires for the probe connected to a MAX31865 board, 2-4. Default: 2
 | 
					 | 
				
			||||||
 *   MAX31865_50HZ:  Enable 50Hz filter instead of the default 60Hz.
 | 
					 | 
				
			||||||
 *   MAX31865_USE_READ_ERROR_DETECTION: Detects random read errors from value spikes (a 20°C difference in less than 1sec)
 | 
					 | 
				
			||||||
 *   MAX31865_USE_AUTO_MODE: Faster and more frequent reads than 1-shot, but bias voltage always on, slightly affecting RTD temperature.
 | 
					 | 
				
			||||||
 *   MAX31865_MIN_SAMPLING_TIME_MSEC: in 1-shot mode, the minimum time between subsequent reads. This reduces the effect of bias voltage by leaving the sensor unpowered for longer intervals.
 | 
					 | 
				
			||||||
 *   MAX31865_WIRE_OHMS: In 2-wire configurations, manually set the wire resistance for more accurate readings
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
//#define TEMP_SENSOR_FORCE_HW_SPI
 | 
					//#define TEMP_SENSOR_FORCE_HW_SPI                // Ignore SCK/MOSI/MISO pins; use CS and the default SPI bus.
 | 
				
			||||||
//#define MAX31865_SENSOR_WIRES_0 2
 | 
					//#define MAX31865_SENSOR_WIRES_0 2               // (2-4) Number of wires for the probe connected to a MAX31865 board.
 | 
				
			||||||
//#define MAX31865_SENSOR_WIRES_1 2
 | 
					//#define MAX31865_SENSOR_WIRES_1 2
 | 
				
			||||||
//#define MAX31865_50HZ_FILTER
 | 
					
 | 
				
			||||||
//#define MAX31865_USE_READ_ERROR_DETECTION
 | 
					//#define MAX31865_50HZ_FILTER                    // Use a 50Hz filter instead of the default 60Hz.
 | 
				
			||||||
//#define MAX31865_USE_AUTO_MODE
 | 
					//#define MAX31865_USE_READ_ERROR_DETECTION       // Treat value spikes (20°C delta in under 1s) as read errors.
 | 
				
			||||||
//#define MAX31865_MIN_SAMPLING_TIME_MSEC 100
 | 
					
 | 
				
			||||||
//#define MAX31865_WIRE_OHMS_0 0.0f
 | 
					//#define MAX31865_USE_AUTO_MODE                  // Read faster and more often than 1-shot; bias voltage always on; slight effect on RTD temperature.
 | 
				
			||||||
//#define MAX31865_WIRE_OHMS_1 0.0f
 | 
					//#define MAX31865_MIN_SAMPLING_TIME_MSEC     100 // (ms) 1-shot: minimum read interval. Reduces bias voltage effects by leaving sensor unpowered for longer intervals.
 | 
				
			||||||
 | 
					//#define MAX31865_IGNORE_INITIAL_FAULTY_READS 10 // Ignore some read faults (keeping the temperature reading) to work around a possible issue (#23439).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//#define MAX31865_WIRE_OHMS_0              0.95f // For 2-wire, set the wire resistances for more accurate readings.
 | 
				
			||||||
 | 
					//#define MAX31865_WIRE_OHMS_1              0.0f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Hephestos 2 24V heated bed upgrade kit.
 | 
					 * Hephestos 2 24V heated bed upgrade kit.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -166,6 +166,8 @@ void calibrate_delay_loop();
 | 
				
			|||||||
  // Delay in microseconds
 | 
					  // Delay in microseconds
 | 
				
			||||||
  #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
 | 
					  #define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #define DELAY_CYCLES_VAR DELAY_CYCLES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif defined(ESP32) || defined(__PLAT_LINUX__) || defined(__PLAT_NATIVE_SIM__)
 | 
					#elif defined(ESP32) || defined(__PLAT_LINUX__) || defined(__PLAT_NATIVE_SIM__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // DELAY_CYCLES specified inside platform
 | 
					  // DELAY_CYCLES specified inside platform
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,10 +50,6 @@
 | 
				
			|||||||
  #define MAX31865_MIN_SAMPLING_TIME_MSEC 0
 | 
					  #define MAX31865_MIN_SAMPLING_TIME_MSEC 0
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TARGET_LPC1768
 | 
					 | 
				
			||||||
  #include <SoftwareSPI.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define DEBUG_OUT ENABLED(DEBUG_MAX31865)
 | 
					#define DEBUG_OUT ENABLED(DEBUG_MAX31865)
 | 
				
			||||||
#include "../core/debug_out.h"
 | 
					#include "../core/debug_out.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -151,24 +147,62 @@ void MAX31865::begin(max31865_numwires_t wires, float zero_res, float ref_res, f
 | 
				
			|||||||
  digitalWrite(cselPin, HIGH);
 | 
					  digitalWrite(cselPin, HIGH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (sclkPin != TERN(LARGE_PINMAP, -1UL, 255))
 | 
					  if (sclkPin != TERN(LARGE_PINMAP, -1UL, 255))
 | 
				
			||||||
    softSpiBegin(SPI_QUARTER_SPEED); // Define pin modes for Software SPI
 | 
					    softSpiInit(); // Define pin modes for Software SPI
 | 
				
			||||||
  else {
 | 
					  else {
 | 
				
			||||||
    DEBUG_ECHOLNPGM("Initializing MAX31865 Hardware SPI");
 | 
					    DEBUG_ECHOLNPGM("Init MAX31865 Hardware SPI");
 | 
				
			||||||
    SPI.begin();    // Start and configure hardware SPI
 | 
					    SPI.begin();    // Start and configure hardware SPI
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  initFixedFlags(wires);
 | 
					  initFixedFlags(wires);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  clearFault(); // also initializes flags
 | 
					  DEBUG_ECHOLNPGM("MAX31865 Regs: CFG ", readRegister8(MAX31865_CONFIG_REG),
 | 
				
			||||||
 | 
					    "|RTD ", readRegister16(MAX31865_RTDMSB_REG),
 | 
				
			||||||
 | 
					    "|HTHRS ", readRegister16(MAX31865_HFAULTMSB_REG),
 | 
				
			||||||
 | 
					    "|LTHRS ", readRegister16(MAX31865_LFAULTMSB_REG),
 | 
				
			||||||
 | 
					    "|FLT  ", readRegister8(MAX31865_FAULTSTAT_REG));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #if DISABLED(MAX31865_USE_AUTO_MODE) // make a proper first 1 shot read to initialize _lastRead
 | 
					  // fault detection cycle seems to initialize the sensor better
 | 
				
			||||||
 | 
					  runAutoFaultDetectionCycle(); // also initializes flags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (lastFault)
 | 
				
			||||||
 | 
					    SERIAL_ECHOLNPGM("MAX31865 init fault ", lastFault);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  writeRegister16(MAX31865_HFAULTMSB_REG, 0xFFFF);
 | 
				
			||||||
 | 
					  writeRegister16(MAX31865_LFAULTMSB_REG, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #if ENABLED(MAX31865_USE_AUTO_MODE) // make a proper first read to initialize _lastRead
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #if MAX31865_IGNORE_INITIAL_FAULTY_READS > 0
 | 
				
			||||||
 | 
					      rtd = fixFault(rtd);
 | 
				
			||||||
 | 
					    #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rtd & 1) {
 | 
				
			||||||
 | 
					      lastRead = 0xFFFF; // some invalid value
 | 
				
			||||||
 | 
					      lastFault = readRegister8(MAX31865_FAULTSTAT_REG);
 | 
				
			||||||
 | 
					      clearFault(); // also clears the bias voltage flag, so no further action is required
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      DEBUG_ECHOLNPGM("MAX31865 read fault: ", rtd);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      DEBUG_ECHOLNPGM("RTD MSB:", (rtd >> 8), "  RTD LSB:", (rtd & 0x00FF));
 | 
				
			||||||
 | 
					      lastRead = rtd;
 | 
				
			||||||
 | 
					      TERN_(MAX31865_USE_READ_ERROR_DETECTION, lastReadStamp = millis());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    enableBias();
 | 
					    enableBias();
 | 
				
			||||||
    DELAY_US(11500);
 | 
					    DELAY_US(2000); // according to the datasheet, 10.5τ+1msec (see below)
 | 
				
			||||||
    oneShot();
 | 
					    oneShot();
 | 
				
			||||||
    DELAY_US(65000);
 | 
					    DELAY_US(63000);
 | 
				
			||||||
    uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG);
 | 
					    uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #if MAX31865_IGNORE_INITIAL_FAULTY_READS > 0
 | 
				
			||||||
 | 
					      rtd = fixFault(rtd);
 | 
				
			||||||
 | 
					    #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (rtd & 1) {
 | 
					    if (rtd & 1) {
 | 
				
			||||||
      lastRead = 0xFFFF; // some invalid value
 | 
					      lastRead = 0xFFFF; // some invalid value
 | 
				
			||||||
      lastFault = readRegister8(MAX31865_FAULTSTAT_REG);
 | 
					      lastFault = readRegister8(MAX31865_FAULTSTAT_REG);
 | 
				
			||||||
@@ -189,7 +223,7 @@ void MAX31865::begin(max31865_numwires_t wires, float zero_res, float ref_res, f
 | 
				
			|||||||
      TERN_(MAX31865_USE_READ_ERROR_DETECTION, lastReadStamp = now);
 | 
					      TERN_(MAX31865_USE_READ_ERROR_DETECTION, lastReadStamp = now);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #endif // !MAX31865_USE_AUTO_MODE
 | 
					  #endif // MAX31865_USE_AUTO_MODE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  DEBUG_ECHOLNPGM(
 | 
					  DEBUG_ECHOLNPGM(
 | 
				
			||||||
    TERN(LARGE_PINMAP, "LARGE_PINMAP", "Regular")
 | 
					    TERN(LARGE_PINMAP, "LARGE_PINMAP", "Regular")
 | 
				
			||||||
@@ -198,7 +232,7 @@ void MAX31865::begin(max31865_numwires_t wires, float zero_res, float ref_res, f
 | 
				
			|||||||
    " sclkPin: ", sclkPin,
 | 
					    " sclkPin: ", sclkPin,
 | 
				
			||||||
    " mosiPin: ", mosiPin,
 | 
					    " mosiPin: ", mosiPin,
 | 
				
			||||||
    " config: ", readRegister8(MAX31865_CONFIG_REG)
 | 
					    " config: ", readRegister8(MAX31865_CONFIG_REG)
 | 
				
			||||||
  );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -240,6 +274,29 @@ void MAX31865::oneShot() {
 | 
				
			|||||||
  setConfig(MAX31865_CONFIG_1SHOT | MAX31865_CONFIG_BIAS, 1);
 | 
					  setConfig(MAX31865_CONFIG_1SHOT | MAX31865_CONFIG_BIAS, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MAX31865::runAutoFaultDetectionCycle() {
 | 
				
			||||||
 | 
					  writeRegister8(MAX31865_CONFIG_REG, (stdFlags & 0x11) | 0x84 ); // cfg reg = 100X010Xb
 | 
				
			||||||
 | 
					  DELAY_US(600);
 | 
				
			||||||
 | 
					  for (int i = 0; i < 10 && (readRegister8(MAX31865_CONFIG_REG) & 0xC) > 0; i++) DELAY_US(100); // Fault det completes when bits 2 and 3 are zero (or after 10 tries)
 | 
				
			||||||
 | 
					  readFault();
 | 
				
			||||||
 | 
					  clearFault();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Set a value in the configuration register.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param config  8-bit value for the config item
 | 
				
			||||||
 | 
					 * @param enable  whether to enable or disable the value
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void MAX31865::setConfig(uint8_t config, bool enable) {
 | 
				
			||||||
 | 
					  uint8_t t = stdFlags;
 | 
				
			||||||
 | 
					  if (enable)
 | 
				
			||||||
 | 
					    t |= config;
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    t &= ~config;
 | 
				
			||||||
 | 
					  writeRegister8(MAX31865_CONFIG_REG, t);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Initialize standard flags with flags that will not change during operation (Hz, polling mode and no. of wires)
 | 
					 * Initialize standard flags with flags that will not change during operation (Hz, polling mode and no. of wires)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -249,12 +306,59 @@ void MAX31865::initFixedFlags(max31865_numwires_t wires) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // set config-defined flags (same for all sensors)
 | 
					  // set config-defined flags (same for all sensors)
 | 
				
			||||||
  stdFlags = TERN(MAX31865_50HZ_FILTER, MAX31865_CONFIG_FILT50HZ, MAX31865_CONFIG_FILT60HZ) |
 | 
					  stdFlags = TERN(MAX31865_50HZ_FILTER, MAX31865_CONFIG_FILT50HZ, MAX31865_CONFIG_FILT60HZ) |
 | 
				
			||||||
              TERN(MAX31865_USE_AUTO_MODE, MAX31865_CONFIG_MODEAUTO | MAX31865_CONFIG_BIAS, MAX31865_CONFIG_MODEOFF);
 | 
					             TERN(MAX31865_USE_AUTO_MODE, MAX31865_CONFIG_MODEAUTO | MAX31865_CONFIG_BIAS, MAX31865_CONFIG_MODEOFF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (wires == MAX31865_3WIRE)
 | 
					  if (wires == MAX31865_3WIRE)
 | 
				
			||||||
    stdFlags |= MAX31865_CONFIG_3WIRE;
 | 
					    stdFlags |= MAX31865_CONFIG_3WIRE;   // 3 wire
 | 
				
			||||||
  else  // 2 or 4 wire
 | 
					  else
 | 
				
			||||||
    stdFlags &= ~MAX31865_CONFIG_3WIRE;
 | 
					    stdFlags &= ~MAX31865_CONFIG_3WIRE;  // 2 or 4 wire
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if MAX31865_IGNORE_INITIAL_FAULTY_READS > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  inline uint16_t MAX31865::fixFault(uint16_t rtd) {
 | 
				
			||||||
 | 
					    if (!ignore_faults || !(rtd & 1))
 | 
				
			||||||
 | 
					      return rtd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ignore_faults--;
 | 
				
			||||||
 | 
					    clearFault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DEBUG_ECHOLNPGM("MAX31865 ignoring fault ", (MAX31865_IGNORE_INITIAL_FAULTY_READS) - ignore_faults);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rtd & ~1;  // 0xFFFE
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline uint16_t MAX31865::readRawImmediate() {
 | 
				
			||||||
 | 
					  uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG);
 | 
				
			||||||
 | 
					  DEBUG_ECHOLNPGM("MAX31865 RTD MSB:", (rtd >> 8), " LSB:", (rtd & 0x00FF));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #if MAX31865_IGNORE_INITIAL_FAULTY_READS > 0
 | 
				
			||||||
 | 
					    rtd = fixFault(rtd);
 | 
				
			||||||
 | 
					  #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rtd & 1) {
 | 
				
			||||||
 | 
					    lastFault = readRegister8(MAX31865_FAULTSTAT_REG);
 | 
				
			||||||
 | 
					    lastRead |= 1;
 | 
				
			||||||
 | 
					    clearFault(); // also clears the bias voltage flag, so no further action is required
 | 
				
			||||||
 | 
					    DEBUG_ECHOLNPGM("MAX31865 read fault: ", lastFault);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else {
 | 
				
			||||||
 | 
					    TERN_(MAX31865_USE_READ_ERROR_DETECTION, const millis_t ms = millis());
 | 
				
			||||||
 | 
					    if (TERN0(MAX31865_USE_READ_ERROR_DETECTION, ABS((int)(lastRead - rtd)) > 500 && PENDING(ms, lastReadStamp + 1000))) {
 | 
				
			||||||
 | 
					      // If 2 readings within 1s differ too much (~20°C) it's a read error.
 | 
				
			||||||
 | 
					      lastFault = 0x01;
 | 
				
			||||||
 | 
					      lastRead |= 1;
 | 
				
			||||||
 | 
					      DEBUG_ECHOLNPGM("MAX31865 read error: ", rtd);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      lastRead = rtd;
 | 
				
			||||||
 | 
					      TERN_(MAX31865_USE_READ_ERROR_DETECTION, lastReadStamp = ms);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rtd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -267,30 +371,13 @@ uint16_t MAX31865::readRaw() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  #if ENABLED(MAX31865_USE_AUTO_MODE)
 | 
					  #if ENABLED(MAX31865_USE_AUTO_MODE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG);
 | 
					    readRawImmediate();
 | 
				
			||||||
    DEBUG_ECHOLNPGM("MAX31865 RTD MSB:", (rtd >> 8), " LSB:", (rtd & 0x00FF));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (rtd & 1) {
 | 
					 | 
				
			||||||
      lastFault = readRegister8(MAX31865_FAULTSTAT_REG);
 | 
					 | 
				
			||||||
      lastRead |= 1;
 | 
					 | 
				
			||||||
      clearFault(); // also clears the bias voltage flag, so no further action is required
 | 
					 | 
				
			||||||
      DEBUG_ECHOLNPGM("MAX31865 read fault: ", rtd);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #if ENABLED(MAX31865_USE_READ_ERROR_DETECTION)
 | 
					 | 
				
			||||||
      else if (ABS(lastRead - rtd) > 500 && PENDING(millis(), lastReadStamp + 1000)) { // if two readings within a second differ too much (~20°C), consider it a read error.
 | 
					 | 
				
			||||||
        lastFault = 0x01;
 | 
					 | 
				
			||||||
        lastRead |= 1;
 | 
					 | 
				
			||||||
        DEBUG_ECHOLNPGM("MAX31865 read error: ", rtd);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    #endif
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
      lastRead = rtd;
 | 
					 | 
				
			||||||
      TERN_(MAX31865_USE_READ_ERROR_DETECTION, lastReadStamp = millis());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #else
 | 
					  #else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (PENDING(millis(), nextEventStamp)) {
 | 
					    const millis_t ms = millis();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (PENDING(ms, nextEventStamp)) {
 | 
				
			||||||
      DEBUG_ECHOLNPGM("MAX31865 waiting for event ", nextEvent);
 | 
					      DEBUG_ECHOLNPGM("MAX31865 waiting for event ", nextEvent);
 | 
				
			||||||
      return lastRead;
 | 
					      return lastRead;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -298,46 +385,26 @@ uint16_t MAX31865::readRaw() {
 | 
				
			|||||||
    switch (nextEvent) {
 | 
					    switch (nextEvent) {
 | 
				
			||||||
      case SETUP_BIAS_VOLTAGE:
 | 
					      case SETUP_BIAS_VOLTAGE:
 | 
				
			||||||
        enableBias();
 | 
					        enableBias();
 | 
				
			||||||
        nextEventStamp = millis() + 11; // wait at least 11msec before enabling 1shot
 | 
					        nextEventStamp = ms + 2; // wait at least 10.5*τ (τ = 100nF*430Ω max for PT100 / 10nF*4.3ΚΩ for PT1000 = 43μsec) + 1msec
 | 
				
			||||||
        nextEvent = SETUP_1_SHOT_MODE;
 | 
					        nextEvent = SETUP_1_SHOT_MODE;
 | 
				
			||||||
        DEBUG_ECHOLNPGM("MAX31865 bias voltage enabled");
 | 
					        DEBUG_ECHOLNPGM("MAX31865 bias voltage enabled");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      case SETUP_1_SHOT_MODE:
 | 
					      case SETUP_1_SHOT_MODE:
 | 
				
			||||||
        oneShot();
 | 
					        oneShot();
 | 
				
			||||||
        nextEventStamp = millis() + 65; // wait at least 65msec before reading RTD register
 | 
					        nextEventStamp = ms + TERN(MAX31865_50HZ_FILTER, 63, 52); // wait at least 52msec for 60Hz (63msec for 50Hz) before reading RTD register
 | 
				
			||||||
        nextEvent = READ_RTD_REG;
 | 
					        nextEvent = READ_RTD_REG;
 | 
				
			||||||
        DEBUG_ECHOLNPGM("MAX31865 1 shot mode enabled");
 | 
					        DEBUG_ECHOLNPGM("MAX31865 1 shot mode enabled");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      case READ_RTD_REG: {
 | 
					      case READ_RTD_REG:
 | 
				
			||||||
        const uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG);
 | 
					 | 
				
			||||||
        DEBUG_ECHOLNPGM("MAX31865 RTD MSB:", (rtd >> 8), " LSB:", (rtd & 0x00FF));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (rtd & 1) {
 | 
					        if (!(readRawImmediate() & 1))   // if clearFault() was not invoked, need to clear the bias voltage and 1-shot flags
 | 
				
			||||||
          lastFault = readRegister8(MAX31865_FAULTSTAT_REG);
 | 
					 | 
				
			||||||
          lastRead |= 1;
 | 
					 | 
				
			||||||
          clearFault(); // also clears the bias voltage flag, so no further action is required
 | 
					 | 
				
			||||||
          DEBUG_ECHOLNPGM("MAX31865 read fault: ", rtd);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        #if ENABLED(MAX31865_USE_READ_ERROR_DETECTION)
 | 
					 | 
				
			||||||
          else if (ABS(lastRead - rtd) > 500 && PENDING(millis(), lastReadStamp + 1000)) { // if two readings within a second differ too much (~20°C), consider it a read error.
 | 
					 | 
				
			||||||
            lastFault = 0x01;
 | 
					 | 
				
			||||||
            lastRead |= 1;
 | 
					 | 
				
			||||||
            DEBUG_ECHOLNPGM("MAX31865 read error: ", rtd);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        #endif
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
          lastRead = rtd;
 | 
					 | 
				
			||||||
          TERN_(MAX31865_USE_READ_ERROR_DETECTION, lastReadStamp = millis());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!(rtd & 1))   // if clearFault() was not invoked, need to clear the bias voltage and 1-shot flags
 | 
					 | 
				
			||||||
          resetFlags();
 | 
					          resetFlags();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        nextEvent = SETUP_BIAS_VOLTAGE;
 | 
					        nextEvent = SETUP_BIAS_VOLTAGE;
 | 
				
			||||||
        nextEventStamp = millis() + MAX31865_MIN_SAMPLING_TIME_MSEC; // next step should not occur within less than MAX31865_MIN_SAMPLING_TIME_MSEC from the last one
 | 
					        nextEventStamp = ms + (MAX31865_MIN_SAMPLING_TIME_MSEC); // next step should not occur within less than MAX31865_MIN_SAMPLING_TIME_MSEC from the last one
 | 
				
			||||||
      } break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #endif
 | 
					  #endif
 | 
				
			||||||
@@ -411,21 +478,17 @@ float MAX31865::temperature(float rtd_res) {
 | 
				
			|||||||
  return temp;
 | 
					  return temp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// private:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Set a value in the configuration register.
 | 
					 * MAX31865 SPI Timing constants
 | 
				
			||||||
 *
 | 
					 * See MAX31865 datasheet (https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf)
 | 
				
			||||||
 * @param config  8-bit value for the config item
 | 
					 * All timings in nsec, minimum values.
 | 
				
			||||||
 * @param enable  whether to enable or disable the value
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void MAX31865::setConfig(uint8_t config, bool enable) {
 | 
					
 | 
				
			||||||
  uint8_t t = stdFlags;
 | 
					#define MAX31865_SPI_TIMING_TCC    400    // CS to SCLK setup
 | 
				
			||||||
  if (enable) t |= config; else t &= ~config;
 | 
					#define MAX31865_SPI_TIMING_TDC     35    // Data to SCLK setup
 | 
				
			||||||
  writeRegister8(MAX31865_CONFIG_REG, t);
 | 
					#define MAX31865_SPI_TIMING_TCL    100    // SCK half period
 | 
				
			||||||
}
 | 
					#define MAX31865_SPI_TIMING_TCCH   100    // SCK to CS hold
 | 
				
			||||||
 | 
					#define MAX31865_SPI_TIMING_TCWH   400    // CS inactive time (min)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Read a single byte from the specified register address.
 | 
					 * Read a single byte from the specified register address.
 | 
				
			||||||
@@ -459,18 +522,10 @@ uint16_t MAX31865::readRegister16(uint8_t addr) {
 | 
				
			|||||||
 * @param n       the number of bytes to read
 | 
					 * @param n       the number of bytes to read
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void MAX31865::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) {
 | 
					void MAX31865::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  addr &= 0x7F; // make sure top bit is not set
 | 
					  addr &= 0x7F; // make sure top bit is not set
 | 
				
			||||||
  if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
 | 
					 | 
				
			||||||
    SPI.beginTransaction(spiConfig);
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
    digitalWrite(sclkPin, LOW);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  digitalWrite(cselPin, LOW);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  #ifdef TARGET_LPC1768
 | 
					 | 
				
			||||||
    DELAY_CYCLES(spiSpeed);
 | 
					 | 
				
			||||||
  #endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spiBeginTransaction();
 | 
				
			||||||
  spiTransfer(addr);
 | 
					  spiTransfer(addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while (n--) {
 | 
					  while (n--) {
 | 
				
			||||||
@@ -478,10 +533,15 @@ void MAX31865::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) {
 | 
				
			|||||||
    buffer++;
 | 
					    buffer++;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
 | 
					  spiEndTransaction();
 | 
				
			||||||
    SPI.endTransaction();
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  digitalWrite(cselPin, HIGH);
 | 
					void MAX31865::writeRegister16(uint8_t addr, uint16_t data) {
 | 
				
			||||||
 | 
					  spiBeginTransaction();
 | 
				
			||||||
 | 
					  spiTransfer(addr | 0x80); // make sure top bit is set
 | 
				
			||||||
 | 
					  spiTransfer(data >> 8);
 | 
				
			||||||
 | 
					  spiTransfer(data & 0xFF);
 | 
				
			||||||
 | 
					  spiEndTransaction();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -491,22 +551,31 @@ void MAX31865::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) {
 | 
				
			|||||||
 * @param data  the data to write
 | 
					 * @param data  the data to write
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void MAX31865::writeRegister8(uint8_t addr, uint8_t data) {
 | 
					void MAX31865::writeRegister8(uint8_t addr, uint8_t data) {
 | 
				
			||||||
 | 
					  spiBeginTransaction();
 | 
				
			||||||
 | 
					  spiTransfer(addr | 0x80); // make sure top bit is set
 | 
				
			||||||
 | 
					  spiTransfer(data);
 | 
				
			||||||
 | 
					  spiEndTransaction();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MAX31865::spiBeginTransaction() {
 | 
				
			||||||
 | 
					  digitalWrite(sclkPin, LOW); // ensure CPOL0
 | 
				
			||||||
 | 
					  DELAY_NS_VAR(MAX31865_SPI_TIMING_TCWH); // ensure minimum time of CS inactivity after previous operation
 | 
				
			||||||
 | 
					  digitalWrite(cselPin, LOW);
 | 
				
			||||||
 | 
					  DELAY_NS_VAR(MAX31865_SPI_TIMING_TCC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
 | 
					  if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
 | 
				
			||||||
    SPI.beginTransaction(spiConfig);
 | 
					    SPI.beginTransaction(spiConfig);
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    digitalWrite(sclkPin, LOW);
 | 
					    digitalWrite(sclkPin, HIGH);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
  digitalWrite(cselPin, LOW);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  #ifdef TARGET_LPC1768
 | 
					 | 
				
			||||||
    DELAY_CYCLES(spiSpeed);
 | 
					 | 
				
			||||||
  #endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  spiTransfer(addr | 0x80); // make sure top bit is set
 | 
					 | 
				
			||||||
  spiTransfer(data);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void MAX31865::spiEndTransaction() {
 | 
				
			||||||
  if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
 | 
					  if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
 | 
				
			||||||
    SPI.endTransaction();
 | 
					    SPI.endTransaction();
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    digitalWrite(sclkPin, LOW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DELAY_NS_VAR(MAX31865_SPI_TIMING_TCCH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  digitalWrite(cselPin, HIGH);
 | 
					  digitalWrite(cselPin, HIGH);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -521,42 +590,30 @@ void MAX31865::writeRegister8(uint8_t addr, uint8_t data) {
 | 
				
			|||||||
 * @return    the 8-bit response
 | 
					 * @return    the 8-bit response
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
uint8_t MAX31865::spiTransfer(uint8_t x) {
 | 
					uint8_t MAX31865::spiTransfer(uint8_t x) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
 | 
					  if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
 | 
				
			||||||
    return SPI.transfer(x);
 | 
					    return SPI.transfer(x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #ifdef TARGET_LPC1768
 | 
					  uint8_t reply = 0;
 | 
				
			||||||
 | 
					  for (int i = 7; i >= 0; i--) {
 | 
				
			||||||
    return swSpiTransfer(x, spiSpeed, sclkPin, misoPin, mosiPin);
 | 
					    digitalWrite(mosiPin, x & _BV(i));
 | 
				
			||||||
 | 
					    DELAY_NS_VAR(MAX31865_SPI_TIMING_TDC);
 | 
				
			||||||
  #else
 | 
					    digitalWrite(sclkPin, LOW);
 | 
				
			||||||
 | 
					    DELAY_NS_VAR(MAX31865_SPI_TIMING_TCL - MAX31865_SPI_TIMING_TDC);
 | 
				
			||||||
    uint8_t reply = 0;
 | 
					    reply <<= 1;
 | 
				
			||||||
    for (int i = 7; i >= 0; i--) {
 | 
					    if (digitalRead(misoPin)) reply |= 1;
 | 
				
			||||||
      digitalWrite(sclkPin, HIGH);       DELAY_NS_VAR(spiDelay);
 | 
					    DELAY_NS_VAR(MAX31865_SPI_TIMING_TDC);
 | 
				
			||||||
      reply <<= 1;
 | 
					    digitalWrite(sclkPin, HIGH);
 | 
				
			||||||
      digitalWrite(mosiPin, x & _BV(i)); DELAY_NS_VAR(spiDelay);
 | 
					    DELAY_NS_VAR(MAX31865_SPI_TIMING_TCL - MAX31865_SPI_TIMING_TDC);
 | 
				
			||||||
      if (digitalRead(misoPin)) reply |= 1;
 | 
					  }
 | 
				
			||||||
      digitalWrite(sclkPin, LOW);        DELAY_NS_VAR(spiDelay);
 | 
					  return reply;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return reply;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  #endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MAX31865::softSpiBegin(const uint8_t spi_speed) {
 | 
					void MAX31865::softSpiInit() {
 | 
				
			||||||
  DEBUG_ECHOLNPGM("Initializing MAX31865 Software SPI");
 | 
					  DEBUG_ECHOLNPGM("Initializing MAX31865 Software SPI");
 | 
				
			||||||
 | 
					  pinMode(sclkPin, OUTPUT);
 | 
				
			||||||
  #ifdef TARGET_LPC1768
 | 
					  digitalWrite(sclkPin, LOW);
 | 
				
			||||||
    swSpiBegin(sclkPin, misoPin, mosiPin);
 | 
					  pinMode(mosiPin, OUTPUT);
 | 
				
			||||||
    spiSpeed = swSpiInit(spi_speed, sclkPin, mosiPin);
 | 
					  pinMode(misoPin, INPUT);
 | 
				
			||||||
  #else
 | 
					 | 
				
			||||||
    spiDelay = (100UL << spi_speed) / 3; // Calculate delay in ns. Top speed is ~10MHz, or 100ns delay between bits.
 | 
					 | 
				
			||||||
    pinMode(sclkPin, OUTPUT);
 | 
					 | 
				
			||||||
    digitalWrite(sclkPin, LOW);
 | 
					 | 
				
			||||||
    pinMode(mosiPin, OUTPUT);
 | 
					 | 
				
			||||||
    pinMode(misoPin, INPUT);
 | 
					 | 
				
			||||||
  #endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // HAS_MAX31865 && !USE_ADAFRUIT_MAX31865
 | 
					#endif // HAS_MAX31865 && !USE_ADAFRUIT_MAX31865
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,11 +101,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  TERN(LARGE_PINMAP, uint32_t, uint8_t) sclkPin, misoPin, mosiPin, cselPin;
 | 
					  TERN(LARGE_PINMAP, uint32_t, uint8_t) sclkPin, misoPin, mosiPin, cselPin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #ifdef TARGET_LPC1768
 | 
					  uint16_t spiDelay;
 | 
				
			||||||
    uint8_t spiSpeed;
 | 
					 | 
				
			||||||
  #else
 | 
					 | 
				
			||||||
    uint16_t spiDelay;
 | 
					 | 
				
			||||||
  #endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  float zeroRes, refRes, wireRes;
 | 
					  float zeroRes, refRes, wireRes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -121,6 +117,11 @@ private:
 | 
				
			|||||||
    one_shot_event_t nextEvent;
 | 
					    one_shot_event_t nextEvent;
 | 
				
			||||||
  #endif
 | 
					  #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #ifdef MAX31865_IGNORE_INITIAL_FAULTY_READS
 | 
				
			||||||
 | 
					    uint8_t ignore_faults = MAX31865_IGNORE_INITIAL_FAULTY_READS;
 | 
				
			||||||
 | 
					    uint16_t fixFault(uint16_t rtd);
 | 
				
			||||||
 | 
					  #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint8_t stdFlags = 0;
 | 
					  uint8_t stdFlags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void setConfig(uint8_t config, bool enable);
 | 
					  void setConfig(uint8_t config, bool enable);
 | 
				
			||||||
@@ -130,9 +131,12 @@ private:
 | 
				
			|||||||
  uint16_t readRegister16(uint8_t addr);
 | 
					  uint16_t readRegister16(uint8_t addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void writeRegister8(uint8_t addr, uint8_t reg);
 | 
					  void writeRegister8(uint8_t addr, uint8_t reg);
 | 
				
			||||||
  uint8_t spiTransfer(uint8_t addr);
 | 
					  void writeRegister16(uint8_t addr, uint16_t reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void softSpiBegin(const uint8_t spi_speed);
 | 
					  void softSpiInit();
 | 
				
			||||||
 | 
					  void spiBeginTransaction();
 | 
				
			||||||
 | 
					  uint8_t spiTransfer(uint8_t addr);
 | 
				
			||||||
 | 
					  void spiEndTransaction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void initFixedFlags(max31865_numwires_t wires);
 | 
					  void initFixedFlags(max31865_numwires_t wires);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -141,6 +145,10 @@ private:
 | 
				
			|||||||
  void oneShot();
 | 
					  void oneShot();
 | 
				
			||||||
  void resetFlags();
 | 
					  void resetFlags();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint16_t readRawImmediate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void runAutoFaultDetectionCycle();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  #if ENABLED(LARGE_PINMAP)
 | 
					  #if ENABLED(LARGE_PINMAP)
 | 
				
			||||||
    MAX31865(uint32_t spi_cs, uint8_t pin_mapping);
 | 
					    MAX31865(uint32_t spi_cs, uint8_t pin_mapping);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user