Skip to content

Commit 86d977f

Browse files
committed
Remove hard-coded pin and fix timing
1 parent 6800f48 commit 86d977f

File tree

9 files changed

+119
-62
lines changed

9 files changed

+119
-62
lines changed

DCCTimer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ class DCCTimer {
6262
static bool isPWMPin(byte pin);
6363
static void setPWM(byte pin, bool high);
6464
static void clearPWM();
65-
static void startRailcomTimer(byte brakePin);
66-
static void ackRailcomTimer();
65+
static void startRailcomTimer(bool isMain, bool lastBit);
66+
static void ackRailcomTimer(bool isMain);
6767
static void DCCEXanalogWriteFrequency(uint8_t pin, uint32_t frequency);
6868
static void DCCEXanalogWrite(uint8_t pin, int value, bool invert);
6969
static void DCCEXledcDetachPin(uint8_t pin);

DCCTimerAVR.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
6060
}
6161

6262

63-
void DCCTimer::startRailcomTimer(byte brakePin) {
63+
void DCCTimer::startRailcomTimer(bool isMain, bool lastBit) {
6464
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
6565
/* The Railcom timer is started in such a way that it
6666
- First triggers 28uS after the last TIMER1 tick.
@@ -77,9 +77,11 @@ void DCCTimer::startRailcomTimer(byte brakePin) {
7777
(there will be 7 DCC timer1 ticks in which to do this.)
7878
7979
*/
80-
(void) brakePin; // Ignored... works on pin 9 only
80+
(void) lastBit; // Ignored
8181
const int cutoutDuration = 430; // Desired interval in microseconds
8282

83+
if (!isMain) return;
84+
8385
// Set up Timer2 for CTC mode (Clear Timer on Compare Match)
8486
TCCR2A = 0; // Clear Timer2 control register A
8587
TCCR2B = 0; // Clear Timer2 control register B
@@ -117,8 +119,9 @@ void DCCTimer::startRailcomTimer(byte brakePin) {
117119
#endif
118120
}
119121

120-
void DCCTimer::ackRailcomTimer() {
122+
void DCCTimer::ackRailcomTimer(bool isMain) {
121123
#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
124+
if (!isMain) return;
122125
OCR2B= 0x00; // brake pin pwm duty cycle 0 at next tick
123126
#endif
124127
}

DCCTimerMEGAAVR.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,15 @@ extern char *__malloc_heap_start;
8080
interruptHandler();
8181
}
8282

83-
void DCCTimer::startRailcomTimer(byte brakePin) {
83+
void DCCTimer::startRailcomTimer(bool isMain, bool lastBit) {
8484
// TODO: for intended operation see DCCTimerAVR.cpp
85-
(void) brakePin;
85+
(void) isMain;
86+
(void) lastBit;
8687
}
8788

88-
void DCCTimer::ackRailcomTimer() {
89+
void DCCTimer::ackRailcomTimer(bool isMain) {
8990
// TODO: for intended operation see DCCTimerAVR.cpp
91+
(void) isMain;
9092
}
9193

9294
bool DCCTimer::isPWMPin(byte pin) {

DCCTimerSAMD.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,15 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
7676
interrupts();
7777
}
7878

79-
void DCCTimer::startRailcomTimer(byte brakePin) {
79+
void DCCTimer::startRailcomTimer(bool isMain, bool lastBit) {
8080
// TODO: for intended operation see DCCTimerAVR.cpp
81-
(void) brakePin;
81+
(void) isMain;
82+
(void) lastBit;
8283
}
8384

84-
void DCCTimer::ackRailcomTimer() {
85+
void DCCTimer::ackRailcomTimer(bool isMain) {
8586
// TODO: for intended operation see DCCTimerAVR.cpp
87+
(void) isMain;
8688
}
8789

8890
// Timer IRQ handlers replace the dummy handlers (in cortex_handlers)

DCCTimerSTM32.cpp

Lines changed: 82 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@
3030
#ifdef ARDUINO_ARCH_STM32
3131

3232
#include "DCCTimer.h"
33-
#ifdef DEBUG_ADC
3433
#include "TrackManager.h"
35-
#endif
3634
#include "DIAG.h"
3735
#include <wiring_private.h>
3836

@@ -215,68 +213,106 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
215213
interrupts();
216214
}
217215

218-
// Static variables for Railcom timer shared between functions
219-
static HardwareTimer *railcomTimer = nullptr;
220-
static byte railcomBrakePin = 255;
216+
// Static variables for Railcom timers - separate for main and prog tracks
217+
static HardwareTimer *railcomMainTimer = nullptr;
218+
static HardwareTimer *railcomProgTimer = nullptr;
221219

222-
// Timer callback functions
223-
void railcomEndCallback() {
224-
if (railcomBrakePin != 255) {
225-
digitalWrite(railcomBrakePin, LOW);
220+
// Timer callback functions for main track
221+
void railcomMainEndCallback() {
222+
TrackManager::setMainBrake(false, true);
223+
if (railcomMainTimer) {
224+
railcomMainTimer->pause();
225+
railcomMainTimer->detachInterrupt();
226226
}
227-
if (railcomTimer) {
228-
railcomTimer->pause();
229-
railcomTimer->detachInterrupt();
227+
}
228+
229+
void railcomMainStartCallback() {
230+
TrackManager::setMainBrake(true, true);
231+
if (railcomMainTimer) {
232+
railcomMainTimer->pause();
233+
railcomMainTimer->detachInterrupt();
234+
// Start timer for cutout duration (430us)
235+
railcomMainTimer->setOverflow(430, MICROSEC_FORMAT);
236+
railcomMainTimer->attachInterrupt(railcomMainEndCallback);
237+
railcomMainTimer->refresh();
238+
railcomMainTimer->resume();
230239
}
231240
}
232241

233-
void railcomStartCallback() {
234-
if (railcomBrakePin != 255) {
235-
digitalWrite(railcomBrakePin, HIGH);
242+
// Timer callback functions for prog track
243+
void railcomProgEndCallback() {
244+
TrackManager::setProgBrake(false, true);
245+
if (railcomProgTimer) {
246+
railcomProgTimer->pause();
247+
railcomProgTimer->detachInterrupt();
236248
}
237-
if (railcomTimer) {
238-
railcomTimer->pause();
239-
railcomTimer->detachInterrupt();
249+
}
250+
251+
void railcomProgStartCallback() {
252+
TrackManager::setProgBrake(true, true);
253+
if (railcomProgTimer) {
254+
railcomProgTimer->pause();
255+
railcomProgTimer->detachInterrupt();
240256
// Start timer for cutout duration (430us)
241-
railcomTimer->setOverflow(430, MICROSEC_FORMAT);
242-
railcomTimer->attachInterrupt(railcomEndCallback);
243-
railcomTimer->refresh();
244-
railcomTimer->resume();
257+
railcomProgTimer->setOverflow(430, MICROSEC_FORMAT);
258+
railcomProgTimer->attachInterrupt(railcomProgEndCallback);
259+
railcomProgTimer->refresh();
260+
railcomProgTimer->resume();
245261
}
246262
}
247263

248-
void DCCTimer::startRailcomTimer(byte brakePin) {
249-
const uint32_t cutoutOffset = 10; // 26-32 microseconds after last DCC tick minus overhead
264+
void DCCTimer::startRailcomTimer(bool isMain, bool lastBit) {
265+
uint32_t cutoutOffset;
266+
HardwareTimer *timer = nullptr;
267+
268+
// We're just starting the last XOR bit, wait for the bit length, terminator bit, and initial cutout delay, minus some overhead
269+
if (lastBit) {
270+
// 1-bit
271+
cutoutOffset = 2 * 58 + 116 + 10;
272+
} else {
273+
// 0-bit
274+
cutoutOffset = 2 * 116 + 116 + 10;
275+
}
250276

251-
// Configure brakePin as output
252-
pinMode(brakePin, OUTPUT);
253-
digitalWrite(brakePin, LOW);
277+
if (isMain) {
278+
TrackManager::setMainBrake(false, true);
254279

255-
// Initialize timer if not already done
256-
if (!railcomTimer) {
257-
railcomTimer = new HardwareTimer(TIM3);
258-
}
280+
// Initialize main timer if not already done
281+
if (!railcomMainTimer) {
282+
railcomMainTimer = new HardwareTimer(TIM3);
283+
}
284+
timer = railcomMainTimer;
285+
} else {
286+
TrackManager::setProgBrake(false, true);
259287

260-
// Store the brake pin for callbacks
261-
railcomBrakePin = brakePin;
288+
// Initialize prog timer if not already done (use TIM4 for prog track)
289+
if (!railcomProgTimer) {
290+
railcomProgTimer = new HardwareTimer(TIM4);
291+
}
292+
timer = railcomProgTimer;
293+
}
262294

263295
// Start timer for offset
264-
railcomTimer->pause();
265-
railcomTimer->setPrescaleFactor(1);
266-
railcomTimer->setOverflow(cutoutOffset, MICROSEC_FORMAT);
267-
railcomTimer->attachInterrupt(railcomStartCallback);
268-
railcomTimer->refresh();
269-
railcomTimer->resume();
296+
timer->pause();
297+
timer->setPrescaleFactor(1);
298+
timer->setOverflow(cutoutOffset, MICROSEC_FORMAT);
299+
timer->attachInterrupt(isMain ? railcomMainStartCallback : railcomProgStartCallback);
300+
timer->refresh();
301+
timer->resume();
270302
}
271303

272-
void DCCTimer::ackRailcomTimer() {
273-
// Immediately end the Railcom cutout: set brake pin LOW and stop timer
274-
if (railcomBrakePin != 255) {
275-
digitalWrite(railcomBrakePin, LOW);
304+
void DCCTimer::ackRailcomTimer(bool isMain) {
305+
// Immediately end the Railcom cutout for whichever timer is active
306+
// Check both timers and stop any that are running
307+
if (isMain && railcomMainTimer) {
308+
railcomMainTimer->pause();
309+
railcomMainTimer->detachInterrupt();
310+
TrackManager::setMainBrake(false, true);
276311
}
277-
if (railcomTimer) {
278-
railcomTimer->pause();
279-
railcomTimer->detachInterrupt();
312+
if (!isMain && railcomProgTimer) {
313+
railcomProgTimer->pause();
314+
railcomProgTimer->detachInterrupt();
315+
TrackManager::setProgBrake(false, true);
280316
}
281317
}
282318

DCCTimerTEENSY.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,15 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
3939
myDCCTimer.begin(interruptHandler, DCC_SIGNAL_TIME);
4040
}
4141

42-
void DCCTimer::startRailcomTimer(byte brakePin) {
42+
void DCCTimer::startRailcomTimer(bool isMain, bool lastBit) {
4343
// TODO: for intended operation see DCCTimerAVR.cpp
44-
(void) brakePin;
44+
(void) isMain;
45+
(void) lastBit;
4546
}
4647

47-
void DCCTimer::ackRailcomTimer() {
48+
void DCCTimer::ackRailcomTimer(bool isMain) {
4849
// TODO: for intended operation see DCCTimerAVR.cpp
50+
(void) isMain;
4951
}
5052

5153
bool DCCTimer::isPWMPin(byte pin) {

DCCWaveform.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ void DCCWaveform::interrupt2() {
147147
// that the reminder doesn't block a more urgent packet.
148148
reminderWindowOpen=transmitRepeats==0 && remainingPreambles<12 && remainingPreambles>1;
149149
if (remainingPreambles==1) promotePendingPacket();
150-
else if (remainingPreambles==10 && isMainTrack && railcomActive) DCCTimer::ackRailcomTimer();
150+
else if (remainingPreambles==10 && railcomActive) DCCTimer::ackRailcomTimer(isMainTrack);
151151
// Update free memory diagnostic as we don't have anything else to do this time.
152152
// Allow for checkAck and its called functions using 22 bytes more.
153153
else DCCTimer::updateMinimumFreeMemoryISR(22);
@@ -176,7 +176,7 @@ void DCCWaveform::interrupt2() {
176176
// through the first preamble bit.
177177
// Note.. we are still sending the last packet bit
178178
// and we then have to allow for the packet end bit
179-
if (isMainTrack && railcomActive) DCCTimer::startRailcomTimer(9);
179+
if (railcomActive) DCCTimer::startRailcomTimer(isMainTrack, state == WAVE_MID_1);
180180
}
181181
}
182182
}

TrackManager.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,14 @@ void TrackManager::reportGauges(Print* stream) {
653653
StringFormatter::send(stream,F(">\n"));
654654
}
655655

656+
void TrackManager::setTrackBrake(TRACK_MODE trackmode, bool on, bool interruptContext) {
657+
FOR_EACH_TRACK(t) {
658+
if (track[t]->getMode() & trackmode) {
659+
track[t]->setBrake(on, interruptContext);
660+
}
661+
}
662+
}
663+
656664
void TrackManager::setJoinRelayPin(byte joinRelayPin) {
657665
joinRelay=joinRelayPin;
658666
if (joinRelay!=UNUSED_PIN) {

TrackManager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ class TrackManager {
7070
static void setMainPower(POWERMODE mode) {setTrackPower(TRACK_MODE_MAIN, mode);}
7171
static void setProgPower(POWERMODE mode) {setTrackPower(TRACK_MODE_PROG, mode);}
7272

73+
static void setTrackBrake(TRACK_MODE trackmode, bool on, bool interruptContext=false);
74+
static void setMainBrake(bool on, bool interruptContext=false) {setTrackBrake(TRACK_MODE_MAIN, on, interruptContext);}
75+
static void setProgBrake(bool on, bool interruptContext=false) {setTrackBrake(TRACK_MODE_PROG, on, interruptContext);}
76+
7377
static const int16_t MAX_TRACKS=8;
7478
static bool setTrackMode(byte track, TRACK_MODE mode, int16_t DCaddr=0);
7579
static bool parseEqualSign(Print * stream, int16_t params, int16_t p[]);

0 commit comments

Comments
 (0)