Skip to main content

Hello Again!


Abstract of this post


This is a follow-on of my previous post on capturing DCS signals into a terminal (Old Post). In this previous post I talked about how to capture a DCS signal from an engine and TIU towards spoofing the signal (IE generating fake TIU signals to control your engine).

As mentioned last time.... There are some interesting things you can do with this, like make non-train things respond to train commands or have parts of the layout react on certain conditions (like something only happens if the train is a certain speed when it passes by... or only happens if the train's lights are on) or other creative stuff.  The .v code in this example simply sends a static command to the engine, but you can certainly modify it to do all kinds of great stuff...

if (some condition == true)


 (make the train do something)


Then you can have the train react to the layout (sensors and blocks and such), like have it auto slow down at stations, auto ring the bell in the yard, auto blow the horn at level crossings... use your imagination!  Again like the last one, this post is just equipping everyone with a framework for completing the transmission process. This is not a finished product. The idea is you can build on what's here to get you started.



Hardware Interfacing for DCS spoofing


Similar to the (Old Post), I use the ARTY 7 FPGA (FPGA) with Xilinx Vivado for my train projects. Basically we use the technique from the old post to capture the sequence, and then stream it to the engine using the spreading codes. If you want to know more about the spread-spectrum format details that DCS uses you can check the post that explains all the details (DCS details). While that previous post was for capturing/receiving the DCS packets and used a 74HCxx chip as a comparator, this project will send the commands to the engine so we need a line driver.

It turns out looking into the track is a pretty low impedance (a few ohms), and so we need drive strength from our digital output so that we can source/sink enough current that the track propagates our signal voltages. A regular FPGA pin or CMOS chip won't be able to sink/source more than a few mA, so we turn to line driver chips. The one I went with is the SN75121 from Texas Instruments available for a few dollars (SN75121) which can drive as high as 75mA. If you look at the schematic on the data-sheet the output of the chip is only a pull up stage, so we need an external pull-down resistor outside. I've found 25 ohms works nicely. Note: it's going to 5V so that resistor needs to dissipate at least 1W of power.. (5V)^2 /(25 ohms) = 1W.



Basic Schematic Diagram

Now the track carries about 20V AC from the transformer, so that would blow up the line driver chip if we directly connect the pin. The trick we use to fix this is selective AC coupling. By using capacitive coupling we can keep a low impedance connection at the high DCS frequency while avoiding letting the 60Hz flow back into the chip. The cutoff frequency depends on our pull-down resistor and the capacitor. For the cap, I found 4uF would be a pretty good choice:


The voltage that the 18V sees at 60 Hz is the voltage divider of the 25 ohms and capacitor so

Vin X (25 ohms) / mag(25 ohms + j[1/2pi 60Hz 4uF])   =  0.03 Vin = 0.75V

This is pretty okay for the low impedance line driver. However  at DCS frequencies (lets say 1 MHz for simplicity) traveling in the other direction the series impedance is only going to be

 j [1/(2pi 1MHz 4uF)]   =  ~0.05 ohms (so basically directly connected)

In this way the DCS can flow to the track, but the track power can't flow back into our driver chip and blow it up. Remember that capacitor can't be a polarized one or you'll blow yourself up.



Packet Formats and What to Send


 Okay before I go any further a gigantic thank you to SanDiegoMark here on the forum who helped me sooooooooooo much going through the data we captured and figuring out the command structure. I was able to build the hardware, but he had the insight to see what was going on with the bits inside the captured packets. Here is what he figured out from the captures in the (Old Post):

The DCS track signal format is essentially made up of:

 <ENGINE NUMBER +1 in LSB to MSB order>
< some command>

All run together. The long string of 1's at the start/end of the packet allow the DC conditions to stabilize before the actual command is sent. The # of 1s doesn't matter as long as it's longer than the time constant of the coupling structure above. Remember for each 1 or 0 we are actually sending an entire spread-spectrum sequence at much higher frequency (chip rate is 3.75 MHz).

So everytime we encounter a "1" in the transmit sequence we send 0100010111110110011100001101010

and everytime we encounter a "0" in the transmit sequence 1011101000001001100011110010101 (flipped)

You can use the other material from the (Old Post) to capture all the commands you want to use for engine.

For my train (engine #49) here are two sample commands:

1111111111111110010011001010000000000000010000000110001111111111;  makes the whistle blow
1111111111111110010011001001000000000000000000000010001111111111;  makes the front coupler fire

Looking at the whistle more closely:

111111111111111    0     01001100    101000000000000001000000011000      1111111111

(leadings 1s)   (a single zero)    (engine # +1 in LSB to MSB)      (Command)     (trailing 1s)


So that's all there is too it really, just make a dictionary of commands with the capture program, and write code to send these sequences in spread-spectrum format with the spreading code above.


In terms of code, I've attached my RTL/verilog to the post in case anyone wants to play with it. It's a very simple test code. Also attached is my XDC contraints file specifically for the ARTY7 FPGA. There's really not much to it.... Just read the command bits one by one and stream out the appropriate spreading code. Repeat until the packet is done and the train will respond.





Here is an oscilloscope capture at the output of the line driver comparing the real TIU output to our spoofed one:


One interesting thing we found is that 3750 KHz isn't necessarily best. I found 3748 KHz works better. The time base inside the engine or the cheapo signal generator I'm using may be slightly off in it's frequency reference crystal. Anyways don't feel it has to be exactly 3750.00000, the double-edge sampling nature of spread-spectrum has some slop built into it.


Finally a short video showing me blowing the whistle on my MTH train from the FPGA spoofer.  Note I'm only sending the whistle start signal for the whistle in this example, so I need the remote to send the stop signal so the train will stop making noise.




          Summary & Conclusions


 Between this post on how to transmit and the (Old Post) on how to receive and capture this now equips everyone with the means to mold/modify/enhance the DCS system to do whatever they want. All the engineering and design has been presented so all that's left is to sit down and capture all the codes for a given engine and make a command dictionary. You can add DCS functionality to anything, and have anything interact with the train.


If you were ambitious enough, you could even combine this setup with SanDiegoMark's neat PC program and basically run your DCS with no TIUs or remotes at all. Again, thanks so much to him on helping us figure out the packet format.


Last note: If you watch the video at 00:21 there is a USB stick that looks like a train. At only $16 how can you not buy this (usb-train) and still call yourself a train enthusiast?



 Cheers all!





Images (2)
  • SPOOF_schematic
  • spoof_capture
Videos (1)
Files (2)
Last edited by Adrian!
Original Post

Replies sorted oldest to newest

SanDiegoMark posted:

Do you see any evidence of return packets from the engine? In the earlier captures that you sent me there were none which makes me think that the return packets use a different spreading code.

I also think this is exactly what's going on... the reverse direction has some other spreading code. It's tough to catch them though. I can see them go by when I zoom out to ms timescales on the scope but then the sample rate is low so I can't resolve them. The train-bound signal always starts the exchange so catching those codes are easy because you can just trigger the scope on the first positive edge you see.


You need at least 10-20 MS/s to oversample the 3.75MHz waveform enough to pick out the ones and zeros clearly. The issue is the TIU-bound packet comes like 100ms later. I don't think any hobby-sized scope I've seen has enough waveform memory to sample 20MS/s for 100ms.... that's 2000K samples... I'm going to use the fpga to make a delayed trigger next and see if I can catch the TIU-bound sequence by tuning the delay ... 

Thanks again!




Last edited by Adrian!
Severn posted:

any thoughts on building one of these without an fpga?  (say a arduino or raspberry pi or similar and some add on boards?)


To produce a 3.75 Mhz waveform, you need to be able to toggle an output port about every 125ns. I find slightly different answers but it looks like about the best you can do with an Arduino gives an output frequency of 2.66Mhz. Then there is the problem of getting an accurate 3.75 Mhz rate. An ATtiny85 running at 18.75 Mhz might be able to generate the correct speed it but I've never used one.

how about a PWM channel, something like that?   It has to be 3.75mhz?   some of the pis have 2 pwm hw channels... but i don't think you can nail 3.75 with them...   my math on the available settings says 4.8 or 2.2 ... and I'm not sure those are really legal values.   then of course you could try for something external...

Severn posted:

how about a PWM channel, something like that?   It has to be 3.75mhz?   some of the pis have 2 pwm hw channels... but i don't think you can nail 3.75 with them...   my math on the available settings says 4.8 or 2.2 ... and I'm not sure those are really legal values.   then of course you could try for something external...

It's not just a pwm tone, you actually need to encode the command data and spread signal... fpga is the only reasonable way to do all the logic fast enough with an exact clock



Severn posted:

Ok you've convinced to try build an fpga... i mean not today, not tomorrow... but sometime soon.  I've a vague familiarity with it through osmosis.   I once had a verilog book but I lost it.

What stuff do I need?  (&I'm rather assuming you'll give out the design...)


you need an fpga, a breadboard to work on, the driver chips I mentioned above, a sign gen or other clock source for the 3.75MHz, an MTH train and layout with DCS, a remote, and a few discretes (some caps and resistors) . Between part one and part two I think I linked sources for everything... all this stuff is under $250 total... 

The other thing is the oscilloscope... it's not needed to make it work but sure helps you see what's going on if you need to debug...





Arduino has come out with a board with and FPGA that might make this DCS spoofing practical for the hoi polloi.

The board is the MKR Vidor 4000.

MKR Vidor 4000

This board is programmable using the Arduino IDE.  It has a SAMD21 processor and an Intel Cyclone 10CL016 FPGA. The board has a whole lot of other fancy features also. About $70.

They haven't announced programming tools yet for the FPGA but it might be possible for anyone to build up Adrian's DCS signal capture design and maybe communicate directly to the DCS engine over the 3.75MHz track signal.

The Intel Cyclone 10CL016 FPGA is the low end of Intel's Cyclone 10 LP series. It has 6,272 logic elements and a clocking rate of up to 155.5 MHz.

Well that sounds very interesting.  I even bought a scope.  What apparently I lack completely is much HW sense.  I've tried and failed to build a voltage sensor for a homebrew motor bemf circuit.  I'm game but not sure I have any ability at all to program an FPGA.   (Also i don't have any adjustable power supplies -- there's a total lack of clarity on what is good or bad here with many cheap offerings that i suspect are bad)

Add Reply

The DCS Forum is sponsored by

OGR Publishing, Inc., 1310 Eastside Centre Ct, Suite 6, Mountain Home, AR 72653
800-980-OGRR (6477)

Link copied to your clipboard.