From 5d1b3a7a0390456407c17bfa7da8ced44a06f28b Mon Sep 17 00:00:00 2001 From: Ash-4 Date: Tue, 28 Jan 2025 16:06:08 -0600 Subject: [PATCH] DC mode timer sync STM32 and JL command --- DCCEXParser.cpp | 7 ++++++- DCCTimerSTM32.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++- IODeviceList.h | 6 ++++-- MotorDriver.cpp | 4 ++-- TrackManager.cpp | 30 +++++++++++++++++++++++++++++- TrackManager.h | 3 +++ version.h | 4 +++- 7 files changed, 92 insertions(+), 8 deletions(-) diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index f48d07b..f4f3fa5 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -2,7 +2,7 @@ * © 2022 Paul M Antoine * © 2021 Neil McKechnie * © 2021 Mike S - * © 2021-2024 Herb Morton + * © 2021-2025 Herb Morton * © 2020-2023 Harald Barth * © 2020-2021 M Steve Todd * © 2020-2021 Fred Decker @@ -788,6 +788,11 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) TrackManager::reportCurrent(stream); // return; + case "L"_hk: // track state and mA value on display + if (params<3) break; + TrackManager::reportCurrentLCD(p[1], p[2]); // Track power status + return; + case "A"_hk: // intercepted by EXRAIL// returns automations/routes if (params!=1) break; // StringFormatter::send(stream, F("\n")); diff --git a/DCCTimerSTM32.cpp b/DCCTimerSTM32.cpp index df00df3..8092160 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,17 @@ #include "DIAG.h" #include +// Function prototypes +void refreshDCmodeTimers(); +void resetCounterDCmodeTimers(); + +HardwareTimer *Timer1 = new HardwareTimer(TIM1); +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 +302,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 @@ -329,6 +341,7 @@ void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency { 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); + resetCounterDCmodeTimers(); } else DIAG(F("DCCEXanalogWriteFrequency::failed to allocate HardwareTimer instance!")); @@ -341,6 +354,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 +379,9 @@ 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 +676,31 @@ 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, 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(); + 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; + TIM4->CNT = 0; + TIM9->CNT = 0; + #if defined(TIM13) + TIM13->CNT = 0; + #endif +} + #endif diff --git a/IODeviceList.h b/IODeviceList.h index 2b82e1b..f02a0d6 100644 --- a/IODeviceList.h +++ b/IODeviceList.h @@ -1,5 +1,7 @@ /* - * © 2024, Chris Harlow. All rights reserved. + * © 2024, Chris Harlow. + * © 2025 Herb Morton + * All rights reserved. * * This file is part of CommandStation-EX * @@ -35,4 +37,4 @@ It has been moved here to be easier to maintain than editing IODevice.h #include "IO_EXSensorCAM.h" #include "IO_DS1307.h" #include "IO_I2CRailcom.h" - +#include "IO_HALDisplay.h" diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 39ec08d..b7df4a1 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -1,6 +1,6 @@ /* * © 2022-2024 Paul M Antoine - * © 2024 Herb Morton + * © 2024-2025 Herb Morton * © 2021 Mike S * © 2021 Fred Decker * © 2020-2023 Harald Barth @@ -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..e6001c1 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. * @@ -42,6 +42,7 @@ MotorDriver * TrackManager::track[MAX_TRACKS] = { NULL }; int16_t TrackManager::trackDCAddr[MAX_TRACKS] = { 0 }; +int16_t TrackManager::tPwr_mA[8]={0,0,0,0,0,0,0,0}; int8_t TrackManager::lastTrack=-1; bool TrackManager::progTrackSyncMain=false; @@ -646,6 +647,33 @@ void TrackManager::reportCurrent(Print* stream) { StringFormatter::send(stream,F(">\n")); } +void TrackManager::reportCurrentLCD(uint8_t display, byte row) { + FOR_EACH_TRACK(t) { + bool pstate = TrackManager::isPowerOn(t); // checks if power is on or off + TRACK_MODE tMode=(TrackManager::getMode(t)); // gets to current power mode + int16_t DCAddr=(TrackManager::returnDCAddr(t)); + + if (pstate) { // if power is on do this section + tPwr_mA[t]=(3*tPwr_mA[t]>>2) + ((track[t]->getPower()==POWERMODE::OVERLOAD) ? -1 : + track[t]->raw2mA(track[t]->getCurrentRaw(false))); + if (tMode & TRACK_MODE_DC) { // Test if track is in DC or DCX mode + SCREEN(display, row+t, F("%c: %S %d ON %dmA"), t+'A', (TrackManager::getModeName(tMode)),DCAddr, tPwr_mA[t]>>2); + } + else { // formats without DCAddress + SCREEN(display, row+t, F("%c: %S ON %dmA"), t+'A', (TrackManager::getModeName(tMode)), tPwr_mA[t]>>2); + } + } + /* else { // if power is off do this section + if (tMode & TRACK_MODE_DC) { // DC / DCX + SCREEN(display, row+t, F("Track %c: %S %d OFF"), t+'A', (TrackManager::getModeName(tMode)),DCAddr); + } + else { // Not DC or DCX + SCREEN(display, row+t, F("Track %c: %S OFF"), t+'A', (TrackManager::getModeName(tMode))); + } + } */ + } + } + void TrackManager::reportGauges(Print* stream) { StringFormatter::send(stream,F(" command private: static void addTrack(byte t, MotorDriver* driver); diff --git a/version.h b/version.h index ea1326d..8a58a90 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,9 @@ #include "StringFormatter.h" -#define VERSION "5.5.12" +#define VERSION "5.5.12 F439" +// - Nucleo-F4 DC mode timer sync +// - Track power status // 5.5.12 - Websocket support (wifi only) // 5.5.11 - (5.4.2) accessory command reverse // 5.5.10 - CamParser fix