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:
David Crocker 2017-06-04 09:54:49 +01:00
parent a915f98447
commit fe571d4396
12 changed files with 124 additions and 19 deletions

View file

@ -105,12 +105,13 @@ static_assert(DefaultMaxTempExcursion > TEMPERATURE_CLOSE_ENOUGH, "DefaultMaxTem
// Temperature sense channels // Temperature sense channels
const unsigned int FirstThermocoupleChannel = 100; // Temperature sensor channels 100... are thermocouples 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 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 // PWM frequencies
const unsigned int SlowHeaterPwmFreq = 10; // slow PWM frequency for bed and chamber heaters, compatible with DC/AC SSRs 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 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 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 // Default Z probe values

View file

@ -177,6 +177,7 @@ void NetworkResponder::ConnectionLost()
{ {
CancelUpload(); CancelUpload();
OutputBuffer::ReleaseAll(outBuf); OutputBuffer::ReleaseAll(outBuf);
outBuf = nullptr;
outStack->ReleaseAll(); outStack->ReleaseAll();
if (fileBeingSent != nullptr) if (fileBeingSent != nullptr)

View file

@ -3147,6 +3147,7 @@ void GCodes::SetHeaterParameters(GCodeBuffer& gb, StringRef& reply)
if ( (0 <= thermistor && thermistor < HEATERS) if ( (0 <= thermistor && thermistor < HEATERS)
|| ((int)FirstThermocoupleChannel <= thermistor && thermistor < (int)(FirstThermocoupleChannel + MaxSpiTempSensors)) || ((int)FirstThermocoupleChannel <= thermistor && thermistor < (int)(FirstThermocoupleChannel + MaxSpiTempSensors))
|| ((int)FirstRtdChannel <= thermistor && thermistor < (int)(FirstRtdChannel + MaxSpiTempSensors)) || ((int)FirstRtdChannel <= thermistor && thermistor < (int)(FirstRtdChannel + MaxSpiTempSensors))
|| ((int)FirstLinearAdcChannel <= thermistor && thermistor < (int)(FirstLinearAdcChannel + MaxSpiTempSensors))
) )
{ {
platform.SetThermistorNumber(heater, thermistor); platform.SetThermistorNumber(heater, thermistor);

View file

@ -48,16 +48,19 @@
const uint32_t MAX31855_Frequency = 4000000; // maximum for MAX31855 is 5MHz 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 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: // 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): // 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. // 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. // 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 MAX31855_SpiMode = SPI_MODE_0;
const uint8_t MAX31865_SpiMode = SPI_MODE_1; 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. // 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 const uint32_t MinimumReadInterval = 100; // minimum interval between reads, in milliseconds
@ -175,11 +178,38 @@ TemperatureError TemperatureSensor::TryInitRtd() const
: sts; : 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) if (inInterrupt() || millis() - lastReadingTime < MinimumReadInterval)
{ {
*t = lastTemperature; t = lastTemperature;
} }
else else
{ {
@ -247,7 +277,7 @@ TemperatureError TemperatureSensor::GetThermocoupleTemperature(float *t)
rawVal |= (0 - (rawVal & 0x2000)); // sign-extend the sign bit rawVal |= (0 - (rawVal & 0x2000)); // sign-extend the sign bit
// And convert to from units of 1/4C to 1C // 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; lastResult = TemperatureError::success;
} }
} }
@ -255,11 +285,11 @@ TemperatureError TemperatureSensor::GetThermocoupleTemperature(float *t)
return lastResult; return lastResult;
} }
TemperatureError TemperatureSensor::GetRtdTemperature(float *t) TemperatureError TemperatureSensor::GetRtdTemperature(float& t)
{ {
if (inInterrupt() || millis() - lastReadingTime < MinimumReadInterval) if (inInterrupt() || millis() - lastReadingTime < MinimumReadInterval)
{ {
*t = lastTemperature; t = lastTemperature;
} }
else else
{ {
@ -325,7 +355,7 @@ TemperatureError TemperatureSensor::GetRtdTemperature(float *t)
else else
{ {
const float interpolationFraction = (float)(adcVal - tempTable[low - 1].adcReading)/(float)(tempTable[low].adcReading - tempTable[low - 1].adcReading); 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; + (float)tempTable[low - 1].temperature;
//debugPrintf("raw %u low %u interp %f temp %f\n", adcVal, low, interpolationFraction, *t); //debugPrintf("raw %u low %u interp %f temp %f\n", adcVal, low, interpolationFraction, *t);
lastResult = TemperatureError::success; lastResult = TemperatureError::success;
@ -336,6 +366,49 @@ TemperatureError TemperatureSensor::GetRtdTemperature(float *t)
return lastResult; 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 // 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 TemperatureError TemperatureSensor::DoSpiTransaction(const uint8_t dataOut[], size_t nbytes, uint32_t& rslt) const
{ {

View file

@ -11,17 +11,23 @@ public:
TemperatureSensor() {} TemperatureSensor() {}
void InitThermocouple(uint8_t cs); void InitThermocouple(uint8_t cs);
void InitRtd(uint8_t cs); void InitRtd(uint8_t cs);
TemperatureError GetThermocoupleTemperature(float *temp); void InitLinearAdc(uint8_t cs);
TemperatureError GetRtdTemperature(float *temp); TemperatureError GetThermocoupleTemperature(float& t);
TemperatureError GetRtdTemperature(float& t);
TemperatureError GetLinearAdcTemperature(float& t);
private: private:
TemperatureError DoSpiTransaction(const uint8_t dataOut[], size_t nbytes, uint32_t& rslt) const; TemperatureError DoSpiTransaction(const uint8_t dataOut[], size_t nbytes, uint32_t& rslt) const;
TemperatureError TryInitRtd() const; TemperatureError TryInitRtd() const;
void TryGetLinearAdcTemperature();
sspi_device device; sspi_device device;
uint32_t lastReadingTime; uint32_t lastReadingTime;
float lastTemperature; float lastTemperature;
TemperatureError lastResult; 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 #endif // TEMPERATURESENSOR_H

View file

@ -408,7 +408,7 @@ size_t OutputBuffer::EncodeReply(OutputBuffer *src, bool allowControlChars)
/*static */ OutputBuffer *OutputBuffer::Release(OutputBuffer *buf) /*static */ OutputBuffer *OutputBuffer::Release(OutputBuffer *buf)
{ {
const irqflags_t flags = cpu_irq_save(); 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 this one is reused by another piece of code, don't free it up
if (buf->references > 1) if (buf->references > 1)

View file

@ -640,6 +640,10 @@ void Platform::SetThermistorNumber(size_t heater, size_t thermistor)
{ {
SpiTempSensors[thermistor - FirstRtdChannel].InitRtd(spiTempSenseCsPins[thermistor - FirstRtdChannel]); 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); reprap.GetHeat().ResetFault(heater);
} }
@ -2067,7 +2071,7 @@ float Platform::GetTemperature(size_t heater, TemperatureError& err)
{ {
// MAX31855 thermocouple chip // MAX31855 thermocouple chip
float temp; float temp;
err = SpiTempSensors[heaterTempChannels[heater] - FirstThermocoupleChannel].GetThermocoupleTemperature(&temp); err = SpiTempSensors[heaterTempChannels[heater] - FirstThermocoupleChannel].GetThermocoupleTemperature(temp);
return (err == TemperatureError::success) ? temp : BAD_ERROR_TEMPERATURE; return (err == TemperatureError::success) ? temp : BAD_ERROR_TEMPERATURE;
} }
@ -2075,7 +2079,15 @@ float Platform::GetTemperature(size_t heater, TemperatureError& err)
{ {
// MAX31865 RTD chip // MAX31865 RTD chip
float temp; 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; return (err == TemperatureError::success) ? temp : BAD_ERROR_TEMPERATURE;
} }
@ -2929,7 +2941,7 @@ void Platform::Message(const MessageType type, OutputBuffer *buffer)
break; break;
case HOST_MESSAGE: case HOST_MESSAGE:
if (!SERIAL_MAIN_DEVICE if ( !SERIAL_MAIN_DEVICE
#if SUPPORT_SCANNER #if SUPPORT_SCANNER
|| (reprap.GetScanner().IsRegistered() && !reprap.GetScanner().DoingGCodes()) || (reprap.GetScanner().IsRegistered() && !reprap.GetScanner().DoingGCodes())
#endif #endif

View file

@ -537,6 +537,9 @@ public:
bool IsRtdChannel(uint8_t heater) const bool IsRtdChannel(uint8_t heater) const
pre(heater < HEATERS); pre(heater < HEATERS);
bool IsLinearAdcChannel(uint8_t heater) const
pre(heater < HEATERS);
void UpdateConfiguredHeaters(); void UpdateConfiguredHeaters();
bool AnyHeaterHot(uint16_t heaters, float t); // called to see if we need to turn on the hot end fan 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; && 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 inline const uint8_t* Platform::GetIPAddress() const
{ {
return ipAddress; return ipAddress;

View file

@ -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 // 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);
} }
} }
} }

View file

@ -9,11 +9,11 @@
#define SRC_VERSION_H_ #define SRC_VERSION_H_
#ifndef VERSION #ifndef VERSION
# define VERSION "1.19beta4" # define VERSION "1.19beta5"
#endif #endif
#ifndef DATE #ifndef DATE
# define DATE "2017-06-01" # define DATE "2017-06-04"
#endif #endif
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman" #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"