1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-04-02 19:50:13 +02:00

DC mode timer sync STM32 and JL command

This commit is contained in:
Ash-4 2025-01-28 16:06:08 -06:00
parent f3b87877ef
commit 5d1b3a7a03
7 changed files with 92 additions and 8 deletions

View File

@ -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); // <g limit...limit>
return;
case "L"_hk: // <JL display row> track state and mA value on display
if (params<3) break;
TrackManager::reportCurrentLCD(p[1], p[2]); // Track power status
return;
case "A"_hk: // <JA> intercepted by EXRAIL// <JA> returns automations/routes
if (params!=1) break; // <JA>
StringFormatter::send(stream, F("<jA>\n"));

View File

@ -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 <wiring_private.h>
// 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

View File

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

View File

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

View File

@ -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("<jG"));
FOR_EACH_TRACK(t) {

View File

@ -1,6 +1,7 @@
/*
* © 2022 Chris Harlow
* © 2022-2024 Harald Barth
* © 2025 Herb Morton
* © 2023 Colin Murdoch
*
* All rights reserved.
@ -87,6 +88,7 @@ class TrackManager {
static void sampleCurrent();
static void reportGauges(Print* stream);
static void reportCurrent(Print* stream);
static void reportCurrentLCD(uint8_t display, byte row);
static void reportObsoleteCurrent(Print* stream);
static void streamTrackState(Print* stream, byte t);
static bool isPowerOn(byte t);
@ -105,6 +107,7 @@ class TrackManager {
private:
#endif
static MotorDriver* track[MAX_TRACKS];
static int16_t tPwr_mA[8]; // for <JL ..> command
private:
static void addTrack(byte t, MotorDriver* driver);

View File

@ -3,7 +3,9 @@
#include "StringFormatter.h"
#define VERSION "5.5.12"
#define VERSION "5.5.12 F439"
// - Nucleo-F4 DC mode timer sync
// - <JL display startRow> Track power status
// 5.5.12 - Websocket support (wifi only)
// 5.5.11 - (5.4.2) accessory command reverse
// 5.5.10 - CamParser fix