diff --git a/src/Heating/LocalHeater.cpp b/src/Heating/LocalHeater.cpp
index d22a43735..d87f29b83 100644
--- a/src/Heating/LocalHeater.cpp
+++ b/src/Heating/LocalHeater.cpp
@@ -287,64 +287,64 @@ void LocalHeater::Spin() noexcept
 		{
 			// Get the target temperature and the error
 			const float targetTemperature = min<float>(GetTargetTemperature() + extrusionTemperatureBoost, GetHighestTemperatureLimit());
-			const float error = targetTemperature - temperature;
 
-			if (extrusionTemperatureBoost != 0.0 || lastExtrusionTemperatureBoost != extrusionTemperatureBoost)
+			if (IsPidMode(mode) && extrusionTemperatureBoost != lastExtrusionTemperatureBoost)
 			{
 				// Calculate new heater mode to prevent heater fault due to exceededAllowedExcursion
-				String<1> dummy;
-				(void)SwitchOn(dummy.GetRef());
+				mode = (temperature + TemperatureCloseEnough < targetTemperature) ? HeaterMode::heating
+						: (temperature > targetTemperature + TemperatureCloseEnough) ? HeaterMode::cooling
+							: HeaterMode::stable;
+				lastExtrusionTemperatureBoost = extrusionTemperatureBoost;
 			}
-			lastExtrusionTemperatureBoost = extrusionTemperatureBoost;
+
+			const float error = targetTemperature - temperature;
 
 			// Do the heating checks
-			switch(mode)
+			switch (mode)
 			{
 			case HeaterMode::heating:
+				if (error <= TemperatureCloseEnough)
 				{
-					if (error <= TemperatureCloseEnough)
+					mode = HeaterMode::stable;
+					heatingFaultCount = 0;
+				}
+				else
+				{
+					const uint32_t now = millis();
+					if ((float)(now - timeSetHeating) < GetModel().GetDeadTime() * SecondsToMillis * 2)		// wait for twice the dead time before we start looking at the temperature rise
 					{
-						mode = HeaterMode::stable;
-						heatingFaultCount = 0;
+						// Record the temperature for when we are past the dead time
+						lastTemperatureValue = temperature;
+						lastTemperatureMillis = now;
 					}
-					else
+					else if (gotDerivative)												// this is a check in case we just had a temperature spike
 					{
-						const uint32_t now = millis();
-						if ((float)(now - timeSetHeating) < GetModel().GetDeadTime() * SecondsToMillis * 2)		// wait for twice the dead time before we start looking at the temperature rise
-						{
-							// Record the temperature for when we are past the dead time
-							lastTemperatureValue = temperature;
-							lastTemperatureMillis = now;
-						}
-						else if (gotDerivative)												// this is a check in case we just had a temperature spike
+						const float expectedRate = GetExpectedHeatingRate();
+						const float minSamplingInterval = 3.0/expectedRate;				// only check the temperature when we expect at least 3C rise since last time
+						const float actualInterval = (float)(now - lastTemperatureMillis) * MillisToSeconds;
+						if (actualInterval >= minSamplingInterval)
 						{
-							const float expectedRate = GetExpectedHeatingRate();
-							const float minSamplingInterval = 3.0/expectedRate;				// only check the temperature when we expect at least 3C rise since last time
-							const float actualInterval = (float)(now - lastTemperatureMillis) * MillisToSeconds;
-							if (actualInterval >= minSamplingInterval)
+							// Check that we are heating fast enough, and if so, take another sample
+							const float expectedTemperatureRise = expectedRate * actualInterval;
+							const float actualTemperatureRise = temperature - lastTemperatureValue;
+							// Bed heaters sometimes have much slower long term heating rates than their short term heating rates, so allow them a lower measured heating rate
+							if (actualTemperatureRise < expectedTemperatureRise * ((IsBedOrChamber()) ? MinBedTemperatureRiseFactor : MinToolTemperatureRiseFactor))
 							{
-								// Check that we are heating fast enough, and if so, take another sample
-								const float expectedTemperatureRise = expectedRate * actualInterval;
-								const float actualTemperatureRise = temperature - lastTemperatureValue;
-								// Bed heaters sometimes have much slower long term heating rates than their short term heating rates, so allow them a lower measured heating rate
-								if (actualTemperatureRise < expectedTemperatureRise * ((IsBedOrChamber()) ? MinBedTemperatureRiseFactor : MinToolTemperatureRiseFactor))
+								++heatingFaultCount;
+								if (heatingFaultCount * HeatSampleIntervalMillis > GetMaxHeatingFaultTime() * SecondsToMillis)
 								{
-									++heatingFaultCount;
-									if (heatingFaultCount * HeatSampleIntervalMillis > GetMaxHeatingFaultTime() * SecondsToMillis)
-									{
-										RaiseHeaterFault(HeaterFaultType::temperatureRisingTooSlowly,
-															"expected %.2f" DEGREE_SYMBOL "C/sec measured %.2f" DEGREE_SYMBOL "C/sec",
-																(double)expectedRate, (double)(actualTemperatureRise/actualInterval));
-									}
+									RaiseHeaterFault(HeaterFaultType::temperatureRisingTooSlowly,
+														"expected %.2f" DEGREE_SYMBOL "C/sec measured %.2f" DEGREE_SYMBOL "C/sec",
+															(double)expectedRate, (double)(actualTemperatureRise/actualInterval));
 								}
-								else
+							}
+							else
+							{
+								lastTemperatureValue = temperature;
+								lastTemperatureMillis = now;
+								if (heatingFaultCount != 0)
 								{
-									lastTemperatureValue = temperature;
-									lastTemperatureMillis = now;
-									if (heatingFaultCount != 0)
-									{
-										--heatingFaultCount;
-									}
+									--heatingFaultCount;
 								}
 							}
 						}
diff --git a/src/Movement/DDARing.cpp b/src/Movement/DDARing.cpp
index 4760195e3..f28e9a3f7 100644
--- a/src/Movement/DDARing.cpp
+++ b/src/Movement/DDARing.cpp
@@ -84,6 +84,7 @@ void DDARing::Init1(unsigned int numDdas) noexcept
 
 	getPointer = addPointer;
 	lastFeedForwardTool = nullptr;
+	lastAverageExtrusionSpeed = 0.0;
 }
 
 // This must be called from Move::Init, not from the Move constructor, because it indirectly refers to the GCodes module which must therefore be initialised first
@@ -731,6 +732,8 @@ uint32_t DDARing::ManageIOBitsAndFeedForward() noexcept
 	SetBasePriority(NvicPriorityStep);
 	DDA *cdda = getPointer;
 	const uint32_t now = StepTimer::GetMovementTimerTicks();
+	const Tool *_ecv_null feedForwardTool;
+	float feedForwardAverageExtrusionSpeed = 0.0;
 
 	while (cdda->IsCommitted())
 	{
@@ -752,22 +755,25 @@ uint32_t DDARing::ManageIOBitsAndFeedForward() noexcept
 			}
 		}
 
-		const Tool *_ecv_null t;
-		if (!doneFeedForward && (t = cdda->GetTool()) != nullptr && timeToMoveStart < (int32_t)t->GetFeedForwardAdvanceClocks() && timeToMoveEnd > (int32_t)t->GetFeedForwardAdvanceClocks())
+		if (!doneFeedForward)
 		{
-			// This move is current from the perspective of feedforward
-			if (!cdda->HaveDoneFeedForward())
+			feedForwardTool = cdda->GetTool();
+			if (feedForwardTool != nullptr && timeToMoveStart < (int32_t)feedForwardTool->GetFeedForwardAdvanceClocks() && timeToMoveEnd > (int32_t)feedForwardTool->GetFeedForwardAdvanceClocks())
 			{
-				// Don't set feedforward here because we have set a very high base priority and we may need to send CAN messages. Just record that we need to set it.
-				setFeedForward = true;
-				lastFeedForwardTool = t;
-				cdda->SetDoneFeedForward();
-			}
-			nextWakeupDelay = min<uint32_t>(nextWakeupDelay, (uint32_t)timeToMoveEnd > t->GetFeedForwardAdvanceClocks());
-			doneFeedForward = true;
-			if (doneIoBits)
-			{
-				break;
+				// This move is current from the perspective of feedforward
+				if (!cdda->HaveDoneFeedForward())
+				{
+					// Don't set feedforward here because we have set a very high base priority and we may need to send CAN messages. Just record that we need to set it.
+					cdda->SetDoneFeedForward();
+					feedForwardAverageExtrusionSpeed = cdda->GetAverageExtrusionSpeed();
+					setFeedForward = true;
+				}
+				nextWakeupDelay = min<uint32_t>(nextWakeupDelay, (uint32_t)timeToMoveEnd > feedForwardTool->GetFeedForwardAdvanceClocks());
+				doneFeedForward = true;
+				if (doneIoBits)
+				{
+					break;
+				}
 			}
 		}
 		cdda = cdda->GetNext();
@@ -782,12 +788,18 @@ uint32_t DDARing::ManageIOBitsAndFeedForward() noexcept
 
 	if (setFeedForward)
 	{
-		lastFeedForwardTool->ApplyExtrusionFeedForward(cdda->GetAverageExtrusionSpeed());
+		if (feedForwardTool != lastFeedForwardTool || fabsf(feedForwardAverageExtrusionSpeed - lastAverageExtrusionSpeed) > lastAverageExtrusionSpeed * 0.05)
+		{
+			feedForwardTool->ApplyExtrusionFeedForward(feedForwardAverageExtrusionSpeed);
+			lastFeedForwardTool = feedForwardTool;
+			lastAverageExtrusionSpeed = feedForwardAverageExtrusionSpeed;
+		}
 	}
-	else if (!doneFeedForward && lastFeedForwardTool != nullptr)
+	else if (!doneFeedForward && lastFeedForwardTool != nullptr && lastAverageExtrusionSpeed != 0.0)
 	{
 		lastFeedForwardTool->StopExtrusionFeedForward();							// no move with a tool active so cancel the last feedforward we commanded
 		lastFeedForwardTool = nullptr;
+		lastAverageExtrusionSpeed = 0.0;
 	}
 
 	return (nextWakeupDelay + StepClockRate/1000 - 1)/(StepClockRate/1000);			// convert step clocks to milliseconds, rounding up
diff --git a/src/Movement/DDARing.h b/src/Movement/DDARing.h
index 0db2cf07f..8b946f73a 100644
--- a/src/Movement/DDARing.h
+++ b/src/Movement/DDARing.h
@@ -98,6 +98,7 @@ class DDARing INHERIT_OBJECT_MODEL
 	uint32_t gracePeriod;														// The minimum idle time in milliseconds, before we should start a move. Better to have a few moves in the queue so that we can do lookahead
 
 	const Tool *_ecv_null lastFeedForwardTool;									// the tool we last applied heater feedforward to
+	float lastAverageExtrusionSpeed;											// the extrusion speed we last set heater feedforward for
 
 	uint32_t scheduledMoves;													// Number of moves scheduled in this ring
 	uint32_t completedMoves;													// Number of moves completed in this ring
diff --git a/src/Version.h b/src/Version.h
index 905ca2335..528222911 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -10,7 +10,7 @@
 
 #ifndef VERSION
 // Note: the complete VERSION string must be in standard version number format and must not contain spaces! This is so that DWC can parse it.
-# define MAIN_VERSION	"3.6.0-beta.1+3"
+# define MAIN_VERSION	"3.6.0-beta.2"
 # ifdef USE_CAN0
 #  define VERSION_SUFFIX	"(CAN0)"
 # else