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
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

View file

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

View file

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

View file

@ -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
{

View file

@ -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

View file

@ -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)

View file

@ -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
)
{

View file

@ -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;

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
}
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_
#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"