Sharing SPI between Ethernet / SD Shield and RTD-1000 Breakout

Greetings,

I am new to the Arduino community and would like to seek for programming help for my project.

I have built a Pt-1000 temperature measurement system using a Arduino UNO board with a Pt-1000 breakout board by playwithfusion.com utilizing MAX31865. I have everything working till I start trying to log the data from the serial monitor onto the microSD card on the Arduino Ethernet shield. I was unable to obtain correct reading anymore.

To be honest, I am still a bit confuse about the SS pin selection. I know that the SD card reader uses SS at pin 4 and the Ethernet port uses SS at pin 10. The Pt-1000 breakout board also uses SS/CS at pin 10, but because the breakout board is capable of connecting two Pt-1000 sensors, I have assigned pin 8 and pin 9 as SS pins for the two Pt-1000 sensors. I realize that there may be SPI conflicting because I have the Pt-1000 breakout board and SD card sharing the the SPI.

Here are my codes. I only show the code for one Pt-1000 sensor. Your help is much appreciated.

// 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

// SD library
#include <SD.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 = 0x01; // Addr of first byte of data (start reading at RTD MSB)
const byte ADC_FAULT_REG = 0x07; // Addr of the fault reg

// CS for the SD card
const int chipSelect = 4;

// CS pin used for the connection with the RTD sensor
// other connections are controlled by the SPI library)
const int CS_PIN1 = 8;
const int CS_PIN2 = 9;

PWFusion_MAX31865_RTD rtd_ch0(CS_PIN1);
PWFusion_MAX31865_RTD rtd_ch1(CS_PIN2);

// Pt-1000 sensor characteristics curve constants
const float A = 3.9083E-3; // [deg C^-1]
const float B = -5.775E-7; // [deg C^-2]
const float C = -4.183E-12; // [deg C^-4]
const int R0 = 1000; // [ohms]

// Declare resistance variables
double r1;
double r2;

// Decalre temperature variables
double tmp1;
double tmp2;

const float voltage = 5.0;
const int rhPin1 = 0;
const int rhPin2 = 1;

float rhReading1;
float rhReading2;

void setup() 
{
  Serial.begin(9600);
  
  // Make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  Serial.print("Initializing SD card ... ");
    
  // See if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) 
  {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  // 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_PIN1, OUTPUT);
  pinMode(CS_PIN2, OUTPUT);
      
  rtd_ch0.MAX31865_config();
  rtd_ch1.MAX31865_config();
   
  // give the sensor time to set up
  delay(1000);
}

void loop() 
{
  static struct var_max31865 RTD_CH0;
  static struct var_max31865 RTD_CH1;
    
  // RTD_CH0.RTD_type = 1;                         // un-comment for PT100 RTD
  RTD_CH0.RTD_type = 2;                        // un-comment for PT1000 RTD
  
  // RTD_CH0.RTD_type = 1;                         // un-comment for PT100 RTD
  RTD_CH1.RTD_type = 2;                        // un-comment for PT1000 RTD
    
  struct var_max31865 * rtd_ptr0;
  struct var_max31865 * rtd_ptr1;
    
  rtd_ptr0 = &RTD_CH0;
  rtd_ptr1 = &RTD_CH1;
    
  rtd_ch0.MAX31865_full_read(rtd_ptr0);         // Update MAX31855 readings 
  rtd_ch1.MAX31865_full_read(rtd_ptr1);
  
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  
  // RTD Sensor # 1     
  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
      r1 = (double)RTD_CH0.rtd_res_raw * 400 / 32768;
      
      // if the file is available, write to it:
      if(dataFile) 
      {
        dataFile.print(r1);
        dataFile.print("   ");
                
        // print to the serial port too:
        Serial.print(r1);
        Serial.print("   ");
      }  
      else
      {
        Serial.print(r1);
        Serial.print("   ");
      }
    }
    else if(2 == RTD_CH0.RTD_type)              // handle values for PT1000
    {
      // calculate RTD resistance
      r1 = (double)RTD_CH0.rtd_res_raw * 4000 / 32768;
      
      // if the file is available, write to it:
      if(dataFile) 
      {
        dataFile.print(r1);
        dataFile.print("   ");
            
        // print to the serial port too:
        Serial.print(r1);
        Serial.print("   ");
      }  
      else
      {
        // Serial.println("error opening datalog.txt");
        Serial.print(r1);
        Serial.print("   ");
      }
    }
     
    /* 
    calculate RTD temperature (simple calc, +/- 2 deg C from -100C to 100C) 
    more accurate curve can be used outside that range
    tmp1 = ((double)RTD_CH0.rtd_res_raw / 32) - 256;
    */
    
    tmp1 = (-A+sqrt(pow(A,2)-4*B*(1-r1/R0)))/(2*B);
    if(dataFile)
    {
      dataFile.print(tmp1);
      dataFile.print("   ");
          
      // print to the serial port too:
      Serial.print(tmp1);
      Serial.print("   ");
    }
    else
    {
      // Serial.println("error opening datalog.txt");
      Serial.print(tmp1);
      Serial.print("   ");
    }
  } // end of no-fault handling
  else 
  {
    Serial.print("RTD Fault, register: ");
    Serial.print(RTD_CH0.status);
    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
  
  // Humidity Sensor # 1
  rhReading1 = analogRead(rhPin1);
  double rh1 = ( rhReading1 / 1024.0 ) * voltage * 100.0;
  if(dataFile)
  {
    dataFile.print(rh1);
    dataFile.print("   ");
           
    // print to the serial port too:
    Serial.print(rh1);
    Serial.print("   ");
  }
  else
  {
    // Serial.println("error opening datalog.txt");
    Serial.print(rh1);
    Serial.print("   ");
  }

Th SD card is a Mode0 device last I checked. You will probably need to switch modes when accessing one or the other, then switch back.

You should also disable all SPI devices before initializing any of them. Starting the SD card with the RTD-1000 SPI CS pins floating is risky at best.

Thanks SurferTim!

I have read some of your notes in the past and disable all the SPI devices with "pinMode(SS, OUTPUT)" and "digitalWrite(SS, HIGH)" in the void setup() section.

Regarding to the SPI.setDataMode() function, per your suggestion, should I include a line: SPI.setDataMode(Mode0) before the sketch executes any SD commands and switch it back to SPI.setDataMode(Mode3) afterwards? Also, this switching is only within the void setup() and not within the void loop()?

Thanks again.

Eric

I use the w5100 and the SD card in most of my sketches, so I prefer to leave the SPI settings default (Mode0 and MSBFIRST). If I need to change them for another device, then I set the SPI settings, do the read/write, and set the settings back to default. You can do anything you want, depending on your sketch and how often you access each SPI device.

The most important thing I have found is do not change the mode settings with any SPI slave select active (LOW). Insure all SPI device slave select pins are HIGH (disabled) when changing that MODE setting.

Hi SurferTim,

My sketch started to read and log correctly until this week when the sketch becomes “unstable”. When the microSD card is removed, the readings on the serial monitor are correct. However, the readings become unstable when the microSD is inserted. I included codes to make sure that all the CS pins are at HIGH at the beginning of the loop and played around the setBitOrder and setClockDivider, but still the code readings are jumping around. Here are my updated sketch. Your expertise is appreciated.

/*
The following code is intent to read from two RTD-1000 sensors,
connected to a two channels SPI (Mode 3) RTD-1000 breakout board,
utilizing MAX31865 (www.playwithfusion.com) and two analog relative 
humidity sensor modules (www.ist-ag.com). The data from the sensors
is logged by the SD on the Arduino ethernet shield through SPI. 
*/

// The RTD-1000 sensor communicates using SPI.
#include <SPI.h>

// Playing With Fusion MAX31865 libraries
#include <PlayingWithFusion_MAX31865.h>            // Core library
#include <PlayingWithFusion_MAX31865_STRUCT.h>     // Struct library

// Include SD library
#include <SD.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 = 0x01;   // Addr of first byte of data (start reading at RTD MSB)
const byte ADC_FAULT_REG = 0x07;  // Addr of the fault reg

// SS for microSD on Ethernet shield
const int SS_SD = 4;
// SS for RTD #1
const int SS_RTD1 = 8;
// SS for RTD #2
const int SS_RTD2 = 9;

// Analog pin assignments for the two humidity sensors
const int rhSen1 = 2;
const int rhSen2 = 3;

// Pt-1000 sensor characteristics curve constants
const float A = 3.9083E-3;   // [deg C^-1]
const float B = -5.775E-7;   // [deg C^-2]
const float C = -4.183E-12;  // [deg C^-4]
const int R0 = 1000;         // [ohms]

// Declare resistance variables
float R1;
float R2;

// Decalre temperature variables
float tmp1;
float tmp2;

// Declare reading variable (0-255) for the two analog humidity sensors
float rhRead1;
float rhRead2;

// Declare the voltage variable for humidity conversion
const float voltage = 5.0;

// Assign the relative SS pins to the SPI RTD channel
PWFusion_MAX31865_RTD rtd_ch0(SS_RTD1);
PWFusion_MAX31865_RTD rtd_ch1(SS_RTD2);

void setup()
{
  Serial.begin(9600);                    
  
  // Check for amount of free memory
  Serial.print("Free Memory: ");
  freeMem();
  
  // Disable SPI of RTD #1
  pinMode(SS_RTD1, OUTPUT);
  digitalWrite(SS_RTD1, HIGH);
  
  // Disable SPI of RTD #2
  pinMode(SS_RTD2, OUTPUT);
  digitalWrite(SS_RTD2, HIGH);
  
  // Disable W5100
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);
  
  // Disable SD
  pinMode(SS_SD,OUTPUT);
  digitalWrite(SS_SD,HIGH);
      
  SPI.begin();                   // begin SPI
  SPI.setDataMode(SPI_MODE3);    // MAX31865 is a Mode 3 device
  
  rtd_ch0.MAX31865_config();
  rtd_ch1.MAX31865_config();
      
  // Check for SD card
  SPI.setDataMode(SPI_MODE0);
  Serial.print("Initializing SD card ... ");
  if (!SD.begin(SS_SD))
  {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("Card initialized.");
  
  delay(1000);
}

void loop()
{
  digitalWrite(SS_RTD1,HIGH);
  digitalWrite(SS_RTD2,HIGH);
  digitalWrite(SS_SD,HIGH);
  
  SPI.setDataMode(SPI_MODE3);

  // RTD #1
  static struct var_max31865 RTD_CH0;
    
  // Handle values: 1: Pt-100, 2: Pt-1000 
  // RTD_CH0.RTD_type = 1;                        
  RTD_CH0.RTD_type = 2;                        
      
  struct var_max31865 * rtd_ptr0;
  rtd_ptr0 = &RTD_CH0;
    
  // Update MAX31855 readings
  rtd_ch0.MAX31865_full_read(rtd_ptr0);
   
  if(0 == RTD_CH0.status)                       // No fault, print info to serial port
  {
    if(1 == RTD_CH0.RTD_type)                   // Handle values for PT-100
    {
      // calculate RTD resistance
      R1 = (double)RTD_CH0.rtd_res_raw * 400 / 32768;
      
      Serial.print(R1);                         
      Serial.print("   ");
    }
    else if(2 == RTD_CH0.RTD_type)                // Handle values for PT-1000
    {
      // calculate RTD resistance
      R1 = (double)RTD_CH0.rtd_res_raw * 4000 / 32768;
      Serial.print(R1);                         
      Serial.print("   ");
    }
    // calculate RTD temperature (simple calc, +/- 2 deg C from -100C to 100C)
    // more accurate curve can be used outside that range
    // tmp1 = ((double)RTD_CH0.rtd_res_raw / 32) - 256;
    tmp1 = (-A + sqrt(pow(A,2) - 4*B*(1 - R1/R0))) / (2*B);
    Serial.print(tmp1);                         
    Serial.print("   ");
  }  // End of no-fault handling RTD #1
  else 
  {
    Serial.print("RTD Fault, register: ");
    Serial.print(RTD_CH0.status);
    if(0x80 & RTD_CH0.status)
    {
      Serial.print("RTD High Threshold Met ");            // RTD high threshold fault
    }
    else if(0x40 & RTD_CH0.status)
    {
      Serial.print("RTD Low Threshold Met ");             // RTD low threshold fault
    }
    else if(0x20 & RTD_CH0.status)
    {
      Serial.print("REFin- > 0.85 x Vbias ");             // REFin- > 0.85 x Vbias
    }
    else if(0x10 & RTD_CH0.status)
    {
      Serial.print("FORCE- open ");                       // REFin- < 0.85 x Vbias, FORCE- open
    }
    else if(0x08 & RTD_CH0.status)
    {
      Serial.print("FORCE- open ");                       // RTDin- < 0.85 x Vbias, FORCE- open
    }
    else if(0x04 & RTD_CH0.status)
    {
      Serial.print("Over/Under voltage fault ");          // overvoltage/undervoltage fault
    }
    else
    {
      Serial.print("Unknown fault, check connection ");   // print RTD temperature heading
    }
  }  // end of fault handling RTD #1
  
  /*
  ----------------------------------------------------------------------------------------------------------------------------
  */
  
  // Reading analog humidity modules
  rhRead1 = analogRead(rhSen1);
  float rh1 = ( rhRead1 / 1024.0 ) * voltage * 100.0;
  Serial.print(rh1);
  Serial.print("   ");
    
  rhRead2 = analogRead(rhSen2);
  float rh2 = ( rhRead2 / 1024.0 ) * voltage * 100.0;
  Serial.println(rh2);
  /*
  ----------------------------------------------------------------------------------------------------------------------------
  */
  
  // Save the data to the microSD card
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  SPI.setDataMode(SPI_MODE0);                            // microSD is a Mode 0 device
  File dataFile = SD.open("test.csv", FILE_WRITE);
  
  if(dataFile)
  {
    dataFile.print(R1);
    dataFile.print(",");
    dataFile.print(tmp1);
    dataFile.print(",");
    dataFile.print(R2);
    dataFile.print(",");
    dataFile.print(tmp2);
    dataFile.print(",");
    dataFile.print(rh1);
    dataFile.print(",");
    dataFile.println(rh2);
    dataFile.close();
  }
  else
  {
    Serial.println("Error opening file");
  }   
  delay(1000);
}

/*
------------------------------------------------------------------------------------------------------------------------------
*/

// Function for checking free memory on Arduino
uint16_t freeMem()
{
  char top;
  extern char *__brkval;
  extern char __bss_end;
  Serial.println( __brkval ? &top - __brkval : &top - &__bss_end);
}

What exactly do you mean by "unstable"? Is the instability consistent or random? In other words, is the instability happening all the time, or just now and then?

Is it inserting the SD card, or initializing it that causes the instability? Try inserting the SD and disabling the SD SPI by setting D4 output and high, but don't call SD.begin(4).

edit: I took a look at the datasheet for your MAX devices, and they will work with SPI mode 3 or mode 0. The SPI timing on the datasheet shows the clock can be either polarity, and that is the difference between the modes. Page 5 here shows this: http://datasheets.maximintegrated.com/en/ds/MAX31865.pdf

The SD card is not so flexible. My tests show they require mode 0.

Sorry for the confusion. The sketch produces fault RTD signals / readings , when the sketch realizes the microSD card is available for data logging. When the microSD card is not available (not inserted), the data reading is OK. In both conditions, SPI.begin() is used in the setup.

Maybe I should use SPI.begin(SS_SD) before data logging and SPI.begin(SS_RTD) before temperature reading instead of one SPI.begin()?

What is your thought in terms of using the SdFat.h instead of the conventional SD.h library?

Thanks again!