Skip to content

Commit 20beb1b

Browse files
committed
Merge branch 'devel' into devel-mcpwm
2 parents 0a4ee98 + ffc9c78 commit 20beb1b

File tree

10 files changed

+78
-84
lines changed

10 files changed

+78
-84
lines changed

DCCEXParser.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,24 +1306,19 @@ bool DCCEXParser::parseC(Print *stream, int16_t params, int16_t p[]) {
13061306
{ // <C RAILCOM ON|OFF|DEBUG >
13071307
if (params<2) return false;
13081308
bool on=false;
1309-
bool debug=false;
13101309
switch (p[1]) {
13111310
case "ON"_hk:
13121311
case 1:
13131312
on=true;
13141313
break;
1315-
case "DEBUG"_hk:
1316-
on=true;
1317-
debug=true;
1318-
break;
13191314
case "OFF"_hk:
13201315
case 0:
13211316
break;
13221317
default:
13231318
return false;
13241319
}
13251320
DIAG(F("Railcom %S")
1326-
,DCCWaveform::setRailcom(on,debug)?F("ON"):F("OFF"));
1321+
,DCCWaveform::setRailcom(on)?F("ON"):F("OFF"));
13271322
return true;
13281323
}
13291324
#endif

DCCTimerAVR.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,14 @@ void DCCTimer::startRailcomTimer(byte brakePin) {
6666
// diagnostic digitalWrite(4,HIGH);
6767

6868
/* The Railcom timer is started in such a way that it
69-
- First triggers 58+29 uS after the previous TIMER1 tick.
69+
- First triggers a calculated time after the previous TIMER1 tick.
7070
This provides an accurate offset (in High Accuracy mode)
71-
for the start of the Railcom cutout.
72-
- Sets the Railcom pin high at first tick and subsequent ticks
71+
for the start of the Railcom cutout. The delayBeforeCutout value
72+
reflects that this call is made at the start of the end-packet bit
73+
thus the delay is nominally 58+58+Tcs BUT
74+
in HA mode, the dcc pin is flipped at the NEXT
75+
interrupt so runs 1 tick behind the code. Thus an extra 58uS is needed.
76+
- Timer2 Sets the Railcom pin high at first tick and subsequent ticks
7377
until its reset to setting pin 9 low at next tick.
7478
7579
- Cycles at cutoutDuration so the second tick is the
@@ -80,29 +84,32 @@ void DCCTimer::startRailcomTimer(byte brakePin) {
8084
(there will be 7 DCC timer1 ticks in which to do this.)
8185
8286
*/
83-
const int Tcs=28; // (26+32)/2 would be half way spec Desired time from idealised setup call (at previous DCC timer interrupt) to the cutout but choose even
84-
const int cutoutDuration = 450; // As chosen by most
85-
const byte delayBeforeCutout=58+58+Tcs; // Expected time from idealised setup call (at previous DCC timer interrupt) to the cutout. This is the time we need to wait before we can set pin 9 high. We will then set pin 9 low at the next tick which is cutoutDuration later. This value should be reduced to reflect the Timer1 value measuring the time since the previous hardware interrupt.
87+
const int Tcs=28; // NMRA spec is 26..32
88+
const int cutoutDuration_uS = 450; // As chosen by most
89+
const uint16_t delayBeforeCutout_uS=58+58+58+Tcs;
90+
const uint16_t timer1_ticks_per_uS = 8;
91+
const uint16_t timer2_uS_per_tick = 2;
8692

8793
// Set Timer2 to CTC mode with set on compare match
8894
TCCR2A = (1 << WGM21) | (1 << COM2B0) | (1 << COM2B1);
8995
// Prescaler of 32
9096
TCCR2B = (1 << CS21) | (1 << CS20);
91-
OCR2A = cutoutDuration/2; // Compare match value for cutout duration in timer2 ticks (2uSec)
97+
OCR2A = cutoutDuration_uS/timer2_uS_per_tick; // Compare match value for cutout duration in timer2 ticks (2uSec)
9298
// Enable Timer2 output on pin 9 (OC2B)
9399
DDRB |= (1 << DDB1);
94100

95101
// timeSlip is the expired time since the DCC timer interrupt that triggered this call.
96102
// This allows us to cope with any delays between the interrupt and this code executing.
97103

98-
// tcnt1 = prescaler 64, tcnt2 prescaler=32
104+
99105
noInterrupts();
100-
uint16_t timeSlip=(TCNT1/64)*32;
101-
// Adjust the Timer2 counter so it first triggers at the right place in the waveform.
102-
// TCNT1 moves 8 ticks per uSec
103-
// TCNT2 uses 2 uSec for each tick
104-
// TCNT1 is 8*2 = 16 times faster than TCNT2
105-
TCNT2=(cutoutDuration+TCNT1/8-delayBeforeCutout)/2;
106+
// Time already used since DCC interrupt
107+
uint16_t timeSlip_uS=TCNT1/timer1_ticks_per_uS;
108+
109+
// Calculate the time left before the cutout is to be triggered
110+
uint16_t timeToCutout_uS=cutoutDuration_uS+timeSlip_uS-delayBeforeCutout_uS;
111+
// Adjust clock2 to trigger on time
112+
TCNT2=timeToCutout_uS/timer2_uS_per_tick;
106113
interrupts();
107114
}
108115

DCCWaveform.cpp

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "DCCTimer.h"
3030
#include "DCCACK.h"
3131
#include "DIAG.h"
32+
#include "Railcom.h"
3233

3334
bool DCCWaveform::cutoutNextTime=false;
3435
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
@@ -77,8 +78,7 @@ void DCCWaveform::interruptHandler() {
7778
#if defined(HAS_ENOUGH_MEMORY)
7879
if (cutoutNextTime) {
7980
cutoutNextTime=false;
80-
railcomSampleWindow=false; // about to cutout, stop reading railcom data.
81-
railcomCutoutCounter++;
81+
Railcom::incCutout();
8282
DCCTimer::startRailcomTimer(9);
8383
}
8484
#endif
@@ -126,12 +126,16 @@ DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) {
126126

127127
bool DCCWaveform::railcomPossible=false; // High accuracy only
128128
volatile bool DCCWaveform::railcomActive=false; // switched on by user
129-
volatile bool DCCWaveform::railcomDebug=false; // switched on by user
130-
volatile bool DCCWaveform::railcomSampleWindow=false; // true during packet transmit
131-
volatile byte DCCWaveform::railcomCutoutCounter=0; // cyclic cutout
132-
volatile byte DCCWaveform::railcomLastAddressHigh=0;
133-
volatile byte DCCWaveform::railcomLastAddressLow=0;
134-
129+
130+
bool DCCWaveform::setRailcom(bool on) {
131+
if (on && railcomPossible) {
132+
railcomActive=true;
133+
}
134+
else {
135+
railcomActive=false;
136+
}
137+
return railcomActive;
138+
}
135139

136140
#pragma GCC push_options
137141
#pragma GCC optimize ("-O3")
@@ -162,9 +166,7 @@ void DCCWaveform::interrupt2() {
162166
// if preamble length is 16 then this evaluates to 5
163167
// Remember address bytes of last sent packet so that Railcom can
164168
// work out where the channel2 data came from.
165-
railcomLastAddressHigh=transmitPacket[0];
166-
railcomLastAddressLow =transmitPacket[1];
167-
railcomSampleWindow=true;
169+
Railcom::setLoco(transmitPacket[0],transmitPacket[1]);
168170
} else if (remainingPreambles==(requiredPreambles-3)) {
169171
// cutout can be ended when read
170172
// see above for requiredPreambles
@@ -246,11 +248,7 @@ void DCCWaveform::promotePendingPacket() {
246248

247249
// nothing to do, just send idles or resets
248250
// Fortunately reset and idle packets are the same length
249-
// Note: If railcomDebug is on, then we send resets to the main
250-
// track instead of idles. This means that all data will be zeros
251-
// and only the presets will be ones, making it much
252-
// easier to read on a logic analyser.
253-
memcpy( transmitPacket, (isMainTrack && (!railcomDebug)) ? idlePacket : resetPacket, sizeof(idlePacket));
251+
memcpy( transmitPacket, isMainTrack ? idlePacket : resetPacket, sizeof(idlePacket));
254252
transmitLength = sizeof(idlePacket);
255253
transmitRepeats = 0;
256254
if (getResets() < 250) sentResetsSincePacket++; // only place to increment (private!)

DCCWaveform.h

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -82,45 +82,18 @@ class DCCWaveform {
8282
void schedulePacket(const byte buffer[], byte byteCount, byte repeats);
8383
bool isReminderWindowOpen();
8484
void promotePendingPacket();
85-
static bool setRailcom(bool on, bool debug) {
86-
if (on && railcomPossible) {
87-
railcomActive=true;
88-
railcomDebug=debug;
89-
}
90-
else {
91-
railcomActive=false;
92-
railcomDebug=false;
93-
railcomSampleWindow=false;
94-
}
95-
return railcomActive;
96-
}
97-
85+
static bool setRailcom(bool on);
9886
inline static bool isRailcom() {
9987
return railcomActive;
10088
};
101-
inline static byte getRailcomCutoutCounter() {
102-
return railcomCutoutCounter;
103-
};
104-
inline static void incCutoutCounter() {
105-
railcomCutoutCounter++;
106-
}
107-
inline static bool isRailcomSampleWindow() {
108-
return railcomSampleWindow;
109-
};
11089
inline static bool isRailcomPossible() {
11190
return railcomPossible;
11291
};
11392
inline static void setRailcomPossible(bool yes) {
11493
railcomPossible=yes;
115-
if (!yes) setRailcom(false,false);
94+
if (!yes) setRailcom(false);
11695
};
117-
inline static uint16_t getRailcomLastLocoAddress() {
118-
// first 2 bits 00=short loco, 11=long loco , 01/10 = accessory
119-
byte addressType=railcomLastAddressHigh & 0xC0;
120-
if (addressType==0xC0) return ((railcomLastAddressHigh & 0x3f)<<8) | railcomLastAddressLow;
121-
if (addressType==0x00) return railcomLastAddressHigh & 0x3F;
122-
return 0;
123-
}
96+
12497

12598
private:
12699
#ifndef ARDUINO_ARCH_ESP32
@@ -148,10 +121,6 @@ class DCCWaveform {
148121
byte pendingRepeats;
149122
static bool railcomPossible; // High accuracy mode only
150123
static volatile bool railcomActive; // switched on by user
151-
static volatile bool railcomDebug; // switched on by user
152-
static volatile bool railcomSampleWindow; // when safe to sample
153-
static volatile byte railcomCutoutCounter; // incremented for each cutout
154-
static volatile byte railcomLastAddressHigh,railcomLastAddressLow;
155124
static bool cutoutNextTime; // railcom
156125

157126

DCCWaveformRMT.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ RMTChannel *DCCWaveform::rmtProgChannel = NULL;
3434

3535
bool DCCWaveform::railcomPossible=false; // High accuracy only
3636
volatile bool DCCWaveform::railcomActive=false; // switched on by user
37-
volatile bool DCCWaveform::railcomDebug=false; // switched on by user
38-
volatile bool DCCWaveform::railcomSampleWindow=false; // true during packet transmit
39-
volatile byte DCCWaveform::railcomCutoutCounter=0; // cyclic cutout
40-
volatile byte DCCWaveform::railcomLastAddressHigh=0;
41-
volatile byte DCCWaveform::railcomLastAddressLow=0;
4237

4338
DCCWaveform::DCCWaveform(byte preambleBits, bool isMain) {
4439
isMainTrack = isMain;
@@ -117,4 +112,9 @@ void IRAM_ATTR DCCWaveform::loop() {
117112
DCCACK::checkAck(progTrack.getResets());
118113
}
119114

115+
bool DCCWaveform::setRailcom(bool on) {
116+
// TODO... ESP32 railcom waveform
117+
return false;
118+
}
119+
120120
#endif

GITHUB_SHA.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
#define GITHUB_SHA "devel-202603012041Z"
1+
#define GITHUB_SHA "devel-202603061339Z"

IO_I2CRailcom.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,15 @@ void I2CRailcom::create(VPIN firstVpin, int nPins, I2CAddress i2cAddress) {
8383

8484
// have we read this cutout already?
8585
// basically we only poll once per packet when railcom cutout is working
86-
auto cut=DCCWaveform::getRailcomCutoutCounter();
86+
auto cut=Railcom::getCutout();
8787
if (cutoutCounter==cut) return;
8888
cutoutCounter=cut;
8989
Railcom::loop(); // in case a csv read has timed out
9090

9191
// Obtain data length from the collector
9292
byte inbuf[1];
93-
byte queryLength[]={'?'};
93+
uint16_t loco=Railcom::getLoco();
94+
byte queryLength[]={'?',(byte)(loco >>8) , (byte)(loco & 0xff)};
9495
auto state=I2CManager.read(_I2CAddress, inbuf, 1,queryLength,sizeof(queryLength));
9596
if (state) {
9697
DIAG(F("RC ? state=%d"),state);

Railcom.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "EXRAIL2.h"
3232

3333
uint16_t Railcom::expectLoco=0;
34+
uint16_t Railcom::nextLoco=0;
35+
3436
uint16_t Railcom::expectCV=0;
3537
unsigned long Railcom::expectWait=0;
3638
ACK_CALLBACK Railcom::expectCallback=0;
@@ -42,6 +44,17 @@ enum ResponseType: byte {
4244
CV_VALUE_LIST=0xC0, // list of cv values read from a POM, cv id and 4 values follow
4345
};
4446

47+
void Railcom::setLoco(byte packet0, byte packet1) {
48+
// first 2 bits 00=short loco, 11=long loco , 01/10 = accessory
49+
byte addressType=packet0 & 0xC0;
50+
if (addressType==0xC0) nextLoco=((packet0 & 0x3f)<<8) | packet1;
51+
else if (addressType==0x00) nextLoco=packet0 & 0x3F;
52+
else nextLoco=0;
53+
}
54+
55+
uint16_t Railcom::getLoco() {
56+
return nextLoco;
57+
}
4558

4659
// anticipate is used when waiting for a CV read from a railcom loco
4760
void Railcom::anticipate(uint16_t loco, uint16_t cv, ACK_CALLBACK callback) {
@@ -75,10 +88,7 @@ void Railcom::process(int16_t firstVpin,byte * buffer, byte length) {
7588
break;
7689
case CV_VALUE: { // csv value from POM read
7790
byte value=buffer[i+1];
78-
if (expectCV && DCCWaveform::getRailcomLastLocoAddress()==expectLoco) {
79-
if (expectCallback) expectCallback(value);
80-
expectCV=0;
81-
}
91+
if (expectCallback) expectCallback(value);
8292
i+=2;
8393
}
8494
break;
@@ -97,3 +107,8 @@ void Railcom::loop() {
97107
expectCV=0;
98108
}
99109
}
110+
111+
byte Railcom::cutoutCounter=0;
112+
void Railcom::incCutout() {cutoutCounter++;};
113+
byte Railcom::getCutout() {return cutoutCounter;};
114+

Railcom.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,18 @@ class Railcom {
2828
public:
2929
static void anticipate(uint16_t loco, uint16_t cv, ACK_CALLBACK callback);
3030
static void process(int16_t firstVpin,byte * buffer, byte length );
31+
static void setLoco(byte packet0,byte packet1);
32+
static uint16_t getLoco();
3133
static void loop();
34+
static void incCutout();
35+
static byte getCutout();
3236
private:
3337
static const unsigned long POM_READ_TIMEOUT=500; // as per spec
34-
static uint16_t expectCV,expectLoco;
38+
static uint16_t expectCV,expectLoco, nextLoco;
3539
static unsigned long expectWait;
3640
static ACK_CALLBACK expectCallback;
41+
static byte cutoutCounter; // cyclic cutout
42+
3743
static const byte MAX_WAIT_FOR_GLITCH=20; // number of dead or empty packets before assuming loco=0
3844
};
3945

version.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
#include "StringFormatter.h"
55

6-
#define VERSION "5.5.66"
6+
#define VERSION "5.5.67"
7+
// 5.5.67 - RailCom, AVR: Correct cutout timer calculation
8+
// - RailCom: Improved block handling
9+
// - EXRAIL: new IF_ALL,IF_ANY
710
// 5.5.66 - Bugfix: NeoPixel buffer size for RGBW devices
811
// - <D WIFI/ETHERNET ON> for SerialUsbLog diagnostics
912
// 5.5.65 - Enable ETHERNET_HOST_NAME (defaults to WIFI_HOST_NAME)

0 commit comments

Comments
 (0)