From 9c5e48c3d5f9b4c6a99bb713468a8dc6bec54e88 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 30 Jun 2023 02:05:10 +0200 Subject: [PATCH 01/10] test more tolerant alg --- MotorDriver.cpp | 17 ++++++++++++----- MotorDriver.h | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 12a263c..1d7b2bc 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -401,22 +401,26 @@ void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) { lastCurrent = -lastCurrent; { if (lastCurrent < tripValue) { - if (power_sample_overload_wait <= (POWER_SAMPLE_OVERLOAD_WAIT * 10) && // almost virgin + if (/*power_sample_overload_wait <= (POWER_SAMPLE_OVERLOAD_WAIT * 10) &&*/ // almost virgin microsSinceLastPowerChange() < POWER_SAMPLE_IGNORE_FAULT_LOW) { // Ignore 50ms fault pin if no current DIAG(F("TRACK %c FAULT PIN (50ms ignore)"), trackno + 'A'); break; } - lastCurrent = tripValue; // exaggerate so condition below (*) is true + setPower(POWERMODE::OVERLOAD); + overloadNow=false; + DIAG(F("TRACK %c FAULT PIN"), trackno + 'A'); + break; + //lastCurrent = tripValue; // exaggerate so condition below (*) is true } else { - if (power_sample_overload_wait <= POWER_SAMPLE_OVERLOAD_WAIT && // virgin + if (/*power_sample_overload_wait <= POWER_SAMPLE_OVERLOAD_WAIT && */ // virgin microsSinceLastPowerChange() < POWER_SAMPLE_IGNORE_FAULT_HIGH) { // Ignore 5ms fault pin if we see current DIAG(F("TRACK %c FAULT PIN (5ms ignore)"), trackno + 'A'); break; } } - DIAG(F("TRACK %c FAULT PIN"), trackno + 'A'); + DIAG(F("TRACK %c FAULT PIN AND OVERCURRENT"), trackno + 'A'); } } // // // @@ -441,8 +445,11 @@ void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) { setLastPowerChange(); } unsigned long uSecs = microsSinceLastPowerChange(); - if (power_sample_overload_wait > POWER_SAMPLE_OVERLOAD_WAIT || // not virgin + if (/*power_sample_overload_wait > POWER_SAMPLE_OVERLOAD_WAIT || */ // not virgin uSecs > POWER_SAMPLE_OFF_DELAY) { + /* + if (micros() - overloadStart > POWER_SAMPLE_OFF_DELAY) { + */ // Overload has existed longer than delay (typ. 10ms) setPower(POWERMODE::OVERLOAD); if (overloadNow) { diff --git a/MotorDriver.h b/MotorDriver.h index b268aea..b6f4670 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -256,7 +256,7 @@ class MotorDriver { // Times for overload management. Unit: microseconds. // Base for wait time until power is turned on again - static const unsigned long POWER_SAMPLE_OVERLOAD_WAIT = 100UL; + static const unsigned long POWER_SAMPLE_OVERLOAD_WAIT = 10000UL; // Time after we consider all faults old and forgotten static const unsigned long POWER_SAMPLE_ALL_GOOD = 5000000UL; // How long to ignore fault pin if current is under limit @@ -264,7 +264,7 @@ class MotorDriver { // How long to ignore fault pin if current is higher than limit static const unsigned long POWER_SAMPLE_IGNORE_FAULT_HIGH = 5000UL; // How long to wait between overcurrent and turning off - static const unsigned long POWER_SAMPLE_OFF_DELAY = 10000UL; + static const unsigned long POWER_SAMPLE_OFF_DELAY = 100000UL; // Upper limit for retry period static const unsigned long POWER_SAMPLE_RETRY_MAX = 10000000UL; From 7c41ec7c25efc8d8576ffa8943b72f2135bd7986 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Fri, 30 Jun 2023 02:06:12 +0200 Subject: [PATCH 02/10] version tag --- GITHUB_SHA.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 6ae3e6c..0f05328 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-202306261801Z" +#define GITHUB_SHA "devel-overcurrent-202306300005Z" From 70d4c016ef79e09af5189735154073061ff85693 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sun, 2 Jul 2023 01:33:41 +0200 Subject: [PATCH 03/10] completely new overcurrent detection --- GITHUB_SHA.h | 2 +- MotorDriver.cpp | 193 +++++++++++++++++++++++------------------------- MotorDriver.h | 48 ++++++------ version.h | 3 +- 4 files changed, 121 insertions(+), 125 deletions(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 0f05328..07d9123 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-overcurrent-202306300005Z" +#define GITHUB_SHA "devel-overcurrent-202307012332Z" diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 1d7b2bc..e05059b 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -173,7 +173,11 @@ bool MotorDriver::isPWMCapable() { void MotorDriver::setPower(POWERMODE mode) { if (powerMode == mode) return; - bool on=mode==POWERMODE::ON; + //DIAG(F("POWERMODE=%d"), (int)mode); + lastPowerChange[(int)mode] = micros(); + if (mode == POWERMODE::OVERLOAD) + globalOverloadStart = lastPowerChange[(int)mode]; + bool on=(mode==POWERMODE::ON || mode ==POWERMODE::ALERT); if (on) { // when switching a track On, we need to check the crrentOffset with the pin OFF if (powerMode==POWERMODE::OFF && currentPin!=UNUSED_PIN) { @@ -213,8 +217,8 @@ bool MotorDriver::canMeasureCurrent() { return currentPin!=UNUSED_PIN; } /* - * Return the current reading as pin reading 0 to 1023. If the fault - * pin is activated return a negative current to show active fault pin. + * Return the current reading as pin reading 0 to max resolution (1024 or 4096). + * If the fault pin is activated return a negative current to show active fault pin. * As there is no -0, cheat a little and return -1 in that case. * * senseOffset handles the case where a shield returns values above or below @@ -373,118 +377,103 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res } void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) { - int tripValue= useProgLimit?progTripValue:getRawCurrentTripValue(); switch (powerMode) { - case POWERMODE::OFF: - if (overloadNow) { - // reset overload condition as we have just turned off power - // DIAG(F("OVERLOAD POFF OFF")); - overloadNow=false; - setLastPowerChange(); - } - if (microsSinceLastPowerChange() > POWER_SAMPLE_ALL_GOOD) { - power_sample_overload_wait = POWER_SAMPLE_OVERLOAD_WAIT; - } - break; - case POWERMODE::ON: - // Check current - lastCurrent=getCurrentRaw(); - if (lastCurrent < 0) { - // We have a fault pin condition to take care of - if (!overloadNow) { - // turn on overload condition as fault pin has gone active - // DIAG(F("OVERLOAD FPIN ON")); - overloadNow=true; - setLastPowerChangeOverload(); - } - lastCurrent = -lastCurrent; - { - if (lastCurrent < tripValue) { - if (/*power_sample_overload_wait <= (POWER_SAMPLE_OVERLOAD_WAIT * 10) &&*/ // almost virgin - microsSinceLastPowerChange() < POWER_SAMPLE_IGNORE_FAULT_LOW) { - // Ignore 50ms fault pin if no current - DIAG(F("TRACK %c FAULT PIN (50ms ignore)"), trackno + 'A'); - break; - } - setPower(POWERMODE::OVERLOAD); - overloadNow=false; - DIAG(F("TRACK %c FAULT PIN"), trackno + 'A'); - break; - //lastCurrent = tripValue; // exaggerate so condition below (*) is true - } else { - if (/*power_sample_overload_wait <= POWER_SAMPLE_OVERLOAD_WAIT && */ // virgin - microsSinceLastPowerChange() < POWER_SAMPLE_IGNORE_FAULT_HIGH) { - // Ignore 5ms fault pin if we see current - DIAG(F("TRACK %c FAULT PIN (5ms ignore)"), trackno + 'A'); - break; - } - } - DIAG(F("TRACK %c FAULT PIN AND OVERCURRENT"), trackno + 'A'); - } - } - // // // - // above we looked at fault pin, below we look at current - // // // - if (lastCurrent < tripValue) { // see above (*) - if (overloadNow) { - // current is below trip value, turn off overload condition - // DIAG(F("OVERLOAD PON OFF")); - overloadNow=false; - setLastPowerChange(); - } - if (microsSinceLastPowerChange() > POWER_SAMPLE_ALL_GOOD) { - power_sample_overload_wait = POWER_SAMPLE_OVERLOAD_WAIT; - } + + case POWERMODE::OFF: { + lastPowerMode = POWERMODE::OFF; + power_sample_overload_wait = POWER_SAMPLE_OVERLOAD_WAIT; + break; + } + + case POWERMODE::ON: { + lastPowerMode = POWERMODE::ON; + bool cF = checkFault(); + bool cC = checkCurrent(useProgLimit); + if(cF || cC ) { + if (cC) { + unsigned int mA=raw2mA(lastCurrent); + DIAG(F("TRACK %c ALERT %s %dmA"), trackno + 'A', + cF ? "FAULT" : "", + mA); } else { - // too much current - if (!overloadNow) { - // current is over trip value, turn on overload condition - // DIAG(F("OVERLOAD PON ON")); - overloadNow=true; - setLastPowerChange(); - } - unsigned long uSecs = microsSinceLastPowerChange(); - if (/*power_sample_overload_wait > POWER_SAMPLE_OVERLOAD_WAIT || */ // not virgin - uSecs > POWER_SAMPLE_OFF_DELAY) { - /* - if (micros() - overloadStart > POWER_SAMPLE_OFF_DELAY) { - */ - // Overload has existed longer than delay (typ. 10ms) - setPower(POWERMODE::OVERLOAD); - if (overloadNow) { - // the setPower just turned off, so overload is now gone - // DIAG(F("OVERLOAD PON OFF")); - overloadNow=false; - setLastPowerChangeOverload(); - } - unsigned int mA=raw2mA(lastCurrent); - unsigned int maxmA=raw2mA(tripValue); - DIAG(F("TRACK %c POWER OVERLOAD %4dmA (max %4dmA) detected after %4M. Pause %4M"), - trackno + 'A', mA, maxmA, uSecs, power_sample_overload_wait); - } + DIAG(F("TRACK %c ALERT FAULT"), trackno + 'A'); } + setPower(POWERMODE::ALERT); break; - case POWERMODE::OVERLOAD: - { - // Try setting it back on after the OVERLOAD_WAIT - unsigned long mslpc = (commonFaultPin ? (micros() - globalOverloadStart) : microsSinceLastPowerChange()); + } + // all well + if (microsSinceLastPowerChange(POWERMODE::ON) > POWER_SAMPLE_ALL_GOOD) { + power_sample_overload_wait = POWER_SAMPLE_OVERLOAD_WAIT; + } + break; + } + + case POWERMODE::ALERT: { + // set local flags that handle how much is output to diag (do not output duplicates) + bool notFromOverload = (lastPowerMode != POWERMODE::OVERLOAD); + bool newPowerMode = (powerMode != lastPowerMode); + unsigned long now = micros(); + if (newPowerMode) + lastBadSample = now; + lastPowerMode = POWERMODE::ALERT; + // check how long we have been in this state + unsigned long mslpc = microsSinceLastPowerChange(POWERMODE::ALERT); + if(checkFault()) { + lastBadSample = now; + unsigned long timeout = checkCurrent(useProgLimit) ? POWER_SAMPLE_IGNORE_FAULT_HIGH : POWER_SAMPLE_IGNORE_FAULT_LOW; + if ( mslpc < timeout) { + if (newPowerMode) + DIAG(F("TRACK %c FAULT PIN (%M ignore)"), trackno + 'A', timeout); + break; + } + DIAG(F("TRACK %c FAULT PIN detected after %4M. Pause %4M)"), trackno + 'A', mslpc, power_sample_overload_wait); + setPower(POWERMODE::OVERLOAD); + break; + } + if (checkCurrent(useProgLimit)) { + lastBadSample = now; + if (mslpc < POWER_SAMPLE_IGNORE_CURRENT) { + if (newPowerMode) { + unsigned int mA=raw2mA(lastCurrent); + DIAG(F("TRACK %c CURRENT (%M ignore) %dmA"), trackno + 'A', POWER_SAMPLE_IGNORE_CURRENT, mA); + } + break; + } + unsigned int mA=raw2mA(lastCurrent); + unsigned int maxmA=raw2mA(tripValue); + DIAG(F("TRACK %c POWER OVERLOAD %4dmA (max %4dmA) detected after %4M. Pause %4M"), + trackno + 'A', mA, maxmA, mslpc, power_sample_overload_wait); + setPower(POWERMODE::OVERLOAD); + break; + } + // all well + unsigned long goodtime = micros() - lastBadSample; + if (goodtime > POWER_SAMPLE_ALERT_GOOD) { + if (true || notFromOverload) { // we did a RESTORE message XXX + unsigned int mA=raw2mA(lastCurrent); + DIAG(F("TRACK %c NORMAL (after %M/%M) %dmA"), trackno + 'A', goodtime, mslpc, mA); + } + setPower(POWERMODE::ON); + } + break; + } + + case POWERMODE::OVERLOAD: { + lastPowerMode = POWERMODE::OVERLOAD; + unsigned long mslpc = (commonFaultPin ? (micros() - globalOverloadStart) : microsSinceLastPowerChange(POWERMODE::OVERLOAD)); if (mslpc > power_sample_overload_wait) { // adjust next wait time - power_sample_overload_wait *= 2; + power_sample_overload_wait *= 4; if (power_sample_overload_wait > POWER_SAMPLE_RETRY_MAX) power_sample_overload_wait = POWER_SAMPLE_RETRY_MAX; // power on test - setPower(POWERMODE::ON); - // here we change power but not the overloadNow as that was - // already changed to false when we entered POWERMODE::OVERLOAD - // so we need to set the lastPowerChange anyway. - overloadNow=false; - setLastPowerChange(); DIAG(F("TRACK %c POWER RESTORE (after %4M)"), trackno + 'A', mslpc); + setPower(POWERMODE::ALERT); } + break; } - break; + default: break; } diff --git a/MotorDriver.h b/MotorDriver.h index b6f4670..0ebf494 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -107,7 +107,7 @@ extern volatile portreg_t shadowPORTA; extern volatile portreg_t shadowPORTB; extern volatile portreg_t shadowPORTC; -enum class POWERMODE : byte { OFF, ON, OVERLOAD }; +enum class POWERMODE : byte { OFF, ON, OVERLOAD, ALERT }; class MotorDriver { public: @@ -192,24 +192,13 @@ class MotorDriver { // 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() { + inline unsigned long microsSinceLastPowerChange(POWERMODE mode) { unsigned long now = micros(); - unsigned long diff = now - lastPowerChange; + unsigned long diff = now - lastPowerChange[(int)mode]; if (diff > (1UL << (7 *sizeof(unsigned long)))) // 2^(4*7)us = 268.4 seconds - lastPowerChange = now - 30000000UL; // 30 seconds ago + lastPowerChange[(int)mode] = now - 30000000UL; // 30 seconds ago return diff; }; - inline void setLastPowerChange() { - lastPowerChange = micros(); - }; - // as setLastPowerChange but sets the global timestamp as well which - // is only used to sync power restore in case of common Fault pin. - inline void setLastPowerChangeOverload() { - if (commonFaultPin) - globalOverloadStart = lastPowerChange = micros(); - else - setLastPowerChange(); - }; #ifdef ANALOG_READ_INTERRUPT bool sampleCurrentFromHW(); void startCurrentFromHW(); @@ -218,9 +207,22 @@ class MotorDriver { char trackLetter = '?'; bool isProgTrack = false; // tells us if this is a prog track void getFastPin(const FSH* type,int pin, bool input, FASTPIN & result); - void getFastPin(const FSH* type,int pin, FASTPIN & result) { + inline void getFastPin(const FSH* type,int pin, FASTPIN & result) { getFastPin(type, pin, 0, result); - } + }; + // side effect sets lastCurrent and tripValue + inline bool checkCurrent(bool useProgLimit) { + tripValue= useProgLimit?progTripValue:getRawCurrentTripValue(); + lastCurrent = getCurrentRaw(); + if (lastCurrent < 0) + lastCurrent = -lastCurrent; + return lastCurrent >= tripValue; + }; + // side effect sets lastCurrent + inline bool checkFault() { + lastCurrent = getCurrentRaw(); + return lastCurrent < 0; + }; VPIN powerPin; byte signalPin, signalPin2, currentPin, faultPin, brakePin; FASTPIN fastSignalPin, fastSignalPin2, fastBrakePin,fastFaultPin; @@ -241,12 +243,14 @@ class MotorDriver { int rawCurrentTripValue; // current sampling POWERMODE powerMode; - bool overloadNow = false; - unsigned long lastPowerChange; // timestamp in microseconds + POWERMODE lastPowerMode; + unsigned long lastPowerChange[4]; // timestamp in microseconds + unsigned long lastBadSample; // timestamp in microseconds // used to sync restore time when common Fault pin detected static unsigned long globalOverloadStart; // timestamp in microseconds int progTripValue; - int lastCurrent; + int lastCurrent; //temp value + int tripValue; //temp value #ifdef ANALOG_READ_INTERRUPT volatile unsigned long sampleCurrentTimestamp; volatile uint16_t sampleCurrent; @@ -259,12 +263,14 @@ class MotorDriver { static const unsigned long POWER_SAMPLE_OVERLOAD_WAIT = 10000UL; // Time after we consider all faults old and forgotten static const unsigned long POWER_SAMPLE_ALL_GOOD = 5000000UL; + // Time after which we consider a ALERT over + static const unsigned long POWER_SAMPLE_ALERT_GOOD = 20000UL; // How long to ignore fault pin if current is under limit static const unsigned long POWER_SAMPLE_IGNORE_FAULT_LOW = 50000UL; // How long to ignore fault pin if current is higher than limit static const unsigned long POWER_SAMPLE_IGNORE_FAULT_HIGH = 5000UL; // How long to wait between overcurrent and turning off - static const unsigned long POWER_SAMPLE_OFF_DELAY = 100000UL; + static const unsigned long POWER_SAMPLE_IGNORE_CURRENT = 100000UL; // Upper limit for retry period static const unsigned long POWER_SAMPLE_RETRY_MAX = 10000000UL; diff --git a/version.h b/version.h index 2325ceb..3741dc4 100644 --- a/version.h +++ b/version.h @@ -4,7 +4,8 @@ #include "StringFormatter.h" -#define VERSION "4.2.61" +#define VERSION "4.2.62pre1" +// 4.2.62 - completely new overcurrent detection // 4.2.61 - MAX_CURRENT restriction (caps motor shield value) // 4.2.60 - Add mDNS capability to ESP32 for autodiscovery // 4.2.59 - Fix: AP SSID was DCC_ instead of DCCEX_ From ab1356d07061fd056da9dbe718206126297a2cbf Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sun, 2 Jul 2023 13:55:56 +0200 Subject: [PATCH 04/10] Change first join/unjoin and set power after that --- DCCEXParser.cpp | 4 ++-- GITHUB_SHA.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 1e3df90..aa635ae 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -487,9 +487,9 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) #endif else break; // will reply } + TrackManager::setJoin(join); if (main) TrackManager::setMainPower(POWERMODE::ON); if (prog) TrackManager::setProgPower(POWERMODE::ON); - TrackManager::setJoin(join); CommandDistributor::broadcastPower(); return; @@ -516,12 +516,12 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) else break; // will reply } + TrackManager::setJoin(false); if (main) TrackManager::setMainPower(POWERMODE::OFF); if (prog) { TrackManager::progTrackBoosted=false; // Prog track boost mode will not outlive prog track off TrackManager::setProgPower(POWERMODE::OFF); } - TrackManager::setJoin(false); CommandDistributor::broadcastPower(); return; diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 07d9123..c676511 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-overcurrent-202307012332Z" +#define GITHUB_SHA "devel-overcurrent-202307021155Z" From 10c59028e1525f1c12949d2c4a5434183cb241c8 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sun, 2 Jul 2023 20:33:29 +0200 Subject: [PATCH 05/10] Add documentation --- GITHUB_SHA.h | 2 +- MotorDriver.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index c676511..ddcb181 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-overcurrent-202307021155Z" +#define GITHUB_SHA "devel-overcurrent-202307021833Z" diff --git a/MotorDriver.cpp b/MotorDriver.cpp index e05059b..64bb8ca 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -173,7 +173,7 @@ bool MotorDriver::isPWMCapable() { void MotorDriver::setPower(POWERMODE mode) { if (powerMode == mode) return; - //DIAG(F("POWERMODE=%d"), (int)mode); + //DIAG(F("Track %c POWERMODE=%d"), trackLetter, (int)mode); lastPowerChange[(int)mode] = micros(); if (mode == POWERMODE::OVERLOAD) globalOverloadStart = lastPowerChange[(int)mode]; @@ -376,6 +376,67 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res // DIAG(F(" port=0x%x, inoutpin=0x%x, isinput=%d, mask=0x%x"),port, result.inout,input,result.maskHIGH); } +/////////////////////////////////////////////////////////////////////////////////////////// +// checkPowerOverload(useProgLimit, trackno) +// bool useProgLimit: Trackmanager knows if this track is in prog mode or in main mode +// byte trackno: trackmanager knows it's number (could be skipped?) +// +// Short ciruit handling strategy: +// +// There are the following power states: ON ALERT OVERLOAD OFF +// OFF state is only changed to/from manually. Power is on +// during ON and ALERT. Power is off during OVERLOAD and OFF. +// The overload mechanism changes between the other states like +// +// ON -1-> ALERT -2-> OVERLOAD -3-> ALERT -4-> ON +// or +// ON -1-> ALERT -4-> ON +// +// Times are in class MotorDriver (MotorDriver.h). +// +// 1. ON to ALERT: +// Transition on fault pin condition or current overload +// +// 2. ALERT to OVERLOAD: +// Transition happens if different timeouts have elapsed. +// If only the fault pin is active, timeout is +// POWER_SAMPLE_IGNORE_FAULT_LOW (50ms) +// If only overcurrent is detected, timeout is +// POWER_SAMPLE_IGNORE_CURRENT (100ms) +// If fault pin and overcurrent are active, timeout is +// POWER_SAMPLE_IGNORE_FAULT_HIGH (5ms) +// Transition to OVERLOAD turns off power to the affected +// output (unless fault pins are shared) +// If the transition conditions are not fullfilled, +// transition according to 4 is tested. +// +// 3. OVERLOAD to ALERT +// Transiton happens when timeout has elapsed, timeout +// is named power_sample_overload_wait. It is started +// at POWER_SAMPLE_OVERLOAD_WAIT (10ms) at first entry +// to OVERLOAD and then increased by a factor of 2 +// at further entries to the OVERLOAD condition. This +// happens until POWER_SAMPLE_RETRY_MAX (10sec) is reached. +// power_sample_overload_wait is reset by a poweroff or +// a POWER_SAMPLE_ALL_GOOD (5sec) period during ON. +// After timeout power is turned on again and state +// goes back to ALERT. +// +// 4. ALERT to ON +// Transition happens by watching the current and fault pin +// samples during POWER_SAMPLE_ALERT_GOOD (20ms) time. If +// values have been good during that time, transition is +// made back to ON. Note that even if state is back to ON, +// the power_sample_overload_wait time is first reset +// later (see above). +// +// The time keeping is handled by timestamps lastPowerChange[] +// which are set by each power change and by lastBadSample which +// keeps track if conditions during ALERT have been good enough +// to go back to ON. The time differences are calculated by +// microsSinceLastPowerChange(). +// + void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) { switch (powerMode) { From 96a46f36c2a4008b11377b82352d7f39b02911ec Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 3 Jul 2023 00:21:52 +0200 Subject: [PATCH 06/10] Adjust overcurrent timeouts --- GITHUB_SHA.h | 2 +- MotorDriver.cpp | 6 +++--- MotorDriver.h | 4 ++-- version.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index ddcb181..f2440cb 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-overcurrent-202307021833Z" +#define GITHUB_SHA "devel-overcurrent-202307022222Z" diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 64bb8ca..dc82044 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -400,7 +400,7 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res // 2. ALERT to OVERLOAD: // Transition happens if different timeouts have elapsed. // If only the fault pin is active, timeout is -// POWER_SAMPLE_IGNORE_FAULT_LOW (50ms) +// POWER_SAMPLE_IGNORE_FAULT_LOW (100ms) // If only overcurrent is detected, timeout is // POWER_SAMPLE_IGNORE_CURRENT (100ms) // If fault pin and overcurrent are active, timeout is @@ -413,7 +413,7 @@ void MotorDriver::getFastPin(const FSH* type,int pin, bool input, FASTPIN & res // 3. OVERLOAD to ALERT // Transiton happens when timeout has elapsed, timeout // is named power_sample_overload_wait. It is started -// at POWER_SAMPLE_OVERLOAD_WAIT (10ms) at first entry +// at POWER_SAMPLE_OVERLOAD_WAIT (40ms) at first entry // to OVERLOAD and then increased by a factor of 2 // at further entries to the OVERLOAD condition. This // happens until POWER_SAMPLE_RETRY_MAX (10sec) is reached. @@ -525,7 +525,7 @@ void MotorDriver::checkPowerOverload(bool useProgLimit, byte trackno) { unsigned long mslpc = (commonFaultPin ? (micros() - globalOverloadStart) : microsSinceLastPowerChange(POWERMODE::OVERLOAD)); if (mslpc > power_sample_overload_wait) { // adjust next wait time - power_sample_overload_wait *= 4; + power_sample_overload_wait *= 2; if (power_sample_overload_wait > POWER_SAMPLE_RETRY_MAX) power_sample_overload_wait = POWER_SAMPLE_RETRY_MAX; // power on test diff --git a/MotorDriver.h b/MotorDriver.h index 0ebf494..454015d 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -260,13 +260,13 @@ class MotorDriver { // Times for overload management. Unit: microseconds. // Base for wait time until power is turned on again - static const unsigned long POWER_SAMPLE_OVERLOAD_WAIT = 10000UL; + static const unsigned long POWER_SAMPLE_OVERLOAD_WAIT = 40000UL; // Time after we consider all faults old and forgotten static const unsigned long POWER_SAMPLE_ALL_GOOD = 5000000UL; // Time after which we consider a ALERT over static const unsigned long POWER_SAMPLE_ALERT_GOOD = 20000UL; // How long to ignore fault pin if current is under limit - static const unsigned long POWER_SAMPLE_IGNORE_FAULT_LOW = 50000UL; + static const unsigned long POWER_SAMPLE_IGNORE_FAULT_LOW = 100000UL; // How long to ignore fault pin if current is higher than limit static const unsigned long POWER_SAMPLE_IGNORE_FAULT_HIGH = 5000UL; // How long to wait between overcurrent and turning off diff --git a/version.h b/version.h index 3741dc4..e445bb1 100644 --- a/version.h +++ b/version.h @@ -4,7 +4,7 @@ #include "StringFormatter.h" -#define VERSION "4.2.62pre1" +#define VERSION "4.2.62pre2" // 4.2.62 - completely new overcurrent detection // 4.2.61 - MAX_CURRENT restriction (caps motor shield value) // 4.2.60 - Add mDNS capability to ESP32 for autodiscovery From e6a40e622c7ab89ee94335595ad4de245a9e6ecc Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 3 Jul 2023 23:43:21 +0200 Subject: [PATCH 07/10] download graphic installer if DISPLAY --- installer.sh | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/installer.sh b/installer.sh index 17a9c04..4821284 100755 --- a/installer.sh +++ b/installer.sh @@ -1,7 +1,7 @@ #!/bin/bash # -# © 2022 Harald Barth +# © 2022,2023 Harald Barth # # This file is part of CommandStation-EX # @@ -29,14 +29,28 @@ ACLI="./bin/arduino-cli" function need () { type -p $1 > /dev/null && return + dpkg -l $1 2>&1 | egrep ^ii >/dev/null && return sudo apt-get install $1 type -p $1 > /dev/null && return echo "Could not install $1, abort" exit 255 } - need git + +if [ x$DISPLAY != x ] ; then + # we have DISPLAY, do the graphic thing + need python3-tk + need python3.8-venv + mkdir -p ~/ex-installer/venv + python3 -m venv ~/ex-installer/venv + cd ~/ex-installer/venv || exit 255 + source ./bin/activate + git clone https://github.com/DCC-EX/EX-Installer + cd EX-Installer || exit 255 + pip3 install -r requirements.txt + exec python3 -m ex_installer +fi if test -d `basename "$DCCEXGITURL"` ; then : assume we are almost there cd `basename "$DCCEXGITURL"` || exit 255 From f19db3aa5cc956833cb59198841542c796425d8f Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Tue, 4 Jul 2023 16:25:15 +0200 Subject: [PATCH 08/10] DISABLE_PROG does count as less RAM as well --- GITHUB_SHA.h | 2 +- defines.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index f2440cb..6238066 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-overcurrent-202307022222Z" +#define GITHUB_SHA "devel-overcurrent-202307041424Z" diff --git a/defines.h b/defines.h index 48f7c6b..f40ed2f 100644 --- a/defines.h +++ b/defines.h @@ -205,7 +205,7 @@ #define WIFI_SERIAL_LINK_SPEED 115200 #if __has_include ( "myAutomation.h") - #if defined(HAS_ENOUGH_MEMORY) || defined(DISABLE_EEPROM) + #if defined(HAS_ENOUGH_MEMORY) || defined(DISABLE_EEPROM) || defined(DISABLE_PROG) #define EXRAIL_ACTIVE #else #define EXRAIL_WARNING From c2fcdddd1f079c98d5746b9c561e7d40e2c292ce Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Thu, 6 Jul 2023 15:19:44 +0200 Subject: [PATCH 09/10] ESP32 protect from race in RMT code --- DCCRMT.cpp | 4 ++++ DCCWaveform.cpp | 3 +++ GITHUB_SHA.h | 2 +- version.h | 3 ++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/DCCRMT.cpp b/DCCRMT.cpp index 631cc16..cbd9af6 100644 --- a/DCCRMT.cpp +++ b/DCCRMT.cpp @@ -194,8 +194,10 @@ int RMTChannel::RMTfillData(const byte buffer[], byte byteCount, byte repeatCoun setDCCBit1(data + bitcounter-1); // overwrite previous zero bit with one bit setEOT(data + bitcounter++); // EOT marker dataLen = bitcounter; + noInterrupts(); // keep dataReady and dataRepeat consistnet to each other dataReady = true; dataRepeat = repeatCount+1; // repeatCount of 0 means send once + interrupts(); return 0; } @@ -212,6 +214,8 @@ void IRAM_ATTR RMTChannel::RMTinterrupt() { if (dataReady) { // if we have new data, fill while preamble is running rmt_fill_tx_items(channel, data, dataLen, preambleLen-1); dataReady = false; + if (dataRepeat == 0) // all data should go out at least once + DIAG(F("Channel %d DCC signal lost data"), channel); } if (dataRepeat > 0) // if a repeat count was specified, work on that dataRepeat--; diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index e065648..4a99997 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -247,6 +247,9 @@ void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repea pendingPacket[byteCount] = checksum; pendingLength = byteCount + 1; pendingRepeats = repeats; +// DIAG repeated commands (accesories) +// if (pendingRepeats > 0) +// DIAG(F("Repeats=%d on %s track"), pendingRepeats, isMainTrack ? "MAIN" : "PROG"); // The resets will be zero not only now but as well repeats packets into the future clearResets(repeats+1); { diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 6238066..2b88c4b 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-overcurrent-202307041424Z" +#define GITHUB_SHA "devel-overcurrent-202307061318Z" diff --git a/version.h b/version.h index e445bb1..93df891 100644 --- a/version.h +++ b/version.h @@ -4,8 +4,9 @@ #include "StringFormatter.h" -#define VERSION "4.2.62pre2" +#define VERSION "4.2.62pre3" // 4.2.62 - completely new overcurrent detection +// - ESP32 protect from race in RMT code // 4.2.61 - MAX_CURRENT restriction (caps motor shield value) // 4.2.60 - Add mDNS capability to ESP32 for autodiscovery // 4.2.59 - Fix: AP SSID was DCC_ instead of DCCEX_ From 4192c1f5a331a0127a20cdd0201b2e720cd906d8 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Thu, 6 Jul 2023 16:58:36 +0200 Subject: [PATCH 10/10] Do not invoke graphical install on Raspbian --- GITHUB_SHA.h | 2 +- installer.sh | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 2b88c4b..5c0ffb6 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-overcurrent-202307061318Z" +#define GITHUB_SHA "devel-overcurrent-202307061457Z" diff --git a/installer.sh b/installer.sh index 4821284..857710e 100755 --- a/installer.sh +++ b/installer.sh @@ -38,6 +38,11 @@ function need () { need git +if cat /etc/issue | egrep '^Raspbian' 2>&1 >/dev/null ; then + # we are on a raspi where we do not support graphical + unset DISPLAY +fi + if [ x$DISPLAY != x ] ; then # we have DISPLAY, do the graphic thing need python3-tk