@ -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
) ;
# if ndef 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
* Re turn 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 50 Hz noise or 60 Hz noise
*
* @ param b If true , 50 Hz noise is filtered , else 60 Hz ( 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 - wire Res) ;
}
/**
@ -301,7 +371,7 @@ float MAX31865::temperature() {
* @ return Temperature in C
*/
float MAX31865 : : temperature ( uint16_t adc_val ) {
return temperature ( ( ( adc_val ) / 32768.0f ) * ref Res) ;
return temperature ( ( ( adc_val ) * RECIPROCAL ( 32768.0f ) ) * refRes - wire Res) ;
}
/**
@ -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
}