MAX31865 help - loss of resolution

Hi,

I have an Arduino Uno with a RTD 4 wire probe and a ADC MAX31865, working well with a resolution with 0.03ºC.

I installed a uSD card to do datalogging, both SPI connection like my ADC, and my probe lost resolution to 0.06ºC.

Anyone can help me solve this problem.

Regards
CDC

There are no links to the used hardware, no sketch you're using for these tests and no links to the libraries you might have used. There is also no wiring diagram of how you connected everything together.
How do you measure the resolution?

Hi,

I am using arduino Uno with ADC MAX31865 (from http://www.playingwithfusion.com), with a Arduino wireless SD Shield and my LCD is a 4D system 32WPTU.
The ADC and SD card use SPI comunication and the LCD use I2C.
The resolution I am reading in LCD. without SD Shield the value of temperature changes 0.03ºC (20.00 to 20.03 or 19.97ºC), when a connect it changes to 0.06ºC (20.00 to 20.06 or 19.94ºC)

The code I am using is from the library.

/*    Arduino Uno   -->  SEN-30201
*    CS: pin 2     -->  CS
*    MOSI: pin 11  -->  SDI (must not be changed for hardware SPI)
*    MISO: pin 12  -->  SDO (must not be changed for hardware SPI)
*    SCK: pin 13   -->  SCLK (must not be changed for hardware SPI)
*    GND           -->  GND
*    5V            -->  Vin (supply with same voltage as Arduino I/O, 5V)
***************************************************************************/

// the sensor communicates using SPI, so include the hardware SPI library:
#include <SPI.h>
// include Playing With Fusion MAX31865 libraries
#include <PlayingWithFusion_MAX31865.h>              // core library
#include <PlayingWithFusion_MAX31865_STRUCT.h>       // struct library

#include <SD.h>
#include <elapsedMillis.h>
#include <Time.h>
//#include <TimeAlarms.h>

#include <genieArduino.h>

//Sensor addresses:
const byte CONFIG_REG_W = 0x80; // Config register write addr
const byte CONFIG_VALUE = 0xC3; // Config register value (Vbias+Auto+FaultClear+50Hz, see pg 12 of datasheet)
const byte ADC_WORD_MSB = 0x00; // Addr of first byte of data (start reading at RTD MSB)
const byte ADC_FAULT_REG = 0x07; // Addr of the fault reg

// CS pin used for the connection with the sensor
// other connections are controlled by the SPI library)
const int CS_PIN = 2;
const int chipSelect = 4;

double Temp_PT1;
unsigned int interval = 1000;


time_t t = now();
int hours = 17;
int minutes = 47;
int seconds = 0;
int days = 22;
int months = 4;
int years = 2014;

elapsedMillis timeElapsed; //declare global if you don't want it reset every time loop runs

PWFusion_MAX31865_RTD rtd_ch0(CS_PIN);

void setup() {
  //Serial.begin(9600);

  //-------------------------------------------------------------------------  
  // setup for the the SPI library:
  SPI.begin();               // begin SPI
  SPI.setDataMode(SPI_MODE3);         // MAX31865 is a Mode 3 device
  
  // initalize the chip select pin
  pinMode(CS_PIN, OUTPUT);
  rtd_ch0.MAX31865_config();

  SPI.setClockDivider(SPI_CLOCK_DIV2);

  //-------------------------------------------------------------------------
  //Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);

  SD.begin(chipSelect);// {
    //Serial.println("Card failed, or not present"); Display
    // don't do anything more:
   // return;}
  
  //-------------------------------------------------------------------------
  
  setTime(hours, minutes, seconds, days, months, years);
  
  //-------------------------------------------------------------------------
  genieBegin (GENIE_SERIAL,9600);  //Serial0

  genieAttachEventHandler(myGenieEventHandler);
  
  genieWriteContrast(1); // 1 = Display ON, 0 = Display OFF
  //-------------------------------------------------------------------------
  

  
  delay(100);
}

Did the change really happen, when you connected the Wireless SD shield? Or did it change when you changed the code to access the SD card?

BTW: the sketch is not complete, please add the loop() routine. The SD card is a mode 0 device so you might have to switch between the modes for each access. Many cards may also have problems with the increased bus speed of 8MHz.

Hi,

If I start the sd in Setup(), it loss resolution.

void loop() 
{
  genieDoEvents(); 

  temp_sensor();
  
   DataLogging();
}

void DataLogging()
{
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.

  char datalog[ ] = "probe.txt";
  
  File dataFile = SD.open(datalog, FILE_WRITE);

  if (timeElapsed > interval) 
  {				
    // if the file is available, write to it:
    if (dataFile) {
      dataFile.print(hour());dataFile.print(":");dataFile.print(minute());dataFile.print(":");dataFile.print(second());dataFile.print(" ");
      dataFile.print(day());dataFile.print("/");dataFile.print(month());dataFile.print("/");dataFile.print(year());dataFile.print(" ");
      dataFile.print("S1: ");dataFile.println(Temp_PT1);
      dataFile.close();
    }  
    // if the file isn't open, pop up an error:
    else {
      //dataFile.println("error opening datalog.txt"); Enviar para display
    } 
    timeElapsed = 0;              // reset the counter to 0 so the counting starts over...
  }
  dataFile.close();
}

void temp_sensor()
{
  static struct var_max31865 RTD_CH0;
  double tmp;
  
  RTD_CH0.RTD_type = 1;                         // un-comment for PT100 RTD
  
  struct var_max31865 *rtd_ptr;
  rtd_ptr = &RTD_CH0;
  
  rtd_ch0.MAX31865_full_read(rtd_ptr);          // Update MAX31855 readings 
  

  if(0 == RTD_CH0.status)                       // no fault, print info to serial port
  {
    if(1 == RTD_CH0.RTD_type)                   // handle values for PT100
    {
      // calculate RTD resistance
      tmp = (double)RTD_CH0.rtd_res_raw * 400 / 32768;
    }
    // calculate RTD temperature (simple calc, +/- 2 deg C from -100C to 100C)
    // more accurate curve can be used outside that range
    tmp = ((double)RTD_CH0.rtd_res_raw / 16) - 256;
    
    Temp_PT1 = tmp;
    tmp = tmp*100;
    int Temp = tmp;

    //if (tmp > 0){
    genieWriteObject(GENIE_OBJ_LED_DIGITS, 0x00,(Temp));
    //} 
    delay(100);
    
  }  // end of no-fault handling
  else 
  {
    File dataFile = SD.open("probe1.txt", FILE_WRITE);
    
    if (dataFile) {
      dataFile.print(hour());dataFile.print(":");dataFile.print(minute());dataFile.print(":");dataFile.print(second());dataFile.print(" ");
      dataFile.print(day());dataFile.print("/");dataFile.print(month());dataFile.print("/");dataFile.print(year());dataFile.print(" ");
      
      dataFile.print("RTD Fault, register: ");
      dataFile.print(RTD_CH0.status);
      dataFile.print(" - ");
    
      if(0x80 & RTD_CH0.status){
        dataFile.println("RTD High Threshold Met");}  // RTD high threshold fault
      else if(0x40 & RTD_CH0.status){
        dataFile.println("RTD Low Threshold Met");}   // RTD low threshold fault
      else if(0x20 & RTD_CH0.status){
        dataFile.println("REFin- > 0.85 x Vbias");}   // REFin- > 0.85 x Vbias
      else if(0x10 & RTD_CH0.status){
        dataFile.println("FORCE- open");}             // REFin- < 0.85 x Vbias, FORCE- open
      else if(0x08 & RTD_CH0.status){
        dataFile.println("FORCE- open");}             // RTDin- < 0.85 x Vbias, FORCE- open
      else if(0x04 & RTD_CH0.status){
        dataFile.println("Over/Under voltage fault");}  // overvoltage/undervoltage fault
      else{
        dataFile.println("Unknown fault, check connection");} // print RTD temperature heading
      
    dataFile.close();}
      // end of fault handling
  dataFile.close();}
  
}

void myGenieEventHandler(void) //Keyboard function
{
  genieFrame Event;
  genieDequeueEvent(&Event);
}

Remove the following two lines from your sketch:

  SPI.setDataMode(SPI_MODE3);         // MAX31865 is a Mode 3 device

  SPI.setClockDivider(SPI_CLOCK_DIV2);

The MAX31865 is a mode 0 or mode 3 device and sets it's internal mode automatically when you pull the CS pin low. After that you probably get correct results again.

Does that help?

HI,

Doesn't work. I remove the lines, and it is the same.

Arduino Uno has only one SPI master, I am using two slaves, can be because of this the device is lossing one byte?

Arduino Uno has only one SPI master, I am using two slaves, can be because of this the device is lossing one byte?

The SPI bus is made to act exactly like that. No, the device is not loosing a byte.

The UNO doesn't have much memory and the SD library is using more than half of it.

Try inserting the F() macro to all print statements with string constants:

dataFile.print("RTD Fault, register: ");

gets

dataFile.print(F("RTD Fault, register: "));

Does that help?

Hi,

Return an error: initializer fails to determine size of '__c'

Post the new code and the complete error message.

void DataLogging()
{
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.

  char datalog[ ] = "probe.txt";
  
  File dataFile = SD.open(datalog, FILE_WRITE);

  if (timeElapsed > interval) 
  {				
    // if the file is available, write to it:
    if (dataFile) {
      //dataFile.print(hour());dataFile.print(":");dataFile.print(minute());dataFile.print(":");dataFile.print(second());dataFile.print(" ");
      //dataFile.print(day());dataFile.print("/");dataFile.print(month());dataFile.print("/");dataFile.print(year());dataFile.print(" ");
      dataFile.print(F("S1: "));dataFile.println(F(Temp_PT1));
      dataFile.close();
    }  
    // if the file isn't open, pop up an error:
    else {
      //dataFile.println("error opening datalog.txt"); Enviar para display
    } 
    timeElapsed = 0;              // reset the counter to 0 so the counting starts over...
  }
  dataFile.close();
}
dataFile.println(F(Temp_PT1));

Is TempPT1 a string constant? Please use the F() macro only with string constants. It's used to read these strings directly from the flash without making a copy in the RAM, so you save a lot of RAM.

Hi,

I remove the datalogging(), and the problem it's the same. If I remove the SD.Begin() in loop, the problem dissapears.

It looks like it's mainly a memory problem but we have to check a few things first.

Can you insert this line after the call to SD.begin() in the setup() routine?

  SPI.setClockDivider(SPI_CLOCK_DIV4); // set standard SPI speed

Done. Nothing happened.

Can you do a measurement series with different temperatures (ice water, boiling water, etc.) also writing out the raw read value (RTD_CH0.rtd_res_raw) and posting the results?

What I think is very interesting:

tmp = ((double)RTD_CH0.rtd_res_raw / 16) - 256;

The resolution of that calculation has always a resolution of 0.06. That means the wrong result was when you got a 0.03 resolution.

Hi,

The ADC is 16 bits, this means the resolution is 0.03.

When I istalled the uSD card, the values from ADC changed, and I saw if I divided the raw value by 2, the values are corret. But I losses resolution :slight_smile: 8)

The ADC is 16 bits, this means the resolution is 0.03.

That's from the datasheet page 1:

15-Bit ADC Resolution

But anyway, with the calculation you have in your sketch, the resolution is 0.06. If you use another sketch, why didn't you post it? Is the calculation in my previous post wrong? If that is correct the resolution is 0.06° because the source value is an integer and you divide by 16 you cannot get a resolution finer than 0.06.

The lowest bit of the two result bytes is the fault bit, that doesn't add to the resolution.

I change this, and installed in arduino. I am trying using PID, without LCD. the output is:

RTD Sensor Trtd = 18.50 deg C
RTD Sensor Trtd = 18.47 deg C
RTD Sensor Trtd = 18.50 deg C

/*    Arduino Uno   -->  SEN-30201
*    CS: pin 4     -->  CS
*    MOSI: pin 11  -->  SDI (must not be changed for hardware SPI)
*    MISO: pin 12  -->  SDO (must not be changed for hardware SPI)
*    SCK: pin 13   -->  SCLK (must not be changed for hardware SPI)
*    GND           -->  GND
*    5V            -->  Vin (supply with same voltage as Arduino I/O, 5V)
***************************************************************************/

// the sensor communicates using SPI, so include the hardware SPI library:
#include <SPI.h>
// include Playing With Fusion MAX31865 libraries
#include <PlayingWithFusion_MAX31865.h>              // core library
#include <PlayingWithFusion_MAX31865_STRUCT.h>       // struct library

#include <PID_v1.h>

#define RelayPin 6

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;


//Sensor addresses:
const byte CONFIG_REG_W = 0x80; // Config register write addr
const byte CONFIG_VALUE = 0xC3; // Config register value (Vbias+Auto+FaultClear+50Hz, see pg 12 of datasheet)
const byte ADC_WORD_MSB = 0x01; // Addr of first byte of data (start reading at RTD MSB)
const byte ADC_FAULT_REG = 0x07; // Addr of the fault reg

// CS pin used for the connection with the sensor
// other connections are controlled by the SPI library)
const int CS_PIN = 4;

PWFusion_MAX31865_RTD rtd_ch0(CS_PIN);


void setup() {
  Serial.begin(9600);

  // setup for the the SPI library:
  SPI.begin();                        // begin SPI
  SPI.setDataMode(SPI_MODE3);         // MAX31865 is a Mode 3 device
  
  // initalize the chip select pin
  pinMode(CS_PIN, OUTPUT);
  rtd_ch0.MAX31865_config();
  
    // give the sensor time to set up
  delay(100);
  
  windowStartTime = millis();
  
  //initialize the variables we're linked to
  Setpoint = 40;

  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}


void loop() 
{
  temp_sensor();
  
  myPID.Compute();

  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if(millis() - windowStartTime>WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
  else digitalWrite(RelayPin,LOW);
  
}

void temp_sensor()
{
  static struct var_max31865 RTD_CH0;
  double tmp;
  
  RTD_CH0.RTD_type = 1;                         // un-comment for PT100 RTD
  
  struct var_max31865 *rtd_ptr;
  rtd_ptr = &RTD_CH0;
  
  rtd_ch0.MAX31865_full_read(rtd_ptr);          // Update MAX31855 readings 
  
  // Print information to serial port
  Serial.print("RTD Sensor ");              // Print RTD0 header
  
  if(0 == RTD_CH0.status)                       // no fault, print info to serial port
  {
    // calculate RTD temperature (simple calc, +/- 2 deg C from -100C to 100C)
    // more accurate curve can be used outside that range
    tmp = ((double)RTD_CH0.rtd_res_raw / 32) - 256;
    Input = tmp;
    delay(500);
    Serial.print("Trtd = ");                    // print RTD temperature heading
    Serial.print(tmp);
    Serial.println(" deg C");                   // print RTD temperature heading

  }  // end of no-fault handling
  else 
  {
    Serial.print("RTD Fault, register: ");
    Serial.print(RTD_CH0.status);
    Serial.print(" - ");
    if(0x80 & RTD_CH0.status)
    {
      Serial.println("RTD High Threshold Met");  // RTD high threshold fault
    }
    else if(0x40 & RTD_CH0.status)
    {
      Serial.println("RTD Low Threshold Met");   // RTD low threshold fault
    }
    else if(0x20 & RTD_CH0.status)
    {
      Serial.println("REFin- > 0.85 x Vbias");   // REFin- > 0.85 x Vbias
    }
    else if(0x10 & RTD_CH0.status)
    {
      Serial.println("FORCE- open");             // REFin- < 0.85 x Vbias, FORCE- open
    }
    else if(0x08 & RTD_CH0.status)
    {
      Serial.println("FORCE- open");             // RTDin- < 0.85 x Vbias, FORCE- open
    }
    else if(0x04 & RTD_CH0.status)
    {
      Serial.println("Over/Under voltage fault");  // overvoltage/undervoltage fault
    }
    else
    {
      Serial.println("Unknown fault, check connection"); // print RTD temperature heading
    }
  }  // end of fault handling
}

Have you tried with the SD card using the same code? If you change the calculation method between the two configuration it cannot return the same results.