🐛 Fix and improve MAX31865 (#23215)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						 Scott Lahteine
						Scott Lahteine
					
				
			
			
				
	
			
			
			
						parent
						
							a6bed22839
						
					
				
				
					commit
					f2ca70e232
				
			| @@ -142,11 +142,20 @@ | ||||
|  *   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 MAX31865_SENSOR_WIRES_0 2 | ||||
| //#define MAX31865_SENSOR_WIRES_1 2 | ||||
| //#define MAX31865_50HZ_FILTER | ||||
| //#define MAX31865_USE_READ_ERROR_DETECTION | ||||
| //#define MAX31865_USE_AUTO_MODE | ||||
| //#define MAX31865_MIN_SAMPLING_TIME_MSEC 100 | ||||
| //#define MAX31865_WIRE_OHMS_0 0.0f | ||||
| //#define MAX31865_WIRE_OHMS_1 0.0f | ||||
|  | ||||
| /** | ||||
|  * Hephestos 2 24V heated bed upgrade kit. | ||||
|   | ||||
| @@ -159,6 +159,9 @@ | ||||
|     #ifndef MAX31865_SENSOR_WIRES_0 | ||||
|       #define MAX31865_SENSOR_WIRES_0 2 | ||||
|     #endif | ||||
|     #ifndef MAX31865_WIRE_OHMS_0 | ||||
|       #define MAX31865_WIRE_OHMS_0 0.0f | ||||
|     #endif | ||||
|   #elif TEMP_SENSOR_0 == -3 | ||||
|     #define TEMP_SENSOR_0_IS_MAX31855 1 | ||||
|     #define TEMP_SENSOR_0_MAX_TC_TMIN -270 | ||||
| @@ -193,6 +196,9 @@ | ||||
|     #ifndef MAX31865_SENSOR_WIRES_1 | ||||
|       #define MAX31865_SENSOR_WIRES_1 2 | ||||
|     #endif | ||||
|     #ifndef MAX31865_WIRE_OHMS_1 | ||||
|       #define MAX31865_WIRE_OHMS_1 0.0f | ||||
|     #endif | ||||
|   #elif TEMP_SENSOR_1 == -3 | ||||
|     #define TEMP_SENSOR_1_IS_MAX31855 1 | ||||
|     #define TEMP_SENSOR_1_MAX_TC_TMIN -270 | ||||
|   | ||||
| @@ -40,20 +40,23 @@ | ||||
|  * All rights reserved. | ||||
|  */ | ||||
|  | ||||
| // Useful for RTD debugging. | ||||
| //#define MAX31865_DEBUG | ||||
| //#define MAX31865_DEBUG_SPI | ||||
|  | ||||
| #include "../inc/MarlinConfig.h" | ||||
|  | ||||
| #if HAS_MAX31865 && !USE_ADAFRUIT_MAX31865 | ||||
|  | ||||
| #include "MAX31865.h" | ||||
|  | ||||
| #ifndef MAX31865_MIN_SAMPLING_TIME_MSEC | ||||
|   #define MAX31865_MIN_SAMPLING_TIME_MSEC 0 | ||||
| #endif | ||||
|  | ||||
| #ifdef TARGET_LPC1768 | ||||
|   #include <SoftwareSPI.h> | ||||
| #endif | ||||
|  | ||||
| #define DEBUG_OUT ENABLED(DEBUG_MAX31865) | ||||
| #include "../core/debug_out.h" | ||||
|  | ||||
| // The maximum speed the MAX31865 can do is 5 MHz | ||||
| SPISettings MAX31865::spiConfig = SPISettings( | ||||
|   TERN(TARGET_LPC1768, SPI_QUARTER_SPEED, TERN(ARDUINO_ARCH_STM32, SPI_CLOCK_DIV4, 500000)), | ||||
| @@ -61,7 +64,7 @@ SPISettings MAX31865::spiConfig = SPISettings( | ||||
|   SPI_MODE1 // CPOL0 CPHA1 | ||||
| ); | ||||
|  | ||||
| #ifndef LARGE_PINMAP | ||||
| #if DISABLED(LARGE_PINMAP) | ||||
|  | ||||
|   /** | ||||
|    * Create the interface object using software (bitbang) SPI for PIN values | ||||
| @@ -137,117 +140,121 @@ SPISettings MAX31865::spiConfig = SPISettings( | ||||
|  * @param wires  The number of wires in enum format. Can be MAX31865_2WIRE, MAX31865_3WIRE, or MAX31865_4WIRE. | ||||
|  * @param zero   The resistance of the RTD at 0 degC, in ohms. | ||||
|  * @param ref    The resistance of the reference resistor, in ohms. | ||||
|  * @param wire   The resistance of the wire connecting the sensor to the RTD, in ohms. | ||||
|  */ | ||||
| void MAX31865::begin(max31865_numwires_t wires, float zero, float ref) { | ||||
|   zeroRes = zero; | ||||
|   refRes = ref; | ||||
| void MAX31865::begin(max31865_numwires_t wires, float zero_res, float ref_res, float wire_res) { | ||||
|   zeroRes = zero_res; | ||||
|   refRes = ref_res; | ||||
|   wireRes = wire_res; | ||||
|  | ||||
|   OUT_WRITE(cselPin, HIGH); | ||||
|   pinMode(cselPin, OUTPUT); | ||||
|   digitalWrite(cselPin, HIGH); | ||||
|  | ||||
|   if (sclkPin != TERN(LARGE_PINMAP, -1UL, -1)) { | ||||
|   if (sclkPin != TERN(LARGE_PINMAP, -1UL, 255)) | ||||
|     softSpiBegin(SPI_QUARTER_SPEED); // Define pin modes for Software SPI | ||||
|   } | ||||
|   else { | ||||
|     #ifdef MAX31865_DEBUG | ||||
|       SERIAL_ECHOLNPGM("Initializing MAX31865 Hardware SPI"); | ||||
|     #endif | ||||
|     DEBUG_ECHOLNPGM("Initializing MAX31865 Hardware SPI"); | ||||
|     SPI.begin();    // Start and configure hardware SPI | ||||
|   } | ||||
|  | ||||
|   setWires(wires); | ||||
|   enableBias(false); | ||||
|   autoConvert(false); | ||||
|   clearFault(); | ||||
|   initFixedFlags(wires); | ||||
|  | ||||
|   #ifdef MAX31865_DEBUG_SPI | ||||
|     SERIAL_ECHOLNPGM( | ||||
|       TERN(LARGE_PINMAP, "LARGE_PINMAP", "Regular") | ||||
|       " begin call with cselPin: ", cselPin, | ||||
|       " misoPin: ", misoPin, | ||||
|       " sclkPin: ", sclkPin, | ||||
|       " mosiPin: ", mosiPin, | ||||
|       " config: ", readRegister8(MAX31865_CONFIG_REG) | ||||
|     ); | ||||
|   #endif | ||||
|   clearFault(); // also initializes flags | ||||
|  | ||||
|   #if DISABLED(MAX31865_USE_AUTO_MODE) // make a proper first 1 shot read to initialize _lastRead | ||||
|  | ||||
|     enableBias(); | ||||
|     DELAY_US(11500); | ||||
|     oneShot(); | ||||
|     DELAY_US(65000); | ||||
|     uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG); | ||||
|  | ||||
|     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)); | ||||
|  | ||||
|       resetFlags(); | ||||
|  | ||||
|       lastRead = rtd; | ||||
|       nextEvent = SETUP_BIAS_VOLTAGE; | ||||
|       millis_t now = millis(); | ||||
|       nextEventStamp = now + MAX31865_MIN_SAMPLING_TIME_MSEC; | ||||
|  | ||||
|       TERN_(MAX31865_USE_READ_ERROR_DETECTION, lastReadStamp = now); | ||||
|     } | ||||
|  | ||||
|   #endif // !MAX31865_USE_AUTO_MODE | ||||
|  | ||||
|   DEBUG_ECHOLNPGM( | ||||
|     TERN(LARGE_PINMAP, "LARGE_PINMAP", "Regular") | ||||
|     " begin call with cselPin: ", cselPin, | ||||
|     " misoPin: ", misoPin, | ||||
|     " sclkPin: ", sclkPin, | ||||
|     " mosiPin: ", mosiPin, | ||||
|     " config: ", readRegister8(MAX31865_CONFIG_REG) | ||||
|   ); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Read the raw 8-bit FAULTSTAT register | ||||
|  * Return and clear the last fault value | ||||
|  * | ||||
|  * @return The raw unsigned 8-bit FAULT status register | ||||
|  * @return The raw unsigned 8-bit FAULT status register or spike fault | ||||
|  */ | ||||
| uint8_t MAX31865::readFault() { | ||||
|   return readRegister8(MAX31865_FAULTSTAT_REG); | ||||
|   uint8_t r = lastFault; | ||||
|   lastFault = 0; | ||||
|   return r; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Clear all faults in FAULTSTAT. | ||||
|  * Clear last fault | ||||
|  */ | ||||
| void MAX31865::clearFault() { | ||||
|   setConfig(MAX31865_CONFIG_FAULTSTAT, 1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Whether we want to have continuous conversions (50/60 Hz) | ||||
|  * | ||||
|  * @param b  If true, auto conversion is enabled | ||||
|  * Reset flags | ||||
|  */ | ||||
| void MAX31865::autoConvert(bool b) { | ||||
|   setConfig(MAX31865_CONFIG_MODEAUTO, b); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Whether we want filter out 50Hz noise or 60Hz noise | ||||
|  * | ||||
|  * @param b  If true, 50Hz noise is filtered, else 60Hz(default) | ||||
|  */ | ||||
| void MAX31865::enable50HzFilter(bool b) { | ||||
|   setConfig(MAX31865_CONFIG_FILT50HZ, b); | ||||
| void MAX31865::resetFlags() { | ||||
|   writeRegister8(MAX31865_CONFIG_REG, stdFlags); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Enable the bias voltage on the RTD sensor | ||||
|  * | ||||
|  * @param b  If true bias is enabled, else disabled | ||||
|  */ | ||||
| void MAX31865::enableBias(bool b) { | ||||
|   setConfig(MAX31865_CONFIG_BIAS, b); | ||||
|  | ||||
|   // From the datasheet: | ||||
|   // Note that if VBIAS is off (to reduce supply current between conversions), any filter | ||||
|   // capacitors at the RTDIN inputs need to charge before an accurate conversion can be | ||||
|   // performed. Therefore, enable VBIAS and wait at least 10.5 time constants of the input | ||||
|   // RC network plus an additional 1ms before initiating the conversion. | ||||
|   if (b) | ||||
|     DELAY_US(11500); //11.5ms | ||||
| void MAX31865::enableBias() { | ||||
|   setConfig(MAX31865_CONFIG_BIAS, 1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Start a one-shot temperature reading. | ||||
|  */ | ||||
| void MAX31865::oneShot() { | ||||
|   setConfig(MAX31865_CONFIG_1SHOT, 1); | ||||
|  | ||||
|   // From the datasheet: | ||||
|   // Note that a single conversion requires approximately 52ms in 60Hz filter | ||||
|   // mode or 62.5ms in 50Hz filter mode to complete. 1-Shot is a self-clearing bit. | ||||
|   // TODO: switch this out depending on the filter mode. | ||||
|   DELAY_US(65000); // 65ms | ||||
|   setConfig(MAX31865_CONFIG_1SHOT | MAX31865_CONFIG_BIAS, 1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * How many wires we have in our RTD setup, can be MAX31865_2WIRE, | ||||
|  * MAX31865_3WIRE, or MAX31865_4WIRE | ||||
|  * Initialize standard flags with flags that will not change during operation (Hz, polling mode and no. of wires) | ||||
|  * | ||||
|  * @param wires The number of wires in enum format | ||||
|  */ | ||||
| void MAX31865::setWires(max31865_numwires_t wires) { | ||||
|   uint8_t t = readRegister8(MAX31865_CONFIG_REG); | ||||
| void MAX31865::initFixedFlags(max31865_numwires_t wires) { | ||||
|  | ||||
|   // set config-defined flags (same for all sensors) | ||||
|   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); | ||||
|  | ||||
|   if (wires == MAX31865_3WIRE) | ||||
|     t |= MAX31865_CONFIG_3WIRE; | ||||
|   else // 2 or 4 wire | ||||
|     t &= ~MAX31865_CONFIG_3WIRE; | ||||
|   writeRegister8(MAX31865_CONFIG_REG, t); | ||||
|     stdFlags |= MAX31865_CONFIG_3WIRE; | ||||
|   else  // 2 or 4 wire | ||||
|     stdFlags &= ~MAX31865_CONFIG_3WIRE; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -257,33 +264,96 @@ void MAX31865::setWires(max31865_numwires_t wires) { | ||||
|  * @return The raw unsigned 16-bit register value with ERROR bit attached, NOT temperature! | ||||
|  */ | ||||
| uint16_t MAX31865::readRaw() { | ||||
|   clearFault(); | ||||
|   enableBias(true); | ||||
|  | ||||
|   oneShot(); | ||||
|   uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG); | ||||
|   #if ENABLED(MAX31865_USE_AUTO_MODE) | ||||
|  | ||||
|     const uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG); | ||||
|     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 | ||||
|  | ||||
|     if (PENDING(millis(), nextEventStamp)) { | ||||
|       DEBUG_ECHOLNPGM("MAX31865 waiting for event ", nextEvent); | ||||
|       return lastRead; | ||||
|     } | ||||
|  | ||||
|     switch (nextEvent) { | ||||
|       case SETUP_BIAS_VOLTAGE: | ||||
|         enableBias(); | ||||
|         nextEventStamp = millis() + 11; // wait at least 11msec before enabling 1shot | ||||
|         nextEvent = SETUP_1_SHOT_MODE; | ||||
|         DEBUG_ECHOLN("MAX31865 bias voltage enabled"); | ||||
|         break; | ||||
|  | ||||
|       case SETUP_1_SHOT_MODE: | ||||
|         oneShot(); | ||||
|         nextEventStamp = millis() + 65; // wait at least 65msec before reading RTD register | ||||
|         nextEvent = READ_RTD_REG; | ||||
|         DEBUG_ECHOLN("MAX31865 1 shot mode enabled"); | ||||
|         break; | ||||
|  | ||||
|       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) { | ||||
|           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(); | ||||
|  | ||||
|         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 | ||||
|       } break; | ||||
|     } | ||||
|  | ||||
|   #ifdef MAX31865_DEBUG | ||||
|     SERIAL_ECHOLNPGM("RTD MSB:", (rtd >> 8), "  RTD LSB:", (rtd & 0x00FF)); | ||||
|   #endif | ||||
|  | ||||
|   // Disable the bias to lower power dissipation between reads. | ||||
|   // If the ref resistor heats up, the temperature reading will be skewed. | ||||
|   enableBias(false); | ||||
|  | ||||
|   return rtd; | ||||
|   return lastRead; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Calculate and return the resistance value of the connected RTD. | ||||
|  * | ||||
|  * @param  refResistor The value of the matching reference resistor, usually 430 or 4300 | ||||
|  * @return             The raw RTD resistance value, NOT temperature! | ||||
|  */ | ||||
| float MAX31865::readResistance() { | ||||
|   // Strip the error bit (D0) and convert to a float ratio. | ||||
|   // less precise method: (readRaw() * refRes) >> 16 | ||||
|   return (((readRaw() >> 1) / 32768.0f) * refRes); | ||||
|   return ((readRaw() * RECIPROCAL(65536.0f)) * refRes - wireRes); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -301,7 +371,7 @@ float MAX31865::temperature() { | ||||
|  * @return  Temperature in C | ||||
|  */ | ||||
| float MAX31865::temperature(uint16_t adc_val) { | ||||
|   return temperature(((adc_val) / 32768.0f) * refRes); | ||||
|   return temperature(((adc_val) * RECIPROCAL(32768.0f)) * refRes - wireRes); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -352,11 +422,8 @@ float MAX31865::temperature(float rtd_res) { | ||||
|  * @param enable  whether to enable or disable the value | ||||
|  */ | ||||
| void MAX31865::setConfig(uint8_t config, bool enable) { | ||||
|   uint8_t t = readRegister8(MAX31865_CONFIG_REG); | ||||
|   if (enable) | ||||
|     t |= config; | ||||
|   else | ||||
|     t &= ~config; // disable | ||||
|   uint8_t t = stdFlags; | ||||
|   if (enable) t |= config; else t &= ~config; | ||||
|   writeRegister8(MAX31865_CONFIG_REG, t); | ||||
| } | ||||
|  | ||||
| @@ -369,7 +436,6 @@ void MAX31865::setConfig(uint8_t config, bool enable) { | ||||
| uint8_t MAX31865::readRegister8(uint8_t addr) { | ||||
|   uint8_t ret = 0; | ||||
|   readRegisterN(addr, &ret, 1); | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| @@ -380,14 +446,9 @@ uint8_t MAX31865::readRegister8(uint8_t addr) { | ||||
|  * @return       both register contents as a single 16-bit int | ||||
|  */ | ||||
| uint16_t MAX31865::readRegister16(uint8_t addr) { | ||||
|   uint8_t buffer[2] = {0, 0}; | ||||
|   uint8_t buffer[2] = { 0 }; | ||||
|   readRegisterN(addr, buffer, 2); | ||||
|  | ||||
|   uint16_t ret = buffer[0]; | ||||
|   ret <<= 8; | ||||
|   ret |= buffer[1]; | ||||
|  | ||||
|   return ret; | ||||
|   return uint16_t(buffer[0]) << 8 | buffer[1]; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -399,12 +460,12 @@ uint16_t MAX31865::readRegister16(uint8_t addr) { | ||||
|  */ | ||||
| void MAX31865::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) { | ||||
|   addr &= 0x7F; // make sure top bit is not set | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, -1)) | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255)) | ||||
|     SPI.beginTransaction(spiConfig); | ||||
|   else | ||||
|     WRITE(sclkPin, LOW); | ||||
|     digitalWrite(sclkPin, LOW); | ||||
|  | ||||
|   WRITE(cselPin, LOW); | ||||
|   digitalWrite(cselPin, LOW); | ||||
|  | ||||
|   #ifdef TARGET_LPC1768 | ||||
|     DELAY_CYCLES(spiSpeed); | ||||
| @@ -414,16 +475,13 @@ void MAX31865::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) { | ||||
|  | ||||
|   while (n--) { | ||||
|     buffer[0] = spiTransfer(0xFF); | ||||
|     #ifdef MAX31865_DEBUG_SPI | ||||
|       SERIAL_ECHOLNPGM("buffer read ", n, " data: ", buffer[0]); | ||||
|     #endif | ||||
|     buffer++; | ||||
|   } | ||||
|  | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, -1)) | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255)) | ||||
|     SPI.endTransaction(); | ||||
|  | ||||
|   WRITE(cselPin, HIGH); | ||||
|   digitalWrite(cselPin, HIGH); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -433,12 +491,12 @@ void MAX31865::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) { | ||||
|  * @param data  the data to write | ||||
|  */ | ||||
| void MAX31865::writeRegister8(uint8_t addr, uint8_t data) { | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, -1)) | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255)) | ||||
|     SPI.beginTransaction(spiConfig); | ||||
|   else | ||||
|     WRITE(sclkPin, LOW); | ||||
|     digitalWrite(sclkPin, LOW); | ||||
|  | ||||
|   WRITE(cselPin, LOW); | ||||
|   digitalWrite(cselPin, LOW); | ||||
|  | ||||
|   #ifdef TARGET_LPC1768 | ||||
|     DELAY_CYCLES(spiSpeed); | ||||
| @@ -447,10 +505,10 @@ void MAX31865::writeRegister8(uint8_t addr, uint8_t data) { | ||||
|   spiTransfer(addr | 0x80); // make sure top bit is set | ||||
|   spiTransfer(data); | ||||
|  | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, -1)) | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255)) | ||||
|     SPI.endTransaction(); | ||||
|  | ||||
|   WRITE(cselPin, HIGH); | ||||
|   digitalWrite(cselPin, HIGH); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -463,36 +521,41 @@ void MAX31865::writeRegister8(uint8_t addr, uint8_t data) { | ||||
|  * @return    the 8-bit response | ||||
|  */ | ||||
| uint8_t MAX31865::spiTransfer(uint8_t x) { | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, -1)) | ||||
|  | ||||
|   if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255)) | ||||
|     return SPI.transfer(x); | ||||
|  | ||||
|   #ifdef TARGET_LPC1768 | ||||
|  | ||||
|     return swSpiTransfer(x, spiSpeed, sclkPin, misoPin, mosiPin); | ||||
|  | ||||
|   #else | ||||
|  | ||||
|     uint8_t reply = 0; | ||||
|     for (int i = 7; i >= 0; i--) { | ||||
|       WRITE(sclkPin, HIGH);         DELAY_NS_VAR(spiDelay); | ||||
|       digitalWrite(sclkPin, HIGH);       DELAY_NS_VAR(spiDelay); | ||||
|       reply <<= 1; | ||||
|       WRITE(mosiPin, x & _BV(i));   DELAY_NS_VAR(spiDelay); | ||||
|       if (READ(misoPin)) reply |= 1; | ||||
|       WRITE(sclkPin, LOW);          DELAY_NS_VAR(spiDelay); | ||||
|       digitalWrite(mosiPin, x & _BV(i)); DELAY_NS_VAR(spiDelay); | ||||
|       if (digitalRead(misoPin)) reply |= 1; | ||||
|       digitalWrite(sclkPin, LOW);        DELAY_NS_VAR(spiDelay); | ||||
|     } | ||||
|     return reply; | ||||
|  | ||||
|   #endif | ||||
| } | ||||
|  | ||||
| void MAX31865::softSpiBegin(const uint8_t spi_speed) { | ||||
|   #ifdef MAX31865_DEBUG | ||||
|     SERIAL_ECHOLNPGM("Initializing MAX31865 Software SPI"); | ||||
|   #endif | ||||
|   DEBUG_ECHOLNPGM("Initializing MAX31865 Software SPI"); | ||||
|  | ||||
|   #ifdef TARGET_LPC1768 | ||||
|     swSpiBegin(sclkPin, misoPin, mosiPin); | ||||
|     spiSpeed = swSpiInit(spi_speed, sclkPin, mosiPin); | ||||
|   #else | ||||
|     spiDelay = (100UL << spi_speed) / 3; // Calculate delay in ns. Top speed is ~10MHz, or 100ns delay between bits. | ||||
|     OUT_WRITE(sclkPin, LOW); | ||||
|     SET_OUTPUT(mosiPin); | ||||
|     SET_INPUT(misoPin); | ||||
|     pinMode(sclkPin, OUTPUT); | ||||
|     digitalWrite(sclkPin, LOW); | ||||
|     pinMode(mosiPin, OUTPUT); | ||||
|     pinMode(misoPin, INPUT); | ||||
|   #endif | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -41,6 +41,8 @@ | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| //#define DEBUG_MAX31865 | ||||
|  | ||||
| #include "../inc/MarlinConfig.h" | ||||
| #include "../HAL/shared/Delay.h" | ||||
| #include HAL_PATH(../HAL, MarlinSPI.h) | ||||
| @@ -84,6 +86,14 @@ typedef enum max31865_numwires { | ||||
|   MAX31865_4WIRE = 0 | ||||
| } max31865_numwires_t; | ||||
|  | ||||
| #if DISABLED(MAX31865_USE_AUTO_MODE) | ||||
|   typedef enum one_shot_event : uint8_t { | ||||
|     SETUP_BIAS_VOLTAGE, | ||||
|     SETUP_1_SHOT_MODE, | ||||
|     READ_RTD_REG | ||||
|   } one_shot_event_t; | ||||
| #endif | ||||
|  | ||||
| /* Interface class for the MAX31865 RTD Sensor reader */ | ||||
| class MAX31865 { | ||||
| private: | ||||
| @@ -97,7 +107,21 @@ private: | ||||
|     uint16_t spiDelay; | ||||
|   #endif | ||||
|  | ||||
|   float zeroRes, refRes; | ||||
|   float zeroRes, refRes, wireRes; | ||||
|  | ||||
|   #if ENABLED(MAX31865_USE_READ_ERROR_DETECTION) | ||||
|     millis_t lastReadStamp = 0; | ||||
|   #endif | ||||
|  | ||||
|   uint16_t lastRead = 0; | ||||
|   uint8_t lastFault = 0; | ||||
|  | ||||
|   #if DISABLED(MAX31865_USE_AUTO_MODE) | ||||
|     millis_t nextEventStamp; | ||||
|     one_shot_event_t nextEvent; | ||||
|   #endif | ||||
|  | ||||
|   uint8_t stdFlags = 0; | ||||
|  | ||||
|   void setConfig(uint8_t config, bool enable); | ||||
|  | ||||
| @@ -110,8 +134,15 @@ private: | ||||
|  | ||||
|   void softSpiBegin(const uint8_t spi_speed); | ||||
|  | ||||
|   void initFixedFlags(max31865_numwires_t wires); | ||||
|  | ||||
|   void enable50HzFilter(bool b); | ||||
|   void enableBias(); | ||||
|   void oneShot(); | ||||
|   void resetFlags(); | ||||
|  | ||||
| public: | ||||
|   #ifdef LARGE_PINMAP | ||||
|   #if ENABLED(LARGE_PINMAP) | ||||
|     MAX31865(uint32_t spi_cs, uint8_t pin_mapping); | ||||
|     MAX31865(uint32_t spi_cs, uint32_t spi_mosi, uint32_t spi_miso, | ||||
|              uint32_t spi_clk, uint8_t pin_mapping); | ||||
| @@ -121,17 +152,11 @@ public: | ||||
|              int8_t spi_clk); | ||||
|   #endif | ||||
|  | ||||
|   void begin(max31865_numwires_t wires, float zero, float ref); | ||||
|   void begin(max31865_numwires_t wires, float zero_res, float ref_res, float wire_res); | ||||
|  | ||||
|   uint8_t readFault(); | ||||
|   void clearFault(); | ||||
|  | ||||
|   void setWires(max31865_numwires_t wires); | ||||
|   void autoConvert(bool b); | ||||
|   void enable50HzFilter(bool b); | ||||
|   void enableBias(bool b); | ||||
|   void oneShot(); | ||||
|  | ||||
|   uint16_t readRaw(); | ||||
|   float readResistance(); | ||||
|   float temperature(); | ||||
|   | ||||
| @@ -2204,11 +2204,8 @@ void Temperature::init() { | ||||
|     #elif TEMP_SENSOR_IS_MAX(0, 31865) | ||||
|       max31865_0.begin( | ||||
|         MAX31865_WIRES(MAX31865_SENSOR_WIRES_0) // MAX31865_2WIRE, MAX31865_3WIRE, MAX31865_4WIRE | ||||
|         OPTARG(LIB_INTERNAL_MAX31865, MAX31865_SENSOR_OHMS_0, MAX31865_CALIBRATION_OHMS_0) | ||||
|         OPTARG(LIB_INTERNAL_MAX31865, MAX31865_SENSOR_OHMS_0, MAX31865_CALIBRATION_OHMS_0, MAX31865_WIRE_OHMS_0) | ||||
|       ); | ||||
|       #if defined(LIB_INTERNAL_MAX31865) && ENABLED(MAX31865_50HZ_FILTER) | ||||
|         max31865_0.enable50HzFilter(1); | ||||
|       #endif | ||||
|     #endif | ||||
|  | ||||
|     #if TEMP_SENSOR_IS_MAX(1, 6675) && HAS_MAX6675_LIBRARY | ||||
| @@ -2218,11 +2215,8 @@ void Temperature::init() { | ||||
|     #elif TEMP_SENSOR_IS_MAX(1, 31865) | ||||
|       max31865_1.begin( | ||||
|         MAX31865_WIRES(MAX31865_SENSOR_WIRES_1) // MAX31865_2WIRE, MAX31865_3WIRE, MAX31865_4WIRE | ||||
|         OPTARG(LIB_INTERNAL_MAX31865, MAX31865_SENSOR_OHMS_1, MAX31865_CALIBRATION_OHMS_1) | ||||
|         OPTARG(LIB_INTERNAL_MAX31865, MAX31865_SENSOR_OHMS_1, MAX31865_CALIBRATION_OHMS_1, MAX31865_WIRE_OHMS_1) | ||||
|       ); | ||||
|       #if defined(LIB_INTERNAL_MAX31865) && ENABLED(MAX31865_50HZ_FILTER) | ||||
|         max31865_1.enable50HzFilter(1); | ||||
|       #endif | ||||
|     #endif | ||||
|     #undef MAX31865_WIRES | ||||
|     #undef _MAX31865_WIRES | ||||
|   | ||||
		Reference in New Issue
	
	Block a user