1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-23 21:01:25 +01:00

Handle shields with common fault pins (Pololu)

This commit is contained in:
Harald Barth 2021-02-15 00:31:36 +01:00
parent 8240a24193
commit 9368a69e30
6 changed files with 36 additions and 9 deletions

View File

@ -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);

View File

@ -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++;

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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
}