diff --git a/DCCTimer.h b/DCCTimer.h index 4ce8590..44c85f2 100644 --- a/DCCTimer.h +++ b/DCCTimer.h @@ -65,10 +65,12 @@ class DCCTimer { static void startRailcomTimer(byte brakePin); static void ackRailcomTimer(); static void DCCEXanalogWriteFrequency(uint8_t pin, uint32_t frequency); - static void DCCEXanalogWrite(uint8_t pin, int value); + static void DCCEXanalogWrite(uint8_t pin, int value, bool invert); static void DCCEXledcDetachPin(uint8_t pin); - static void DCCEXanalogCopyChannel(uint8_t frompin, uint8_t topin); - static void DCCEXInrushControlOn(uint8_t pin, int duty); + static void DCCEXanalogCopyChannel(int8_t frompin, int8_t topin); + static void DCCEXInrushControlOn(uint8_t pin, int duty, bool invert); + static void DCCEXledcAttachPin(uint8_t pin, int8_t channel, bool inverted); + // Update low ram level. Allow for extra bytes to be specified // by estimation or inspection, that may be used by other // called subroutines. Must be called with interrupts disabled. diff --git a/DCCTimerESP.cpp b/DCCTimerESP.cpp index b651a49..93711aa 100644 --- a/DCCTimerESP.cpp +++ b/DCCTimerESP.cpp @@ -197,13 +197,48 @@ void DCCTimer::DCCEXledcDetachPin(uint8_t pin) { pinMatrixOutDetach(pin, false, false); } +static byte LEDCToMux[] = { + LEDC_HS_SIG_OUT0_IDX, + LEDC_HS_SIG_OUT1_IDX, + LEDC_HS_SIG_OUT2_IDX, + LEDC_HS_SIG_OUT3_IDX, + LEDC_HS_SIG_OUT4_IDX, + LEDC_HS_SIG_OUT5_IDX, + LEDC_HS_SIG_OUT6_IDX, + LEDC_HS_SIG_OUT7_IDX, + LEDC_LS_SIG_OUT0_IDX, + LEDC_LS_SIG_OUT1_IDX, + LEDC_LS_SIG_OUT2_IDX, + LEDC_LS_SIG_OUT3_IDX, + LEDC_LS_SIG_OUT4_IDX, + LEDC_LS_SIG_OUT5_IDX, + LEDC_LS_SIG_OUT6_IDX, + LEDC_LS_SIG_OUT7_IDX, +}; -void DCCTimer::DCCEXanalogCopyChannel(uint8_t frompin, uint8_t topin) { - DIAG(F("Pin %d copied to %d channel %d"), frompin, topin, pin_to_channel[frompin]); - pin_to_channel[topin] = pin_to_channel[frompin]; - ledcAttachPin(topin, pin_to_channel[topin]); +void DCCTimer::DCCEXledcAttachPin(uint8_t pin, int8_t channel, bool inverted) { + DIAG(F("Attaching pin %d to channel %d %c"), pin, channel, inverted ? 'I' : ' '); + ledcAttachPin(pin, channel); + if (inverted) // we attach again but with inversion + gpio_matrix_out(pin, LEDCToMux[channel], inverted, 0); } -void DCCTimer::DCCEXanalogWrite(uint8_t pin, int value) { + +void DCCTimer::DCCEXanalogCopyChannel(int8_t frompin, int8_t topin) { + // arguments are signed depending on inversion of pins + DIAG(F("Pin %d copied to %d"), frompin, topin); + bool inverted = false; + if (frompin<0) + frompin = -frompin; + if (topin<0) { + inverted = true; + topin = -topin; + } + int channel = pin_to_channel[frompin]; // after abs(frompin) + pin_to_channel[topin] = channel; + DCCTimer::DCCEXledcAttachPin(topin, channel, inverted); +} + +void DCCTimer::DCCEXanalogWrite(uint8_t pin, int value, bool invert) { // This allocates channels 15, 13, 11, .... // so each channel gets its own timer. if (pin < SOC_GPIO_PIN_COUNT) { @@ -237,17 +272,20 @@ void DCCTimer::DCCEXanalogWrite(uint8_t pin, int value) { --cnt_channel; // Now we are at 14, 12, ... } ledcSetup(pin_to_channel[pin], 1000, 8); - ledcAttachPin(pin, pin_to_channel[pin]); + DCCEXledcAttachPin(pin, pin_to_channel[pin], invert); } else { - //DIAG(F("Pin %d assigned to old channel %d"), pin, pin_to_channel[pin]); - ledcAttachPin(pin, pin_to_channel[pin]); + // This else is only here so we can enable diag + // Pin should be already attached to channel + // DIAG(F("Pin %d assigned to old channel %d"), pin, pin_to_channel[pin]); } ledcWrite(pin_to_channel[pin], value); } } -void DCCTimer::DCCEXInrushControlOn(uint8_t pin, int duty) { + +void DCCTimer::DCCEXInrushControlOn(uint8_t pin, int duty, bool inverted) { + // this uses hardcoded channel 0 ledcSetup(0, 62500, 8); - ledcAttachPin(pin, 0); + DCCEXledcAttachPin(pin, 0, inverted); ledcWrite(0, duty); } diff --git a/DCCTimerSTM32.cpp b/DCCTimerSTM32.cpp index 43c8ece..0c1d5d6 100644 --- a/DCCTimerSTM32.cpp +++ b/DCCTimerSTM32.cpp @@ -333,7 +333,9 @@ void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency return; } -void DCCTimer::DCCEXanalogWrite(uint8_t pin, int value) { +void DCCTimer::DCCEXanalogWrite(uint8_t pin, int value, bool invert) { + if (invert) + value = 255-value; // Calculate percentage duty cycle from value given uint32_t duty_cycle = (value * 100 / 256) + 1; if (pin_timer[pin] != NULL) { diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 47c359e..1ab52d8 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -336,8 +336,6 @@ void MotorDriver::setDCSignal(byte speedcode, uint8_t frequency /*default =0*/) if (tSpeed <= 1) brake = 255; else if (tSpeed >= 127) brake = 0; else brake = 2 * (128-tSpeed); - if (invertBrake) - brake=255-brake; { // new block because of variable f #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_STM32) @@ -351,10 +349,10 @@ void MotorDriver::setDCSignal(byte speedcode, uint8_t frequency /*default =0*/) #endif //DIAG(F("Brake pin %d freqency %d"), brakePin, f); DCCTimer::DCCEXanalogWriteFrequency(brakePin, f); // set DC PWM frequency - DCCTimer::DCCEXanalogWrite(brakePin,brake); + DCCTimer::DCCEXanalogWrite(brakePin, brake, invertBrake); #else // all AVR here DCCTimer::DCCEXanalogWriteFrequency(brakePin, frequency); // frequency steps - analogWrite(brakePin,brake); + analogWrite(brakePin, invertBrake ? 255-brake : brake); #endif } @@ -407,16 +405,16 @@ void MotorDriver::throttleInrush(bool on) { if ( !(trackMode & (TRACK_MODE_MAIN | TRACK_MODE_PROG | TRACK_MODE_EXT | TRACK_MODE_BOOST))) return; byte duty = on ? 207 : 0; // duty of 81% at 62500Hz this gives pauses of 3usec - if (invertBrake) - duty = 255-duty; #if defined(ARDUINO_ARCH_ESP32) if(on) { - DCCTimer::DCCEXInrushControlOn(brakePin, duty); + DCCTimer::DCCEXInrushControlOn(brakePin, duty, invertBrake); } else { ledcDetachPin(brakePin); // not DCCTimer::DCCEXledcDetachPin() as we have not // registered the pin in the pin to channel array } #elif defined(ARDUINO_ARCH_STM32) + if (invertBrake) + duty = 255-duty; if(on) { DCCTimer::DCCEXanalogWriteFrequency(brakePin, 7); // 7 means max DCCTimer::DCCEXanalogWrite(brakePin,duty); @@ -424,6 +422,8 @@ void MotorDriver::throttleInrush(bool on) { pinMode(brakePin, OUTPUT); } #else // all AVR here + if (invertBrake) + duty = 255-duty; if(on){ DCCTimer::DCCEXanalogWriteFrequency(brakePin, 7); // 7 means max } diff --git a/MotorDriver.h b/MotorDriver.h index 945e4ee..a6ed1f6 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -193,7 +193,7 @@ class MotorDriver { } }; inline pinpair getSignalPin() { return pinpair(signalPin,signalPin2); }; - inline byte getBrakePin() { return brakePin; }; + inline int8_t getBrakePinSigned() { return invertBrake ? -brakePin : brakePin; }; void setDCSignal(byte speedByte, uint8_t frequency=0); void throttleInrush(bool on); inline void detachDCSignal() { diff --git a/TrackManager.cpp b/TrackManager.cpp index 21fe44a..06b6a18 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -264,14 +264,18 @@ bool TrackManager::setTrackMode(byte trackToSet, TRACK_MODE mode, int16_t dcAddr #ifdef ARDUINO_ARCH_ESP32 int trackfound = -1; FOR_EACH_TRACK(t) { - if ((track[t]->getMode() & TRACK_MODE_DC) && trackDCAddr[t] == dcAddr) { + //DIAG(F("Checking track %c mode %x dcAddr %d"), 'A'+t, track[t]->getMode(), trackDCAddr[t]); + if (t != trackToSet // not our track + && (track[t]->getMode() & TRACK_MODE_DC) // right mode + && trackDCAddr[t] == dcAddr) { // right addr + //DIAG(F("Found track %c"), 'A'+t); trackfound = t; break; } } if (trackfound > -1) { - DCCTimer::DCCEXanalogCopyChannel(track[trackfound]->getBrakePin(), - track[trackToSet]->getBrakePin()); + DCCTimer::DCCEXanalogCopyChannel(track[trackfound]->getBrakePinSigned(), + track[trackToSet]->getBrakePinSigned()); } #endif }