diff --git a/docs/README.md b/docs/README.md index c0752f1..4dd0f7e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,7 +18,7 @@ https://www.arduino.cc/reference/en/libraries/arduino_portentamachinecontrol/ - Manages input signals, including: - 8 digital inputs at 24Vdc - 2 channels for encoder readings - - 3 analog inputs for PT100/J/K temperature probes + - 3 analog inputs for PT100 and TC J/K/T temperature probes - 3 analog inputs for 4-20mA/0-10V/NTC signals - Manages output signals, including: @@ -81,6 +81,7 @@ void loop() { - **[RTC_Alarm](../examples/RTC_Alarm):** This example demonstrates how to set up and utilize RTC alarms. - **[Temp_probes_RTD](../examples/Temp_probes_RTD):** This example demonstrates the temperature probe readings using RTD sensors. - **[Temp_probes_Thermocouples](../examples/Temp_probes_Thermocouples):** This example demonstrates the temperature probe readings using thermocouple sensors. +- **[Temp_probes_Mixed](../examples/Temp_probes_Mixed):** This example demonstrates the temperature probe readings using both thermocouple and RTD sensors at the same time. - **[USB_host](../examples/USB_host):** This example shows the USB host functionality. ## API diff --git a/docs/api.md b/docs/api.md index 40250fb..21aacfb 100644 --- a/docs/api.md +++ b/docs/api.md @@ -13,6 +13,7 @@ `class` [`RTDTempProbeClass`](#class-rtdtempprobeclass) | Class for managing the Resistance Temperature Detector (RTD) temperature sensor connector of the Portenta Machine Control. `class` [`RtcControllerClass`](#class-rtccontrollerclass) | Class for controlling the PCF8563T RTC of the Portenta Machine Control. `class` [`TCTempProbeClass`](#class-tctempprobeclass) | Class for managing the Thermocouple (TC) temperature sensor connector of the Portenta Machine Control. +`class` [`TempProbeClass`](#class-tempprobeclass) | Class for managing the temperature sensor connector in mixed configurations of the Portenta Machine Control. `class` [`USBClass`](#class-usbclass) | Class for managing the USB functionality of the Portenta Machine Control. # class `AnalogInClass` @@ -128,11 +129,12 @@ Class for managing RTD temperature sensor inputs of the Portenta Machine Control Members | Descriptions --------------------------------|--------------------------------------------- -`public ` [`RTDTempProbeClass`](#public-rtdtempprobeclasspinname-rtd_cs_pin--mc_rtd_cs_pin-pinname-ch_sel0_pin--mc_rtd_sel0_pin-pinname-ch_sel1_pin--mc_rtd_sel1_pin-pinname-ch_sel2_pin--mc_rtd_sel2_pin-pinname-rtd_th_pin--mc_rtd_th_pin)`(PinName rtd_cs_pin, PinName ch_sel0_pin, PinName ch_sel1_pin, PinName ch_sel2_pin, PinName rtd_th_pin)` | Construct a RTDTempProbeClass object. +`public ` [`RTDTempProbeClass`](#public-rtdtempprobeclasspinname-rtd_cs_pin--mc_rtd_cs_pin-pinname-ch_sel0_pin--mc_tp_sel0_pin-pinname-ch_sel1_pin--mc_tp_sel1_pin-pinname-ch_sel2_pin--mc_tp_sel2_pin-pinname-rtd_th_pin--mc_rtd_th_pin)`(PinName rtd_cs_pin, PinName ch_sel0_pin, PinName ch_sel1_pin, PinName ch_sel2_pin, PinName rtd_th_pin)` | Construct a RTDTempProbeClass object. `public ` [`~RTDTempProbeClass`](#public-rtdtempprobeclass)`()` | Destruct the RTDTempProbeClass object. -`public bool` [`begin`](#public-bool-beginuint8_t-io_address--three_wire)`(uint8_t io_address)` | Initialize the RTDTempProbeClass with the specified I/O address. +`public bool` [`begin`](#public-bool-beginuint8_t-io_address--probe_rtd_3w)`(uint8_t io_address)` | Initialize the RTDTempProbeClass with the specified I/O address. `public void` [`end`](#public-void-end)`()` | Disable the temperature sensors and release any resources. `public void` [`selectChannel`](#public-void-selectchannelint-channel)`(int channel)` | Select the input channel to be read (3 channels available). +`public float` [`readTemperature`](#public-float-readTemperaturefloat-rtdnominal-float-refresistor)`(float RTDnominal, float refResistor)` | Read temperature value of the connected RTD. # class `RtcControllerClass` Class for controlling the PCF8563T RTC. @@ -151,11 +153,27 @@ Class for managing thermocouples temperature sensor of the Portenta Machine Cont Members | Descriptions --------------------------------|--------------------------------------------- -`public ` [`TCTempProbeClass`](#public-tctempprobeclasspinname-tc_cs_pin--mc_tc_cs_pin-pinname-ch_sel0_pin--mc_tc_sel0_pin-pinname-ch_sel1_pin--mc_tc_sel1_pin-pinname-ch_sel2_pin--mc_tc_sel2_pin)`(PinName tc_cs_pin, PinName ch_sel0_pin, PinName ch_sel1_pin, PinName ch_sel2_pin)` | Construct a TCTempProbeClass object. +`public ` [`TCTempProbeClass`](#public-tctempprobeclasspinname-tc_cs_pin--mc_tc_cs_pin-pinname-ch_sel0_pin--mc_tp_sel0_pin-pinname-ch_sel1_pin--mc_tp_sel1_pin-pinname-ch_sel2_pin--mc_tp_sel2_pin)`(PinName tc_cs_pin, PinName ch_sel0_pin, PinName ch_sel1_pin, PinName ch_sel2_pin)` | Construct a TCTempProbeClass object. `public ` [`~TCTempProbeClass`](#public-tctempprobeclass)`()` | Destruct the TCTempProbeClass object. `public bool` [`begin`](#public-bool-begin)`()` | Initialize the TCTempProbeClass. `public void` [`end`](#public-void-end)`()` | Disable the temperature sensors and release any resources. `public void` [`selectChannel`](#public-void-selectchannelint-channel)`(int channel)` | Select the input channel to be read (3 channels available). +`public float` [`readTemperature`](#public-float-readTemperatureuint8_t-type--probe_tc_k)`(uint8_t type)` | Read temperature value of the connected thermocouple. + +# class `TempProbeClass` +Class for managing Resistance Temperature Detector (RTD) and Thermocouple (TC) temperature sensor connectors of the Portenta Machine Control. + +## Summary + + Members | Descriptions +--------------------------------|--------------------------------------------- +`public ` [`TempProbeClass`](#public-tctempprobeclasspinname-ch_sel0_pin--mc_tp_sel0_pin-pinname-ch_sel1_pin--mc_tp_sel1_pin-pinname-ch_sel2_pin--mc_tp_sel2_pin-pinname-tc_cs_pin--mc_tc_cs_pin-pinname-rtd_cs_pin--mc_rtd_cs_pin-pinname-rtd_th_pin--mc_rtd_th_pin)`(PinName ch_sel0_pin, PinName ch_sel1_pin, PinName ch_sel2_pin, PinName tc_cs_pin, PinName rtd_cs_pin, PinName rtd_th_pin)` | Construct a TempProbeClass object. +`public ` [`~TempProbeClass`](#public-tctempprobeclass)`()` | Destruct the TCTempProbeClass object. +`public bool` [`beginTC`](#public-bool-begintc)`()` | Initialize the TempProbeClass for TC measurements. +`public bool` [`beginRTD`](#public-bool-beginrtd)`()` | Initialize the TempProbeClass for RTD measurements. +`public void` [`endTC`](#public-void-endtc)`()` | Disable the TC temperature sensors and release any resources. +`public void` [`endRTD`](#public-void-endrtd)`()` | Disable the temperature sensors and release any resources. +`public void` [`selectChannel`](#public-void-selectchanneluint8_t-channel-uint8_t-uint8_t-probetype)`(uint8_t channel, uint8_t probeType)` | Select the input channel and probe type to be read (3 channels available). # class `USBClass` Class for managing the USB functionality of the Portenta Machine Control. diff --git a/examples/Temp_probes_Mixed/Temp_probes_Mixed.ino b/examples/Temp_probes_Mixed/Temp_probes_Mixed.ino new file mode 100644 index 0000000..34e194e --- /dev/null +++ b/examples/Temp_probes_Mixed/Temp_probes_Mixed.ino @@ -0,0 +1,137 @@ +/* + * Portenta Machine Control - Temperature Probes Mixed Example + * + * This example provides a method to test the RTD/TC inputs + * on the Machine Control Carrier for mixed setups. + * + * Acquisition of 2-wire RTDs is possible by shorting the RTDx pin to the TPx pin. + * The Machine Control Carrier features a precise 400 ohm 0.1% reference resistor, + * which serves as a reference for the MAX31865. + * + * Circuit: + * - Portenta H7 + * - Portenta Machine Control + * - RTDs 3-wire or 2-wire + * - TCs type K/J/T + * + * This example code is in the public domain. + * Copyright (c) 2024 Arduino + * SPDX-License-Identifier: MPL-2.0 + */ + +#include + +// The value of the Rref resistor. +#define RREF 400.0 +// The 'nominal' 0-degrees-C resistance of the sensor +// 100.0 for PT100 +#define RNOMINAL 100.0 + +void setup() { + Serial.begin(9600); + while (!Serial) { + ; + } + + // Initialize RTD temperature probes + MachineControl_TempProbe.beginRTD(); + Serial.println("RTD Temperature probes initialization done"); + + // Initialize TC temperature probes + MachineControl_TCTempProbe.beginTC(); + Serial.println("TC Temperature probes initialization done"); +} + +void loop() { + MachineControl_TempProbe.selectChannel(0, PROBE_RTD_3W); + Serial.println("CHANNEL 0 SELECTED"); + uint16_t rtd = MachineControl_TempProbe.readRTD(); + float ratio = rtd; + ratio /= 32768; + + // Check and print any faults + if (!checkRTDFault()) { + Serial.print("RTD value: "); Serial.println(rtd); + Serial.print("Ratio = "); Serial.println(ratio, 8); + Serial.print("Resistance = "); Serial.println(RREF * ratio, 8); + Serial.print("Temperature = "); Serial.println(MachineControl_TempProbe.convertRTDTemperature(RNOMINAL, RREF)); + } + Serial.println(); + delay(100); + + //Set CH1, has internal 150 ms delay + MachineControl_TempProbe.selectChannel(0, PROBE_TC_T); + Serial.println("CHANNEL 0 SELECTED"); + //Take CH0 measurement + float temp_ch1 = MachineControl_TempProbe.readTCTemperature(); + // Check and print any faults + if (!checkTCFault()) { + Serial.print("TC Temperature CH1 [°C]: "); + Serial.print(temp_ch1); + Serial.println(); + } + + MachineControl_TempProbe.selectChannel(2, PROBE_RTD_3W); + Serial.println("CHANNEL 2 SELECTED"); + rtd = MachineControl_TempProbe.readRTD(); + ratio = rtd; + ratio /= 32768; + + // Check and print any faults + if (!checkRTDFault()) { + Serial.print("RTD value: "); Serial.println(rtd); + Serial.print("Ratio = "); Serial.println(ratio, 8); + Serial.print("Resistance = "); Serial.println(RREF * ratio, 8); + Serial.print("Temperature = "); Serial.println(MachineControl_TempProbe.convertRTDTemperature(RNOMINAL, RREF)); + } + Serial.println(); + delay(1000); +} + +bool checkRTDFault() { + // Check and print any faults + uint8_t fault = MachineControl_TempProbe.readRTDFault(); + if (fault) { + Serial.print("Fault 0x"); Serial.println(fault, HEX); + if (MachineControl_TempProbe.getRTDHighThresholdFault(fault)) { + Serial.println("RTD High Threshold"); + } + if (MachineControl_TempProbe.getRTDLowThresholdFault(fault)) { + Serial.println("RTD Low Threshold"); + } + if (MachineControl_TempProbe.getRTDLowREFINFault(fault)) { + Serial.println("REFIN- > 0.85 x Bias"); + } + if (MachineControl_TempProbe.getRTDHighREFINFault(fault)) { + Serial.println("REFIN- < 0.85 x Bias - FORCE- open"); + } + if (MachineControl_TempProbe.getRTDLowRTDINFault(fault)) { + Serial.println("RTDIN- < 0.85 x Bias - FORCE- open"); + } + if (MachineControl_TempProbe.getRTDVoltageFault(fault)) { + Serial.println("Under/Over voltage"); + } + MachineControl_TempProbe.clearRTDFault(); + return true; + } else { + return false; + } +} + +bool checkTCFault() { + // Check and print any faults + uint8_t fault = MachineControl_TempProbe.getTCLastFault(); + if (fault & TC_FAULT_OPEN) { + Serial.println("Thermocouple is open - no connections."); + return true; + } + if (fault & TC_FAULT_SHORT_GND) { + Serial.println("Thermocouple is short-circuited to GND."); + return true; + } + if (fault & TC_FAULT_SHORT_VCC) { + Serial.println("Thermocouple is short-circuited to VCC."); + return true; + } + return false; +} \ No newline at end of file diff --git a/examples/Temp_probes_RTD/Temp_probes_RTD.ino b/examples/Temp_probes_RTD/Temp_probes_RTD.ino index b732bec..d2ecc9b 100644 --- a/examples/Temp_probes_RTD/Temp_probes_RTD.ino +++ b/examples/Temp_probes_RTD/Temp_probes_RTD.ino @@ -12,7 +12,7 @@ * - Portenta Machine Control * - 3-wire RTD or 2-wire RTD * - * This example code is in the public domain. + * This example code is in the public domain. * Copyright (c) 2024 Arduino * SPDX-License-Identifier: MPL-2.0 */ @@ -31,10 +31,12 @@ void setup() { ; } - MachineControl_RTDTempProbe.begin(THREE_WIRE); + MachineControl_RTDTempProbe.begin(PROBE_RTD_3W); + Serial.println("RTD Temperature probes initialization done"); } void loop() { + //Set CH0, has internal 75 ms delay MachineControl_RTDTempProbe.selectChannel(0); Serial.println("CHANNEL 0 SELECTED"); uint16_t rtd = MachineControl_RTDTempProbe.readRTD(); @@ -42,29 +44,7 @@ void loop() { ratio /= 32768; // Check and print any faults - uint8_t fault = MachineControl_RTDTempProbe.readFault(); - if (fault) { - Serial.print("Fault 0x"); Serial.println(fault, HEX); - if (MachineControl_RTDTempProbe.getHighThresholdFault(fault)) { - Serial.println("RTD High Threshold"); - } - if (MachineControl_RTDTempProbe.getLowThresholdFault(fault)) { - Serial.println("RTD Low Threshold"); - } - if (MachineControl_RTDTempProbe.getLowREFINFault(fault)) { - Serial.println("REFIN- > 0.85 x Bias"); - } - if (MachineControl_RTDTempProbe.getHighREFINFault(fault)) { - Serial.println("REFIN- < 0.85 x Bias - FORCE- open"); - } - if (MachineControl_RTDTempProbe.getLowRTDINFault(fault)) { - Serial.println("RTDIN- < 0.85 x Bias - FORCE- open"); - } - if (MachineControl_RTDTempProbe.getVoltageFault(fault)) { - Serial.println("Under/Over voltage"); - } - MachineControl_RTDTempProbe.clearFault(); - } else { + if (!checkRTDFault()) { Serial.print("RTD value: "); Serial.println(rtd); Serial.print("Ratio = "); Serial.println(ratio, 8); Serial.print("Resistance = "); Serial.println(RREF * ratio, 8); @@ -73,6 +53,7 @@ void loop() { Serial.println(); delay(100); + //Set CH1, has internal 75 ms delay MachineControl_RTDTempProbe.selectChannel(1); Serial.println("CHANNEL 1 SELECTED"); rtd = MachineControl_RTDTempProbe.readRTD(); @@ -80,29 +61,7 @@ void loop() { ratio /= 32768; // Check and print any faults - fault = MachineControl_RTDTempProbe.readFault(); - if (fault) { - Serial.print("Fault 0x"); Serial.println(fault, HEX); - if (MachineControl_RTDTempProbe.getHighThresholdFault(fault)) { - Serial.println("RTD High Threshold"); - } - if (MachineControl_RTDTempProbe.getLowThresholdFault(fault)) { - Serial.println("RTD Low Threshold"); - } - if (MachineControl_RTDTempProbe.getLowREFINFault(fault)) { - Serial.println("REFIN- > 0.85 x Bias"); - } - if (MachineControl_RTDTempProbe.getHighREFINFault(fault)) { - Serial.println("REFIN- < 0.85 x Bias - FORCE- open"); - } - if (MachineControl_RTDTempProbe.getLowRTDINFault(fault)) { - Serial.println("RTDIN- < 0.85 x Bias - FORCE- open"); - } - if (MachineControl_RTDTempProbe.getVoltageFault(fault)) { - Serial.println("Under/Over voltage"); - } - MachineControl_RTDTempProbe.clearFault(); - } else { + if (!checkRTDFault()) { Serial.print("RTD value: "); Serial.println(rtd); Serial.print("Ratio = "); Serial.println(ratio, 8); Serial.print("Resistance = "); Serial.println(RREF * ratio, 8); @@ -111,6 +70,7 @@ void loop() { Serial.println(); delay(100); + //Set CH2, has internal 75 ms delay MachineControl_RTDTempProbe.selectChannel(2); Serial.println("CHANNEL 2 SELECTED"); rtd = MachineControl_RTDTempProbe.readRTD(); @@ -118,7 +78,19 @@ void loop() { ratio /= 32768; // Check and print any faults - fault = MachineControl_RTDTempProbe.readFault(); + if (!checkRTDFault()) { + Serial.print("RTD value: "); Serial.println(rtd); + Serial.print("Ratio = "); Serial.println(ratio, 8); + Serial.print("Resistance = "); Serial.println(RREF * ratio, 8); + Serial.print("Temperature = "); Serial.println(MachineControl_RTDTempProbe.readTemperature(RNOMINAL, RREF)); + } + Serial.println(); + delay(1000); +} + +bool checkRTDFault() { + // Check and print any faults + uint8_t fault = MachineControl_RTDTempProbe.readFault(); if (fault) { Serial.print("Fault 0x"); Serial.println(fault, HEX); if (MachineControl_RTDTempProbe.getHighThresholdFault(fault)) { @@ -140,12 +112,8 @@ void loop() { Serial.println("Under/Over voltage"); } MachineControl_RTDTempProbe.clearFault(); + return true; } else { - Serial.print("RTD value: "); Serial.println(rtd); - Serial.print("Ratio = "); Serial.println(ratio, 8); - Serial.print("Resistance = "); Serial.println(RREF * ratio, 8); - Serial.print("Temperature = "); Serial.println(MachineControl_RTDTempProbe.readTemperature(RNOMINAL, RREF)); + return false; } - Serial.println(); - delay(1000); -} +} \ No newline at end of file diff --git a/examples/Temp_probes_Thermocouples/Temp_probes_Thermocouples.ino b/examples/Temp_probes_Thermocouples/Temp_probes_Thermocouples.ino index db62fd7..e43d8aa 100644 --- a/examples/Temp_probes_Thermocouples/Temp_probes_Thermocouples.ino +++ b/examples/Temp_probes_Thermocouples/Temp_probes_Thermocouples.ino @@ -11,7 +11,7 @@ * - Two K Type thermocouple temperature sensors connected to TEMP PROBES CH0 and CH1 * - A J Type thermocouple temperature sensor connected to TEMP PROBES CH3 * - * This example code is in the public domain. + * This example code is in the public domain. * Copyright (c) 2024 Arduino * SPDX-License-Identifier: MPL-2.0 */ @@ -24,35 +24,65 @@ void setup() { ; } - // Initialize temperature probes + // Initialize TC temperature probes MachineControl_TCTempProbe.begin(); - Serial.println("Temperature probes initialization done"); + Serial.println("TC Temperature probes initialization done"); } void loop() { //Set CH0, has internal 150 ms delay MachineControl_TCTempProbe.selectChannel(0); + Serial.println("CHANNEL 0 SELECTED"); //Take CH0 measurement - float temp_ch0 = MachineControl_TCTempProbe.readTemperature(); - Serial.print("Temperature CH0 [°C]: "); - Serial.print(temp_ch0); - Serial.println(); + float temp_ch0 = MachineControl_TCTempProbe.readTemperature(PROBE_TC_K); + // Check and print any faults + if (!checkTCFault()) { + Serial.print("TC Temperature CH0 [°C]: "); + Serial.print(temp_ch0); + Serial.println(); + } //Set CH1, has internal 150 ms delay MachineControl_TCTempProbe.selectChannel(1); + Serial.println("CHANNEL 1 SELECTED"); //Take CH1 measurement - float temp_ch1 = MachineControl_TCTempProbe.readTemperature(); - Serial.print("Temperature CH1 [°C]: "); - Serial.print(temp_ch1); - Serial.println(); - + float temp_ch1 = MachineControl_TCTempProbe.readTemperature(PROBE_TC_K); + // Check and print any faults + if (!checkTCFault()) { + Serial.print("TC Temperature CH1 [°C]: "); + Serial.print(temp_ch1); + Serial.println(); + } + //Set CH2, has internal 150 ms delay MachineControl_TCTempProbe.selectChannel(2); + Serial.println("CHANNEL 2 SELECTED"); //Take CH2 measurement - float temp_ch2 = MachineControl_TCTempProbe.readTemperature(); - Serial.print("Temperature CH2 [°C]: "); - Serial.print(temp_ch2); - Serial.println(); + float temp_ch2 = MachineControl_TCTempProbe.readTemperature(PROBE_TC_J); + // Check and print any faults + if (!checkTCFault()) { + Serial.print("TC Temperature CH2 [°C]: "); + Serial.print(temp_ch2); + Serial.println(); + } Serial.println(); +} + +bool checkTCFault() { + // Check and print any faults + uint8_t fault = MachineControl_TCTempProbe.getLastFault(); + if (fault & TC_FAULT_OPEN) { + Serial.println("Thermocouple is open - no connections."); + return true; + } + if (fault & TC_FAULT_SHORT_GND) { + Serial.println("Thermocouple is short-circuited to GND."); + return true; + } + if (fault & TC_FAULT_SHORT_VCC) { + Serial.println("Thermocouple is short-circuited to VCC."); + return true; + } + return false; } \ No newline at end of file diff --git a/keywords.txt b/keywords.txt index 4ac5d86..4298a58 100644 --- a/keywords.txt +++ b/keywords.txt @@ -14,6 +14,7 @@ MachineControl_Encoders KEYWORD1 MachineControl_DigitalInputs KEYWORD1 MachineControl_DigitalProgrammables KEYWORD1 MachineControl_RS485Comm KEYWORD1 +MachineControl_TempProbe KEYWORD1 MachineControl_RTDTempProbe KEYWORD1 MachineControl_RTCController KEYWORD1 MachineControl_TCTempProbe KEYWORD1 diff --git a/src/Arduino_PortentaMachineControl.h b/src/Arduino_PortentaMachineControl.h index 885830b..57f362f 100644 --- a/src/Arduino_PortentaMachineControl.h +++ b/src/Arduino_PortentaMachineControl.h @@ -6,6 +6,7 @@ #include "DigitalOutputsClass.h" #include "ProgrammableDIOClass.h" #include "ProgrammableDINClass.h" +#include "TempProbeClass.h" #include "RTDTempProbeClass.h" #include "TCTempProbeClass.h" #include "RtcControllerClass.h" diff --git a/src/RTDTempProbeClass.cpp b/src/RTDTempProbeClass.cpp index 382c21a..0994b9d 100644 --- a/src/RTDTempProbeClass.cpp +++ b/src/RTDTempProbeClass.cpp @@ -7,99 +7,36 @@ /* Includes -----------------------------------------------------------------*/ #include "RTDTempProbeClass.h" -#if __has_include("portenta_info.h") -#include "portenta_info.h" -#define TRY_REV2_RECOGNITION -uint8_t* boardInfo(); -#define PMC_R2_SKU (24 << 8 | 3) -#endif - /* Functions -----------------------------------------------------------------*/ RTDTempProbeClass::RTDTempProbeClass(PinName rtd_cs_pin, - PinName ch_sel0_pin, + PinName ch_sel0_pin, PinName ch_sel1_pin, PinName ch_sel2_pin, PinName rtd_th_pin) -: MAX31865Class(rtd_cs_pin), _rtd_cs{rtd_cs_pin}, _ch_sel0{ch_sel0_pin}, _ch_sel1{ch_sel1_pin}, _ch_sel2{ch_sel2_pin}, _rtd_th{rtd_th_pin} -{ } - -RTDTempProbeClass::~RTDTempProbeClass() -{ } - -bool RTDTempProbeClass::begin(uint8_t io_address) { - MAX31865Class::begin(io_address); - - pinMode(_ch_sel0, OUTPUT); - pinMode(_ch_sel1, OUTPUT); - pinMode(_ch_sel2, OUTPUT); - pinMode(_rtd_th, OUTPUT); - - pinMode(_rtd_cs, OUTPUT); - - _enable(); +: TempProbeClass(ch_sel0_pin, ch_sel1_pin, ch_sel2_pin, MC_TC_CS_PIN, rtd_cs_pin, rtd_th_pin) { +} - return true; +RTDTempProbeClass::~RTDTempProbeClass() { } -void RTDTempProbeClass::selectChannel(int channel) { +bool RTDTempProbeClass::begin(uint8_t rtd_type) { + TempProbeClass::beginRTD(); + TempProbeClass::setRTDType(rtd_type); + _current_probe_type = rtd_type; -#ifdef TRY_REV2_RECOGNITION - // check if OTP data is present AND the board is mounted on a r2 carrier - auto info = (PortentaBoardInfo*)boardInfo(); - if (info->magic == 0xB5 && info->carrier == PMC_R2_SKU) { - // reverse channels 0 and 2 - switch (channel) { - case 0: - channel = 2; - break; - case 2: - channel = 0; - break; - default: - break; - } - } -#endif -#undef TRY_REV2_RECOGNITION - switch(channel) { - case 0: - digitalWrite(_ch_sel0, HIGH); - digitalWrite(_ch_sel1, LOW); - digitalWrite(_ch_sel2, LOW); - break; - case 1: - digitalWrite(_ch_sel0, LOW); - digitalWrite(_ch_sel1, HIGH); - digitalWrite(_ch_sel2, LOW); - break; - case 2: - digitalWrite(_ch_sel0, LOW); - digitalWrite(_ch_sel1, LOW); - digitalWrite(_ch_sel2, HIGH); - break; - default: - digitalWrite(_ch_sel0, LOW); - digitalWrite(_ch_sel1, LOW); - digitalWrite(_ch_sel2, LOW); - break; - } - delay(150); + return true; } void RTDTempProbeClass::end() { - MAX31865Class::end(); - - _disable(); + TempProbeClass::endRTD(); } -void RTDTempProbeClass::_enable() { - digitalWrite(_rtd_th, HIGH); - - digitalWrite(_rtd_cs, LOW); +void RTDTempProbeClass::selectChannel(int channel) { + TempProbeClass::selectChannel(channel, _current_probe_type); } -void RTDTempProbeClass::_disable() { - digitalWrite(_rtd_cs, HIGH); +float RTDTempProbeClass::readTemperature(float RTDnominal, float refResistor) { + return TempProbeClass::convertRTDTemperature(RTDnominal, refResistor); } RTDTempProbeClass MachineControl_RTDTempProbe; diff --git a/src/RTDTempProbeClass.h b/src/RTDTempProbeClass.h index 9b1443f..ccba411 100644 --- a/src/RTDTempProbeClass.h +++ b/src/RTDTempProbeClass.h @@ -3,7 +3,7 @@ * @author Leonardo Cavagnis * @brief Header file for the Resistance Temperature Detector (RTD) temperature sensor connector of the Portenta Machine Control. * - * This library allows interfacing with RTD temperature sensors using the MAX31865 digital converter. + * This library allows interfacing with RTD temperature sensors using the MAX31865 digital converter. * It provides methods to select input channel, enabling and disabling the sensor, and reading temperature values. */ @@ -11,8 +11,7 @@ #define __RTD_TEMPPROBE_CLASS_H /* Includes -------------------------------------------------------------------*/ -#include "utility/MAX31865/MAX31865.h" -#include "utility/THERMOCOUPLE/MAX31855.h" +#include "TempProbeClass.h" #include #include #include "pins_mc.h" @@ -26,7 +25,7 @@ * This class allows interfacing with RTD temperature sensors through the use of the MAX31865 digital converter. * It provides methods to configure and read temperature values from the selected input channel. */ -class RTDTempProbeClass: public MAX31865Class { +class RTDTempProbeClass: public TempProbeClass { public: /** * @brief Construct a RTDTempProbeClass object. @@ -39,12 +38,12 @@ class RTDTempProbeClass: public MAX31865Class { * @param ch_sel2_pin The pin number for the third channel selection bit. * @param rtd_th_pin The pin number for the RTD connection. */ - RTDTempProbeClass(PinName rtd_cs_pin = MC_RTD_CS_PIN, - PinName ch_sel0_pin = MC_RTD_SEL0_PIN, - PinName ch_sel1_pin = MC_RTD_SEL1_PIN, - PinName ch_sel2_pin = MC_RTD_SEL2_PIN, + RTDTempProbeClass(PinName rtd_cs_pin = MC_RTD_CS_PIN, + PinName ch_sel0_pin = MC_TP_SEL0_PIN, + PinName ch_sel1_pin = MC_TP_SEL1_PIN, + PinName ch_sel2_pin = MC_TP_SEL2_PIN, PinName rtd_th_pin = MC_RTD_TH_PIN); - + /** * @brief Destruct the RTDTempProbeClass object. * @@ -53,12 +52,12 @@ class RTDTempProbeClass: public MAX31865Class { ~RTDTempProbeClass(); /** - * @brief Initialize the RTDTempProbeClass with the specified I/O address. + * @brief Initialize the RTDTempProbeClass with the specified RTD wiring type. * - * @param io_address The I/O address for communication with the digital converters (default is THREE_WIRE). + * @param rtd_type The RTD wiring type for connection to the digital converters (default is PROBE_RTD_3W). * @return true If initialization is successful, false otherwise. */ - bool begin(uint8_t io_address = THREE_WIRE); + bool begin(uint8_t rtd_type = PROBE_RTD_3W); /** * @brief Disable the temperature sensors and release any resources. @@ -72,22 +71,16 @@ class RTDTempProbeClass: public MAX31865Class { */ void selectChannel(int channel); -private: - PinName _rtd_cs; // Pin for the CS of RTD - PinName _ch_sel0; // Pin for the first channel selection bit - PinName _ch_sel1; // Pin for the second channel selection bit - PinName _ch_sel2; // Pin for the third channel selection bit - PinName _rtd_th; // Pin for the RTD connection - /** - * @brief Enable the chip select (CS) of the MAX31865 digital converter. + * @brief Read temperature value of the connected RTD + * + * @param RTDnominal The 'nominal' resistance of the RTD sensor at 0 °C + * @param refResistor The value of the reference sensor */ - void _enable(); + float readTemperature(float RTDnominal, float refResistor); - /** - * @brief Disable the chip select (CS) of the MAX31865 digital converter. - */ - void _disable(); +private: + uint8_t _current_probe_type; }; extern RTDTempProbeClass MachineControl_RTDTempProbe; diff --git a/src/TCTempProbeClass.cpp b/src/TCTempProbeClass.cpp index 9e74a62..a4b080e 100644 --- a/src/TCTempProbeClass.cpp +++ b/src/TCTempProbeClass.cpp @@ -7,95 +7,34 @@ /* Includes -----------------------------------------------------------------*/ #include "TCTempProbeClass.h" -#if __has_include("portenta_info.h") -#include "portenta_info.h" -#define TRY_REV2_RECOGNITION -uint8_t* boardInfo(); -#define PMC_R2_SKU (24 << 8 | 3) -#endif - /* Functions -----------------------------------------------------------------*/ TCTempProbeClass::TCTempProbeClass(PinName tc_cs_pin, - PinName ch_sel0_pin, + PinName ch_sel0_pin, PinName ch_sel1_pin, PinName ch_sel2_pin) -: MAX31855Class(tc_cs_pin), _tc_cs{tc_cs_pin}, _ch_sel0{ch_sel0_pin}, _ch_sel1{ch_sel1_pin}, _ch_sel2{ch_sel2_pin} -{ } +: TempProbeClass(ch_sel0_pin, ch_sel1_pin, ch_sel2_pin, tc_cs_pin, MC_RTD_CS_PIN, MC_RTD_TH_PIN) { +} -TCTempProbeClass::~TCTempProbeClass() -{ } +TCTempProbeClass::~TCTempProbeClass() { +} bool TCTempProbeClass::begin() { - MAX31855Class::begin(); - - pinMode(_ch_sel0, OUTPUT); - pinMode(_ch_sel1, OUTPUT); - pinMode(_ch_sel2, OUTPUT); - - pinMode(_tc_cs, OUTPUT); - - _enable(); + TempProbeClass::beginTC(); return true; } -void TCTempProbeClass::selectChannel(int channel) { - -#ifdef TRY_REV2_RECOGNITION - // check if OTP data is present AND the board is mounted on a r2 carrier - auto info = (PortentaBoardInfo*)boardInfo(); - if (info->magic == 0xB5 && info->carrier == PMC_R2_SKU) { - // reverse channels 0 and 2 - switch (channel) { - case 0: - channel = 2; - break; - case 2: - channel = 0; - break; - default: - break; - } - } -#endif -#undef TRY_REV2_RECOGNITION - switch(channel) { - case 0: - digitalWrite(_ch_sel0, HIGH); - digitalWrite(_ch_sel1, LOW); - digitalWrite(_ch_sel2, LOW); - break; - case 1: - digitalWrite(_ch_sel0, LOW); - digitalWrite(_ch_sel1, HIGH); - digitalWrite(_ch_sel2, LOW); - break; - case 2: - digitalWrite(_ch_sel0, LOW); - digitalWrite(_ch_sel1, LOW); - digitalWrite(_ch_sel2, HIGH); - break; - default: - digitalWrite(_ch_sel0, LOW); - digitalWrite(_ch_sel1, LOW); - digitalWrite(_ch_sel2, LOW); - break; - } - delay(150); -} - void TCTempProbeClass::end() { - MAX31855Class::end(); - - _disable(); + TempProbeClass::endTC(); } -void TCTempProbeClass::_enable() { - digitalWrite(_tc_cs, LOW); +void TCTempProbeClass::selectChannel(int channel) { + TempProbeClass::selectChannel(channel, PROBE_TC_K); } -void TCTempProbeClass::_disable() { - digitalWrite(_tc_cs, HIGH); +float TCTempProbeClass::readTemperature(uint8_t type) { + TempProbeClass::setTCType(type); + return TempProbeClass::readTCTemperature(); } TCTempProbeClass MachineControl_TCTempProbe; diff --git a/src/TCTempProbeClass.h b/src/TCTempProbeClass.h index 7001042..b4f2e47 100644 --- a/src/TCTempProbeClass.h +++ b/src/TCTempProbeClass.h @@ -3,7 +3,7 @@ * @author Leonardo Cavagnis * @brief Header file for the Thermocouple (TC) temperature sensor connector of the Portenta Machine Control. * - * This library allows interfacing with TC temperature sensors using the MAX31855 digital converter. + * This library allows interfacing with TC temperature sensors using the MAX31855 digital converter. * It provides methods to select input channel, enabling and disabling the sensor, and reading temperature values. */ @@ -11,8 +11,7 @@ #define __TC_TEMPPROBE_CLASS_H /* Includes -------------------------------------------------------------------*/ -#include "utility/MAX31865/MAX31865.h" -#include "utility/THERMOCOUPLE/MAX31855.h" +#include "TempProbeClass.h" #include #include #include "pins_mc.h" @@ -26,7 +25,7 @@ * This class allows interfacing with thermocouple temperature sensors through the use of the MAX31855 digital converter. * It provides methods to configure and read temperature values from the selected input channel. */ -class TCTempProbeClass: public MAX31855Class { +class TCTempProbeClass: public TempProbeClass { public: /** * @brief Construct a TCTempProbeClass object. @@ -38,11 +37,11 @@ class TCTempProbeClass: public MAX31855Class { * @param ch_sel1_pin The pin number for the second channel selection bit. * @param ch_sel2_pin The pin number for the third channel selection bit. */ - TCTempProbeClass(PinName tc_cs_pin = MC_TC_CS_PIN, - PinName ch_sel0_pin = MC_TC_SEL0_PIN, - PinName ch_sel1_pin = MC_TC_SEL1_PIN, - PinName ch_sel2_pin = MC_TC_SEL2_PIN); - + TCTempProbeClass(PinName tc_cs_pin = MC_TC_CS_PIN, + PinName ch_sel0_pin = MC_TP_SEL0_PIN, + PinName ch_sel1_pin = MC_TP_SEL1_PIN, + PinName ch_sel2_pin = MC_TP_SEL2_PIN); + /** * @brief Destruct the TCTempProbeClass object. * @@ -69,21 +68,12 @@ class TCTempProbeClass: public MAX31855Class { */ void selectChannel(int channel); -private: - PinName _tc_cs; // Pin for the CS of Thermocouple - PinName _ch_sel0; // Pin for the first channel selection bit - PinName _ch_sel1; // Pin for the second channel selection bit - PinName _ch_sel2; // Pin for the third channel selection bit - - /** - * @brief Enable the chip select (CS) of the MAX31855 digital converter. - */ - void _enable(); - /** - * @brief Disable the chip select (CS) of the MAX31855 digital converter. + * @brief Read temperature value of the connected thermocouple + * + * @param type The type of the connected thermocouple */ - void _disable(); + float readTemperature(uint8_t type = PROBE_TC_K); }; extern TCTempProbeClass MachineControl_TCTempProbe; diff --git a/src/TempProbeClass.cpp b/src/TempProbeClass.cpp new file mode 100644 index 0000000..3394523 --- /dev/null +++ b/src/TempProbeClass.cpp @@ -0,0 +1,188 @@ +/** + * @file TCTempProbeClass.cpp + * @author Jan Henrik Sawatzki + * @brief Source file for the shared Resistance Temperature Detector (RTD) and Thermocouple (TC) temperature sensor connectors of the Portenta Machine Control. + */ + +/* Includes -----------------------------------------------------------------*/ +#include "TempProbeClass.h" + +#if __has_include("portenta_info.h") +#include "portenta_info.h" +#define TRY_REV2_RECOGNITION +uint8_t* boardInfo(); +#define PMC_R2_SKU (24 << 8 | 3) +#endif + +/* Functions -----------------------------------------------------------------*/ +TempProbeClass::TempProbeClass(PinName ch_sel0_pin, + PinName ch_sel1_pin, + PinName ch_sel2_pin, + PinName tc_cs_pin, + PinName rtd_cs_pin, + PinName rtd_th_pin) +: MAX31855Class(tc_cs_pin), MAX31865Class(rtd_cs_pin), _ch_sel0{ch_sel0_pin}, _ch_sel1{ch_sel1_pin}, _ch_sel2{ch_sel2_pin},/* _tc_cs{tc_cs_pin}, _rtd_cs{rtd_cs_pin},*/ _rtd_th{rtd_th_pin} { +} + +TempProbeClass::~TempProbeClass() { +} + +bool TempProbeClass::beginTC() { + if(!_tc_init) { + if(!_rtd_init) { + pinMode(_ch_sel0, OUTPUT); + pinMode(_ch_sel1, OUTPUT); + pinMode(_ch_sel2, OUTPUT); + + digitalWrite(_ch_sel0, LOW); + digitalWrite(_ch_sel1, LOW); + digitalWrite(_ch_sel2, LOW); + } + + MAX31855Class::begin(); + + _tc_init = true; + } + + return true; +} + +bool TempProbeClass::beginRTD() { + if(!_rtd_init) { + if(!_tc_init) { + pinMode(_ch_sel0, OUTPUT); + pinMode(_ch_sel1, OUTPUT); + pinMode(_ch_sel2, OUTPUT); + + digitalWrite(_ch_sel0, LOW); + digitalWrite(_ch_sel1, LOW); + digitalWrite(_ch_sel2, LOW); + } + + pinMode(_rtd_th, OUTPUT); + + digitalWrite(_rtd_th, LOW); + + MAX31865Class::begin(); + + _rtd_init = true; + } + + return true; +} + +void TempProbeClass::endTC() { + if(_tc_init) { + MAX31855Class::end(); + + _tc_init = false; + + if(!_rtd_init) { + pinMode(_ch_sel0, INPUT); + pinMode(_ch_sel1, INPUT); + pinMode(_ch_sel2, INPUT); + + digitalWrite(_ch_sel0, LOW); + digitalWrite(_ch_sel1, LOW); + digitalWrite(_ch_sel2, LOW); + } + } +} + +void TempProbeClass::endRTD() { + if(_rtd_init) { + MAX31865Class::end(); + + pinMode(_rtd_th, INPUT); + + digitalWrite(_rtd_th, LOW); + + _rtd_init = false; + + if(!_tc_init) { + pinMode(_ch_sel0, INPUT); + pinMode(_ch_sel1, INPUT); + pinMode(_ch_sel2, INPUT); + + digitalWrite(_ch_sel0, LOW); + digitalWrite(_ch_sel1, LOW); + digitalWrite(_ch_sel2, LOW); + } + } +} + +void TempProbeClass::selectChannel(uint8_t channel, uint8_t probeType) { +#ifdef TRY_REV2_RECOGNITION + // check if OTP data is present AND the board is mounted on a r2 carrier + auto info = (PortentaBoardInfo*)boardInfo(); + if (info->magic == 0xB5 && info->carrier == PMC_R2_SKU) { + // reverse channels 0 and 2 + switch (channel) { + case 0: + channel = 2; + break; + case 2: + channel = 0; + break; + default: + break; + } + } +#endif +#undef TRY_REV2_RECOGNITION + if (_current_channel != channel) { + switch(channel) { + case 0: + digitalWrite(_ch_sel0, HIGH); + digitalWrite(_ch_sel1, LOW); + digitalWrite(_ch_sel2, LOW); + break; + case 1: + digitalWrite(_ch_sel0, LOW); + digitalWrite(_ch_sel1, HIGH); + digitalWrite(_ch_sel2, LOW); + break; + case 2: + digitalWrite(_ch_sel0, LOW); + digitalWrite(_ch_sel1, LOW); + digitalWrite(_ch_sel2, HIGH); + break; + default: + digitalWrite(_ch_sel0, LOW); + digitalWrite(_ch_sel1, LOW); + digitalWrite(_ch_sel2, LOW); + break; + } + uint8_t switch_delay; + switch (probeType) { + case PROBE_TC_K: + case PROBE_TC_J: + case PROBE_TC_T: + digitalWrite(_rtd_th, LOW); + if (_current_probe_type != probeType) { + MAX31855Class::setTCType(probeType); + } + switch_delay = 150; + break; + + case PROBE_RTD_2W: + case PROBE_RTD_3W: + digitalWrite(_rtd_th, HIGH); + if (_current_probe_type != probeType) { + MAX31865Class::setRTDType(probeType); + } + switch_delay = 75; + break; + + default: + switch_delay = 150; + break; + } + delay(switch_delay); + _current_channel = channel; + _current_probe_type = probeType; + } +} + +TempProbeClass MachineControl_TempProbe; +/**** END OF FILE ****/ diff --git a/src/TempProbeClass.h b/src/TempProbeClass.h new file mode 100644 index 0000000..a85a068 --- /dev/null +++ b/src/TempProbeClass.h @@ -0,0 +1,100 @@ +/** + * @file TempProbeClass.h + * @author Jan Henrik Sawatzki + * @brief Header file for the shared Resistance Temperature Detector (RTD) and Thermocouple (TC) temperature sensor connectors of the Portenta Machine Control. + * + * This library allows interfacing with TC temperature sensors using the MAX31855 digital converter and RTD temperature sensors using the MAX31865 digital converter. + * It provides methods to select input channel, enabling and disabling the sensor, and reading temperature values. + */ + +#ifndef __TEMPPROBE_CLASS_H +#define __TEMPPROBE_CLASS_H + +/* Includes -------------------------------------------------------------------*/ +#include "utility/RTD/MAX31865.h" +#include "utility/THERMOCOUPLE/MAX31855.h" +#include +#include +#include "pins_mc.h" + +/* Class ----------------------------------------------------------------------*/ + +/** + * @class TempProbeClass + * @brief Class for managing thermocouples temperature sensor of the Portenta Machine Control. + * + * This allows interfacing with TC temperature sensors using the MAX31855 digital converter and RTD temperature sensors using the MAX31865 digital converter. + * It provides methods to select input channel, enabling and disabling the sensor, and reading temperature values. + */ +class TempProbeClass: public MAX31855Class, public MAX31865Class { +public: + /** + * @brief Construct a TempProbeClass object. + * + * This constructor initializes a TempProbeClass object with the specified pin assignments for channel selection and TC connection. + * + * @param tc_cs_pin The pin number for the chip select (CS) pin of the Thermocouple temperature sensor. + * @param ch_sel0_pin The pin number for the first channel selection bit. + * @param ch_sel1_pin The pin number for the second channel selection bit. + * @param ch_sel2_pin The pin number for the third channel selection bit. + */ + TempProbeClass(PinName ch_sel0_pin = MC_TP_SEL0_PIN, + PinName ch_sel1_pin = MC_TP_SEL1_PIN, + PinName ch_sel2_pin = MC_TP_SEL2_PIN, + PinName tc_cs_pin = MC_TC_CS_PIN, + PinName rtd_cs_pin = MC_RTD_CS_PIN, + PinName rtd_th_pin = MC_RTD_TH_PIN); + + /** + * @brief Destruct the TempProbeClass object. + * + * This destructor releases any resources used by the TempProbeClass object. + */ + ~TempProbeClass(); + + /** + * @brief Initialize the TempProbeClass for TC measurements. + * + * @return true If initialization is successful, false otherwise. + */ + bool beginTC(); + + /** + * @brief Initialize the TempProbeClass for RTD measurements. + * + * @return true If initialization is successful, false otherwise. + */ + bool beginRTD(); + + /** + * @brief Disable the TC temperature sensors and release any resources. + */ + void endTC(); + + /** + * @brief Disable the RTD temperature sensors and release any resources. + */ + void endRTD(); + + /** + * @brief Select the input channel and probe type to be read (3 channels available). + * + * @param channel The channel number (0-2) to be selected for temperature reading. + * @param probeType The probe type(PROBE_TC_K, PROBE_TC_J, PROBE_TC_T, PROBE_RTD_2W, PROBE_RTD_3W) to be selected for temperature reading. + */ + void selectChannel(uint8_t channel, uint8_t probeType); + +private: + PinName _ch_sel0; // Pin for the first channel selection bit + PinName _ch_sel1; // Pin for the second channel selection bit + PinName _ch_sel2; // Pin for the third channel selection bit + PinName _rtd_th; // Pin for the RTD connection + uint8_t _current_channel; + uint8_t _current_probe_type; + bool _tc_init = false; + bool _rtd_init = false; +}; + +extern TempProbeClass MachineControl_TempProbe; + +#endif /* __TEMPPROBE_CLASS_H */ diff --git a/src/pins_mc.h b/src/pins_mc.h index d89a75c..1cffb32 100644 --- a/src/pins_mc.h +++ b/src/pins_mc.h @@ -72,18 +72,17 @@ /* RTC */ #define MC_RTC_INT_PIN PB_9 +/* Temperature probe */ +#define MC_TP_SEL0_PIN PD_6 +#define MC_TP_SEL1_PIN PI_4 +#define MC_TP_SEL2_PIN PG_10 + /* RTD Temperature probe */ #define MC_RTD_CS_PIN PA_6 -#define MC_RTD_SEL0_PIN PD_6 -#define MC_RTD_SEL1_PIN PI_4 -#define MC_RTD_SEL2_PIN PG_10 #define MC_RTD_TH_PIN PC_15 /* TC Temperature probe */ #define MC_TC_CS_PIN PI_0 -#define MC_TC_SEL0_PIN MC_RTD_SEL0_PIN -#define MC_TC_SEL1_PIN MC_RTD_SEL1_PIN -#define MC_TC_SEL2_PIN MC_RTD_SEL2_PIN /* USB */ #define MC_USB_PWR_PIN PB_14 diff --git a/src/utility/MAX31865/MAX31865.cpp b/src/utility/MAX31865/MAX31865.cpp deleted file mode 100644 index cdcd1e4..0000000 --- a/src/utility/MAX31865/MAX31865.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "MAX31865.h" - - -MAX31865Class::MAX31865Class(PinName cs) : _spi(SPI), _cs(cs) { -} - -static SPISettings _spiSettings(1000000, MSBFIRST, SPI_MODE1); - -bool MAX31865Class::begin(int wires) { - _spi.begin(); - - pinMode(_cs, OUTPUT); - digitalWrite(_cs, HIGH); - // sets 2 or 4 wire - if (wires == THREE_WIRE) { - writeByte(MAX31856_CONFIG_REG, (readByte(MAX31856_CONFIG_REG) | MAX31856_CONFIG_3_WIRE)); - } else { - - writeByte(MAX31856_CONFIG_REG, (readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_WIRE_MASK)); - } - - // disable bias - writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_BIAS_MASK); - - // disable auto convert mode - writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_CONV_MODE_MASK); - - // clear fault - writeByte(MAX31856_CONFIG_REG, (readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_CLEAR_FAULT_CYCLE)| MAX31856_CONFIG_CLEAR_FAULT); - - // set filter frequency - writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_60_50_HZ_FILTER_MASK); - - return true; -} - -void MAX31865Class::clearFault(void) { - writeByte(MAX31856_CONFIG_REG, (readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_CLEAR_FAULT_CYCLE) | MAX31856_CONFIG_CLEAR_FAULT); -} - -uint8_t MAX31865Class::readFault(void) { - return readByte(MAX31856_FAULT_STATUS_REG); -} - -bool MAX31865Class::getHighThresholdFault(uint8_t fault) { - if (fault & MAX31865_FAULT_HIGH_THRESH) { - return true; - } - return false; -} - -bool MAX31865Class::getLowThresholdFault(uint8_t fault) { - if (fault & MAX31865_FAULT_LOW_THRESH) { - return true; - } - return false; -} - -bool MAX31865Class::getLowREFINFault(uint8_t fault) { - - if (fault & MAX31865_FAULT_LOW_REFIN) { - return true; - } - return false; -} - -bool MAX31865Class::getHighREFINFault(uint8_t fault) { - - if (fault & MAX31865_FAULT_HIGH_REFIN) { - return true; - } - return false; -} - -bool MAX31865Class::getLowRTDINFault(uint8_t fault) { - - if (fault & MAX31865_FAULT_LOW_RTDIN) { - return true; - } - return false; -} - -bool MAX31865Class::getVoltageFault(uint8_t fault) { - if (fault & MAX31865_FAULT_OVER_UNDER_VOLTAGE) { - return true; - } - return false; -} - -float MAX31865Class::readTemperature(float RTDnominal, float refResistor) { - float Z1, Z2, Z3, Z4, Rt, temp; - - Rt = readRTD(); - Rt /= 32768; - Rt *= refResistor; - - - Z1 = -RTD_A; - Z2 = RTD_A * RTD_A - (4 * RTD_B); - Z3 = (4 * RTD_B) / RTDnominal; - Z4 = 2 * RTD_B; - - temp = Z2 + (Z3 * Rt); - temp = (sqrt(temp) + Z1) / Z4; - - if (temp >= 0) - return temp; - - // ugh. - Rt /= RTDnominal; - Rt *= 100; // normalize to 100 ohm - - float rpoly = Rt; - - temp = -242.02; - temp += 2.2228 * rpoly; - rpoly *= Rt; // square - temp += 2.5859e-3 * rpoly; - rpoly *= Rt; // ^3 - temp -= 4.8260e-6 * rpoly; - rpoly *= Rt; // ^4 - temp -= 2.8183e-8 * rpoly; - rpoly *= Rt; // ^5 - temp += 1.5243e-10 * rpoly; - - return temp; -} - -uint32_t MAX31865Class::readRTD() { - - // clear fault - writeByte(MAX31856_CONFIG_REG, (readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_CLEAR_FAULT_CYCLE) | MAX31856_CONFIG_CLEAR_FAULT); - - // enable bias - writeByte(MAX31856_CONFIG_REG, (readByte(MAX31856_CONFIG_REG) | MAX31856_CONFIG_BIAS_ON)); - delay(10); - - // ONE shot cOnfIg and make readings change with readByte - writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) | MAX31856_CONFIG_ONE_SHOT); - delay(65); - - //readings bytes - uint16_t read = (readBytes(MAX31856_RTD_MSB_REG)); - read = read >>1; - // disable bias - writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) & (MAX31856_CONFIG_BIAS_MASK)); - - return read; -} - -uint8_t MAX31865Class::readByte(uint8_t addr) { - addr &= 0x7F; - uint8_t read = 0; - digitalWrite(_cs, LOW); - - _spi.beginTransaction(_spiSettings); - _spi.transfer(addr); - _spi.transfer(&read,1); - _spi.endTransaction(); - - digitalWrite(_cs, HIGH); - - return read; -} - -uint16_t MAX31865Class::readBytes(uint8_t addr) { - digitalWrite(_cs, LOW); - uint16_t read = 0x00; - _spi.beginTransaction(_spiSettings); - _spi.transfer(addr); - int i; - for (i = 0; i<2; i++) { - read = read << 8; - read |= _spi.transfer(0); - } - - _spi.endTransaction(); - - digitalWrite(_cs, HIGH); - - return read; -} - -void MAX31865Class::writeByte(uint8_t addr, uint8_t data) { - addr |= 0x80; // make sure top bit is set - uint8_t buffer[2] = {addr, data}; - digitalWrite(_cs, LOW); - - _spi.beginTransaction(_spiSettings); - _spi.transfer(buffer,2); - - _spi.endTransaction(); - - digitalWrite(_cs, HIGH); -} diff --git a/src/utility/MAX31865/MAX31865.h b/src/utility/MAX31865/MAX31865.h deleted file mode 100644 index eb689af..0000000 --- a/src/utility/MAX31865/MAX31865.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef MAX31865_H -#define MAX31865_H - -#include -#include -#include - - -#define MAX31856_CONFIG_REG 0x00 -#define MAX31856_RTD_MSB_REG 0x01 -#define MAX31856_FAULT_STATUS_REG 0x07 - -//config bias mask -#define MAX31856_CONFIG_BIAS_MASK 0x7F -#define MAX31856_CONFIG_BIAS_ON 0x80 - -//config conversion mode mask -#define MAX31856_CONFIG_CONV_MODE_MASK 0xBF -#define MAX31856_CONFIG_CONV_MODE_AUTO 0x40 - -//config one shot mask -#define MAX31856_CONFIG_ONE_SHOT_MASK 0xDF -#define MAX31856_CONFIG_ONE_SHOT 0x20 - -//config wire mask -#define MAX31856_CONFIG_WIRE_MASK 0xEF -#define MAX31856_CONFIG_3_WIRE 0x10 - -//config wire fault detection cycle mask -#define MAX31856_CONFIG_FAULT_DECT_CYCLE_MASK 0xF3 -#define MAX31856_CONFIG_CLEAR_FAULT_CYCLE 0xD3 - -//config fault status mask -#define MAX31856_CONFIG_FAULT_STATUS_MASK 0xFD -#define MAX31856_CONFIG_CLEAR_FAULT 0x02 - -// config 50 60 filter frequency mask -#define MAX31856_CONFIG_60_50_HZ_FILTER_MASK 0xFE - -// fault mask -#define MAX31865_FAULT_HIGH_THRESH 0x80 -#define MAX31865_FAULT_LOW_THRESH 0x40 -#define MAX31865_FAULT_LOW_REFIN 0x20 -#define MAX31865_FAULT_HIGH_REFIN 0x10 -#define MAX31865_FAULT_LOW_RTDIN 0x08 -#define MAX31865_FAULT_OVER_UNDER_VOLTAGE 0x04 - -#define RTD_A 3.9083e-3 -#define RTD_B -5.775e-7 - -#define TWO_WIRE 0 -#define THREE_WIRE 1 - - -class MAX31865Class { -public: - MAX31865Class(PinName cs = PA_6); - - bool begin(int wires); - void end(); - - float readTemperature(float RTDnominal, float refResistor); - uint8_t readFault(void); - void clearFault(void); - uint32_t readRTD(); - bool getHighThresholdFault(uint8_t fault); - bool getLowThresholdFault(uint8_t fault); - bool getLowREFINFault(uint8_t fault); - bool getHighREFINFault(uint8_t fault); - bool getLowRTDINFault(uint8_t fault); - bool getVoltageFault(uint8_t fault); - - - -private: - uint8_t readByte(uint8_t addr); - uint16_t readBytes(uint8_t addr); - void writeByte(uint8_t addr, uint8_t data); - - PinName _cs; - SPIClass& _spi; -}; - - -#endif diff --git a/src/utility/RTD/MAX31865.cpp b/src/utility/RTD/MAX31865.cpp new file mode 100644 index 0000000..90274d4 --- /dev/null +++ b/src/utility/RTD/MAX31865.cpp @@ -0,0 +1,236 @@ +#include "MAX31865.h" + +MAX31865Class::MAX31865Class(PinName cs, SPIClass& spi) : _cs(cs), _spi(&spi), _spiSettings(1000000, MSBFIRST, SPI_MODE1) { +} + +bool MAX31865Class::begin() { + _spi->begin(); + + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); + + // disable bias + writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_BIAS_MASK); + + // disable auto convert mode + writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_CONV_MODE_MASK); + + // clear fault + writeByte(MAX31856_CONFIG_REG, (readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_CLEAR_FAULT_CYCLE) | MAX31856_CONFIG_CLEAR_FAULT); + + // set filter frequency + writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_60_50_HZ_FILTER_MASK); + + return true; +} + +bool MAX31865Class::begin(uint8_t probeType) { // Deprecate in future + begin(); + + setRTDType(probeType); + + return true; +} + +void MAX31865Class::setRTDType(uint8_t probeType) { + // sets 2 or 4 wire + if (probeType == PROBE_RTD_3W) { + writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) | MAX31856_CONFIG_3_WIRE); + } else { + writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_WIRE_MASK); + } + _current_probe_type = probeType; +} + +uint8_t MAX31865Class::getRTDType() { + return _current_probe_type; +} + +void MAX31865Class::clearFault(void) { + return clearRTDFault(); +} + +void MAX31865Class::clearRTDFault(void) { + writeByte(MAX31856_CONFIG_REG, (readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_CLEAR_FAULT_CYCLE) | MAX31856_CONFIG_CLEAR_FAULT); +} + +uint8_t MAX31865Class::readFault(void) { + return readRTDFault(); +} + +uint8_t MAX31865Class::readRTDFault(void) { + return readByte(MAX31856_FAULT_STATUS_REG); +} + +bool MAX31865Class::getHighThresholdFault(uint8_t fault) { + return getRTDHighThresholdFault(fault); +} + +bool MAX31865Class::getRTDHighThresholdFault(uint8_t fault) { + if (fault & MAX31865_FAULT_HIGH_THRESH) { + return true; + } + return false; +} + +bool MAX31865Class::getLowThresholdFault(uint8_t fault) { + return getRTDLowThresholdFault(fault); +} + +bool MAX31865Class::getRTDLowThresholdFault(uint8_t fault) { + if (fault & MAX31865_FAULT_LOW_THRESH) { + return true; + } + return false; +} + +bool MAX31865Class::getLowREFINFault(uint8_t fault) { + return getRTDLowREFINFault(fault); +} + +bool MAX31865Class::getRTDLowREFINFault(uint8_t fault) { + if (fault & MAX31865_FAULT_LOW_REFIN) { + return true; + } + return false; +} + +bool MAX31865Class::getHighREFINFault(uint8_t fault) { + return getRTDHighREFINFault(fault); +} + +bool MAX31865Class::getRTDHighREFINFault(uint8_t fault) { + if (fault & MAX31865_FAULT_HIGH_REFIN) { + return true; + } + return false; +} + +bool MAX31865Class::getLowRTDINFault(uint8_t fault) { + return getRTDLowRTDINFault(fault); +} + +bool MAX31865Class::getRTDLowRTDINFault(uint8_t fault) { + if (fault & MAX31865_FAULT_LOW_RTDIN) { + return true; + } + return false; +} + +bool MAX31865Class::getVoltageFault(uint8_t fault) { + return getRTDVoltageFault(fault); +} + +bool MAX31865Class::getRTDVoltageFault(uint8_t fault) { + if (fault & MAX31865_FAULT_OVER_UNDER_VOLTAGE) { + return true; + } + return false; +} + +float MAX31865Class::convertRTDTemperature(float RTDnominal, float refResistor) { + float Z1, Z2, Z3, Z4, Rt, temp; + + Rt = readRTD(); + Rt /= 32768; + Rt *= refResistor; + + Z1 = -RTD_A; + Z2 = RTD_A * RTD_A - (4 * RTD_B); + Z3 = (4 * RTD_B) / RTDnominal; + Z4 = 2 * RTD_B; + + temp = Z2 + (Z3 * Rt); + temp = (sqrt(temp) + Z1) / Z4; + + if (temp >= 0) + return temp; + + // ugh. + Rt /= RTDnominal; + Rt *= 100; // normalize to 100 ohm + + float rpoly = Rt; + + temp = -242.02; + temp += 2.2228 * rpoly; + rpoly *= Rt; // square + temp += 2.5859e-3 * rpoly; + rpoly *= Rt; // ^3 + temp -= 4.8260e-6 * rpoly; + rpoly *= Rt; // ^4 + temp -= 2.8183e-8 * rpoly; + rpoly *= Rt; // ^5 + temp += 1.5243e-10 * rpoly; + + return temp; +} + +uint32_t MAX31865Class::readRTD() { + // clear fault + writeByte(MAX31856_CONFIG_REG, (readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_CLEAR_FAULT_CYCLE) | MAX31856_CONFIG_CLEAR_FAULT); + + // enable bias + writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) | MAX31856_CONFIG_BIAS_ON); + delay(10); + + // one shot config and make readings change with readByte + writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) | MAX31856_CONFIG_ONE_SHOT); + delay(65); + + //reading word + uint16_t read = readWord(MAX31856_RTD_MSB_REG); + read = read >> 1; + + // disable bias + writeByte(MAX31856_CONFIG_REG, readByte(MAX31856_CONFIG_REG) & MAX31856_CONFIG_BIAS_MASK); + + return read; +} + +uint8_t MAX31865Class::readByte(uint8_t addr) { + addr &= 0x7F; + uint8_t read = 0; + + digitalWrite(_cs, LOW); + + _spi->beginTransaction(_spiSettings); + _spi->transfer(addr); + _spi->transfer(&read,1); + _spi->endTransaction(); + + digitalWrite(_cs, HIGH); + + return read; +} + +uint16_t MAX31865Class::readWord(uint8_t addr) { + uint16_t read = 0x00; + + digitalWrite(_cs, LOW); + + _spi->beginTransaction(_spiSettings); + _spi->transfer(addr); + for (int i = 0; i < 2; i++) { + read = read << 8; + read |= _spi->transfer(0); + } + _spi->endTransaction(); + + digitalWrite(_cs, HIGH); + + return read; +} + +void MAX31865Class::writeByte(uint8_t addr, uint8_t data) { + addr |= 0x80; // make sure top bit is set + uint8_t buffer[2] = {addr, data}; + + digitalWrite(_cs, LOW); + + _spi->beginTransaction(_spiSettings); + _spi->transfer(buffer,2); + _spi->endTransaction(); + + digitalWrite(_cs, HIGH); +} diff --git a/src/utility/RTD/MAX31865.h b/src/utility/RTD/MAX31865.h new file mode 100644 index 0000000..c5a7855 --- /dev/null +++ b/src/utility/RTD/MAX31865.h @@ -0,0 +1,101 @@ +#ifndef MAX31865_H +#define MAX31865_H + +#include +#include +#include +#include "pins_mc.h" + +#define MAX31856_CONFIG_REG 0x00 +#define MAX31856_RTD_MSB_REG 0x01 +#define MAX31856_FAULT_STATUS_REG 0x07 + +//config bias mask +#define MAX31856_CONFIG_BIAS_MASK 0x7F +#define MAX31856_CONFIG_BIAS_ON 0x80 + +//config conversion mode mask +#define MAX31856_CONFIG_CONV_MODE_MASK 0xBF +#define MAX31856_CONFIG_CONV_MODE_AUTO 0x40 + +//config one shot mask +#define MAX31856_CONFIG_ONE_SHOT_MASK 0xDF +#define MAX31856_CONFIG_ONE_SHOT 0x20 + +//config wire mask +#define MAX31856_CONFIG_WIRE_MASK 0xEF +#define MAX31856_CONFIG_3_WIRE 0x10 + +//config wire fault detection cycle mask +#define MAX31856_CONFIG_FAULT_DECT_CYCLE_MASK 0xF3 +#define MAX31856_CONFIG_CLEAR_FAULT_CYCLE 0xD3 + +//config fault status mask +#define MAX31856_CONFIG_FAULT_STATUS_MASK 0xFD +#define MAX31856_CONFIG_CLEAR_FAULT 0x02 + +// config 50 60 filter frequency mask +#define MAX31856_CONFIG_60_50_HZ_FILTER_MASK 0xFE + +// fault mask +#define MAX31865_FAULT_HIGH_THRESH 0x80 +#define MAX31865_FAULT_LOW_THRESH 0x40 +#define MAX31865_FAULT_LOW_REFIN 0x20 +#define MAX31865_FAULT_HIGH_REFIN 0x10 +#define MAX31865_FAULT_LOW_RTDIN 0x08 +#define MAX31865_FAULT_OVER_UNDER_VOLTAGE 0x04 + +#define RTD_A 3.9083e-3 +#define RTD_B -5.775e-7 + +#define PROBE_RTD_2W 3 +#define PROBE_RTD_3W 4 + +#define TWO_WIRE PROBE_RTD_2W +#define THREE_WIRE PROBE_RTD_3W + +class MAX31865Class { +public: + MAX31865Class(PinName cs = MC_RTD_CS_PIN, SPIClass& spi = SPI); + + bool begin(); + bool begin(uint8_t probeType); //Deprecate in future + void end(); + + void setRTDType(uint8_t probeType); + uint8_t getRTDType(); + + float convertRTDTemperature(float RTDnominal, float refResistor); + + uint8_t readFault(void); //Deprecate in future + uint8_t readRTDFault(void); + void clearFault(void); //Deprecate in future + void clearRTDFault(void); + + uint32_t readRTD(); + + bool getHighThresholdFault(uint8_t fault); //Deprecate in future + bool getRTDHighThresholdFault(uint8_t fault); + bool getLowThresholdFault(uint8_t fault); //Deprecate in future + bool getRTDLowThresholdFault(uint8_t fault); + bool getLowREFINFault(uint8_t fault); //Deprecate in future + bool getRTDLowREFINFault(uint8_t fault); + bool getHighREFINFault(uint8_t fault); //Deprecate in future + bool getRTDHighREFINFault(uint8_t fault); + bool getLowRTDINFault(uint8_t fault); //Deprecate in future + bool getRTDLowRTDINFault(uint8_t fault); + bool getVoltageFault(uint8_t fault); //Deprecate in future + bool getRTDVoltageFault(uint8_t fault); + +private: + uint8_t readByte(uint8_t addr); + uint16_t readWord(uint8_t addr); + void writeByte(uint8_t addr, uint8_t data); + + PinName _cs; + SPIClass* _spi; + SPISettings _spiSettings; + uint8_t _current_probe_type; +}; + +#endif diff --git a/src/utility/THERMOCOUPLE/MAX31855.cpp b/src/utility/THERMOCOUPLE/MAX31855.cpp index eb2e64a..6696c52 100644 --- a/src/utility/THERMOCOUPLE/MAX31855.cpp +++ b/src/utility/THERMOCOUPLE/MAX31855.cpp @@ -1,228 +1,277 @@ #include "MAX31855.h" -const double MAX31855Class::Jm210_760[] ; -const double MAX31855Class::J760_1200[] ; -const double MAX31855Class::Km270_0[] ; -const double MAX31855Class::K0_1372[] ; +const double MAX31855Class::Jm210_760[]; +const double MAX31855Class::J760_1200[]; -const double MAX31855Class::InvJ_neg[] ; -const double MAX31855Class::InvJ0_760[] ; -const double MAX31855Class::InvJ760_1200[] ; +const double MAX31855Class::Km270_0[]; +const double MAX31855Class::K0_1372[]; -const double MAX31855Class::InvK_neg[] ; -const double MAX31855Class::InvK0_500[] ; -const double MAX31855Class::InvK500_1372[] ; +const double MAX31855Class::Tm270_0[]; +const double MAX31855Class::T0_400[]; + +const double MAX31855Class::InvJ_neg[]; +const double MAX31855Class::InvJ0_760[]; +const double MAX31855Class::InvJ760_1200[]; + +const double MAX31855Class::InvK_neg[]; +const double MAX31855Class::InvK0_500[]; +const double MAX31855Class::InvK500_1372[]; + +const double MAX31855Class::InvT_m200_0[]; +const double MAX31855Class::InvT0_400[]; const MAX31855Class::coefftable MAX31855Class::CoeffJ[]; const MAX31855Class::coefftable MAX31855Class::CoeffK[]; +const MAX31855Class::coefftable MAX31855Class::CoeffT[]; const MAX31855Class::coefftable MAX31855Class::InvCoeffJ[]; const MAX31855Class::coefftable MAX31855Class::InvCoeffK[]; +const MAX31855Class::coefftable MAX31855Class::InvCoeffT[]; -MAX31855Class::MAX31855Class(PinName cs, SPIClass& spi) : - _cs(cs), - _spi(&spi), - _spiSettings(4000000, MSBFIRST, SPI_MODE0), - _coldOffset(2.10f) -{ +MAX31855Class::MAX31855Class(PinName cs, SPIClass& spi) : _cs(cs), _spi(&spi), _spiSettings(4000000, MSBFIRST, SPI_MODE0), _coldOffset(2.10f) { } -int MAX31855Class::begin() -{ - uint32_t rawword; +bool MAX31855Class::begin() { + uint32_t rawword; - pinMode(_cs, OUTPUT); - digitalWrite(_cs, HIGH); - _spi->begin(); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); + _spi->begin(); - rawword = readSensor(); - if (rawword == 0xFFFFFF) { - end(); + rawword = readSensor(); + if (rawword == 0xFFFFFF) { + end(); - return 0; - } + return false; + } - return 1; + return true; } -void MAX31855Class::end() -{ - pinMode(_cs, INPUT); - digitalWrite(_cs, LOW); - _spi->end(); +void MAX31855Class::end() { + pinMode(_cs, INPUT); + digitalWrite(_cs, LOW); + _spi->end(); } -uint32_t MAX31855Class::readSensor() -{ - uint32_t read = 0x00; +uint32_t MAX31855Class::readSensor() { + uint32_t read = 0x00; - digitalWrite(_cs, LOW); - delayMicroseconds(1); + digitalWrite(_cs, LOW); + delayMicroseconds(1); - _spi->beginTransaction(_spiSettings); + _spi->beginTransaction(_spiSettings); + for (int i = 0; i < 4; i++) { + read <<= 8; + read |= _spi->transfer(0); + } + + _spi->endTransaction(); - for (int i = 0; i < 4; i++) { - read <<= 8; - read |= _spi->transfer(0); - } + digitalWrite(_cs, HIGH); + return read; +} - _spi->endTransaction(); +double MAX31855Class::polynomial(double value, int tableEntries, coefftable const (*table)) { + double output = 0; + double valuePower = 1; + for (int i = 0; i < tableEntries; i++) { + if (value < table[i].max) { + if (table[i].size == 0) { + return NAN; + } else { + output = 0; + for (int j = 0; j < table[i].size; j++) { + output += valuePower*table[i].coeffs[j]; + valuePower *= value; + } + return output; + } + } + } + return NAN; +} - digitalWrite(_cs, HIGH); - return read; +double MAX31855Class::tempTomv(double temp) { + coefftable const (*table); + int tableEntries; + double voltage; + + switch (_current_probe_type) { + case PROBE_TC_J: + table = CoeffJ; + tableEntries = sizeof(CoeffJ) / sizeof(coefftable); + break; + case PROBE_TC_K: + table = CoeffK; + tableEntries = sizeof(CoeffK) / sizeof(coefftable); + break; + case PROBE_TC_T: + table = CoeffT; + tableEntries = sizeof(CoeffT) / sizeof(coefftable); + break; + } + voltage = polynomial(temp, tableEntries, table); + // special case... for K probes in temperature range 0-1372 we need + // to add an extra term + if (_current_probe_type == PROBE_TC_K && temp>0) { + voltage += 0.118597600000E+00 * exp(-0.118343200000E-03 * pow(temp - 0.126968600000E+03, 2)); + } + return voltage; } -double MAX31855Class::polynomial(double value, int tableEntries, coefftable const (*table) ) -{ - double output = 0; - double valuePower = 1; - for (int i=0;i0) { - voltage += 0.118597600000E+00 * exp( -0.118343200000E-03 * pow(temp-0.126968600000E+03, 2)); - } - return voltage; -} - -double MAX31855Class::mvtoTemp(int type, double voltage) { - coefftable const (*table); - int tableEntries; - - switch (type) { - case PROBE_J: - table = InvCoeffJ; - tableEntries = sizeof(InvCoeffJ)/sizeof(coefftable); - break; - case PROBE_K: - table = InvCoeffK; - tableEntries = sizeof(InvCoeffJ)/sizeof(coefftable); - break; - } - return polynomial(voltage, tableEntries, table); -} - -float MAX31855Class::readTemperature(int type) -{ - uint32_t rawword; - int32_t measuredTempInt; - int32_t measuredColdInt; - double measuredTemp; - double measuredCold; - double measuredVolt; - - rawword = readSensor(); - - // Check for reading error - if (rawword & 0x7) { - return NAN; - } - // The cold junction temperature is stored in the last 14 word's bits - // whereas the ttermocouple temperature (non linearized) is in the topmost 18 bits - // sent by the Thermocouple-to-Digital Converter - - // sign extend thermocouple value - if (rawword & 0x80000000) { - // Negative value, drop the lower 18 bits and explicitly extend sign bits. - measuredTempInt = 0xFFFC0000 | ((rawword >> 18) & 0x00003FFFF); - } else { - // Positive value, just drop the lower 18 bits. - measuredTempInt = rawword>>18; - } - - // convert it to degrees - measuredTemp = measuredTempInt * 0.25f; - - // sign extend cold junction temperature - measuredColdInt = (rawword>>4)&0xfff; - if (measuredColdInt&0x800) { - // Negative value, sign extend - measuredColdInt |= 0xfffff000; - } - - // convert it to degrees - measuredCold = (measuredColdInt/16.0f); - // now the tricky part... since MAX31855K is considering a linear response - // and is trimemd for K thermocouples, we have to convert the reading back - // to mV and then use NIST polynomial approximation to determine temperature - // we know that reading from chip is calculated as: - // temp = chip_temperature + thermocouple_voltage/0.041276f - // - // convert temperature to mV is accomplished converting the chip temperature - // to mV using NIST polynomial and then by adding the measured voltage - // calculated inverting the function above - // this way we calculate the voltage we would have measured if cold junction - // was at 0 degrees celsius - - measuredVolt = coldTempTomv(type, measuredCold - _coldOffset)+(measuredTemp - measuredCold) * 0.041276f; - - // finally from the cold junction compensated voltage we calculate the temperature - // using NIST polynomial approximation for the thermocouple type we are using - return mvtoTemp(type,measuredVolt); -} - -float MAX31855Class::readReferenceTemperature(int type) -{ - uint32_t rawword; - float ref; - - rawword = readSensor(); - - // ignore first 4 FAULT bits - rawword >>= 4; - - // The cold junction reference temperature is stored in the first 11 word's bits - // sent by the Thermocouple-to-Digital Converter - rawword = rawword & 0x7FF; - // check sign bit and convert to negative value. - if (rawword & 0x800) { - ref = (0xF800 | (rawword & 0x7FF))*0.0625; - } else { - // multiply for the LSB value - ref = rawword * 0.0625f; - } - Serial.println(ref); - return ref; -} - -void MAX31855Class::setColdOffset(float offset) -{ - _coldOffset = offset; -} - -MAX31855Class THERM; + + // The cold junction temperature is stored in the last 14 word's bits + // whereas the thermocouple temperature (non linearized) is in the topmost 18 bits + // sent by the Thermocouple-to-Digital Converter + + // sign extend thermocouple value + if (rawword & 0x80000000) { + // Negative value, drop the lower 18 bits and explicitly extend sign bits. + measuredTempInt = 0xFFFC0000 | ((rawword >> 18) & 0x00003FFFF); + } else { + // Positive value, just drop the lower 18 bits. + measuredTempInt = rawword >> 18; + } + + // convert it to degrees + measuredTemp = measuredTempInt * 0.25f; + + // sign extend cold junction temperature + measuredColdInt = (rawword >> 4) & 0xfff; + if (measuredColdInt & 0x800) { + // Negative value, sign extend + measuredColdInt |= 0xfffff000; + } + + // convert it to degrees + measuredCold = (measuredColdInt / 16.0f); + // now the tricky part... since MAX31855K is considering a linear response + // and is trimmed for K thermocouples, we have to convert the reading back + // to mV and then use NIST polynomial approximation to determine temperature + // we know that reading from chip is calculated as: + // temp = chip_temperature + thermocouple_voltage/0.041276f + // + // convert temperature to mV is accomplished converting the chip temperature + // to mV using NIST polynomial and then by adding the measured voltage + // calculated inverting the function above + // this way we calculate the voltage we would have measured if cold junction + // was at 0 degrees celsius + + measuredVolt = tempTomv(measuredCold - _coldOffset) + (measuredTemp - measuredCold) * 0.041276f; + + return measuredVolt; +} + +double MAX31855Class::readTCTemperature() { + // finally from the cold junction compensated voltage we calculate the temperature + // using NIST polynomial approximation for the thermocouple type we are using + return mvtoTemp(readTCVoltage()); +} + +float MAX31855Class::readReferenceTemperature() { + return readTCReferenceTemperature(); +} + +float MAX31855Class::readTCReferenceTemperature() { + //TODO. Actually use TC _current_probe_type and _coldOffset + uint32_t rawword; + float referenceTemperature; + + rawword = readSensor(); + + // ignore first 4 FAULT bits + rawword >>= 4; + + // The cold junction reference temperature is stored in the first 11 word's bits + // sent by the Thermocouple-to-Digital Converter + rawword = rawword & 0x7FF; + // check sign bit and convert to negative value. + if (rawword & 0x800) { + referenceTemperature = (0xF800 | (rawword & 0x7FF)) * 0.0625; + } else { + // multiply for the LSB value + referenceTemperature = rawword * 0.0625f; + } + + return referenceTemperature; +} + +void MAX31855Class::setColdOffset(float offset) { + setTCColdOffset(offset); +} + +void MAX31855Class::setTCColdOffset(float offset) { + _coldOffset = offset; +} + +float MAX31855Class::getColdOffset() { + return getTCColdOffset(); +} + +float MAX31855Class::getTCColdOffset() { + return _coldOffset; +} + +void MAX31855Class::setFaultChecks(uint8_t faults) { + setTCFaultChecks(faults); +} + +void MAX31855Class::setTCFaultChecks(uint8_t faults) { + _faultMask = faults & TC_FAULT_ALL; +} + +uint8_t MAX31855Class::getLastFault() { + return getTCLastFault(); +} + +uint8_t MAX31855Class::getTCLastFault() { + uint8_t tempLastFault = _lastFault; + _lastFault = 0; + return tempLastFault; +} + +void MAX31855Class::setTCType(uint8_t type) { + _current_probe_type = type; +} + +uint8_t MAX31855Class::getTCType() { + return _current_probe_type; +} diff --git a/src/utility/THERMOCOUPLE/MAX31855.h b/src/utility/THERMOCOUPLE/MAX31855.h index f2924b7..9dc0ce0 100644 --- a/src/utility/THERMOCOUPLE/MAX31855.h +++ b/src/utility/THERMOCOUPLE/MAX31855.h @@ -4,81 +4,126 @@ #include #include #include +#include "pins_mc.h" -#define PROBE_K 0 -#define PROBE_J 1 +#define PROBE_TC_K 0 +#define PROBE_TC_J 1 +#define PROBE_TC_T 2 + +#define PROBE_K PROBE_TC_K +#define PROBE_J PROBE_TC_J +#define PROBE_T PROBE_TC_T + +#define TC_FAULT_NONE (0x00) // Disable all fault checks +#define TC_FAULT_OPEN (0x01) // Enable open circuit fault check +#define TC_FAULT_SHORT_GND (0x02) // Enable short to GND fault check +#define TC_FAULT_SHORT_VCC (0x04) // Enable short to VCC fault check +#define TC_FAULT_ALL (0x07) // Enable all fault checks class MAX31855Class { public: - MAX31855Class(PinName cs = PI_0, SPIClass& spi = SPI); + MAX31855Class(PinName cs = MC_TC_CS_PIN, SPIClass& spi = SPI); - int begin(); - void end(); + bool begin(); + void end(); - float readTemperature(int type = PROBE_K); - float readReferenceTemperature(int type = PROBE_K); - void setColdOffset(float offset); + double readTCVoltage(); + double readTCTemperature(); + float readReferenceTemperature(); + float readTCReferenceTemperature(); -private: - uint32_t readSensor(); - float _coldOffset; - PinName _cs; - SPIClass* _spi; - SPISettings _spiSettings; - - // NIST coefficient tables - static constexpr double Jm210_760[] = { 0.000000000000E+00, 0.503811878150E-01, 0.304758369300E-04,-0.856810657200E-07, 0.132281952950E-09,-0.170529583370E-12, 0.209480906970E-15,-0.125383953360E-18, 0.156317256970E-22 }; - static constexpr double J760_1200[] = { 0.296456256810E+03,-0.149761277860E+01, 0.317871039240E-02,-0.318476867010E-05, 0.157208190040E-08,-0.306913690560E-12 }; - - static constexpr double Km270_0[] = { 0.000000000000E+00, 0.394501280250E-01, 0.236223735980E-04,-0.328589067840E-06,-0.499048287770E-08,-0.675090591730E-10,-0.574103274280E-12,-0.310888728940E-14,-0.104516093650E-16,-0.198892668780E-19,-0.163226974860E-22 }; - static constexpr double K0_1372[] = { -0.176004136860E-01, 0.389212049750E-01, 0.185587700320E-04,-0.994575928740E-07, 0.318409457190E-09,-0.560728448890E-12, 0.560750590590E-15,-0.320207200030E-18, 0.971511471520E-22,-0.121047212750E-25 }; - - static constexpr double InvJ_neg[] = { 0.0000000E+00, 1.9528268E+01, -1.2286185E+00, -1.0752178E+00, -5.9086933E-01, -1.7256713E-01, -2.8131513E-02,-2.3963370E-03,-8.3823321E-05}; - static constexpr double InvJ0_760[] = { 0.000000E+00, 1.978425E+01, -2.001204E-01, 1.036969E-02, -2.549687E-04, 3.585153E-06, -5.344285E-08, 5.099890E-10 }; - static constexpr double InvJ760_1200[] = { -3.11358187E+03, 3.00543684E+02, -9.94773230E+00, 1.70276630E-01, -1.43033468E-03, 4.73886084E-06 }; - - static constexpr double InvK_neg[] = { 0.0000000E+00, 2.5173462E+01, 1.1662878E+00, 1.0833638E+00, 8.9773540E-01, 3.7342377E-01, 8.6632643E-02, 1.0450598E-02, 5.1920577E-04 }; - static constexpr double InvK0_500[] = { 0.000000E+00, 2.508355E+01, 7.860106E-02, -2.503131E-01, 8.315270E-02, -1.228034E-02, 9.804036E-04, -4.413030E-05, 1.057734E-06, -1.052755E-08 }; - static constexpr double InvK500_1372[] = { -1.318058E+02, 4.830222E+01, -1.646031E+00, 5.464731E-02, -9.650715E-04, 8.802193E-06, -3.110810E-08 }; - - typedef struct { - int size; - double max; - const double *coeffs; - } coefftable; - - static constexpr coefftable CoeffJ []= { - {0,-210, NULL}, - {sizeof(Jm210_760) / sizeof(double), 760.0f, &Jm210_760[0]}, - {sizeof(J760_1200) / sizeof(double), 1200.0f, &J760_1200[0]} - }; - - static constexpr coefftable CoeffK []= { - {0,-270, NULL}, - {sizeof(Jm210_760) / sizeof(double), 0.0f, &Km270_0[0]}, - {sizeof(K0_1372) / sizeof(double), 1200.0f, &K0_1372[0]} - }; - - static constexpr coefftable InvCoeffJ []= { - {0,-0.895, NULL}, - {sizeof(InvJ_neg) / sizeof(double), 0.0f, &InvJ_neg[0]}, - {sizeof(InvJ0_760) / sizeof(double), 42.919f, &InvJ0_760[0]}, - {sizeof(InvJ760_1200) / sizeof(double), 69.533f, &InvJ760_1200[0]} - }; - - static constexpr coefftable InvCoeffK []= { - {0,-5.891, NULL}, - {sizeof(InvK_neg) / sizeof(double), 0.0f, &InvK_neg[0]}, - {sizeof(InvK0_500) / sizeof(double), 20.644f, &InvK0_500[0]}, - {sizeof(InvK500_1372) / sizeof(double), 54.886f, &InvK500_1372[0]}, - }; - - double mvtoTemp(int type, double voltage); - double coldTempTomv(int type, double temp); - double polynomial(double value, int tableEntries, coefftable const (*table) ); + void setColdOffset(float offset); //Deprecate in future + void setTCColdOffset(float offset); + float getColdOffset(); //Deprecate in future + float getTCColdOffset(); -}; + void setFaultChecks(uint8_t faults); //Deprecate in future + void setTCFaultChecks(uint8_t faults); + uint8_t getLastFault(); //Deprecate in future + uint8_t getTCLastFault(); -extern MAX31855Class THERM; + void setTCType(uint8_t type); + uint8_t getTCType(); + +private: + float _coldOffset; + uint8_t _faultMask = TC_FAULT_ALL; + uint8_t _lastFault = TC_FAULT_NONE; + uint8_t _current_probe_type; + PinName _cs; + SPIClass* _spi; + SPISettings _spiSettings; + + // NIST coefficient tables + static constexpr double Jm210_760[] = { 0.000000000000E+00, 0.503811878150E-01, 0.304758369300E-04, -0.856810657200E-07, 0.132281952950E-09, -0.170529583370E-12, 0.209480906970E-15, -0.125383953360E-18, 0.156317256970E-22 }; + static constexpr double J760_1200[] = { 0.296456256810E+03, -0.149761277860E+01, 0.317871039240E-02, -0.318476867010E-05, 0.157208190040E-08, -0.306913690560E-12 }; + + static constexpr double Km270_0[] = { 0.000000000000E+00, 0.394501280250E-01, 0.236223735980E-04, -0.328589067840E-06, -0.499048287770E-08, -0.675090591730E-10, -0.574103274280E-12, -0.310888728940E-14, -0.104516093650E-16, -0.198892668780E-19, -0.163226974860E-22 }; + static constexpr double K0_1372[] = { -0.176004136860E-01, 0.389212049750E-01, 0.185587700320E-04, -0.994575928740E-07, 0.318409457190E-09, -0.560728448890E-12, 0.560750590590E-15, -0.320207200030E-18, 0.971511471520E-22, -0.121047212750E-25 }; + + static constexpr double Tm270_0[] = { 0.000000000000E+00, 0.387481063640E-01, 0.441944343470E-04, 0.118443231050E-06, 0.200329735540E-07, 0.901380195590E-09, 0.226511565930E-10, 0.360711542050E-12, 0.384939398830E-14, 0.282135219250E-16, 0.142515947790E-18, 0.487686622860E-21, 0.107955392700E-23, 0.139450270620E-26, 0.797951539270E-30 }; + static constexpr double T0_400[] = { 0.000000000000E+00, 0.387481063640E-01, 0.332922278800E-04, 0.206182434040E-06, -0.218822568460E-08, 0.109968809280E-10, -0.308157587720E-13, 0.454791352900E-16, -0.275129016730E-19 }; + + // NIST inverse coefficient tables + static constexpr double InvJ_neg[] = { 0.0000000E+00, 1.9528268E+01, -1.2286185E+00, -1.0752178E+00, -5.9086933E-01, -1.7256713E-01, -2.8131513E-02, -2.3963370E-03, -8.3823321E-05}; + static constexpr double InvJ0_760[] = { 0.000000E+00, 1.978425E+01, -2.001204E-01, 1.036969E-02, -2.549687E-04, 3.585153E-06, -5.344285E-08, 5.099890E-10 }; + static constexpr double InvJ760_1200[] = { -3.11358187E+03, 3.00543684E+02, -9.94773230E+00, 1.70276630E-01, -1.43033468E-03, 4.73886084E-06 }; + + static constexpr double InvK_neg[] = { 0.0000000E+00, 2.5173462E+01, 1.1662878E+00, 1.0833638E+00, 8.9773540E-01, 3.7342377E-01, 8.6632643E-02, 1.0450598E-02, 5.1920577E-04 }; + static constexpr double InvK0_500[] = { 0.000000E+00, 2.508355E+01, 7.860106E-02, -2.503131E-01, 8.315270E-02, -1.228034E-02, 9.804036E-04, -4.413030E-05, 1.057734E-06, -1.052755E-08 }; + static constexpr double InvK500_1372[] = { -1.318058E+02, 4.830222E+01, -1.646031E+00, 5.464731E-02, -9.650715E-04, 8.802193E-06, -3.110810E-08 }; + + static constexpr double InvT_m200_0[] = { 0.0000000E+00, 2.5949192E+01, -2.1316967E-01, 7.9018692E-01, 4.2527777E-01, 1.3304473E-01, 2.0241446E-02, 1.2668171E-03 }; + static constexpr double InvT0_400[] = { 0.000000E+00, 2.592800E+01, -7.602961E-01, 4.637791E-02, -2.165394E-03, 6.048144E-05, -7.293422E-07, 0.000000E+00 }; + + typedef struct { + int size; + double max; + const double *coeffs; + } coefftable; + + static constexpr coefftable CoeffJ[] = { + {0, -210.0f, NULL}, + {sizeof(Jm210_760) / sizeof(double), 760.0f, &Jm210_760[0]}, + {sizeof(J760_1200) / sizeof(double), 1200.0f, &J760_1200[0]} + }; + + static constexpr coefftable CoeffK[] = { + {0, -270.0f, NULL}, + {sizeof(Km270_0) / sizeof(double), 0.0f, &Km270_0[0]}, + {sizeof(K0_1372) / sizeof(double), 1372.0f, &K0_1372[0]} + }; + + static constexpr coefftable CoeffT []= { + {0,-270.0f, NULL}, + {sizeof(Tm270_0) / sizeof(double), 0.0f, &Tm270_0[0]}, + {sizeof(T0_400) / sizeof(double), 400.0f, &T0_400[0]} + }; + + static constexpr coefftable InvCoeffJ[] = { + {0, -0.895f, NULL}, + {sizeof(InvJ_neg) / sizeof(double), 0.0f, &InvJ_neg[0]}, + {sizeof(InvJ0_760) / sizeof(double), 42.919f, &InvJ0_760[0]}, + {sizeof(InvJ760_1200) / sizeof(double), 69.533f, &InvJ760_1200[0]} + }; + + static constexpr coefftable InvCoeffK[] = { + {0, -5.891f, NULL}, + {sizeof(InvK_neg) / sizeof(double), 0.0f, &InvK_neg[0]}, + {sizeof(InvK0_500) / sizeof(double), 20.644f, &InvK0_500[0]}, + {sizeof(InvK500_1372) / sizeof(double), 54.886f, &InvK500_1372[0]}, + }; + + static constexpr coefftable InvCoeffT []= { + {0, -5.603f, NULL}, + {sizeof(InvT_m200_0) / sizeof(double), 0.0f, &InvT_m200_0[0]}, + {sizeof(InvT0_400) / sizeof(double), 20.872f, &InvT0_400[0]}, + }; + + uint32_t readSensor(); + double mvtoTemp(double voltage); + double tempTomv(double temp); + double polynomial(double value, int tableEntries, coefftable const (*table)); +}; #endif