mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-23 12:04:19 +00:00
🐛 Fix and improve MAX31865 (#23215)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
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.
|
* 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_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_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
|
||||||
//#define MAX31865_SENSOR_WIRES_0 2
|
//#define MAX31865_SENSOR_WIRES_0 2
|
||||||
//#define MAX31865_SENSOR_WIRES_1 2
|
//#define MAX31865_SENSOR_WIRES_1 2
|
||||||
//#define MAX31865_50HZ_FILTER
|
//#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.
|
* Hephestos 2 24V heated bed upgrade kit.
|
||||||
|
@ -159,6 +159,9 @@
|
|||||||
#ifndef MAX31865_SENSOR_WIRES_0
|
#ifndef MAX31865_SENSOR_WIRES_0
|
||||||
#define MAX31865_SENSOR_WIRES_0 2
|
#define MAX31865_SENSOR_WIRES_0 2
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef MAX31865_WIRE_OHMS_0
|
||||||
|
#define MAX31865_WIRE_OHMS_0 0.0f
|
||||||
|
#endif
|
||||||
#elif TEMP_SENSOR_0 == -3
|
#elif TEMP_SENSOR_0 == -3
|
||||||
#define TEMP_SENSOR_0_IS_MAX31855 1
|
#define TEMP_SENSOR_0_IS_MAX31855 1
|
||||||
#define TEMP_SENSOR_0_MAX_TC_TMIN -270
|
#define TEMP_SENSOR_0_MAX_TC_TMIN -270
|
||||||
@ -193,6 +196,9 @@
|
|||||||
#ifndef MAX31865_SENSOR_WIRES_1
|
#ifndef MAX31865_SENSOR_WIRES_1
|
||||||
#define MAX31865_SENSOR_WIRES_1 2
|
#define MAX31865_SENSOR_WIRES_1 2
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef MAX31865_WIRE_OHMS_1
|
||||||
|
#define MAX31865_WIRE_OHMS_1 0.0f
|
||||||
|
#endif
|
||||||
#elif TEMP_SENSOR_1 == -3
|
#elif TEMP_SENSOR_1 == -3
|
||||||
#define TEMP_SENSOR_1_IS_MAX31855 1
|
#define TEMP_SENSOR_1_IS_MAX31855 1
|
||||||
#define TEMP_SENSOR_1_MAX_TC_TMIN -270
|
#define TEMP_SENSOR_1_MAX_TC_TMIN -270
|
||||||
|
@ -40,20 +40,23 @@
|
|||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Useful for RTD debugging.
|
|
||||||
//#define MAX31865_DEBUG
|
|
||||||
//#define MAX31865_DEBUG_SPI
|
|
||||||
|
|
||||||
#include "../inc/MarlinConfig.h"
|
#include "../inc/MarlinConfig.h"
|
||||||
|
|
||||||
#if HAS_MAX31865 && !USE_ADAFRUIT_MAX31865
|
#if HAS_MAX31865 && !USE_ADAFRUIT_MAX31865
|
||||||
|
|
||||||
#include "MAX31865.h"
|
#include "MAX31865.h"
|
||||||
|
|
||||||
|
#ifndef MAX31865_MIN_SAMPLING_TIME_MSEC
|
||||||
|
#define MAX31865_MIN_SAMPLING_TIME_MSEC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TARGET_LPC1768
|
#ifdef TARGET_LPC1768
|
||||||
#include <SoftwareSPI.h>
|
#include <SoftwareSPI.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG_OUT ENABLED(DEBUG_MAX31865)
|
||||||
|
#include "../core/debug_out.h"
|
||||||
|
|
||||||
// The maximum speed the MAX31865 can do is 5 MHz
|
// The maximum speed the MAX31865 can do is 5 MHz
|
||||||
SPISettings MAX31865::spiConfig = SPISettings(
|
SPISettings MAX31865::spiConfig = SPISettings(
|
||||||
TERN(TARGET_LPC1768, SPI_QUARTER_SPEED, TERN(ARDUINO_ARCH_STM32, SPI_CLOCK_DIV4, 500000)),
|
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
|
SPI_MODE1 // CPOL0 CPHA1
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifndef LARGE_PINMAP
|
#if DISABLED(LARGE_PINMAP)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the interface object using software (bitbang) SPI for PIN values
|
* 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 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 zero The resistance of the RTD at 0 degC, in ohms.
|
||||||
* @param ref The resistance of the reference resistor, 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) {
|
void MAX31865::begin(max31865_numwires_t wires, float zero_res, float ref_res, float wire_res) {
|
||||||
zeroRes = zero;
|
zeroRes = zero_res;
|
||||||
refRes = ref;
|
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
|
softSpiBegin(SPI_QUARTER_SPEED); // Define pin modes for Software SPI
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
#ifdef MAX31865_DEBUG
|
DEBUG_ECHOLNPGM("Initializing MAX31865 Hardware SPI");
|
||||||
SERIAL_ECHOLNPGM("Initializing MAX31865 Hardware SPI");
|
|
||||||
#endif
|
|
||||||
SPI.begin(); // Start and configure hardware SPI
|
SPI.begin(); // Start and configure hardware SPI
|
||||||
}
|
}
|
||||||
|
|
||||||
setWires(wires);
|
initFixedFlags(wires);
|
||||||
enableBias(false);
|
|
||||||
autoConvert(false);
|
|
||||||
clearFault();
|
|
||||||
|
|
||||||
#ifdef MAX31865_DEBUG_SPI
|
clearFault(); // also initializes flags
|
||||||
SERIAL_ECHOLNPGM(
|
|
||||||
TERN(LARGE_PINMAP, "LARGE_PINMAP", "Regular")
|
#if DISABLED(MAX31865_USE_AUTO_MODE) // make a proper first 1 shot read to initialize _lastRead
|
||||||
" begin call with cselPin: ", cselPin,
|
|
||||||
" misoPin: ", misoPin,
|
enableBias();
|
||||||
" sclkPin: ", sclkPin,
|
DELAY_US(11500);
|
||||||
" mosiPin: ", mosiPin,
|
oneShot();
|
||||||
" config: ", readRegister8(MAX31865_CONFIG_REG)
|
DELAY_US(65000);
|
||||||
);
|
uint16_t rtd = readRegister16(MAX31865_RTDMSB_REG);
|
||||||
#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));
|
||||||
|
|
||||||
|
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() {
|
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() {
|
void MAX31865::clearFault() {
|
||||||
setConfig(MAX31865_CONFIG_FAULTSTAT, 1);
|
setConfig(MAX31865_CONFIG_FAULTSTAT, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether we want to have continuous conversions (50/60 Hz)
|
* Reset flags
|
||||||
*
|
|
||||||
* @param b If true, auto conversion is enabled
|
|
||||||
*/
|
*/
|
||||||
void MAX31865::autoConvert(bool b) {
|
void MAX31865::resetFlags() {
|
||||||
setConfig(MAX31865_CONFIG_MODEAUTO, b);
|
writeRegister8(MAX31865_CONFIG_REG, stdFlags);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable the bias voltage on the RTD sensor
|
* Enable the bias voltage on the RTD sensor
|
||||||
*
|
|
||||||
* @param b If true bias is enabled, else disabled
|
|
||||||
*/
|
*/
|
||||||
void MAX31865::enableBias(bool b) {
|
void MAX31865::enableBias() {
|
||||||
setConfig(MAX31865_CONFIG_BIAS, b);
|
setConfig(MAX31865_CONFIG_BIAS, 1);
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a one-shot temperature reading.
|
* Start a one-shot temperature reading.
|
||||||
*/
|
*/
|
||||||
void MAX31865::oneShot() {
|
void MAX31865::oneShot() {
|
||||||
setConfig(MAX31865_CONFIG_1SHOT, 1);
|
setConfig(MAX31865_CONFIG_1SHOT | MAX31865_CONFIG_BIAS, 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many wires we have in our RTD setup, can be MAX31865_2WIRE,
|
* Initialize standard flags with flags that will not change during operation (Hz, polling mode and no. of wires)
|
||||||
* MAX31865_3WIRE, or MAX31865_4WIRE
|
|
||||||
*
|
*
|
||||||
* @param wires The number of wires in enum format
|
* @param wires The number of wires in enum format
|
||||||
*/
|
*/
|
||||||
void MAX31865::setWires(max31865_numwires_t wires) {
|
void MAX31865::initFixedFlags(max31865_numwires_t wires) {
|
||||||
uint8_t t = readRegister8(MAX31865_CONFIG_REG);
|
|
||||||
|
// 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)
|
if (wires == MAX31865_3WIRE)
|
||||||
t |= MAX31865_CONFIG_3WIRE;
|
stdFlags |= MAX31865_CONFIG_3WIRE;
|
||||||
else // 2 or 4 wire
|
else // 2 or 4 wire
|
||||||
t &= ~MAX31865_CONFIG_3WIRE;
|
stdFlags &= ~MAX31865_CONFIG_3WIRE;
|
||||||
writeRegister8(MAX31865_CONFIG_REG, t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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!
|
* @return The raw unsigned 16-bit register value with ERROR bit attached, NOT temperature!
|
||||||
*/
|
*/
|
||||||
uint16_t MAX31865::readRaw() {
|
uint16_t MAX31865::readRaw() {
|
||||||
clearFault();
|
|
||||||
enableBias(true);
|
|
||||||
|
|
||||||
oneShot();
|
#if ENABLED(MAX31865_USE_AUTO_MODE)
|
||||||
uint16_t rtd = readRegister16(MAX31865_RTDMSB_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());
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
#endif
|
||||||
|
|
||||||
// Disable the bias to lower power dissipation between reads.
|
return lastRead;
|
||||||
// If the ref resistor heats up, the temperature reading will be skewed.
|
|
||||||
enableBias(false);
|
|
||||||
|
|
||||||
return rtd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate and return the resistance value of the connected RTD.
|
* 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!
|
* @return The raw RTD resistance value, NOT temperature!
|
||||||
*/
|
*/
|
||||||
float MAX31865::readResistance() {
|
float MAX31865::readResistance() {
|
||||||
// Strip the error bit (D0) and convert to a float ratio.
|
// Strip the error bit (D0) and convert to a float ratio.
|
||||||
// less precise method: (readRaw() * refRes) >> 16
|
// 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
|
* @return Temperature in C
|
||||||
*/
|
*/
|
||||||
float MAX31865::temperature(uint16_t adc_val) {
|
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
|
* @param enable whether to enable or disable the value
|
||||||
*/
|
*/
|
||||||
void MAX31865::setConfig(uint8_t config, bool enable) {
|
void MAX31865::setConfig(uint8_t config, bool enable) {
|
||||||
uint8_t t = readRegister8(MAX31865_CONFIG_REG);
|
uint8_t t = stdFlags;
|
||||||
if (enable)
|
if (enable) t |= config; else t &= ~config;
|
||||||
t |= config;
|
|
||||||
else
|
|
||||||
t &= ~config; // disable
|
|
||||||
writeRegister8(MAX31865_CONFIG_REG, t);
|
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 MAX31865::readRegister8(uint8_t addr) {
|
||||||
uint8_t ret = 0;
|
uint8_t ret = 0;
|
||||||
readRegisterN(addr, &ret, 1);
|
readRegisterN(addr, &ret, 1);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,14 +446,9 @@ uint8_t MAX31865::readRegister8(uint8_t addr) {
|
|||||||
* @return both register contents as a single 16-bit int
|
* @return both register contents as a single 16-bit int
|
||||||
*/
|
*/
|
||||||
uint16_t MAX31865::readRegister16(uint8_t addr) {
|
uint16_t MAX31865::readRegister16(uint8_t addr) {
|
||||||
uint8_t buffer[2] = {0, 0};
|
uint8_t buffer[2] = { 0 };
|
||||||
readRegisterN(addr, buffer, 2);
|
readRegisterN(addr, buffer, 2);
|
||||||
|
return uint16_t(buffer[0]) << 8 | buffer[1];
|
||||||
uint16_t ret = buffer[0];
|
|
||||||
ret <<= 8;
|
|
||||||
ret |= buffer[1];
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -399,12 +460,12 @@ uint16_t MAX31865::readRegister16(uint8_t addr) {
|
|||||||
*/
|
*/
|
||||||
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, -1))
|
if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
|
||||||
SPI.beginTransaction(spiConfig);
|
SPI.beginTransaction(spiConfig);
|
||||||
else
|
else
|
||||||
WRITE(sclkPin, LOW);
|
digitalWrite(sclkPin, LOW);
|
||||||
|
|
||||||
WRITE(cselPin, LOW);
|
digitalWrite(cselPin, LOW);
|
||||||
|
|
||||||
#ifdef TARGET_LPC1768
|
#ifdef TARGET_LPC1768
|
||||||
DELAY_CYCLES(spiSpeed);
|
DELAY_CYCLES(spiSpeed);
|
||||||
@ -414,16 +475,13 @@ void MAX31865::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) {
|
|||||||
|
|
||||||
while (n--) {
|
while (n--) {
|
||||||
buffer[0] = spiTransfer(0xFF);
|
buffer[0] = spiTransfer(0xFF);
|
||||||
#ifdef MAX31865_DEBUG_SPI
|
|
||||||
SERIAL_ECHOLNPGM("buffer read ", n, " data: ", buffer[0]);
|
|
||||||
#endif
|
|
||||||
buffer++;
|
buffer++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sclkPin == TERN(LARGE_PINMAP, -1UL, -1))
|
if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
|
||||||
SPI.endTransaction();
|
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
|
* @param data the data to write
|
||||||
*/
|
*/
|
||||||
void MAX31865::writeRegister8(uint8_t addr, uint8_t data) {
|
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);
|
SPI.beginTransaction(spiConfig);
|
||||||
else
|
else
|
||||||
WRITE(sclkPin, LOW);
|
digitalWrite(sclkPin, LOW);
|
||||||
|
|
||||||
WRITE(cselPin, LOW);
|
digitalWrite(cselPin, LOW);
|
||||||
|
|
||||||
#ifdef TARGET_LPC1768
|
#ifdef TARGET_LPC1768
|
||||||
DELAY_CYCLES(spiSpeed);
|
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(addr | 0x80); // make sure top bit is set
|
||||||
spiTransfer(data);
|
spiTransfer(data);
|
||||||
|
|
||||||
if (sclkPin == TERN(LARGE_PINMAP, -1UL, -1))
|
if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
|
||||||
SPI.endTransaction();
|
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
|
* @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, -1))
|
|
||||||
|
if (sclkPin == TERN(LARGE_PINMAP, -1UL, 255))
|
||||||
return SPI.transfer(x);
|
return SPI.transfer(x);
|
||||||
|
|
||||||
#ifdef TARGET_LPC1768
|
#ifdef TARGET_LPC1768
|
||||||
|
|
||||||
return swSpiTransfer(x, spiSpeed, sclkPin, misoPin, mosiPin);
|
return swSpiTransfer(x, spiSpeed, sclkPin, misoPin, mosiPin);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
uint8_t reply = 0;
|
uint8_t reply = 0;
|
||||||
for (int i = 7; i >= 0; i--) {
|
for (int i = 7; i >= 0; i--) {
|
||||||
WRITE(sclkPin, HIGH); DELAY_NS_VAR(spiDelay);
|
digitalWrite(sclkPin, HIGH); DELAY_NS_VAR(spiDelay);
|
||||||
reply <<= 1;
|
reply <<= 1;
|
||||||
WRITE(mosiPin, x & _BV(i)); DELAY_NS_VAR(spiDelay);
|
digitalWrite(mosiPin, x & _BV(i)); DELAY_NS_VAR(spiDelay);
|
||||||
if (READ(misoPin)) reply |= 1;
|
if (digitalRead(misoPin)) reply |= 1;
|
||||||
WRITE(sclkPin, LOW); DELAY_NS_VAR(spiDelay);
|
digitalWrite(sclkPin, LOW); DELAY_NS_VAR(spiDelay);
|
||||||
}
|
}
|
||||||
return reply;
|
return reply;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MAX31865::softSpiBegin(const uint8_t spi_speed) {
|
void MAX31865::softSpiBegin(const uint8_t spi_speed) {
|
||||||
#ifdef MAX31865_DEBUG
|
DEBUG_ECHOLNPGM("Initializing MAX31865 Software SPI");
|
||||||
SERIAL_ECHOLNPGM("Initializing MAX31865 Software SPI");
|
|
||||||
#endif
|
|
||||||
#ifdef TARGET_LPC1768
|
#ifdef TARGET_LPC1768
|
||||||
swSpiBegin(sclkPin, misoPin, mosiPin);
|
swSpiBegin(sclkPin, misoPin, mosiPin);
|
||||||
spiSpeed = swSpiInit(spi_speed, sclkPin, mosiPin);
|
spiSpeed = swSpiInit(spi_speed, sclkPin, mosiPin);
|
||||||
#else
|
#else
|
||||||
spiDelay = (100UL << spi_speed) / 3; // Calculate delay in ns. Top speed is ~10MHz, or 100ns delay between bits.
|
spiDelay = (100UL << spi_speed) / 3; // Calculate delay in ns. Top speed is ~10MHz, or 100ns delay between bits.
|
||||||
OUT_WRITE(sclkPin, LOW);
|
pinMode(sclkPin, OUTPUT);
|
||||||
SET_OUTPUT(mosiPin);
|
digitalWrite(sclkPin, LOW);
|
||||||
SET_INPUT(misoPin);
|
pinMode(mosiPin, OUTPUT);
|
||||||
|
pinMode(misoPin, INPUT);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
//#define DEBUG_MAX31865
|
||||||
|
|
||||||
#include "../inc/MarlinConfig.h"
|
#include "../inc/MarlinConfig.h"
|
||||||
#include "../HAL/shared/Delay.h"
|
#include "../HAL/shared/Delay.h"
|
||||||
#include HAL_PATH(../HAL, MarlinSPI.h)
|
#include HAL_PATH(../HAL, MarlinSPI.h)
|
||||||
@ -84,6 +86,14 @@ typedef enum max31865_numwires {
|
|||||||
MAX31865_4WIRE = 0
|
MAX31865_4WIRE = 0
|
||||||
} max31865_numwires_t;
|
} 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 */
|
/* Interface class for the MAX31865 RTD Sensor reader */
|
||||||
class MAX31865 {
|
class MAX31865 {
|
||||||
private:
|
private:
|
||||||
@ -97,7 +107,21 @@ private:
|
|||||||
uint16_t spiDelay;
|
uint16_t spiDelay;
|
||||||
#endif
|
#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);
|
void setConfig(uint8_t config, bool enable);
|
||||||
|
|
||||||
@ -110,8 +134,15 @@ private:
|
|||||||
|
|
||||||
void softSpiBegin(const uint8_t spi_speed);
|
void softSpiBegin(const uint8_t spi_speed);
|
||||||
|
|
||||||
|
void initFixedFlags(max31865_numwires_t wires);
|
||||||
|
|
||||||
|
void enable50HzFilter(bool b);
|
||||||
|
void enableBias();
|
||||||
|
void oneShot();
|
||||||
|
void resetFlags();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef LARGE_PINMAP
|
#if ENABLED(LARGE_PINMAP)
|
||||||
MAX31865(uint32_t spi_cs, uint8_t pin_mapping);
|
MAX31865(uint32_t spi_cs, uint8_t pin_mapping);
|
||||||
MAX31865(uint32_t spi_cs, uint32_t spi_mosi, uint32_t spi_miso,
|
MAX31865(uint32_t spi_cs, uint32_t spi_mosi, uint32_t spi_miso,
|
||||||
uint32_t spi_clk, uint8_t pin_mapping);
|
uint32_t spi_clk, uint8_t pin_mapping);
|
||||||
@ -121,17 +152,11 @@ public:
|
|||||||
int8_t spi_clk);
|
int8_t spi_clk);
|
||||||
#endif
|
#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();
|
uint8_t readFault();
|
||||||
void clearFault();
|
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();
|
uint16_t readRaw();
|
||||||
float readResistance();
|
float readResistance();
|
||||||
float temperature();
|
float temperature();
|
||||||
|
@ -2204,11 +2204,8 @@ void Temperature::init() {
|
|||||||
#elif TEMP_SENSOR_IS_MAX(0, 31865)
|
#elif TEMP_SENSOR_IS_MAX(0, 31865)
|
||||||
max31865_0.begin(
|
max31865_0.begin(
|
||||||
MAX31865_WIRES(MAX31865_SENSOR_WIRES_0) // MAX31865_2WIRE, MAX31865_3WIRE, MAX31865_4WIRE
|
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
|
#endif
|
||||||
|
|
||||||
#if TEMP_SENSOR_IS_MAX(1, 6675) && HAS_MAX6675_LIBRARY
|
#if TEMP_SENSOR_IS_MAX(1, 6675) && HAS_MAX6675_LIBRARY
|
||||||
@ -2218,11 +2215,8 @@ void Temperature::init() {
|
|||||||
#elif TEMP_SENSOR_IS_MAX(1, 31865)
|
#elif TEMP_SENSOR_IS_MAX(1, 31865)
|
||||||
max31865_1.begin(
|
max31865_1.begin(
|
||||||
MAX31865_WIRES(MAX31865_SENSOR_WIRES_1) // MAX31865_2WIRE, MAX31865_3WIRE, MAX31865_4WIRE
|
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
|
#endif
|
||||||
#undef MAX31865_WIRES
|
#undef MAX31865_WIRES
|
||||||
#undef _MAX31865_WIRES
|
#undef _MAX31865_WIRES
|
||||||
|
Loading…
Reference in New Issue
Block a user