Welcome to mirror list, hosted at ThFree Co, Russian Federation.

RtdSensor31865.cpp « Sensors « Heating « src - github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 44dbfcb0c3de2c8e34f2b5a60bee8485e53ece77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
 * RtdSensor31865.cpp
 *
 *  Created on: 8 Jun 2017
 *      Author: David
 */

#include "RtdSensor31865.h"
#include "RepRap.h"
#include "Platform.h"
#include "GCodes/GCodeBuffer/GCodeBuffer.h"

const uint32_t MAX31865_Frequency = 4000000;	// maximum for MAX31865 is also 5MHz

// SPI modes:
// If the inactive state of SCL is LOW (CPOL = 0) (in the case of the MAX31865, this is sampled on the falling edge of CS):
// The MAX31865 changes data after the rising edge of CLK, and samples input data on the falling edge.
// This requires NCPHA = 0.
const uint8_t MAX31865_SpiMode = SPI_MODE_1;

// Define the minimum interval between readings. The MAX31865 needs 62.5ms in 50Hz filter mode.
const uint32_t MinimumReadInterval = 100;		// minimum interval between reads, in milliseconds

// Default configuration register
// Note that to get the MAX31865 to do continuous conversions, we need to set the bias bit as well as the continuous-conversion bit
//  Vbias=1
//  Conversion mode=1
//	1shot = 0
//	3wire=0
//	Fault detection=00 no action
//	Fault status=1 clear any existing fault
//	50/60Hz reject=1 for 50Hz (0 for 60Hz)
const uint8_t DefaultCr0 = 0b11000011;
const uint8_t Cr0ReadMask = 0b11011101;		// bits 1 and 5 auto clear, so ignore the value read

const uint16_t DefaultRef = 400;

RtdSensor31865::RtdSensor31865(unsigned int sensorNum) noexcept
	: SpiTemperatureSensor(sensorNum, "PT100 (MAX31865)", MAX31865_SpiMode, MAX31865_Frequency),
	  rref(DefaultRef), cr0(DefaultCr0)
{
}

// Configure this temperature sensor
GCodeResult RtdSensor31865::Configure(GCodeBuffer& gb, const StringRef& reply)
{
	bool seen = false;
	if (!ConfigurePort(gb, reply, seen))
	{
		return GCodeResult::error;
	}
	TryConfigureSensorName(gb, seen);
	if (gb.Seen('F'))
	{
		seen = true;
		if (gb.GetIValue() == 60)
		{
			cr0 &= ~0x01;		// set 60Hz rejection
		}
		else
		{
			cr0 |= 0x01;		// default to 50Hz rejection
		}
	}

	if (gb.Seen('W'))
	{
		seen = true;
		if (gb.GetUIValue() == 3)
		{
			cr0 |= 0x10;		// 3 wire configuration
		}
		else
		{
			cr0 &= ~0x10;		// 2 or 4 wire configuration
		}
	}

	if (gb.Seen('R'))
	{
		seen = true;
		rref = (uint16_t)gb.GetUIValue();
	}

	if (seen)
	{
		// Initialise the sensor
		InitSpi();

		TemperatureError rslt;
		for (unsigned int i = 0; i < 3; ++i)		// try 3 times
		{
			rslt = TryInitRtd();
			if (rslt == TemperatureError::success)
			{
				break;
			}
			delay(MinimumReadInterval);
		}

		lastReadingTime = millis();
		lastResult = rslt;
		lastTemperature = 0.0;

		if (rslt != TemperatureError::success)
		{
			reprap.GetPlatform().MessageF(ErrorMessage, "Failed to initialise RTD: %s\n", TemperatureErrorString(rslt));
		}

	}
	else
	{
		CopyBasicDetails(reply);
		reply.catf(", %s wires, reject %dHz, reference resistor %u ohms", (cr0 & 0x10) ? "3" : "2/4", (cr0 & 0x01) ? 50 : 60, (unsigned int)rref);
	}
	return GCodeResult::ok;
}

// Try to initialise the RTD
TemperatureError RtdSensor31865::TryInitRtd() const noexcept
{
	const uint8_t modeData[2] = { 0x80, cr0 };			// write register 0
	uint32_t rawVal;
	TemperatureError sts = DoSpiTransaction(modeData, ARRAY_SIZE(modeData), rawVal);

	if (sts == TemperatureError::success)
	{
		delayMicroseconds(1);
		static const uint8_t readData[2] = { 0x00, 0x00 };	// read register 0
		sts = DoSpiTransaction(readData, ARRAY_SIZE(readData), rawVal);
	}

	//debugPrintf("Status %d data %04x\n", (int)sts, (uint16_t)rawVal);
	if (sts == TemperatureError::success && (rawVal & Cr0ReadMask) != (cr0 & Cr0ReadMask))
	{
		sts = TemperatureError::badResponse;
	}

	return sts;
}

void RtdSensor31865::Poll() noexcept
{
	static const uint8_t dataOut[4] = {0, 0x55, 0x55, 0x55};			// read registers 0 (control), 1 (MSB) and 2 (LSB)
	uint32_t rawVal;
	TemperatureError sts = DoSpiTransaction(dataOut, ARRAY_SIZE(dataOut), rawVal);

	if (sts != TemperatureError::success)
	{
		SetResult(sts);
	}
	else
	{
		if (   (((rawVal >> 16) & Cr0ReadMask) != (cr0 & Cr0ReadMask))	// if control register not as expected
			|| (rawVal & 1) != 0										// or fault bit set
		   )
		{
			static const uint8_t faultDataOut[2] = {0x07, 0x55};
			if (DoSpiTransaction(faultDataOut, ARRAY_SIZE(faultDataOut), rawVal)== TemperatureError::success)	// read the fault register
			{
				sts = (rawVal & 0x04) ? TemperatureError::overOrUnderVoltage
							: (rawVal & 0x18) ? TemperatureError::openCircuit
								: TemperatureError::hardwareError;
			}
			else
			{
				sts = TemperatureError::hardwareError;
			}
			SetResult(sts);
			delayMicroseconds(1);										// MAX31865 requires CS to be high for 400ns minimum
			TryInitRtd();												// clear the fault and hope for better luck next time
		}
		else
		{
			const uint16_t ohmsx100 = (uint16_t)((((rawVal >> 1) & 0x7FFF) * rref * 100) >> 15);
			float t;
			sts = GetPT100Temperature(t, ohmsx100);
			SetResult(t, sts);
		}
	}
}

// End