From 9368a69e30760a5bdde48b5e314a134a365de331 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 15 Feb 2021 00:31:36 +0100 Subject: [PATCH] Handle shields with common fault pins (Pololu) --- DCCEXParser.cpp | 3 ++- DCCWaveform.cpp | 20 +++++++++++++++++--- MotorDriver.cpp | 8 +++++++- MotorDriver.h | 4 ++++ MotorDrivers.h | 8 ++++---- WiThrottle.cpp | 2 ++ 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 56f17a2..9b996e7 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -436,7 +436,8 @@ void DCCEXParser::parse(Print *stream, byte *com, bool blocking) { POWERMODE mode = opcode == '1' ? POWERMODE::ON : POWERMODE::OFF; DCC::setProgTrackSyncMain(false); // Only <1 JOIN> will set this on, all others set it off - if (params == 0) + if (params == 0 || + (MotorDriver::commonFaultPin && p[0] != HASH_KEYWORD_JOIN)) // commonFaultPin prevents individual track handling { DCCWaveform::mainTrack.setPowerMode(mode); DCCWaveform::progTrack.setPowerMode(mode); diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 439717e..4eed0cb 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -40,6 +40,7 @@ void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) { mainTrack.setPowerMode(POWERMODE::OFF); progTrack.setPowerMode(POWERMODE::OFF); MotorDriver::usePWM= mainDriver->isPWMCapable() && progDriver->isPWMCapable(); + MotorDriver::commonFaultPin = (mainDriver->getFaultPin() == progDriver->getFaultPin()); if (MotorDriver::usePWM) DIAG(F("\nWaveform using PWM pins for accuracy.")); else DIAG(F("\nWaveform accuracy limited by signal pin configuration.")); DCCTimer::begin(DCCWaveform::interruptHandler); @@ -109,7 +110,7 @@ void DCCWaveform::setPowerMode(POWERMODE mode) { } -void DCCWaveform::checkPowerOverload() { +void DCCWaveform::checkPowerOverload() { if (millis() - lastSampleTaken < sampleDelay) return; lastSampleTaken = millis(); int tripValue= motorDriver->getRawCurrentTripValue(); @@ -125,10 +126,23 @@ void DCCWaveform::checkPowerOverload() { lastCurrent=motorDriver->getCurrentRaw(); if (lastCurrent < 0) { // We have a fault pin condition to take care of - DIAG(F("\n*** %S FAULT PIN ACTIVE TOGGLE POWER ON THIS OR BOTH TRACKS ***\n"), isMainTrack ? F("MAIN") : F("PROG")); lastCurrent = -lastCurrent; + setPowerMode(POWERMODE::OVERLOAD); // Turn off, decide later how fast to turn on again + if (MotorDriver::commonFaultPin) { + if (lastCurrent <= tripValue) { + setPowerMode(POWERMODE::ON); // maybe other track + } + // 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 + DIAG(F("\n*** COMMON FAULT PIN ACTIVE - TOGGLED POWER on %S ***\n"), isMainTrack ? F("MAIN") : F("PROG")); + } else { + DIAG(F("\n*** %S FAULT PIN ACTIVE - OVERLOAD ***\n"), isMainTrack ? F("MAIN") : F("PROG")); + if (lastCurrent < tripValue) { + lastCurrent = tripValue; // exaggerate + } + } } - if (lastCurrent <= tripValue) { + if (lastCurrent < tripValue) { sampleDelay = POWER_SAMPLE_ON_WAIT; if(power_good_counter<100) power_good_counter++; diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 6cc1d10..c9681d6 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -27,6 +27,7 @@ #define isLOW(fastpin) (!isHIGH(fastpin)) bool MotorDriver::usePWM=false; +bool MotorDriver::commonFaultPin=false; MotorDriver::MotorDriver(byte power_pin, byte signal_pin, byte signal_pin2, int8_t brake_pin, byte current_pin, float sense_factor, unsigned int trip_milliamps, byte fault_pin) { @@ -116,10 +117,15 @@ void MotorDriver::setSignal( bool high) { } } +/* + * 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. + * As there is no -0, ceat a little and return -1 in that case. + */ int MotorDriver::getCurrentRaw() { int current = analogRead(currentPin); if (faultPin != UNUSED_PIN && isLOW(fastFaultPin) && isHIGH(fastPowerPin)) - return -current; + return (current == 0 ? -1 : -current); return current; // IMPORTANT: This function can be called in Interrupt() time within the 56uS timer // The default analogRead takes ~100uS which is catastrphic diff --git a/MotorDriver.h b/MotorDriver.h index 2c6b230..b47ae95 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -46,6 +46,10 @@ class MotorDriver { } bool isPWMCapable(); static bool usePWM; + static bool commonFaultPin; // This is a stupid motor shield which has only a common fault pin for both outputs + inline byte getFaultPin() { + return faultPin; + } private: void getFastPin(const FSH* type,int pin, bool input, FASTPIN & result); diff --git a/MotorDrivers.h b/MotorDrivers.h index a277bbf..2ccf49d 100644 --- a/MotorDrivers.h +++ b/MotorDrivers.h @@ -29,8 +29,8 @@ // Pololu Motor Shield #define POLOLU_MOTOR_SHIELD F("POLOLU_MOTOR_SHIELD"), \ - new MotorDriver( 9, 7, UNUSED_PIN, -4, A0, 18, 3000, 12), \ - new MotorDriver(10, 8, UNUSED_PIN, UNUSED_PIN, A1, 18, 3000, UNUSED_PIN) + new MotorDriver( 9, 7, UNUSED_PIN, -4, A0, 18, 3000, 12), \ + new MotorDriver(10, 8, UNUSED_PIN, UNUSED_PIN, A1, 18, 3000, 12) // // Actually, on the Pololu MC33926 shield the enable lines are tied together on pin 4 and the // pins 9 and 10 work as "inverted brake" but as we turn on and off the tracks individually @@ -38,8 +38,8 @@ // version of the code always will be high. That means this config is not usable for generating // a railcom cuotout in the future. For that one must wire the second ^D2 to pin 2 and define // the motor driver like this: -// new MotorDriver(4, 7, UNUSED_PIN, -9, A0, 18, 3000, 12) -// new MotorDriver(2, 8, UNUSED_PIN, -10, A1, 18, 3000, UNUSED_PIN) +// new MotorDriver(4, 7, UNUSED_PIN, -9, A0, 18, 3000, 12), \ +// new MotorDriver(2, 8, UNUSED_PIN, -10, A1, 18, 3000, 12) // See Pololu dial_mc33926_shield_schematic.pdf and truth table on page 17 of the MC33926 data sheet. // Firebox Mk1 diff --git a/WiThrottle.cpp b/WiThrottle.cpp index d9b9ec7..62b638d 100644 --- a/WiThrottle.cpp +++ b/WiThrottle.cpp @@ -133,6 +133,8 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) { case 'P': if (cmd[1]=='P' && cmd[2]=='A' ) { //PPA power mode DCCWaveform::mainTrack.setPowerMode(cmd[3]=='1'?POWERMODE::ON:POWERMODE::OFF); + if (MotorDriver::commonFaultPin) // commonFaultPin prevents individual track handling + DCCWaveform::progTrack.setPowerMode(cmd[3]=='1'?POWERMODE::ON:POWERMODE::OFF); StringFormatter::send(stream,F("PPA%x\n"),DCCWaveform::mainTrack.getPowerMode()==POWERMODE::ON); lastPowerState = (DCCWaveform::mainTrack.getPowerMode()==POWERMODE::ON); //remember power state sent for comparison later }