diff options
Diffstat (limited to 'src/Fan.cpp')
-rw-r--r-- | src/Fan.cpp | 236 |
1 files changed, 196 insertions, 40 deletions
diff --git a/src/Fan.cpp b/src/Fan.cpp index efdcb737..46cb3b9b 100644 --- a/src/Fan.cpp +++ b/src/Fan.cpp @@ -8,10 +8,12 @@ #include "Fan.h" #include "Platform.h" #include "RepRap.h" +#include "GCodes/GCodeBuffer.h" +#include "Heating/Heat.h" void Fan::Init(Pin p_pin, bool hwInverted) { - val = 0.0; + val = lastVal = 0.0; minVal = 0.1; // 10% minimum fan speed blipTime = 100; // 100ms fan blip freq = DefaultFanPwmFreq; @@ -19,47 +21,150 @@ void Fan::Init(Pin p_pin, bool hwInverted) hardwareInverted = hwInverted; inverted = blipping = false; heatersMonitored = 0; - triggerTemperature = HOT_END_FAN_TEMPERATURE; - thermostatIsOn = false; + triggerTemperatures[0] = triggerTemperatures[1] = HOT_END_FAN_TEMPERATURE; lastPwm = -1.0; // force a refresh Refresh(); } -void Fan::SetValue(float speed) +// Set or report the parameters for this fan +// If 'mcode' is an M-code used to set parameters for the current kinematics (which should only ever be 106) +// then search for parameters used to configure the fan. If any are found, perform appropriate actions and return true. +// If errors were discovered while processing parameters, put an appropriate error message in 'reply' and set 'error' to true. +// If no relevant parameters are found, print the existing ones to 'reply' and return false. +// Exceptions: +// 1. Only process the S parameter unless other values were processed. +// 2. Don't process the R parameter, but if it is present don't print the existing configuration. +bool Fan::Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, StringRef& reply, bool& error) { - if (speed > 1.0) + if (!IsEnabled()) { - speed /= 255.0; + reply.printf("Fan %d is disabled", fanNum); + error = true; + return true; // say we have processed it } - const float newVal = constrain<float>(speed, 0.0, 1.0); - if (val == 0.0 && newVal > 0.0 && newVal < 1.0 && blipTime != 0) + + bool seen = false; + if (mcode == 106) { - // Starting the fan from standstill, so blip the fan - blipping = true; - blipStartTime = millis(); + if (gb.Seen('I')) // Invert cooling + { + seen = true; + const int invert = gb.GetIValue(); + if (invert < 0) + { + Disable(); + } + else + { + inverted = (invert > 0); + } + } + + if (gb.Seen('F')) // Set PWM frequency + { + seen = true; + freq = (uint16_t)constrain<int>(gb.GetIValue(), 1, 65535); + lastPwm = -1.0; // force the PWM to be updated + Refresh(); + } + + if (gb.Seen('T')) + { + seen = true; + size_t numTemps = 2; + gb.GetFloatArray(triggerTemperatures, numTemps, true); + } + + if (gb.Seen('B')) // Set blip time + { + seen = true; + blipTime = (uint32_t)(max<float>(gb.GetFValue(), 0.0) * SecondsToMillis); + } + + if (gb.Seen('L')) // Set minimum speed + { + seen = true; + float speed = gb.GetFValue(); + if (speed > 1.0) + { + speed /= 255.0; + } + minVal = constrain<float>(speed, 0.0, 1.0); + } + + if (gb.Seen('H')) // Set thermostatically-controlled heaters + { + seen = true; + long heaters[Heaters + MaxVirtualHeaters]; + size_t numH = ARRAY_SIZE(heaters); + gb.GetLongArray(heaters, numH); + + // Note that M106 H-1 disables thermostatic mode. The following code implements that automatically. + heatersMonitored = 0; + for (size_t h = 0; h < numH; ++h) + { + const int hnum = heaters[h]; + if (hnum >= 0 && hnum < (int)Heaters) + { + heatersMonitored |= (1u << (unsigned int)hnum); + } + else if (hnum >= (int)FirstVirtualHeater && hnum < (int)(FirstVirtualHeater + MaxVirtualHeaters)) + { + // Heaters 100, 101... are virtual heaters i.e. CPU and driver temperatures + heatersMonitored |= (1u << (Heaters + (unsigned int)hnum - FirstVirtualHeater)); + } + } + if (heatersMonitored != 0) + { + SetValue(1.0); // default the fan speed to full for safety + } + } + + // We only act on the 'S' parameter here if we have processed other parameters + if (seen && gb.Seen('S')) // Set new fan value - process this after processing 'H' or it may not be acted on + { + const float f = constrain<float>(gb.GetFValue(), 0.0, 255.0); + SetValue(f); + } + + if (seen) + { + Refresh(); + } + else if (!gb.Seen('R') && !gb.Seen('S')) + { + // Report the configuration of the specified fan + reply.printf("Fan%i frequency: %uHz, speed: %d%%, min: %d%%, blip: %.2f, inverted: %s", + fanNum, + (unsigned int)freq, + (int)(val * 100.0), + (int)(minVal * 100.0), + (float)blipTime * MillisToSeconds, + (inverted) ? "yes" : "no"); + if (heatersMonitored != 0) + { + reply.catf(", temperature: %.1f:%.1fC, heaters:", triggerTemperatures[0], triggerTemperatures[1]); + for (unsigned int i = 0; i < Heaters + MaxVirtualHeaters; ++i) + { + if ((heatersMonitored & (1u << i)) != 0) + { + reply.catf(" %u", (i < Heaters) ? i : FirstVirtualHeater + i - Heaters); + } + } + } + } } - val = newVal; - Refresh(); + + return seen; } -void Fan::SetMinValue(float speed) +void Fan::SetValue(float speed) { if (speed > 1.0) { speed /= 255.0; } - minVal = constrain<float>(speed, 0.0, 1.0); - Refresh(); -} - -void Fan::SetBlipTime(float t) -{ - blipTime = (uint32_t)(max<float>(t, 0.0) * SecondsToMillis); -} - -void Fan::SetInverted(bool inv) -{ - inverted = inv; + val = constrain<float>(speed, 0.0, 1.0); Refresh(); } @@ -88,17 +193,9 @@ void Fan::SetHardwarePwm(float pwmVal) } } -void Fan::SetPwmFrequency(float p_freq) -{ - freq = (uint16_t)constrain<float>(p_freq, 1.0, 65535.0); - lastPwm = -1.0; // force the PWM to be updated - Refresh(); -} - void Fan::SetHeatersMonitored(uint16_t h) { heatersMonitored = h; - thermostatIsOn = false; Refresh(); } @@ -107,19 +204,59 @@ void Fan::SetHeatersMonitored(uint16_t h) void Fan::Refresh() { float reqVal; +#ifdef DUET_NG + uint32_t driverChannelsMonitored = 0; +#endif + if (heatersMonitored == 0) { reqVal = val; } - else if (reprap.GetPlatform().AnyHeaterHot(heatersMonitored, (thermostatIsOn) ? triggerTemperature - ThermostatHysteresis : triggerTemperature)) - { - thermostatIsOn = true; - reqVal = max<float>(0.5, val); // make sure that thermostatic fans always run at 50% speed or more - } else { - thermostatIsOn = false; reqVal = 0.0; + const bool bangBangMode = (triggerTemperatures[1] <= triggerTemperatures[0]); + for (size_t h = 0; h < Heaters + MaxVirtualHeaters; ++h) + { + // Check if this heater is both monitored by this fan and in use + if ( ((1 << h) & heatersMonitored) != 0 + && (h < reprap.GetToolHeatersInUse() || h >= Heaters || (int)h == reprap.GetHeat().GetBedHeater() || (int)h == reprap.GetHeat().GetChamberHeater()) + ) + { + // This heater is both monitored and potentially active + if (h < Heaters && reprap.GetHeat().IsTuning(h)) + { + reqVal = 1.0; // when turning the PID for a monitored heater, turn the fan on + } + else + { + const size_t heaterHumber = (h >= Heaters) ? (h - Heaters) + FirstVirtualHeater : h; + TemperatureError err; + const float ht = reprap.GetHeat().GetTemperature(heaterHumber, err); + if (err != TemperatureError::success || ht < BAD_LOW_TEMPERATURE || ht >= triggerTemperatures[1]) + { + reqVal = max<float>(reqVal, (bangBangMode) ? max<float>(0.5, val) : 1.0); + } + else if (!bangBangMode && ht > triggerTemperatures[0]) + { + // We already know that ht < triggerTemperatures[1], therefore unless we have NaNs it is safe to divide by (triggerTemperatures[1] - triggerTemperatures[0]) + reqVal = max<float>(reqVal, (ht - triggerTemperatures[0])/(triggerTemperatures[1] - triggerTemperatures[0])); + } + else if (lastVal != 0.0 && ht + ThermostatHysteresis > triggerTemperatures[0]) + { + // If the fan is on, add a hysteresis before turning it off + reqVal = max<float>(reqVal, (bangBangMode) ? max<float>(0.5, val) : minVal); + } +#ifdef DUET_NG + const unsigned int channel = reprap.GetHeat().GetHeaterChannel(heaterHumber); + if (channel >= FirstTmcDriversSenseChannel && channel < FirstTmcDriversSenseChannel + NumTmcDriversSenseChannels) + { + driverChannelsMonitored |= 1 << (channel - FirstTmcDriversSenseChannel); + } +#endif + } + } + } } if (reqVal > 0.0) @@ -129,6 +266,23 @@ void Fan::Refresh() reqVal = minVal; } + if (lastVal == 0.0) + { + // We are turning this fan on +#ifdef DUET_NG + if (driverChannelsMonitored != 0) + { + reprap.GetPlatform().DriverCoolingFansOn(driverChannelsMonitored); // tell Platform that we have started a fan that cools drivers + } +#endif + if (reqVal < 1.0 && blipTime != 0) + { + // Starting the fan from standstill, so blip the fan + blipping = true; + blipStartTime = millis(); + } + } + if (blipping) { if (millis() - blipStartTime < blipTime) @@ -141,7 +295,9 @@ void Fan::Refresh() } } } + SetHardwarePwm(reqVal); + lastVal = reqVal; } void Fan::Check() |