mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2025-04-21 12:31:19 +02:00
Sync DC mode tracks - Nucleo-F4
This commit is contained in:
parent
83a5c52a0d
commit
e76cdd7c06
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* © 2023 Neil McKechnie
|
* © 2023 Neil McKechnie
|
||||||
* © 2022-2024 Paul M. Antoine
|
* © 2022-2024 Paul M. Antoine
|
||||||
|
* © 2025 Herb Morton
|
||||||
* © 2021 Mike S
|
* © 2021 Mike S
|
||||||
* © 2021, 2023 Harald Barth
|
* © 2021, 2023 Harald Barth
|
||||||
* © 2021 Fred Decker
|
* © 2021 Fred Decker
|
||||||
@ -36,6 +37,21 @@
|
|||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
#include <wiring_private.h>
|
#include <wiring_private.h>
|
||||||
|
|
||||||
|
// 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)
|
#if defined(ARDUINO_NUCLEO_F401RE)
|
||||||
// Nucleo-64 boards don't have additional serial ports defined by default
|
// Nucleo-64 boards don't have additional serial ports defined by default
|
||||||
// Serial1 is available on the F401RE, but not hugely convenient.
|
// 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)
|
else if (f >= 3)
|
||||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 16000);
|
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 16000);
|
||||||
else if (f >= 2)
|
else if (f >= 2)
|
||||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 3400);
|
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 3600);
|
||||||
else if (f == 1)
|
else if (f == 1)
|
||||||
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 480);
|
DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 480);
|
||||||
else
|
else
|
||||||
@ -328,7 +344,8 @@ void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency
|
|||||||
if (pin_timer[pin] != NULL)
|
if (pin_timer[pin] != NULL)
|
||||||
{
|
{
|
||||||
pin_timer[pin]->setPWM(pin_channel[pin], pin, frequency, 0); // set frequency in Hertz, 0% dutycycle
|
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
|
else
|
||||||
DIAG(F("DCCEXanalogWriteFrequency::failed to allocate HardwareTimer instance!"));
|
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!
|
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!
|
pin_timer[pin]->setOverflow(frequency, HERTZ_FORMAT); // Just change the frequency if it's already running!
|
||||||
DIAG(F("DCCEXanalogWriteFrequency::setting frequency to %d"), frequency);
|
DIAG(F("DCCEXanalogWriteFrequency::setting frequency to %d"), frequency);
|
||||||
|
resetCounterDCmodeTimers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
channel_frequency[pin] = frequency;
|
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
|
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);
|
DIAG(F("DCCEXanalogWrite::Pin %d, value %d, duty cycle %d"), pin, value, duty_cycle);
|
||||||
// }
|
// }
|
||||||
|
refreshDCmodeTimers();
|
||||||
|
resetCounterDCmodeTimers();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DIAG(F("DCCEXanalogWrite::Pin %d is not configured for PWM!"), pin);
|
DIAG(F("DCCEXanalogWrite::Pin %d is not configured for PWM!"), pin);
|
||||||
@ -659,4 +679,35 @@ void ADCee::begin() {
|
|||||||
#endif
|
#endif
|
||||||
interrupts();
|
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
|
#endif
|
||||||
|
@ -371,8 +371,8 @@ void MotorDriver::setDCSignal(byte speedcode, uint8_t frequency /*default =0*/)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//DIAG(F("Brake pin %d value %d freqency %d"), brakePin, brake, f);
|
//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::DCCEXanalogWriteFrequency(brakePin, f); // set DC PWM frequency
|
||||||
|
DCCTimer::DCCEXanalogWrite(brakePin, brake, invertBrake); // line swapped to set frequency first
|
||||||
#else // all AVR here
|
#else // all AVR here
|
||||||
DCCTimer::DCCEXanalogWriteFrequency(brakePin, frequency); // frequency steps
|
DCCTimer::DCCEXanalogWriteFrequency(brakePin, frequency); // frequency steps
|
||||||
analogWrite(brakePin, invertBrake ? 255-brake : brake);
|
analogWrite(brakePin, invertBrake ? 255-brake : brake);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* © 2022-2025 Chris Harlow
|
* © 2022-2025 Chris Harlow
|
||||||
* © 2022-2024 Harald Barth
|
* © 2022-2024 Harald Barth
|
||||||
* © 2023-2024 Paul M. Antoine
|
* © 2023-2024 Paul M. Antoine
|
||||||
* © 2024 Herb Morton
|
* © 2024-2025 Herb Morton
|
||||||
* © 2023 Colin Murdoch
|
* © 2023 Colin Murdoch
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@ -557,6 +557,20 @@ void TrackManager::setTrackPower(TRACK_MODE trackmodeToMatch, POWERMODE powermod
|
|||||||
}
|
}
|
||||||
if (didChange)
|
if (didChange)
|
||||||
CommandDistributor::broadcastPower();
|
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 <F29..31 was set on a later track than power
|
||||||
|
// Note: this retains power but prevents speed doubling
|
||||||
|
for (byte i=0;i<lastTrack;i++) {
|
||||||
|
setTrackPowerF439ZI(i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set track power for this track, inependent of mode
|
// Set track power for this track, inependent of mode
|
||||||
@ -587,6 +601,20 @@ void TrackManager::setTrackPower(POWERMODE powermode, byte t) {
|
|||||||
driver->setPower(powermode);
|
driver->setPower(powermode);
|
||||||
if (oldpower != driver->getPower())
|
if (oldpower != driver->getPower())
|
||||||
CommandDistributor::broadcastPower();
|
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 <F29..31 was set on a later track than power
|
||||||
|
// Note: this retains power but prevents speed doubling
|
||||||
|
for (byte i=0;i<lastTrack;i++) {
|
||||||
|
setTrackPowerF439ZI(i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns state of the one and only prog track
|
// returns state of the one and only prog track
|
||||||
@ -710,3 +738,38 @@ TRACK_MODE TrackManager::getMode(byte t) {
|
|||||||
int16_t TrackManager::returnDCAddr(byte t) {
|
int16_t TrackManager::returnDCAddr(byte t) {
|
||||||
return (trackDCAddr[t]);
|
return (trackDCAddr[t]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set track power for EACH track, independent of mode
|
||||||
|
// This updates the settings so that speed is correct
|
||||||
|
// following a frequency change - DC mode
|
||||||
|
void TrackManager::setTrackPowerF439ZI(byte t) {
|
||||||
|
MotorDriver *driver=track[t];
|
||||||
|
if (driver == NULL) { // track is not defined at all
|
||||||
|
// DIAG(F("Error: Track %c does not exist"), t+'A');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TRACK_MODE trackmode = driver->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();
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* © 2022 Chris Harlow
|
* © 2022 Chris Harlow
|
||||||
* © 2022-2024 Harald Barth
|
* © 2022-2024 Harald Barth
|
||||||
|
* © 2025 Herb Morton
|
||||||
* © 2023 Colin Murdoch
|
* © 2023 Colin Murdoch
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
@ -69,6 +70,7 @@ class TrackManager {
|
|||||||
static void setTrackPower(TRACK_MODE trackmode, POWERMODE powermode);
|
static void setTrackPower(TRACK_MODE trackmode, POWERMODE powermode);
|
||||||
static void setMainPower(POWERMODE mode) {setTrackPower(TRACK_MODE_MAIN, mode);}
|
static void setMainPower(POWERMODE mode) {setTrackPower(TRACK_MODE_MAIN, mode);}
|
||||||
static void setProgPower(POWERMODE mode) {setTrackPower(TRACK_MODE_PROG, mode);}
|
static void setProgPower(POWERMODE mode) {setTrackPower(TRACK_MODE_PROG, mode);}
|
||||||
|
static void setTrackPowerF439ZI(byte t);
|
||||||
|
|
||||||
static const int16_t MAX_TRACKS=8;
|
static const int16_t MAX_TRACKS=8;
|
||||||
static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0);
|
static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0);
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
#include "StringFormatter.h"
|
#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.21 - Backed out the broken merge with frequency change and
|
||||||
// 5.5.20 - EXRAIL SET/RESET assert fix
|
// 5.5.20 - EXRAIL SET/RESET assert fix
|
||||||
// 5.5.19 - Railcom change to use RailcomCollector device
|
// 5.5.19 - Railcom change to use RailcomCollector device
|
||||||
|
Loading…
x
Reference in New Issue
Block a user