0

At the moment I am running a python script to get the temperature from a PT1000 sensor via MAX31865 with my Raspberry Pi 3B+. With the python code everything works fine:

#!/usr/bin/python
import time, math
import RPi.GPIO as GPIO

class Max31865():
        
    def initPt1000_2WireSensor(self, iCsPin, isTestMode=False):
        self.csPin = iCsPin
        
        # Pt1000 (2-wire)
        self.registerCode = 0xA2
            
        self.setupGPIO()
        self.writeOutputs = isTestMode  # Im Testmodus werden Infos zum Max31865 in der Konsole ausgegeben
            
    def initPt100_3WireSensor(self, iCsPin, isTestMode=False):
        self.csPin = iCsPin
        
        # Pt100 (3-wire)
        #self.registerCode = 0xB2
        self.registerCode = 0xB2
            
        self.setupGPIO()
        self.writeOutputs = isTestMode  # Im Testmodus werden Infos zum Max31865 in der Konsole ausgegeben
        
    def setupGPIO(self):
        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BOARD)
        
        print( "\n\n")
        print ("CS: " + str(self.csPin));
        print ("MISO: " + str(self.misoPin));
        print ("MOSI: " + str(self.mosiPin));
        print ("CLK: " + str(self.clkPin));
        
        GPIO.setup(self.csPin, GPIO.OUT)
        GPIO.setup(self.misoPin, GPIO.IN)
        GPIO.setup(self.mosiPin, GPIO.OUT)
        GPIO.setup(self.clkPin, GPIO.OUT)

        GPIO.output(self.csPin, GPIO.HIGH)
        GPIO.output(self.clkPin, GPIO.LOW)
        GPIO.output(self.mosiPin, GPIO.LOW)

    def getCurrentTemp(self):
        
        # b10000000 = 0x80
        # 0x8x to specify 'write register value'
        # 0xx0 to specify 'configuration register'
        #
        # 0b10110010 = 0xB2
        # Config Register - https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf
        # ---------------
        # bit 7: Vbias -> 1 (ON)
        # bit 6: Conversion Mode -> 0 (MANUAL)
        # bit 5: 1-shot ->1 (ON)
        # bit 4: 3-wire select -> 1 (3 wire config) (0 for 2-/4-wire)
        # bit 3-2: fault detection cycle -> 0 (none)
        # bit 1: fault status clear -> 1 (clear any fault)
        # bit 0: 50/60 Hz filter select -> 0 (60Hz)
        #
        # 0b11010010 or 0xD2 for continuous auto conversion 
        # at 60Hz (faster conversion)

        # one shot
        self.writeRegister(0, self.registerCode)

        # conversion time is less than 100 ms
        time.sleep(.1)  # give it 100ms for conversion

        # read all registers
        out = self.readRegisters(0, 8)
        #print(str(out))
        conf_reg = out[0]
   
        #print("Config register byte: %x" % conf_reg)
        [rtd_msb, rtd_lsb] = [out[1], out[2]]
        rtd_ADC_Code = ((rtd_msb << 8) | rtd_lsb) >> 1
        
        temp = self.calcTemperature(rtd_ADC_Code)
        
        """
        # High fault threshold
        [hft_msb, hft_lsb] = [out[3], out[4]]
        hft = ((hft_msb << 8) | hft_lsb) >> 1

        # Low fault threshold
        [lft_msb, lft_lsb] = [out[5], out[6]]
        lft = ((lft_msb << 8) | lft_lsb) >> 1
        print ("High fault threshold: ", hft , " --- Low fault threshold: " , lft)
        """

        status = out[7]

        # 10 Mohm resistor is on breakout board to help
        # detect cable faults
        # bit 7: RTD High Threshold / cable fault open 
        # bit 6: RTD Low Threshold / cable fault short
        # bit 5: REFIN- > 0.85 x VBias -> must be requested
        # bit 4: REFIN- < 0.85 x VBias (FORCE- open) -> must be requested
        # bit 3: RTDIN- < 0.85 x VBias (FORCE- open) -> must be requested
        # bit 2: Overvoltage / undervoltage fault
        # bits 1,0 don't care    
        # print "Status byte: %x" % status

        if ((status & 0x80) == 1):
            raise FaultError("High threshold limit (Cable fault/open)")
        if ((status & 0x40) == 1):
            raise FaultError("Low threshold limit (Cable fault/short)")
        if ((status & 0x04) == 1):
            raise FaultError("Overvoltage or Undervoltage Error")
        
        return temp
    
    
    def writeRegister(self, regNum, dataByte):
        GPIO.output(self.csPin, GPIO.LOW)
        
        # 0x8x to specify 'write register value'
        addressByte = 0x80 | regNum;
        
        # first byte is address byte
        #print("Cs-Pin: ", self.csPin, "Addresse: ", addressByte)
        self.sendByte(addressByte)
        # the rest are data bytes
        self.sendByte(dataByte)
        GPIO.output(self.csPin, GPIO.HIGH)

    def readRegisters(self, regNumStart, numRegisters):
        out = []
        GPIO.output(self.csPin, GPIO.LOW)
        
        # 0x to specify 'read register value'
        self.sendByte(regNumStart)
        
        for byte in range(numRegisters):    
            data = self.recvByte()
            out.append(data)

        GPIO.output(self.csPin, GPIO.HIGH)
        return out

    def sendByte(self, byte):
        print("Byte: " + str(byte))
        for bit in range(8):
            GPIO.output(self.clkPin, GPIO.HIGH)
            print("Ja")
            if (byte & 0x80):
                print("Evtl")
                GPIO.output(self.mosiPin, GPIO.HIGH)
            else:
                GPIO.output(self.mosiPin, GPIO.LOW)
            byte <<= 1
            GPIO.output(self.clkPin, GPIO.LOW)

    def recvByte(self):
        byte = 0x00
        for bit in range(8):
            GPIO.output(self.clkPin, GPIO.HIGH)
            byte <<= 1
            if GPIO.input(self.misoPin):
                byte |= 0x1
            GPIO.output(self.clkPin, GPIO.LOW)
        return byte    

    def calcTemperature(self, RTD_ADC_Code):
        global temp

        R_REF = 0.0  # Reference Resistor
        Res0 = 0.0;  # Resistance at 0 degC for 400ohm R_Ref
        a = 0.0
        b = 0.0
        c = 0.0

        if (self.registerCode == 0xA2):
            ############# PT1000 #############
            R_REF = 4300.0  # Reference Resistor
            Res0 = 1000.0;  # Resistance at 0 degC for 430ohm R_Ref
            a = .00381
            b = -.000000602
            # c = -4.18301e-12 # for -200 <= T <= 0 (degC)
            c = -0.000000000006
            # c = 0 # for 0 <= T <= 850 (degC)
        else:
            ############# PT100 #############
            R_REF = 430.0  # Reference Resistor
            Res0 = 100.0;  # Resistance at 0 degC for 430ohm R_Ref
            a = .00390830
            b = -.000000577500
            # c = -4.18301e-12 # for -200 <= T <= 0 (degC)
            c = -0.00000000000418301
            # c = 0 # for 0 <= T <= 850 (degC)
        
        Res_RTD = (RTD_ADC_Code * R_REF) / 32768.0  # PT1000 Resistance
        # if(self.writeOutputs):
        #    print("CS-Pin: " , self.csPin, " --- ADC-Value: ", RTD_ADC_Code , " --- Resistance: ", round(Res_RTD, 2) , " Ohms")
        
        # Callendar-Van Dusen equation
        # Res_RTD = Res0 * (1 + a*T + b*T**2 + c*(T-100)*T**3)
        # Res_RTD = Res0 + a*Res0*T + b*Res0*T**2 # c = 0
        # (c*Res0)T**4 - (c*Res0)*100*T**3  
        # + (b*Res0)*T**2 + (a*Res0)*T + (Res0 - Res_RTD) = 0
        #
        # quadratic formula:
        # for 0 <= T <= 850 (degC)
        temp = -(a * Res0) + math.sqrt(a * a * Res0 * Res0 - 4 * (b * Res0) * (Res0 - Res_RTD))
        temp = round(temp / (2 * (b * Res0)), 2)
        temp_line = round((RTD_ADC_Code / 32.0) - 256.0, 2)
        
        # removing numpy.roots will greatly speed things up
        # temp_C_numpy = numpy.roots([c*Res0, -c*Res0*100, b*Res0, a*Res0, (Res0 - Res_RTD)])
        # temp_C_numpy = abs(temp_C_numpy[-1])
        
        # if(self.writeOutputs):
        #    print ("CS-Pin: " , self.csPin, " --- Straight Line Approx. Temp: ", temp_line , " --- Callendar-Van Dusen Temp: " , temp)
        # print "Solving Full Callendar-Van Dusen using numpy: %f" %  temp_C_numpy
        if (temp < 0):  # use straight line approximation if less than 0
            # Can also use python lib numpy to solve cubic
            # Should never get here in this application
            temp = (RTD_ADC_Code / 32) - 256
    
        if(self.writeOutputs):
            print ("CSPin " , self.csPin, " - ADC: ", RTD_ADC_Code , " - Resistance: ", round(Res_RTD, 2) , " Ohms - Temp: " , temp)
        return temp
    ##############################################################################################################################
    #                                                         Program start                                                       #
    ###############################################################################################################################
    csPin = 24
    misoPin = 21
    mosiPin = 19
    clkPin = 23
    registerCode = 0

    # BOARD:21,19,23
    # BCM: 9,10,11

class FaultError(Exception):
    pass

Now I tried to do the same logic just with Java code. The Problem is that the temperature is always -256 degrees. The reason for this is that the GPIO PIN 21 ("MISO") is never in state "HIGH"/1 (line 207 is never true):

import com.pi4j.io.gpio.*;
import java.nio.ByteBuffer;

public class Max31865 {
    private static GpioController gpio;
    private int registerCode;

    private GpioPinDigitalOutput csPin;
    private GpioPinDigitalInput misoPin;
    private GpioPinDigitalOutput mosiPin;
    private GpioPinDigitalOutput clkPin;
    private String name;

    public Max31865(String name, Pin clk, Pin miso, Pin mosi, Pin cs, boolean pt1000_2wire) {
        this.name = name;

        // logger.info("Init MAX31865 (" + name + ")");
        gpio = GpioFactory.getInstance();

        if (pt1000_2wire) {
            // 2 Wire PT1000
            this.registerCode = 0xA2;
        } else {
            // 3 Wire PT100
            this.registerCode = 0xB2;
        }

        setupGPIO(cs, miso, mosi, clk);
    }

    private void setupGPIO(Pin cs, Pin miso, Pin mosi, Pin clk) {
        System.out.println("CS: " + cs.getAddress());
        System.out.println("MISO: " + miso.getAddress());
        System.out.println("MOSI: " + mosi.getAddress());
        System.out.println("CLK: " + clk.getAddress());

        this.csPin = gpio.provisionDigitalOutputPin(cs);
        this.misoPin = gpio.provisionDigitalInputPin(miso);
        this.mosiPin = gpio.provisionDigitalOutputPin(mosi);
        this.clkPin = gpio.provisionDigitalOutputPin(clk);

        // this.csPin.setShutdownOptions(true, PinState.LOW);
        // this.misoPin.setShutdownOptions(true, PinState.LOW,
        // PinPullResistance.OFF);
        // this.mosiPin.setShutdownOptions(true, PinState.LOW);
        // this.clkPin.setShutdownOptions(true, PinState.LOW);

        this.csPin.high();
        this.clkPin.low();
        this.mosiPin.low();
    }

    public double getCurrentTemp() {
        writeRegister(0, registerCode);

        try {
            // COnversion time is less than 100 ms
            Thread.sleep(100);
        } catch (InterruptedException ex) {
            System.out.print(ex.toString());
        }

        byte[] bArray = readRegister(0, 8);

        // System.out.print("bArray: " + bArray);

        // int conf_reg = bArray[0];
        int conf_reg = 0;
        if (bArray[0] < 0) {
            conf_reg = 256 + bArray[0];
        } else {
            conf_reg = bArray[0];
        }
        // System.out.println(String.valueOf(bArray[0]));

        int rtd_msb = 0;
        if (bArray[1] < 0) {
            rtd_msb = 256 + bArray[1];
        } else {
            rtd_msb = bArray[1];
        }
        int rtd_lsb = 0;
        if (bArray[2] < 0) {
            rtd_lsb = 256 + bArray[2];
        } else {
            rtd_lsb = bArray[2];
        }

        // System.out.print("rtd_msb: " + rtd_msb);
        // System.out.print("rtd_lsb: " + rtd_lsb);
        int rtd_ADC_Code = ((rtd_msb << 8) | rtd_lsb) >> 1;
        byte status = bArray[7];

        if ((status & 0x80) == 1) {
            // logger.warn("High threshold limit (Cable fault/open)");
            System.out.println("High threshold limit (Cable fault/open)");
        }
        if ((status & 0x40) == 1) {
            // logger.warn("Low threshold limit (Cable fault/short)");
            System.out.println("Low threshold limit (Cable fault/short)");
        }
        if ((status & 0x04) == 1) {
            // logger.warn("Overvoltage or Undervoltage Error");
            System.out.println("Overvoltage or Undervoltage Error");
        }

        return calcTemperature(rtd_ADC_Code);
    }

    private double calcTemperature(int rtd_ADC_Code) {
        double R_REF = 0.0; // Reference Resistor
        double Res0 = 0.0; // Resistance at 0 degC for 400ohm R_Ref
        double a = 0.0;
        double b = 0.0;
        double c = 0.0;

        if (registerCode == 0xA2) {
            // ############# PT1000 #############
            R_REF = 4300.0; // Reference Resistor
            Res0 = 1000.0; // Resistance at 0 degC for 4300ohm R_Ref
            a = .00381;
            b = -.000000602;
            // c = -4.18301e-12 # for -200 <= T <= 0 (degC)
            c = -0.000000000006;
            // c = 0 # for 0 <= T <= 850 (degC)

        } else {
            // ############# PT100 #############
            R_REF = 430.0; // Reference Resistor
            Res0 = 100.0; // Resistance at 0 degC for 430ohm R_Ref
            a = .00390830;
            b = -.000000577500;
            // # c = -4.18301e-12; # for -200 <= T <= 0 (degC)
            c = -0.00000000000418301;
            // # c = 0 # for 0 <= T <= 850 (degC)
        }

        double Res_RTD = (rtd_ADC_Code * R_REF) / 32768.0; // PT1000 Resistance
        double temp, temp_line;
        temp = -(a * Res0) + Math.sqrt(a * a * Res0 * Res0 - 4 * (b * Res0) * (Res0 - Res_RTD));
        temp = round(temp / (2 * (b * Res0)), 2);
        temp_line = round((rtd_ADC_Code / 32.0) - 256.0, 2);

        if (temp < 0) { // use straight line approximation if less than 0
            temp = (rtd_ADC_Code / 32) - 256;
        }
        return temp;

    }

    private void writeRegister(int regNum, int dataByte) {
        csPin.low();

        // 0x8x to specify 'write register value'
        int addressByte = 0x80 | regNum;

        // first byte is address byte
        sendByte(addressByte);
        // the rest are data bytes
        sendByte(dataByte);
        csPin.high();
    }

    private byte[] readRegister(int regNumStart, int numRegisters) {
        ByteBuffer out = ByteBuffer.allocate(1024);

        csPin.low();
        sendByte(regNumStart);
        for (int i = 0; i < numRegisters; i++) {
            int bInt = recvByte();
            out.put(i, (byte) bInt);
        }

        csPin.high();
        return out.array();
    }

    private void sendByte(int byteToSend) {

        String bString = Integer.toBinaryString(byteToSend);
        if (bString.length() < 8) {
            bString = String.format("%08d", Integer.parseInt(bString));
        } else if (bString.length() > 8) {
            // logger.warn("Wrong byte:" + bString);
            System.out.println("Wrong byte:" + bString);
        }

        for (int i = 0; i < bString.length(); i++) {
            clkPin.high();
            boolean v = (Integer.parseInt(bString.substring(i, i + 1)) != 0);
            if (v) {
                mosiPin.high();
            } else {
                mosiPin.low();
            }
            clkPin.low();
        }
    }

    private int recvByte() {
        int byt = 0x00;
        for (int i = 0; i < 8; i++) {
            clkPin.high();
            byt <<= 1;
            if (misoPin.isHigh()) {
                byt |= 0x1;
            }
            clkPin.low();
        }
        return byt;
    }

    private double round(double zahl, int stellen) {
        return (double) ((int) zahl
                + (Math.round(Math.pow(10, stellen) * (zahl - (int) zahl))) / (Math.pow(10, stellen)));
    }

    public static final byte[] intToByteArray(int value) {
        return new byte[] { (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value };
    }

    public static void main(String[] args) throws InterruptedException {
        Max31865 temp = new Max31865("Test", RaspiPin.GPIO_23, RaspiPin.GPIO_21, RaspiPin.GPIO_19, RaspiPin.GPIO_24,
                true);
        int cnt = 3;
        while (cnt > 0) {
            System.out.println("Temp: " + temp.getCurrentTemp());
            Thread.sleep(1000);
            cnt--;
        }
    }
}

On my Raspberry java-11-openjdk-armhf is installed.

Any ideas or experiences with similar behavior?

Udpate: After several reboots, the MISO is always LOW or always HIGH after a reboot. Debugging as well as using "!pin.IsLow()" instead of "pin.isHigh()" also do not work :(

Lukas
  • 1
  • 5
  • Are you using an IDE? Try running a debugging process, and use the _Force Step Into_ command to evaluate the condition. I found the source for _[#isHigh](https://pi4j.com/1.2/apidocs/src-html/com/pi4j/io/gpio/impl/GpioControllerImpl.html#line.291)_. It looks like _false_ if a _[GpioPinDigital#isLow](https://pi4j.com/1.2/apidocs/com/pi4j/io/gpio/GpioPinDigital.html#isLow--)_ is _true_. – Reilas May 30 '23 at 21:38
  • You are using Linux, correct? Why don't you use the in-kernel driver: drivers/iio/temperature/max31865.c? – 0andriy Jun 01 '23 at 15:09

0 Answers0