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

Compare commits

..

No commits in common. "0d679ad993662d9c5b6885bdb203a7759404686b" and "995c6f8ede39284d1a78ebf2b6e965a486c0672a" have entirely different histories.

7 changed files with 62 additions and 171 deletions

View File

@ -467,7 +467,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
bool prog=false; bool prog=false;
bool join=false; bool join=false;
if (params > 1) break; if (params > 1) break;
if (params==0) { // All if (params==0 || MotorDriver::commonFaultPin) { // <1> or tracks can not be handled individually
main=true; main=true;
prog=true; prog=true;
} }
@ -500,7 +500,7 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream)
bool main=false; bool main=false;
bool prog=false; bool prog=false;
if (params > 1) break; if (params > 1) break;
if (params==0) { // All if (params==0 || MotorDriver::commonFaultPin) { // <0> or tracks can not be handled individually
main=true; main=true;
prog=true; prog=true;
} }

View File

@ -1 +1 @@
#define GITHUB_SHA "devel-202306210849Z" #define GITHUB_SHA "devel-202306182208Z"

View File

@ -27,7 +27,7 @@
#include "DCCTimer.h" #include "DCCTimer.h"
#include "DIAG.h" #include "DIAG.h"
unsigned long MotorDriver::globalOverloadStart = 0; bool MotorDriver::commonFaultPin=false;
volatile portreg_t shadowPORTA; volatile portreg_t shadowPORTA;
volatile portreg_t shadowPORTB; volatile portreg_t shadowPORTB;
@ -159,7 +159,11 @@ 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() {
@ -168,7 +172,6 @@ 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
@ -369,112 +372,63 @@ 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;
lastSampleTaken = millis();
int tripValue= useProgLimit?progTripValue:getRawCurrentTripValue(); int tripValue= useProgLimit?progTripValue:getRawCurrentTripValue();
// Trackname for diag messages later
switch (powerMode) { switch (powerMode) {
case POWERMODE::OFF: case POWERMODE::OFF:
if (overloadNow) { sampleDelay = POWER_SAMPLE_OFF_WAIT;
// 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; 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
if (!overloadNow) { lastCurrent = -lastCurrent;
// turn on overload condition as fault pin has gone active setPower(POWERMODE::OVERLOAD); // Turn off, decide later how fast to turn on again
// DIAG(F("OVERLOAD FPIN ON")); if (commonFaultPin) {
overloadNow=true; if (lastCurrent < tripValue) {
setLastPowerChangeOverload(); setPower(POWERMODE::ON); // maybe other track
} }
lastCurrent = -lastCurrent; // 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
if (lastCurrent < tripValue) { DIAG(F("COMMON FAULT PIN ACTIVE: POWERTOGGLE TRACK %c"), trackno + 'A');
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
} else { } else {
if (power_sample_overload_wait <= POWER_SAMPLE_OVERLOAD_WAIT && // virgin DIAG(F("TRACK %c FAULT PIN ACTIVE - OVERLOAD"), trackno + 'A');
microsSinceLastPowerChange() < POWER_SAMPLE_IGNORE_FAULT_HIGH) { if (lastCurrent < tripValue) {
// Ignore 5ms fault pin if we see current lastCurrent = tripValue; // exaggerate
DIAG(F("TRACK %c FAULT PIN (5ms ignore)"), trackno + 'A'); }
break;
}
} }
DIAG(F("TRACK %c FAULT PIN"), trackno + 'A');
}
} }
// // // if (lastCurrent < tripValue) {
// above we looked at fault pin, below we look at current sampleDelay = POWER_SAMPLE_ON_WAIT;
// // // if(power_good_counter<100)
if (lastCurrent < tripValue) { // see above (*) power_good_counter++;
if (overloadNow) { else
// current is below trip value, turn off overload condition if (power_sample_overload_wait>POWER_SAMPLE_OVERLOAD_WAIT) power_sample_overload_wait=POWER_SAMPLE_OVERLOAD_WAIT;
// DIAG(F("OVERLOAD PON OFF"));
overloadNow=false;
setLastPowerChange();
}
if (microsSinceLastPowerChange() > POWER_SAMPLE_ALL_GOOD) {
power_sample_overload_wait = POWER_SAMPLE_OVERLOAD_WAIT;
}
} else { } else {
// too much current setPower(POWERMODE::OVERLOAD);
if (!overloadNow) { unsigned int mA=raw2mA(lastCurrent);
// current is over trip value, turn on overload condition unsigned int maxmA=raw2mA(tripValue);
// DIAG(F("OVERLOAD PON ON")); power_good_counter=0;
overloadNow=true; sampleDelay = power_sample_overload_wait;
setLastPowerChange(); DIAG(F("TRACK %c POWER OVERLOAD %dmA (limit %dmA) shutdown for %dms"), trackno + 'A', mA, maxmA, sampleDelay);
} if (power_sample_overload_wait >= 10000)
unsigned long uSecs = microsSinceLastPowerChange(); power_sample_overload_wait = 10000;
if (power_sample_overload_wait > POWER_SAMPLE_OVERLOAD_WAIT || // not virgin else
uSecs > POWER_SAMPLE_OFF_DELAY) { power_sample_overload_wait *= 2;
// 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);
}
} }
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
unsigned long mslpc = (commonFaultPin ? (micros() - globalOverloadStart) : microsSinceLastPowerChange());
if (mslpc > power_sample_overload_wait) {
// adjust next wait time
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
setPower(POWERMODE::ON); setPower(POWERMODE::ON);
// here we change power but not the overloadNow as that was sampleDelay = POWER_SAMPLE_ON_WAIT;
// already changed to false when we entered POWERMODE::OVERLOAD // Debug code....
// so we need to set the lastPowerChange anyway. DIAG(F("TRACK %c POWER RESTORE (check %dms)"), trackno + 'A', sampleDelay);
overloadNow=false; break;
setLastPowerChange(); default:
DIAG(F("TRACK %c POWER RESTORE (after %4M)"), trackno + 'A', mslpc); sampleDelay = 999; // cant get here..meaningless statement to avoid compiler warning.
}
}
break;
default:
break;
} }
} }

View File

@ -175,10 +175,7 @@ class MotorDriver {
bool isPWMCapable(); bool isPWMCapable();
bool canMeasureCurrent(); bool canMeasureCurrent();
bool trackPWM = false; // this track uses PWM timer to generate the DCC waveform bool trackPWM = false; // this track uses PWM timer to generate the DCC waveform
bool commonFaultPin = false; // This is a stupid motor shield which has only a common fault pin for both outputs static bool commonFaultPin; // This is a stupid motor shield which has only a common fault pin for both outputs
inline byte setCommonFaultPin() {
return commonFaultPin = true;
}
inline byte getFaultPin() { inline byte getFaultPin() {
return faultPin; return faultPin;
} }
@ -189,27 +186,6 @@ 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 now = micros();
unsigned long diff = now - lastPowerChange;
if (diff > (1UL << (7 *sizeof(unsigned long)))) // 2^(4*7)us = 268.4 seconds
lastPowerChange = 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 #ifdef ANALOG_READ_INTERRUPT
bool sampleCurrentFromHW(); bool sampleCurrentFromHW();
void startCurrentFromHW(); void startCurrentFromHW();
@ -241,10 +217,8 @@ class MotorDriver {
int rawCurrentTripValue; int rawCurrentTripValue;
// current sampling // current sampling
POWERMODE powerMode; POWERMODE powerMode;
bool overloadNow = false; unsigned long lastSampleTaken;
unsigned long lastPowerChange; // timestamp in microseconds unsigned int sampleDelay;
// used to sync restore time when common Fault pin detected
static unsigned long globalOverloadStart; // timestamp in microseconds
int progTripValue; int progTripValue;
int lastCurrent; int lastCurrent;
#ifdef ANALOG_READ_INTERRUPT #ifdef ANALOG_READ_INTERRUPT
@ -254,19 +228,10 @@ class MotorDriver {
int maxmA; int maxmA;
int tripmA; int tripmA;
// Times for overload management. Unit: microseconds. // Wait times for power management. Unit: milliseconds
// Base for wait time until power is turned on again static const int POWER_SAMPLE_ON_WAIT = 100;
static const unsigned long POWER_SAMPLE_OVERLOAD_WAIT = 100UL; static const int POWER_SAMPLE_OFF_WAIT = 1000;
// Time after we consider all faults old and forgotten static const int POWER_SAMPLE_OVERLOAD_WAIT = 20;
static const unsigned long POWER_SAMPLE_ALL_GOOD = 5000000UL;
// 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 = 10000UL;
// Upper limit for retry period
static const unsigned long POWER_SAMPLE_RETRY_MAX = 10000000UL;
// 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.

View File

@ -117,24 +117,6 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) {
case 'o': stream->print(va_arg(args, int), OCT); break; case 'o': stream->print(va_arg(args, int), OCT); break;
case 'x': stream->print((unsigned int)va_arg(args, unsigned int), HEX); break; case 'x': stream->print((unsigned int)va_arg(args, unsigned int), HEX); break;
case 'X': stream->print((unsigned long)va_arg(args, unsigned long), HEX); break; case 'X': stream->print((unsigned long)va_arg(args, unsigned long), HEX); break;
case 'M':
{ // this prints a unsigned long microseconds time in readable format
unsigned long time = va_arg(args, long);
if (time >= 2000) {
time = time / 1000;
if (time >= 2000) {
printPadded(stream, time/1000, formatWidth, formatLeft);
stream->print(F("sec"));
} else {
printPadded(stream,time, formatWidth, formatLeft);
stream->print(F("msec"));
}
} else {
printPadded(stream,time, formatWidth, formatLeft);
stream->print(F("usec"));
}
}
break;
//case 'f': stream->print(va_arg(args, double), 2); break; //case 'f': stream->print(va_arg(args, double), 2); break;
//format width prefix //format width prefix
case '-': case '-':

View File

@ -123,17 +123,9 @@ void TrackManager::Setup(const FSH * shieldname,
setTrackMode(1,TRACK_MODE_MAIN); setTrackMode(1,TRACK_MODE_MAIN);
#endif #endif
// Fault pin config for odd motor boards (example pololu) // TODO Fault pin config for odd motor boards (example pololu)
FOR_EACH_TRACK(t) { // MotorDriver::commonFaultPin = ((mainDriver->getFaultPin() == progDriver->getFaultPin())
for (byte s=t+1;s<=lastTrack;s++) { // && (mainDriver->getFaultPin() != UNUSED_PIN));
if (track[t]->getFaultPin() != UNUSED_PIN &&
track[t]->getFaultPin() == track[s]->getFaultPin()) {
track[t]->setCommonFaultPin();
track[s]->setCommonFaultPin();
DIAG(F("Common Fault pin tracks %c and %c"), t+'A', s+'A');
}
}
}
DCC::begin(shieldname); DCC::begin(shieldname);
} }

View File

@ -4,9 +4,7 @@
#include "StringFormatter.h" #include "StringFormatter.h"
#define VERSION "4.2.57" #define VERSION "4.2.56"
// 4.2.57 - New overload handling (faster and handles commonFaultPin again)
// - Optimize analog read STM32
// 4.2.56 - Update IO_RotaryEncoder.h: // 4.2.56 - Update IO_RotaryEncoder.h:
// - Improved I2C communication, non-blocking reads // - Improved I2C communication, non-blocking reads
// - Enable sending positions to the encoder from EXRAIL via SERVO() // - Enable sending positions to the encoder from EXRAIL via SERVO()