1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-23 08:06:13 +01:00

new overload detection

This commit is contained in:
Harald Barth 2023-06-14 00:58:02 +02:00
parent 8a69403dda
commit f5d4dcb97c
3 changed files with 81 additions and 52 deletions

View File

@ -1 +1 @@
#define GITHUB_SHA "devel-202306031954Z" #define GITHUB_SHA "devel-202306132257Z"

View File

@ -154,11 +154,7 @@ MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, i
// senseFactorInternal, raw2mA(1000),mA2raw(1000)); // senseFactorInternal, raw2mA(1000),mA2raw(1000));
} }
// prepare values for current detection
sampleDelay = 0;
lastSampleTaken = millis();
progTripValue = mA2raw(TRIP_CURRENT_PROG); progTripValue = mA2raw(TRIP_CURRENT_PROG);
} }
bool MotorDriver::isPWMCapable() { bool MotorDriver::isPWMCapable() {
@ -167,6 +163,7 @@ bool MotorDriver::isPWMCapable() {
void MotorDriver::setPower(POWERMODE mode) { void MotorDriver::setPower(POWERMODE mode) {
if (powerMode == mode) return;
bool on=mode==POWERMODE::ON; bool on=mode==POWERMODE::ON;
if (on) { if (on) {
// when switching a track On, we need to check the crrentOffset with the pin OFF // when switching a track On, we need to check the crrentOffset with the pin OFF
@ -367,63 +364,86 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res
} }
void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) { void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) {
if (millis() - lastSampleTaken < sampleDelay) return; //if (millis() - lastSampleTaken < sampleDelay) return;
lastSampleTaken = millis(); //lastSampleTaken = millis();
int tripValue= useProgLimit?progTripValue:getRawCurrentTripValue(); int tripValue= useProgLimit?progTripValue:getRawCurrentTripValue();
// Trackname for diag messages later // check if there was a change from last time
if (powerMode != oldPowerMode) {
lastPowerChange = micros();
oldPowerMode = powerMode;
}
switch (powerMode) { switch (powerMode) {
case POWERMODE::OFF: case POWERMODE::OFF:
sampleDelay = POWER_SAMPLE_OFF_WAIT; if (microsSinceLastPowerChange() > 5000000UL) {
power_sample_overload_wait = 100UL;
}
break; break;
case POWERMODE::ON: case POWERMODE::ON:
// Check current // Check current
lastCurrent=getCurrentRaw(); lastCurrent=getCurrentRaw();
if (lastCurrent < 0) { if (lastCurrent < 0) {
// We have a fault pin condition to take care of // We have a fault pin condition to take care of
lastCurrent = -lastCurrent; lastCurrent = -lastCurrent;
setPower(POWERMODE::OVERLOAD); // Turn off, decide later how fast to turn on again if (commonFaultPin) {
if (commonFaultPin) { if (lastCurrent < tripValue) {
if (lastCurrent < tripValue) { // probably other track, do a fast toggle.
setPower(POWERMODE::ON); // maybe other track setPower(POWERMODE::OVERLOAD); // Turn off, decide later how fast to turn on again
} setPower(POWERMODE::ON); // maybe other track
// Write this after the fact as we want to turn on as fast as possible // Write this after the fact as we want to turn on as fast as possible
// because we don't know which output actually triggered the fault pin // because we don't know which output actually triggered the fault pin
DIAG(F("COMMON FAULT PIN ACTIVE: POWERTOGGLE TRACK %c"), trackno + 'A'); DIAG(F("COMMON FAULT PIN ACTIVE: POWERTOGGLE TRACK %c"), trackno + 'A');
} else {
DIAG(F("TRACK %c FAULT PIN ACTIVE - OVERLOAD"), trackno + 'A');
if (lastCurrent < tripValue) {
lastCurrent = tripValue; // exaggerate
}
} }
} else {
unsigned long us;
if (lastCurrent < tripValue) {
if (power_sample_overload_wait <= 1000UL && // almost virgin
(us = microsSinceLastPowerChange()) < 50000UL) { // Ignore 50ms fault pin if no current
DIAG(F("TRACK %c FAULT PIN ACTIVE - 50ms ignore %lus"), trackno + 'A', us);
break;
}
lastCurrent = tripValue; // exaggerate
} else {
if (power_sample_overload_wait <= 100UL && // virgin
microsSinceLastPowerChange() < 5000UL) { // Ignore 5ms fault pin if we see current
DIAG(F("TRACK %c FAULT PIN ACTIVE - 5ms ignore"), trackno + 'A');
break;
}
}
DIAG(F("TRACK %c FAULT PIN ACTIVE - for real"), trackno + 'A');
}
} }
// // //
if (lastCurrent < tripValue) { if (lastCurrent < tripValue) {
sampleDelay = POWER_SAMPLE_ON_WAIT; if (microsSinceLastPowerChange() > 5000000UL) {
if(power_good_counter<100) power_sample_overload_wait = 100UL;
power_good_counter++; }
else
if (power_sample_overload_wait>POWER_SAMPLE_OVERLOAD_WAIT) power_sample_overload_wait=POWER_SAMPLE_OVERLOAD_WAIT;
} else { } else {
setPower(POWERMODE::OVERLOAD); // too much current
unsigned int mA=raw2mA(lastCurrent); if (power_sample_overload_wait > 100UL || // not virgin
unsigned int maxmA=raw2mA(tripValue); microsSinceLastPowerChange() > 10000UL) { // Longer than 10ms
power_good_counter=0; setPower(POWERMODE::OVERLOAD);
sampleDelay = power_sample_overload_wait; unsigned int mA=raw2mA(lastCurrent);
DIAG(F("TRACK %c POWER OVERLOAD %dmA (limit %dmA) shutdown for %dms"), trackno + 'A', mA, maxmA, sampleDelay); unsigned int maxmA=raw2mA(tripValue);
if (power_sample_overload_wait >= 10000) DIAG(F("TRACK %c POWER OVERLOAD %dmA (limit %dmA) shutdown for %lus"),
power_sample_overload_wait = 10000; trackno + 'A', mA, maxmA, power_sample_overload_wait);
else }
power_sample_overload_wait *= 2;
} }
break; break;
case POWERMODE::OVERLOAD: case POWERMODE::OVERLOAD:
// Try setting it back on after the OVERLOAD_WAIT // Try setting it back on after the OVERLOAD_WAIT
if (microsSinceLastPowerChange() > power_sample_overload_wait) {
// adjust next wait time
power_sample_overload_wait *= 2;
if (power_sample_overload_wait > 10000000UL)
power_sample_overload_wait = 10000000UL;
// power on test
setPower(POWERMODE::ON); setPower(POWERMODE::ON);
sampleDelay = POWER_SAMPLE_ON_WAIT; DIAG(F("TRACK %c POWER RESTORE (check %lus)"), trackno + 'A', power_sample_overload_wait);
// Debug code.... }
DIAG(F("TRACK %c POWER RESTORE (check %dms)"), trackno + 'A', sampleDelay); break;
break; default:
default: break;
sampleDelay = 999; // cant get here..meaningless statement to avoid compiler warning.
} }
} }

View File

@ -186,6 +186,15 @@ class MotorDriver {
inline void setTrackLetter(char c) { inline void setTrackLetter(char c) {
trackLetter = c; trackLetter = c;
}; };
// this returns how much time has passed since the last power change. If it
// was really long ago (approx > 52min) advance counter approx 35 min so that
// we are at 18 minutes again. Times for 32 bit unsigned long.
inline unsigned long microsSinceLastPowerChange() {
unsigned long diff = micros() - lastPowerChange;
if (diff > (1UL << (6 *sizeof(unsigned long))))
lastPowerChange += 1UL << (4 * sizeof(unsigned long));
return diff;
};
#ifdef ANALOG_READ_INTERRUPT #ifdef ANALOG_READ_INTERRUPT
bool sampleCurrentFromHW(); bool sampleCurrentFromHW();
void startCurrentFromHW(); void startCurrentFromHW();
@ -217,8 +226,8 @@ class MotorDriver {
int rawCurrentTripValue; int rawCurrentTripValue;
// current sampling // current sampling
POWERMODE powerMode; POWERMODE powerMode;
unsigned long lastSampleTaken; POWERMODE oldPowerMode;
unsigned int sampleDelay; unsigned long lastPowerChange; // timestamp in microseconds
int progTripValue; int progTripValue;
int lastCurrent; int lastCurrent;
#ifdef ANALOG_READ_INTERRUPT #ifdef ANALOG_READ_INTERRUPT
@ -229,9 +238,9 @@ class MotorDriver {
int tripmA; int tripmA;
// Wait times for power management. Unit: milliseconds // Wait times for power management. Unit: milliseconds
static const int POWER_SAMPLE_ON_WAIT = 100; static const int POWER_SAMPLE_ON_WAIT = 1;
static const int POWER_SAMPLE_OFF_WAIT = 1000; static const int POWER_SAMPLE_OFF_WAIT = 100;
static const int POWER_SAMPLE_OVERLOAD_WAIT = 20; static const int POWER_SAMPLE_OVERLOAD_WAIT = 500UL;
// Trip current for programming track, 250mA. Change only if you really // Trip current for programming track, 250mA. Change only if you really
// need to be non-NMRA-compliant because of decoders that are not either. // need to be non-NMRA-compliant because of decoders that are not either.