Version 1.19beta5
Fixed spin hang in Network module caused by output buffer being re-used after it was released Added support for SPI temperature sensor based on an ADC whose output is linear with temperature
This commit is contained in:
parent
a915f98447
commit
fe571d4396
12 changed files with 124 additions and 19 deletions
Binary file not shown.
Binary file not shown.
|
@ -105,12 +105,13 @@ static_assert(DefaultMaxTempExcursion > TEMPERATURE_CLOSE_ENOUGH, "DefaultMaxTem
|
|||
// Temperature sense channels
|
||||
const unsigned int FirstThermocoupleChannel = 100; // Temperature sensor channels 100... are thermocouples
|
||||
const unsigned int FirstRtdChannel = 200; // Temperature sensor channels 200... are RTDs
|
||||
const unsigned int FirstLinearAdcChannel = 300; // Temperature sensor channels 300... use an ADC that provides a linear output over a temperature range
|
||||
|
||||
// PWM frequencies
|
||||
const unsigned int SlowHeaterPwmFreq = 10; // slow PWM frequency for bed and chamber heaters, compatible with DC/AC SSRs
|
||||
const unsigned int NormalHeaterPwmFreq = 250; // normal PWM frequency used for hot ends
|
||||
const unsigned int DefaultFanPwmFreq = 250; // increase to 25kHz using M106 command to meet Intel 4-wire PWM fan specification
|
||||
const unsigned int DefaultPinWritePwmFreq = 500; // default PWM frequency for M42 pin writes and extrusion ancilliary PWM
|
||||
const unsigned int DefaultPinWritePwmFreq = 500; // default PWM frequency for M42 pin writes and extrusion ancillary PWM
|
||||
|
||||
// Default Z probe values
|
||||
|
||||
|
|
|
@ -177,6 +177,7 @@ void NetworkResponder::ConnectionLost()
|
|||
{
|
||||
CancelUpload();
|
||||
OutputBuffer::ReleaseAll(outBuf);
|
||||
outBuf = nullptr;
|
||||
outStack->ReleaseAll();
|
||||
|
||||
if (fileBeingSent != nullptr)
|
||||
|
|
|
@ -3147,6 +3147,7 @@ void GCodes::SetHeaterParameters(GCodeBuffer& gb, StringRef& reply)
|
|||
if ( (0 <= thermistor && thermistor < HEATERS)
|
||||
|| ((int)FirstThermocoupleChannel <= thermistor && thermistor < (int)(FirstThermocoupleChannel + MaxSpiTempSensors))
|
||||
|| ((int)FirstRtdChannel <= thermistor && thermistor < (int)(FirstRtdChannel + MaxSpiTempSensors))
|
||||
|| ((int)FirstLinearAdcChannel <= thermistor && thermistor < (int)(FirstLinearAdcChannel + MaxSpiTempSensors))
|
||||
)
|
||||
{
|
||||
platform.SetThermistorNumber(heater, thermistor);
|
||||
|
|
|
@ -48,16 +48,19 @@
|
|||
|
||||
const uint32_t MAX31855_Frequency = 4000000; // maximum for MAX31855 is 5MHz
|
||||
const uint32_t MAX31865_Frequency = 4000000; // maximum for MAX31865 is also 5MHz
|
||||
const uint32_t MCP3204_Frequency = 1000000; // maximum for MCP3204 is 1MHz @ 2.7V, will be slightly higher at 3.3V
|
||||
|
||||
// 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 MAX31855 sets up the first data bit after the falling edge of CS, and changes the data on each falling clock edge.
|
||||
// The MAX31855 sets up the first data bit after the falling edge of CLK, and changes the data on each falling clock edge.
|
||||
// So the SAM needs to sample data on the rising clock edge. This requires NCPHA = 1.
|
||||
// The MAX31865 changes data after the rising edge of CS, and samples input data on the falling edge.
|
||||
// The MAX31865 changes data after the rising edge of CLK, and samples input data on the falling edge.
|
||||
// This requires NCPHA = 0.
|
||||
// The MCP3204 samples input data on the rising edge and changes the output data on the rising edge.
|
||||
|
||||
const uint8_t MAX31855_SpiMode = SPI_MODE_0;
|
||||
const uint8_t MAX31865_SpiMode = SPI_MODE_1;
|
||||
const uint8_t MCP3204_SpiMode = SPI_MODE_0;
|
||||
|
||||
// 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
|
||||
|
@ -175,11 +178,38 @@ TemperatureError TemperatureSensor::TryInitRtd() const
|
|||
: sts;
|
||||
}
|
||||
|
||||
TemperatureError TemperatureSensor::GetThermocoupleTemperature(float *t)
|
||||
// Initialise the linear ADC
|
||||
void TemperatureSensor::InitLinearAdc(uint8_t cs)
|
||||
{
|
||||
device.csPin = cs;
|
||||
device.spiMode = MCP3204_SpiMode;
|
||||
device.clockFrequency = MCP3204_Frequency;
|
||||
sspi_master_init(&device, 8);
|
||||
|
||||
for (unsigned int i = 0; i < 3; ++i) // try 3 times
|
||||
{
|
||||
TryGetLinearAdcTemperature();
|
||||
if (lastResult == TemperatureError::success)
|
||||
{
|
||||
break;
|
||||
}
|
||||
delay(MinimumReadInterval);
|
||||
}
|
||||
|
||||
lastReadingTime = millis();
|
||||
|
||||
if (lastResult != TemperatureError::success)
|
||||
{
|
||||
reprap.GetPlatform().MessageF(GENERIC_MESSAGE, "Error: failed to initialise daughter board ADC: %s\n", TemperatureErrorString(lastResult));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TemperatureError TemperatureSensor::GetThermocoupleTemperature(float& t)
|
||||
{
|
||||
if (inInterrupt() || millis() - lastReadingTime < MinimumReadInterval)
|
||||
{
|
||||
*t = lastTemperature;
|
||||
t = lastTemperature;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -247,7 +277,7 @@ TemperatureError TemperatureSensor::GetThermocoupleTemperature(float *t)
|
|||
rawVal |= (0 - (rawVal & 0x2000)); // sign-extend the sign bit
|
||||
|
||||
// And convert to from units of 1/4C to 1C
|
||||
*t = lastTemperature = (float)(0.25 * (float)(int32_t)rawVal);
|
||||
t = lastTemperature = (float)(0.25 * (float)(int32_t)rawVal);
|
||||
lastResult = TemperatureError::success;
|
||||
}
|
||||
}
|
||||
|
@ -255,11 +285,11 @@ TemperatureError TemperatureSensor::GetThermocoupleTemperature(float *t)
|
|||
return lastResult;
|
||||
}
|
||||
|
||||
TemperatureError TemperatureSensor::GetRtdTemperature(float *t)
|
||||
TemperatureError TemperatureSensor::GetRtdTemperature(float& t)
|
||||
{
|
||||
if (inInterrupt() || millis() - lastReadingTime < MinimumReadInterval)
|
||||
{
|
||||
*t = lastTemperature;
|
||||
t = lastTemperature;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -325,7 +355,7 @@ TemperatureError TemperatureSensor::GetRtdTemperature(float *t)
|
|||
else
|
||||
{
|
||||
const float interpolationFraction = (float)(adcVal - tempTable[low - 1].adcReading)/(float)(tempTable[low].adcReading - tempTable[low - 1].adcReading);
|
||||
*t = lastTemperature = ((float)(tempTable[low].temperature - tempTable[low - 1].temperature) * interpolationFraction)
|
||||
t = lastTemperature = ((float)(tempTable[low].temperature - tempTable[low - 1].temperature) * interpolationFraction)
|
||||
+ (float)tempTable[low - 1].temperature;
|
||||
//debugPrintf("raw %u low %u interp %f temp %f\n", adcVal, low, interpolationFraction, *t);
|
||||
lastResult = TemperatureError::success;
|
||||
|
@ -336,6 +366,49 @@ TemperatureError TemperatureSensor::GetRtdTemperature(float *t)
|
|||
return lastResult;
|
||||
}
|
||||
|
||||
TemperatureError TemperatureSensor::GetLinearAdcTemperature(float& t)
|
||||
{
|
||||
if (!inInterrupt() && millis() - lastReadingTime >= MinimumReadInterval)
|
||||
{
|
||||
TryGetLinearAdcTemperature();
|
||||
}
|
||||
|
||||
t = lastTemperature;
|
||||
return lastResult;
|
||||
}
|
||||
|
||||
// Try to get a temperature reading from the linear ADC by doing an SPI transaction
|
||||
void TemperatureSensor::TryGetLinearAdcTemperature()
|
||||
{
|
||||
// The MCP3204 waits for a high input input bit before it does anything. Call this clock 1.
|
||||
// The next input bit it high for single-ended operation, low for differential. This is clock 2.
|
||||
// The next 3 input bits are the channel selection bits. These are clocks 3..5.
|
||||
// Clock 6 produces a null bit on its trailing edge, which is read by the processor on clock 7.
|
||||
// Clocks 7..18 produce data bits B11..B0 on their trailing edges, which are read by the MCU on the leading edges of clocks 8-19.
|
||||
// If we supply further clocks, then clocks 18..29 are the same data but LSB first, omitting bit 0.
|
||||
// Clocks 30 onwards will be zeros.
|
||||
// So we need to use at least 19 clocks. We round this up to 24 clocks, and we check that the extra 5 bits we receive are the 5 least significant data bits in reverse order.
|
||||
|
||||
static const uint8_t adcData[] = { 0xC0, 0x00, 0x00 }; // start bit, single ended, channel 0
|
||||
uint32_t rawVal;
|
||||
lastResult = DoSpiTransaction(adcData, 3, rawVal);
|
||||
//debugPrintf("ADC data %u\n", rawVal);
|
||||
|
||||
if (lastResult == TemperatureError::success)
|
||||
{
|
||||
const uint32_t adcVal1 = (rawVal >> 5) & ((1 << 13) - 1);
|
||||
const uint32_t adcVal2 = ((rawVal & 1) << 5) | ((rawVal & 2) << 3) | ((rawVal & 4) << 1) | ((rawVal & 8) >> 1) | ((rawVal & 16) >> 3) | ((rawVal & 32) >> 5);
|
||||
if (adcVal1 >= 4096 || adcVal2 != (adcVal1 & ((1 << 6) - 1)))
|
||||
{
|
||||
lastResult = TemperatureError::badResponse;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastTemperature = MinLinearAdcTemp + (LinearAdcDegCPerCount * (float)adcVal1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send and receive 1 to 4 bytes of data and return the result as a single 32-bit word
|
||||
TemperatureError TemperatureSensor::DoSpiTransaction(const uint8_t dataOut[], size_t nbytes, uint32_t& rslt) const
|
||||
{
|
||||
|
|
|
@ -11,17 +11,23 @@ public:
|
|||
TemperatureSensor() {}
|
||||
void InitThermocouple(uint8_t cs);
|
||||
void InitRtd(uint8_t cs);
|
||||
TemperatureError GetThermocoupleTemperature(float *temp);
|
||||
TemperatureError GetRtdTemperature(float *temp);
|
||||
void InitLinearAdc(uint8_t cs);
|
||||
TemperatureError GetThermocoupleTemperature(float& t);
|
||||
TemperatureError GetRtdTemperature(float& t);
|
||||
TemperatureError GetLinearAdcTemperature(float& t);
|
||||
|
||||
private:
|
||||
TemperatureError DoSpiTransaction(const uint8_t dataOut[], size_t nbytes, uint32_t& rslt) const;
|
||||
TemperatureError TryInitRtd() const;
|
||||
void TryGetLinearAdcTemperature();
|
||||
|
||||
sspi_device device;
|
||||
uint32_t lastReadingTime;
|
||||
float lastTemperature;
|
||||
TemperatureError lastResult;
|
||||
|
||||
static constexpr float MinLinearAdcTemp = 385.0 - (1600.0 - 385.0) * (4.0/16.0);
|
||||
static constexpr float LinearAdcDegCPerCount = (1600.0 - 385.0)/3200.0;
|
||||
};
|
||||
|
||||
#endif // TEMPERATURESENSOR_H
|
||||
|
|
|
@ -408,7 +408,7 @@ size_t OutputBuffer::EncodeReply(OutputBuffer *src, bool allowControlChars)
|
|||
/*static */ OutputBuffer *OutputBuffer::Release(OutputBuffer *buf)
|
||||
{
|
||||
const irqflags_t flags = cpu_irq_save();
|
||||
OutputBuffer *nextBuffer = buf->next;
|
||||
OutputBuffer * const nextBuffer = buf->next;
|
||||
|
||||
// If this one is reused by another piece of code, don't free it up
|
||||
if (buf->references > 1)
|
||||
|
|
|
@ -640,6 +640,10 @@ void Platform::SetThermistorNumber(size_t heater, size_t thermistor)
|
|||
{
|
||||
SpiTempSensors[thermistor - FirstRtdChannel].InitRtd(spiTempSenseCsPins[thermistor - FirstRtdChannel]);
|
||||
}
|
||||
else if (thermistor >= FirstLinearAdcChannel && thermistor < FirstLinearAdcChannel + MaxSpiTempSensors)
|
||||
{
|
||||
SpiTempSensors[thermistor - FirstRtdChannel].InitLinearAdc(spiTempSenseCsPins[thermistor - FirstLinearAdcChannel]);
|
||||
}
|
||||
|
||||
reprap.GetHeat().ResetFault(heater);
|
||||
}
|
||||
|
@ -2067,7 +2071,7 @@ float Platform::GetTemperature(size_t heater, TemperatureError& err)
|
|||
{
|
||||
// MAX31855 thermocouple chip
|
||||
float temp;
|
||||
err = SpiTempSensors[heaterTempChannels[heater] - FirstThermocoupleChannel].GetThermocoupleTemperature(&temp);
|
||||
err = SpiTempSensors[heaterTempChannels[heater] - FirstThermocoupleChannel].GetThermocoupleTemperature(temp);
|
||||
return (err == TemperatureError::success) ? temp : BAD_ERROR_TEMPERATURE;
|
||||
}
|
||||
|
||||
|
@ -2075,7 +2079,15 @@ float Platform::GetTemperature(size_t heater, TemperatureError& err)
|
|||
{
|
||||
// MAX31865 RTD chip
|
||||
float temp;
|
||||
err = SpiTempSensors[heaterTempChannels[heater] - FirstRtdChannel].GetRtdTemperature(&temp);
|
||||
err = SpiTempSensors[heaterTempChannels[heater] - FirstRtdChannel].GetRtdTemperature(temp);
|
||||
return (err == TemperatureError::success) ? temp : BAD_ERROR_TEMPERATURE;
|
||||
}
|
||||
|
||||
if (IsLinearAdcChannel(heater))
|
||||
{
|
||||
// MAX31865 RTD chip
|
||||
float temp;
|
||||
err = SpiTempSensors[heaterTempChannels[heater] - FirstRtdChannel].GetLinearAdcTemperature(temp);
|
||||
return (err == TemperatureError::success) ? temp : BAD_ERROR_TEMPERATURE;
|
||||
}
|
||||
|
||||
|
@ -2929,9 +2941,9 @@ void Platform::Message(const MessageType type, OutputBuffer *buffer)
|
|||
break;
|
||||
|
||||
case HOST_MESSAGE:
|
||||
if (!SERIAL_MAIN_DEVICE
|
||||
if ( !SERIAL_MAIN_DEVICE
|
||||
#if SUPPORT_SCANNER
|
||||
|| (reprap.GetScanner().IsRegistered() && !reprap.GetScanner().DoingGCodes())
|
||||
|| (reprap.GetScanner().IsRegistered() && !reprap.GetScanner().DoingGCodes())
|
||||
#endif
|
||||
)
|
||||
{
|
||||
|
|
|
@ -537,6 +537,9 @@ public:
|
|||
bool IsRtdChannel(uint8_t heater) const
|
||||
pre(heater < HEATERS);
|
||||
|
||||
bool IsLinearAdcChannel(uint8_t heater) const
|
||||
pre(heater < HEATERS);
|
||||
|
||||
void UpdateConfiguredHeaters();
|
||||
bool AnyHeaterHot(uint16_t heaters, float t); // called to see if we need to turn on the hot end fan
|
||||
|
||||
|
@ -1158,6 +1161,12 @@ inline bool Platform::IsRtdChannel(uint8_t heater) const
|
|||
&& heaterTempChannels[heater] - FirstRtdChannel < MaxSpiTempSensors;
|
||||
}
|
||||
|
||||
inline bool Platform::IsLinearAdcChannel(uint8_t heater) const
|
||||
{
|
||||
return heaterTempChannels[heater] >= FirstLinearAdcChannel
|
||||
&& heaterTempChannels[heater] - FirstLinearAdcChannel < MaxSpiTempSensors;
|
||||
}
|
||||
|
||||
inline const uint8_t* Platform::GetIPAddress() const
|
||||
{
|
||||
return ipAddress;
|
||||
|
|
|
@ -489,7 +489,9 @@ void RepRap::Tick()
|
|||
// We can't set motor currents to 0 here because that requires interrupts to be working, and we are in an ISR
|
||||
}
|
||||
|
||||
platform->SoftwareReset((uint16_t)SoftwareResetReason::stuckInSpin);
|
||||
// We now save the stack when we get stuck in a spin loop
|
||||
register const uint32_t * stackPtr asm ("sp");
|
||||
platform->SoftwareReset((uint16_t)SoftwareResetReason::stuckInSpin, stackPtr + 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
#define SRC_VERSION_H_
|
||||
|
||||
#ifndef VERSION
|
||||
# define VERSION "1.19beta4"
|
||||
# define VERSION "1.19beta5"
|
||||
#endif
|
||||
|
||||
#ifndef DATE
|
||||
# define DATE "2017-06-01"
|
||||
# define DATE "2017-06-04"
|
||||
#endif
|
||||
|
||||
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"
|
||||
|
|
Reference in a new issue