From e76cdd7c06b0d1b54da2c099d62a865d4ced21c0 Mon Sep 17 00:00:00 2001 From: Ash-4 <81280775+Ash-4@users.noreply.github.com> Date: Thu, 17 Apr 2025 11:39:47 -0500 Subject: [PATCH] Sync DC mode tracks - Nucleo-F4 --- DCCTimerSTM32.cpp | 55 +++++++++++++++++++++++++++++++++++++-- MotorDriver.cpp | 2 +- TrackManager.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++++- TrackManager.h | 2 ++ version.h | 3 ++- 5 files changed, 122 insertions(+), 5 deletions(-) diff --git a/DCCTimerSTM32.cpp b/DCCTimerSTM32.cpp index df00df3..5d4e8d5 100644 --- a/DCCTimerSTM32.cpp +++ b/DCCTimerSTM32.cpp @@ -1,6 +1,7 @@ /* * © 2023 Neil McKechnie * © 2022-2024 Paul M. Antoine + * © 2025 Herb Morton * © 2021 Mike S * © 2021, 2023 Harald Barth * © 2021 Fred Decker @@ -36,6 +37,21 @@ #include "DIAG.h" #include +// DC mode timers enable the PWM signal on select pins. +// Code added to sync timers which have the same frequency. +// Function prototypes +void refreshDCmodeTimers(); +void resetCounterDCmodeTimers(); + +HardwareTimer *Timer1 = new HardwareTimer(TIM1); +HardwareTimer *Timer2 = new HardwareTimer(TIM2); +HardwareTimer *Timer3 = new HardwareTimer(TIM3); +HardwareTimer *Timer4 = new HardwareTimer(TIM4); +HardwareTimer *Timer9 = new HardwareTimer(TIM9); +#if defined(TIM13) +HardwareTimer *Timer13 = new HardwareTimer(TIM13); +#endif + #if defined(ARDUINO_NUCLEO_F401RE) // Nucleo-64 boards don't have additional serial ports defined by default // Serial1 is available on the F401RE, but not hugely convenient. @@ -290,7 +306,7 @@ void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) { else if (f >= 3) DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 16000); else if (f >= 2) - DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 3400); + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 3600); else if (f == 1) DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 480); else @@ -328,7 +344,8 @@ void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency if (pin_timer[pin] != NULL) { pin_timer[pin]->setPWM(pin_channel[pin], pin, frequency, 0); // set frequency in Hertz, 0% dutycycle - DIAG(F("DCCEXanalogWriteFrequency::Pin %d on Timer Channel %d, frequency %d"), pin, pin_channel[pin], frequency); + DIAG(F("DCCEXanalogWriteFrequency::Pin %d on Timer %d Channel %d, frequency %d"), pin, pin_timer[pin], pin_channel[pin], frequency); + resetCounterDCmodeTimers(); } else DIAG(F("DCCEXanalogWriteFrequency::failed to allocate HardwareTimer instance!")); @@ -341,6 +358,7 @@ void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency pinmap_pinout(digitalPinToPinName(pin), PinMap_TIM); // ensure the pin has been configured! pin_timer[pin]->setOverflow(frequency, HERTZ_FORMAT); // Just change the frequency if it's already running! DIAG(F("DCCEXanalogWriteFrequency::setting frequency to %d"), frequency); + resetCounterDCmodeTimers(); } } channel_frequency[pin] = frequency; @@ -365,6 +383,8 @@ void DCCTimer::DCCEXanalogWrite(uint8_t pin, int value, bool invert) { pin_timer[pin]->setCaptureCompare(pin_channel[pin], duty_cycle, PERCENT_COMPARE_FORMAT); // DCC_EX_PWM_FREQ Hertz, duty_cycle% dutycycle DIAG(F("DCCEXanalogWrite::Pin %d, value %d, duty cycle %d"), pin, value, duty_cycle); // } + refreshDCmodeTimers(); + resetCounterDCmodeTimers(); } else DIAG(F("DCCEXanalogWrite::Pin %d is not configured for PWM!"), pin); @@ -659,4 +679,35 @@ void ADCee::begin() { #endif interrupts(); } + +// NOTE: additional testing is needed to check the DCC signal +// where the DCC signal pin is a pwm pin on timers 1, 2, 3, 4, 9, 13 +// or the brake pin is defined on a different timer. +// -- example: F411RE/F446RE - pin 10 on stacked EX8874 +// lines added to sync timers -- +// not exact sync, but timers with the same frequency should be in sync +void refreshDCmodeTimers() { + Timer1->refresh(); + Timer2->refresh(); + Timer3->refresh(); + Timer4->refresh(); + Timer9->refresh(); + #if defined(TIM13) + Timer13->refresh(); + #endif +} + +// Function to synchronize timers - called every time there is powerON commmand for any DC track +void resetCounterDCmodeTimers() { + // Reset the counter for all DC mode timers + TIM1->CNT = 0; + TIM2->CNT = 0; + TIM3->CNT = 0; + TIM4->CNT = 0; + TIM9->CNT = 0; + #if defined(TIM13) + TIM13->CNT = 0; + #endif +} + #endif diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 39ec08d..2a04d84 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -371,8 +371,8 @@ void MotorDriver::setDCSignal(byte speedcode, uint8_t frequency /*default =0*/) } #endif //DIAG(F("Brake pin %d value %d freqency %d"), brakePin, brake, f); - DCCTimer::DCCEXanalogWrite(brakePin, brake, invertBrake); DCCTimer::DCCEXanalogWriteFrequency(brakePin, f); // set DC PWM frequency + DCCTimer::DCCEXanalogWrite(brakePin, brake, invertBrake); // line swapped to set frequency first #else // all AVR here DCCTimer::DCCEXanalogWriteFrequency(brakePin, frequency); // frequency steps analogWrite(brakePin, invertBrake ? 255-brake : brake); diff --git a/TrackManager.cpp b/TrackManager.cpp index b793de1..32e4b5f 100644 --- a/TrackManager.cpp +++ b/TrackManager.cpp @@ -2,7 +2,7 @@ * © 2022-2025 Chris Harlow * © 2022-2024 Harald Barth * © 2023-2024 Paul M. Antoine - * © 2024 Herb Morton + * © 2024-2025 Herb Morton * © 2023 Colin Murdoch * All rights reserved. * @@ -557,6 +557,20 @@ void TrackManager::setTrackPower(TRACK_MODE trackmodeToMatch, POWERMODE powermod } if (didChange) CommandDistributor::broadcastPower(); + + // re-initialize DC mode timer settings following powerON + if (powermode == POWERMODE::ON) { + #ifdef ARDUINO_ARCH_STM32 +// for (byte i=0;i<=lastTrack;i++) { +// setTrackPowerF439ZI(i); +// } + // repeated in case the setPower(powermode); if (oldpower != driver->getPower()) CommandDistributor::broadcastPower(); + + // re-initialize DC mode timer settings following powerON + if (powermode == POWERMODE::ON) { + #ifdef ARDUINO_ARCH_STM32 + for (byte i=0;i<=lastTrack;i++) { + setTrackPowerF439ZI(i); + } + // repeated in case the getMode(); + POWERMODE powermode = driver->getPower(); // line added to enable processing for DC mode tracks + POWERMODE oldpower = driver->getPower(); + //if (trackmode & TRACK_MODE_NONE) { + // driver->setBrake(true); // Track is unused. Brake is good to have. + // powermode = POWERMODE::OFF; // Track is unused. Force it to OFF + //} else + if (trackmode & TRACK_MODE_DC) { // includes inverted DC (called DCX) + if (powermode == POWERMODE::ON) { + driver->setBrake(true); // DC starts with brake on + applyDCSpeed(t); // speed match DCC throttles + } + } + //else /* MAIN PROG EXT BOOST */ { + // if (powermode == POWERMODE::ON) { + // // toggle brake before turning power on - resets overcurrent error + // // on the Pololu board if brake is wired to ^D2. + // driver->setBrake(true); + // driver->setBrake(false); // DCC runs with brake off + // } + //} + driver->setPower(powermode); + if (oldpower != driver->getPower()) + CommandDistributor::broadcastPower(); +} diff --git a/TrackManager.h b/TrackManager.h index 7dce0ee..f397132 100644 --- a/TrackManager.h +++ b/TrackManager.h @@ -1,6 +1,7 @@ /* * © 2022 Chris Harlow * © 2022-2024 Harald Barth + * © 2025 Herb Morton * © 2023 Colin Murdoch * * All rights reserved. @@ -69,6 +70,7 @@ class TrackManager { static void setTrackPower(TRACK_MODE trackmode, POWERMODE powermode); static void setMainPower(POWERMODE mode) {setTrackPower(TRACK_MODE_MAIN, mode);} static void setProgPower(POWERMODE mode) {setTrackPower(TRACK_MODE_PROG, mode);} + static void setTrackPowerF439ZI(byte t); static const int16_t MAX_TRACKS=8; static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0); diff --git a/version.h b/version.h index 2854062..09470bc 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.5.21" +#define VERSION "5.5.22" +// 5.5.22 - Sync DC mode tracks - Nucleo-F4 // 5.5.21 - Backed out the broken merge with frequency change and // 5.5.20 - EXRAIL SET/RESET assert fix // 5.5.19 - Railcom change to use RailcomCollector device