Added configurable PWM fan parameters:

- min PWM value (%)
- IRQs per rotation
This commit is contained in:
Blaž Kristan 2021-10-04 11:48:03 +02:00
parent b5c15d97fa
commit 5c9405fffc

View File

@ -26,11 +26,6 @@ class PWMFanUsermod : public Usermod {
bool initDone = false; bool initDone = false;
bool enabled = true; bool enabled = true;
const int numberOfInterrupsInOneSingleRotation = 2; // Number of interrupts ESP32 sees on tacho signal on a single fan rotation. All the fans I've seen trigger two interrups.
const int pwmMinimumValue = 120;
const int pwmStep = 10;
unsigned long msLastTachoMeasurement = 0; unsigned long msLastTachoMeasurement = 0;
uint16_t last_rpm = 0; uint16_t last_rpm = 0;
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
@ -46,6 +41,8 @@ class PWMFanUsermod : public Usermod {
int8_t pwmPin = -1; int8_t pwmPin = -1;
uint8_t tachoUpdateSec = 30; uint8_t tachoUpdateSec = 30;
float targetTemperature = 25.0; float targetTemperature = 25.0;
uint8_t minPWMValuePct = 50;
uint8_t numberOfInterrupsInOneSingleRotation = 2; // Number of interrupts ESP32 sees on tacho signal on a single fan rotation. All the fans I've seen trigger two interrups.
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
static const char _name[]; static const char _name[];
@ -54,6 +51,8 @@ class PWMFanUsermod : public Usermod {
static const char _pwmPin[]; static const char _pwmPin[];
static const char _temperature[]; static const char _temperature[];
static const char _tachoUpdateSec[]; static const char _tachoUpdateSec[];
static const char _minPWMValuePct[];
static const char _IRQperRotation[];
void initTacho(void) { void initTacho(void) {
if (tachoPin < 0 || !pinManager.allocatePin(tachoPin, false, PinOwner::UM_Unspecified)){ if (tachoPin < 0 || !pinManager.allocatePin(tachoPin, false, PinOwner::UM_Unspecified)){
@ -80,7 +79,7 @@ class PWMFanUsermod : public Usermod {
// detach interrupt while calculating rpm // detach interrupt while calculating rpm
detachInterrupt(digitalPinToInterrupt(tachoPin)); detachInterrupt(digitalPinToInterrupt(tachoPin));
// calculate rpm // calculate rpm
last_rpm = counter_rpm * (60 / numberOfInterrupsInOneSingleRotation); last_rpm = (counter_rpm * 60) / numberOfInterrupsInOneSingleRotation;
last_rpm /= tachoUpdateSec; last_rpm /= tachoUpdateSec;
// reset counter // reset counter
counter_rpm = 0; counter_rpm = 0;
@ -146,6 +145,8 @@ class PWMFanUsermod : public Usermod {
float difftemp = temp - targetTemperature; float difftemp = temp - targetTemperature;
// Default to run fan at full speed. // Default to run fan at full speed.
int newPWMvalue = 255; int newPWMvalue = 255;
int pwmStep = ((100 - minPWMValuePct) * newPWMvalue) / (7*100);
int pwmMinimumValue = (minPWMValuePct * newPWMvalue) / 100;
if ((temp == NAN) || (temp <= 0.0)) { if ((temp == NAN) || (temp <= 0.0)) {
DEBUG_PRINTLN(F("WARNING: no temperature value available. Cannot do temperature control. Will set PWM fan to 255.")); DEBUG_PRINTLN(F("WARNING: no temperature value available. Cannot do temperature control. Will set PWM fan to 255."));
@ -153,17 +154,17 @@ class PWMFanUsermod : public Usermod {
// Temperature is below target temperature. Run fan at minimum speed. // Temperature is below target temperature. Run fan at minimum speed.
newPWMvalue = pwmMinimumValue; newPWMvalue = pwmMinimumValue;
} else if (difftemp <= 0.5) { } else if (difftemp <= 0.5) {
newPWMvalue = 140; newPWMvalue = pwmMinimumValue + pwmStep;
} else if (difftemp <= 1.0) { } else if (difftemp <= 1.0) {
newPWMvalue = 160; newPWMvalue = pwmMinimumValue + 2*pwmStep;
} else if (difftemp <= 1.5) { } else if (difftemp <= 1.5) {
newPWMvalue = 180; newPWMvalue = pwmMinimumValue + 3*pwmStep;
} else if (difftemp <= 2.0) { } else if (difftemp <= 2.0) {
newPWMvalue = 200; newPWMvalue = pwmMinimumValue + 4*pwmStep;
} else if (difftemp <= 2.5) { } else if (difftemp <= 2.5) {
newPWMvalue = 220; newPWMvalue = pwmMinimumValue + 5*pwmStep;
} else if (difftemp <= 3.0) { } else if (difftemp <= 3.0) {
newPWMvalue = 240; newPWMvalue = pwmMinimumValue + 6*pwmStep;
} }
updateFanSpeed(newPWMvalue); updateFanSpeed(newPWMvalue);
} }
@ -179,7 +180,7 @@ class PWMFanUsermod : public Usermod {
#endif #endif
initTacho(); initTacho();
initPWMfan(); initPWMfan();
updateFanSpeed(pwmMinimumValue); updateFanSpeed((minPWMValuePct * 255) / 100); // inital fan speed
initDone = true; initDone = true;
} }
@ -250,6 +251,8 @@ class PWMFanUsermod : public Usermod {
top[FPSTR(_tachoPin)] = tachoPin; top[FPSTR(_tachoPin)] = tachoPin;
top[FPSTR(_tachoUpdateSec)] = tachoUpdateSec; top[FPSTR(_tachoUpdateSec)] = tachoUpdateSec;
top[FPSTR(_temperature)] = targetTemperature; top[FPSTR(_temperature)] = targetTemperature;
top[FPSTR(_minPWMValuePct)] = minPWMValuePct;
top[FPSTR(_IRQperRotation)] = numberOfInterrupsInOneSingleRotation;
DEBUG_PRINTLN(F("Autosave config saved.")); DEBUG_PRINTLN(F("Autosave config saved."));
} }
@ -280,6 +283,10 @@ class PWMFanUsermod : public Usermod {
tachoUpdateSec = top[FPSTR(_tachoUpdateSec)] | tachoUpdateSec; tachoUpdateSec = top[FPSTR(_tachoUpdateSec)] | tachoUpdateSec;
tachoUpdateSec = (uint8_t) max(1,(int)tachoUpdateSec); // bounds checking tachoUpdateSec = (uint8_t) max(1,(int)tachoUpdateSec); // bounds checking
targetTemperature = top[FPSTR(_temperature)] | targetTemperature; targetTemperature = top[FPSTR(_temperature)] | targetTemperature;
minPWMValuePct = top[FPSTR(_minPWMValuePct)] | minPWMValuePct;
minPWMValuePct = (uint8_t) min(100,max(0,(int)minPWMValuePct)); // bounds checking
numberOfInterrupsInOneSingleRotation = top[FPSTR(_IRQperRotation)] | numberOfInterrupsInOneSingleRotation;
numberOfInterrupsInOneSingleRotation = (uint8_t) max(1,(int)numberOfInterrupsInOneSingleRotation); // bounds checking
if (!initDone) { if (!initDone) {
// first run: reading from cfg.json // first run: reading from cfg.json
@ -302,7 +309,7 @@ class PWMFanUsermod : public Usermod {
} }
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return !top[FPSTR(_enabled)].isNull(); return !top[FPSTR(_IRQperRotation)].isNull();
} }
/* /*
@ -321,3 +328,5 @@ const char PWMFanUsermod::_tachoPin[] PROGMEM = "tacho-pin";
const char PWMFanUsermod::_pwmPin[] PROGMEM = "PWM-pin"; const char PWMFanUsermod::_pwmPin[] PROGMEM = "PWM-pin";
const char PWMFanUsermod::_temperature[] PROGMEM = "target-temp-C"; const char PWMFanUsermod::_temperature[] PROGMEM = "target-temp-C";
const char PWMFanUsermod::_tachoUpdateSec[] PROGMEM = "tacho-update-s"; const char PWMFanUsermod::_tachoUpdateSec[] PROGMEM = "tacho-update-s";
const char PWMFanUsermod::_minPWMValuePct[] PROGMEM = "min-PWM-percent";
const char PWMFanUsermod::_IRQperRotation[] PROGMEM = "IRQs-per-rotation";