I’ve been playing around with a breakout board (from Adafruit) that has a MAX31865 IC which, I think, is just a later iteration of the MAX31855 (I haven’t looked at the datasheet for the MAX31855 yet). Anyway, I also had some trouble figuring out how to communicate with the IC via SPI but I eventually figured it by reading the source code of the Adafruit python library and running the python library with lots of debug statements sprinkled around.
I have my breakout board wired to a Raspberry Pi Zero. On the breakout board I have I’m using the pin outs for power and ground, of course. For the SPI communication I’m using:
CLK -> BCM 11 (SCLK)
SDO -> BCM 9 (MISO)
SDI -> BCM 10 (MOSI)
CS -> BCM 8 (CE0)
To open a connection I use:
iex(gadget@nerves.local)1> {:ok, ref} = Circuits.SPI.open("spidev0.0", mode: 1, speed_hz: 500_000)
I set the mode
to 1 because the datasheet for the MAX31865 says it works in mode 1 or 3. The speed_hz
to 500_000 because that’s what’s used in the Adafruit documentation and source code (I’m kind of assuming I have the value set correctly).
At this point I can read from the config register (0x00 when reading).
iex(gadget@nerves.local)2> Circuits.SPI.transfer(ref, <<0x00, 0x00>>)
{:ok, <<0, 0>>}
And set the config register (0x80 when writing) to the values that correspond to my setup which is a 3-wire PT100 RTD.
iex(gadget@nerves.local)3> Circuits.SPI.transfer(ref, <<0x80, 0x90>>)
{:ok, <<0, 0>>}
And read from the config register again to make sure it is set correctly.
iex(gadget@nerves.local)4> Circuits.SPI.transfer(ref, <<0x00, 0x00>>)
{:ok, <<0, 144>>}
When reading from the data register of the MAX31865 (0x01) I will get back 3 bytes of binary data. The first byte is ignored (same applies when reading from the config register). Then next 2 bytes are the data that I want. The first 15 bits of that data is the actual resistance value of the RTD. The last bit is the fault bit that will be 0 or 1 (if there was a fault you can read from the fault registers to see what it was). To read the resistance from the chip I do a transfer/2
and pattern match.
First, I have to configure the chip for a 1-shot
data transfer. This value is in the datasheet.
iex(gadget@nerves.local)5> Circuits.SPI.transfer(ref, <<0x80, 0xB0>>)
Then I can initiate a transfer and get the resistance value back in the binary.
iex(gadget@nerves.local)6> {:ok, <<_::size(8), resistance::size(15), fault_bit::size(1)>>} =
Circuits.SPI.transfer(ref, <<0x01, 0x00, 0x00>>)
The first byte of the binary that I’m passing into the transfer\2
function is the hex value of the data register on the MAX31865. I also add 2 more bytes because the transfer function is going to return me the same amount of binary data that I pass in. Since I know that I’m going to get 2 bytes worth of data back, I add 2 empty bytes in my binary that I pass into the transfer function. That’s the part that really tripped me up.
Once I have the resistance value I can do the maths to convert it to a temperature value. I created a Raspbian build to run the python libraries for debugging and to also take a measurement of the resistance value so I could test that it was the same when using Circuits.SPI
on a Nerves build. The values where the same and after converting the resistance value to a temperature value and comparing it to a normal thermometer the values are only off by 2 degrees. So, I think it’s working but this is all an experiment for me too.
Hope that helps.