[SOLVED] SPI communication with MAX31865

Hello,

I got myself a breakout board with the MAX31865 (this one: Playing With Fusion - PT100 RTD Temperature Sensor SPI Digital Interface MAX3186 Breakout)
But I have so far been unable to get any reasonable values from it. I first tried using the example arduino project from playingwithfusion (see the link above). Then I realised I am using a 3-wire PT100 sensor and the default setting is 2 or 4-wire.
Based on the example i created a very much simplified version for setting the config registry for 3-wire.

First i write 0xCA to the config registry (at 0x80) and then i attempt to read it, but it keeps returning 0x80 as the value.

Here is my simplified example that first reads the config registry, then tries to set it to 0xCA and then reads it again.

#include <SPI.h>

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

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);
  digitalWrite(CS_PIN, HIGH);
  
  
  
  // give the sensor time to set up
  delay(500);
    
//Read the registry
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(0x00); //Let it know we want to read the registry, 0x = read, x0 = position 0
  int conf_reg = SPI.transfer(0x00); //Read
  Serial.print(conf_reg, HEX);
  digitalWrite(CS_PIN, HIGH);
  //Serial.print("\t");
  
     delay(500);                                   // 500ms delay... can be much faster

  digitalWrite(CS_PIN, LOW);
  
  SPI.transfer(0x80); //Let it know we want to write, 8x = write, x0 = position 0
  SPI.transfer(0xCA); //The actual configuration
  
  digitalWrite(CS_PIN, HIGH);

  delay(500);

//And the whole read part again
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(0x00);
  conf_reg = SPI.transfer(0x00);
  Serial.print(conf_reg, HEX);
  digitalWrite(CS_PIN, HIGH);
  //Serial.print("\t");
}

void loop() {
  
}

Both reads return 80. I am new to SPI, so maybe I got something wrong? As I said, it is based on the example linked above. The data sheet for the MAX31865 is also available there.

Aaand of course i post this in the wrong part of the forum. Sorry!
If any moderator/admin reads this, could you please move it to the proper place? I'm not allowed to remove my post, apparently.

Thanks,

Which forum would you like it in?

You might also try this code I got from an application engineer at Maxim.
I think he was testing on a Mega, make sure you set the SS pin to match your hardware.

max31865Hani.ino (9.97 KB)

Thank you, will try that immediately! :slight_smile:

About the forum, I'm not sure. "Sensors" or "Networking, Protocols and Devices" maybe?

Thank you for the code, it has very good error messages and makes more sense to me than the example code from playingwithfusion. I changed the configuration bit for 3-wire to 1.

I keep getting an error message about RTD+ and RTD- being shorted (error bit D6), and sometimes the V REFIN - > 0.85 x V BIAS (error bit D5).

I suspect the D5 might be a second result of D6 (something seems shorted). Maybe my wiring is faulty then?

My PT100 sensor has 3 wires. Two blue ones with no resistance between them and a red one that at room temperature gives about 108 Ohm resistance to the blue ones. Than seems reasonable.
I connected red to RTD- and the blue ones to RTD+ and FORCE+. (FORCE+ is connected to FORCE2 according to the diagrams for the board).

So i triple-checked the data sheets and my wiring looks good to me. Dont know where to continue looking now..

CrossRoads, you seem to be the go-to guy on this forum for the MAX31865. Have you worked with 3-wire PT100/1000's? Does my wiring of the sensor seem right to you?

I've only used 2-wire. If you're connected per the datasheet, I don't have any magic insights.
Suggest sending a message to Playing With Fusion guys
CustomerService@PlayingWithFusion.com

"Breakout board for the MAX31865 RTD-to-Digital converter from Maxim. Two breakout hardware configurations are available standard, designed to interface with either the PT100 or PT1000 platinum RTDs. For non-standard applications, including thermistors, custom hardware configurations can be accommodated. Contact Technical Support for more information.

RTD devices may be wired in 2, 3 or 4-wire configurations using the 4-pin screw terminal input. The MAX31865 breakout is interfaced via 3 or 4-wire SPI with a data-ready output for specific operating modes. An LDO and a high-speed level shifter are included to allow interfacing with microcontroller devices between 3.0V and 5V (all Arduinos, Raspberry PI, etc) without sacrificing device performance."

OK. I've sent them an e-mail. Keeping my fingers crossed they will help me.

Thank you again for the code, it did help me forward. I'll take a closer look at what the "real" difference between our code is, except that you're using DRDY-pin and I was using timers. Every day learning something new is a good day. :slight_smile:

Cheers!
/Martin

you're using DRDY-pin and I was using timers

Not me - Maxim.
When I used these on a card, I was going by time as well.

Hi Martin,
I am replying to you here (for the Arduino forum post to see), personally (in response to your email) and then following up with an update to our product documentation on our website (will be a few days, but for the whole world to see!). I suspect that your issues are due to the lack of a jumper connecting RTDIN- and FORCE-. Since this is a 'universal' board, the 4 connections are not hard-wired together on the PCB. Instead, it's set-up for the most precise RTD configuration possible (the 4-wire), forcing the 2 and 3-wire connections to use jumpers to complete circuit paths that get the current flowing and the voltage measured. So, plug your RTD leads into the holes that they're marked for, then wire in a jumper between FORCE- and RTDIN-.

Please let me know if this doesn't work, and we'll do whatever we can to get you up and running. We appreciate your business, and have a great day!

Hah, funny thing is I did try that earlier, before i got the 3-wire bit working and then dismissed (and promptly forgot about) it when it didn't solve my problem. Thank you for putting me back on track fusionstein!

So now I got a new one:
"Error was detected. The RTD resistance measured is not within the range specified in the Threshold Registers."

I did continue to use the code from Maxim. I noticed the reference resistor was set to 4000 Ohm (Pt1000) and the sensor resistance at 0 to 1000 Ohm in the code, so I changed it to 400 and 100 since I'm using the Pt100 sensor, but it didn't make any difference.

The thresholds are set to 0x00 min and 0xFF max. The resistance on the sensor i measured to about 108 Ohm and that is where it should be around room temperature according to this, for example: http://peltierfridge.files.wordpress.com/2011/07/pt100_graph.jpg

So I tried the PlayingWithFusion code again.
In "PlayingWithFusion_MAX31865.cpp" I changed the config register value to include the 3-wire bit.

AND IT WORKS!

Now I just have to figure out why :wink:

Thank you for your help guys, I never would have figured this out on my own!
May you have an awesome week.

/Martin

Aaaaand I'm back....

Apparently, the only way i can make the sensor work is if I first run the Maxim code and then, without powering off the arduino, upload and run playingwithfusions code.

The more I try to understand what's going on with the code the less I understand. >_<
At least the wiring is now correct. So let's start from scratch.

Let's go with the maxim code since it seems more "robust" and a little simpler ot my untrained eyes.
When running the code I actually get a line right at the beginning that states the max31865 did NOT receive the configuration correctly. That is probably why it bugs out when trying to read the 3-wire sensor in it's 2/4-wire setting.
I'm trying to write 11010000 (0xD0 or 208). When I read the value back again I get 1101000 (0x68 or 104), missing the last 0.

Any ideas? I'm attaching my code.

max31865Hani.ino (10.1 KB)

So I let the thing rest for a week, and that gave some results :wink:

The code I posted last week had two problems. The first being that the configuration, when read from the MAX31865 was missing the last bit. This I "solved" with an ugly hack, doing a bit shift to add a 0 at the end. It works, but I still dont know why I'm not getting that last bit.

The second problem was that when reading the RTD MSB and LSB, the MSB was shifted 7 steps left before combining it with the LSB. In the code from playing with fusion it was shifted 8 steps. I changed it to 8 steps and now I'm getting reasonable values.

Then, there's a new problem: randomly, about 50% of the temperature reads, the RTD error bit is set. The values seem correct and the fault register shows nothing at all. Just ignoring the error bit seems to work, but once again it seems like a very ugly hack. There must be a reason it gets set.

So two questions remain:

  1. Why am I only getting 7 bits when reading the configuration registry?

  2. Why is the RTD error bit set (D0 of the RTD LSB) when the fault registry shows no error?

Thanks,
/Martin

Edit: clarifications

So I don't have a reliable reference thermometer to compare with, but shifting the RTD LSB 1 step left, just as I did with the config registry still gives reasonable values (just some changes in the decimals). Could that be it?

If so, the "missing bit" is not consistent. Doing the bit shift on the MSB-value gives ridiculous results..

Can only guess the other hardware on the fusion board is interfering with the transfers somehow.
Do you have a schematic for that board?

For a reference, stick the probes in a glass of ice water. That should yield a predictable result as the temperature should be steady while the ice/water mix completes it's state change.
Similarly, a cup of freshly boiling water should give another good reference.

The schematic (pdf): http://playingwithfusion.com/include/getfile.php?fileid=7021

So I tried with a glass of cold water and now the D7 error registry bit (High threshold fault) gets set. The temp earlier felt a little high (24.x C) and as soon as the high threshold bit gets set and the probe is in the cold water it starts jumping between about 24 and 19 degrees C. (one or the other, nothing between).
Pull it out of the water and dry it off and it goes back to 24C and "all is fine".

Oh, a TXB0108 as a level shifter. That could be part of the problem too. The MAX31865 only has 1.6mA drive capability on its SDO line. The TXB0108 needs 2mA on its input to make it change the data flow direction. I had the same problem, and ended up lifting the SDO related pins on the TXB0108 and had the MAX31865s drive the MISO line directly.

So I am suspecting the comining of the LSB and MSB for RTD is wacky.

The relevant parts of the ORIGINAL code:

byte lsb_rtd = Read(0x02);
byte msb_rtd = Read(0x01);

float RTD = ((msb_rtd << 7) + ((lsb_rtd & 0xFE) >> 1));                 //Combining RTD_MSB and RTD_LSB to protray decimal value. Removing MSB and LSB during   shifting/Anding

It's a 15 bit value. D0 in the LSB is the error bit and we dont want to use that. That's why there is only a 7 bit shift on the MSB and the LSB is shifted 1 to the right. Problem is I only get somewhat reasonable values using 8 bit shift on the MSB.

Is the above example correct?
Also, in the example above, they are masking out the error bit before shifting it. Do we really need to do that?

I googled a bit on bit shift operations, and while i understand the basics every example is different (mostly the operator between LSB and MSB, + in the example, but some use | or |=) depending on the language used. I'm not even sure what is used for arduino. Is it C++ all the way?