Skip to main content
DEJA

Build the DEJA accessory decoder

A do-it-yourself DCC accessory decoder. Wire an ESP32 or an Arduino Nano to the track through an optocoupler, add hobby servos or LEDs, and the command station moves your turnouts and lights your signals. It costs a few dollars in parts, and DEJA writes the firmware configuration for you.

The page follows the build order: see how it fits together, gather the parts, wire the three parts of the circuit, set it up in DEJA, flash, test.

What it is

A pure DCC accessory decoder. It reads the track, like a DS64 or a Switch-It, and nothing else. It has no WiFi in this release and never reports back, so its turnouts are commanded, not confirmed, like any other third-party decoder. Add a feedback sensor if you want proof.

Each decoder has:

  • Up to 16 outputs. Each one is a servo (slow motion, with an optional frog relay), a pulse output (a quarter-second kick for an uncoupler), a steady on/off output, or a signal head. The default build has 4.
  • Signal heads of three lamps (red, yellow, green) on plain GPIO pins or on a WS2812 (NeoPixel) strip. Each head is one output, so heads and turnouts share the 16.
  • A DCC address you can change from the programming track.

How it fits together

Three parts: the track side (an optocoupler that turns DCC into a logic signal), the board, and whatever the board drives. Power comes from the track through a rectifier and a buck converter, or from a separate 5 V supply.

Block diagram: track to optocoupler to board to outputs, with a power path from the track through a rectifier and buck converter to 5 volts Track (DCC) OptocouplerH11L1 / 6N137 ESP32or Arduino NanoDCC in · GPIO out Servo + frog relay Signal lamps Uncoupler (pulse) Bridge rectifier+ 470 µF Buck converterset to 5.0 V 5 V → VIN 5 V servo rail Or skip the bottom row and feed 5 V from a separate supply: its ground joins the board's ground, never a rail. DCC / track5 V powerlogic signal
The whole decoder. The top row is the signal path; the bottom row is one of the two ways to power it.

Parts

Part Notes
ESP32 DevKit v1 or Arduino Nano A plain WROOM DevKit is the easy ESP32 choice; WROVER modules reserve GPIO 16 and 17 for PSRAM.
Optocoupler H11L1 (6-pin) for an ESP32, which runs at 3.3 V. 6N137 (DIP-8) for a Nano at 5 V.
1N4148 diode Protects the opto's LED from the reverse half of the DCC wave.
1 kΩ resistor Sets the opto's LED current.
10 kΩ resistor Pull-up on the opto's output.
0.1 µF capacitor Decoupling, right at the opto.
Bridge rectifier (DB107) Only if you power from the track.
Buck converter (MP1584), set to 5.0 V Only if you power from the track.
470 µF capacitor One after the rectifier, one on the servo rail.
SG90 or MG90S servos One per turnout.
Optional A 3.3 V-input relay module for frog power, LEDs with resistors, a ULN2003A for lamps on a 5 V rail, or a WS2812 strip.

1. Wire the DCC input

The optocoupler is the one part that touches the track. Its LED side sees the rails; its transistor side talks to the board. Nothing else crosses that line.

DCC input circuit: rail A through a 1 kilohm resistor to the H11L1 anode, rail B to its cathode, a 1N4148 across the two, VCC and the 10 kilohm pull-up to 3.3 volts, output to GPIO 34, ground to the board Rail A 1 kΩ Rail B 1N4148 H11L1 1 A2 K VCC 6OUT 4GND 5 3.3 V — the ESP32's 3V3 pin 10 kΩ 0.1 µF ESP32 GPIO 34GND3V3 out The opto's LED conducts on one half of the DCC wave; the diode carries the other half around it. Rails stay left of the opto, logic stays right. Nano instead of ESP32: a 6N137, VCC and the pull-up from 5 V, its enable pin tied to VCC, and OUT landing on D2.
H11L1 pins: 1 anode, 2 cathode, 4 output, 5 GND, 6 VCC. The diode's stripe (cathode) faces the rail A wire.

Step by step:

  1. Rail A → 1 kΩ → pin 1 (anode). Rail B → pin 2 (cathode).
  2. 1N4148 across pins 1 and 2, stripe towards pin 1. It points the opposite way to the opto's own LED, so the LED sees only one half of the DCC wave and the diode carries the other half.
  3. Pin 6 (VCC) → 3.3 V from the ESP32's 3V3 pin. Pin 5 → GND. The 0.1 µF capacitor goes across pins 6 and 5, right at the chip.
  4. Pin 4 (output) → GPIO 34, with the 10 kΩ pull-up from pin 4 to 3.3 V. GPIO 34 to 39 have no internal pull-up, so the resistor is not optional.

On a Nano use the 6N137 instead: rail A → 1 kΩ → pin 2, rail B → pin 3, the diode across pins 2 and 3, pin 8 VCC and pin 7 (enable) to 5 V, pin 5 GND, pin 6 output → D2 with the 10 kΩ pull-up to 5 V. The 6N137 is specified for 4.5 to 5.5 V; it usually works at 3.3 V but is out of spec there, which is why the ESP32 gets the H11L1.

⚠️ ESP32 pins are 3.3 V only. Pull the opto output up to 3.3 V, never 5 V, and never let track voltage near a GPIO.

2. Power it

Pick one of two ways. Both leave the opto listening to the track.

Power from the track: both rails into a bridge rectifier, a 470 microfarad capacitor across its output, a buck converter set to 5 volts feeding the board's VIN and a separate 5 volt servo rail with its own 470 microfarad capacitor, all grounds joined Rail ARail B BridgeDB107 ~~+− 470 µF BuckMP1584 → 5.0 V ESP32 / NanoVIN (5 V)GND 470 µF Servo rail5 V to the servos Set the buck to 5.0 V before you connectthe board. Servos share the rail; the second470 µF sits as close to them as you can get it. Join every ground. Never join a ground to a rail.
Option A, from the track. The board and the servos take the same 5 V, each with its own bulk capacitor.

Option A: from the track. Both rails into the bridge rectifier, a 470 µF capacitor across its output, then the buck converter set to 5.0 V. Feed that 5 V to the ESP32's VIN pin or the Nano's 5V pin, and run the servos from the same rail with their own 470 µF capacitor close to them.

Option B: a separate 5 V supply. A USB supply into the board, or a 5 V wall supply into VIN. Join the supply's ground to the board's ground, but never to a rail. With no servos (a signal-only decoder) the whole thing draws well under 200 mA, and this is the simplest build.

Budget the servos. An MG90S can pull close to an amp as it starts to move, so several moving together on a route can overwhelm a small buck converter like the MP1584. A busy decoder wants a bigger 5 V supply.

3. Wire the outputs

Servos and frog relays

Servo wiring: signal lead from a GPIO, power from the 5 volt servo rail, ground shared; a frog relay module driven from a second GPIO switches the frog between rail A and rail B 5 V servo rail ESP32 / Nano GPIO 13GPIO 25GND signal ServoSG90 / MG90S IN Relay module3.3 V input · VCC 5 V COMNONC rail AFrogmid-travelrail B One servo per output. The frog relay is optional: the firmware flips it halfway through the servo's travel, so the frog never shorts.
A servo needs only its signal lead on the GPIO. Its power comes from the 5 V rail, not from the board.
  • Servo signal lead → the output's GPIO (the pin you assign in DEJA). Power and ground go to the 5 V servo rail, never through the board's 3.3 V pin.
  • Frog relay (optional). Assign a second pin as the output's frog pin and drive a relay module from it. On an ESP32 the module must accept a 3.3 V input, or switch it through a transistor. The relay's common goes to the frog; normally-open and normally-closed go to the two rails.
  • The firmware detaches a servo once it arrives, so it does not buzz, and remembers each position across a power cycle.

Signal lamps

Each head is three lamps, red, yellow and green, on three pins (or -1 for a lamp you have not wired). The question is where the LEDs get their current. ESP32 pins are 3.3 V and comfortable at 12 mA or less each, so a red, yellow or green LED with a small resistor can hang straight off a pin, but a white or blue LED (forward voltage 3 V or more) cannot, and a resistor sized for a 12 V signal leaves almost nothing.

LEDs with an in-line resistor of… From a 3.3 V pin (red / yellow / green) Do this
100 to 220 Ω 5 to 13 mA, bright Drive straight from the GPIO, common cathode to GND.
330 to 470 Ω 2 to 4 mA, dim Usable in a dark room; better behind a ULN2003A on 5 V.
680 Ω to 1.2 kΩ 1 to 2 mA, barely glows ULN2003A on a 12 V rail, or change the resistors.
Any value, white / blue / lunar LEDs ~0 ULN2003A on 5 V or 12 V.

The ULN2003A is a seven-channel driver that switches cleanly from 3.3 V logic. It sinks each lamp's cathode to ground, so the LEDs take their current from a 5 V (or 12 V) rail and the ESP32 pins carry almost nothing. It is the recommended way to wire a signal, and it keeps the resistors you already have.

Signal lamps through a ULN2003A: three GPIO pins into IN1 to IN3, each lamp's resistor and LED from a 5 volt rail into OUT1 to OUT3, the driver's ground joined to the board's ground 5 V rail (12 V if the resistors were sized for 12 V) ESP32 GPIO 18GPIO 19GPIO 21GND ULN2003A IN1IN2IN3 OUT1OUT2OUT3 GND (pin 8) red yellow green LEDyour resistor GPIO high = lamp on. The LEDs' common lead is their anode (+) on the rail; each cathode comes back to an OUT pin, which sinks it to ground.
One head. A second head takes IN4 to IN6; the seventh channel is free for a marker lamp.
  • Direct drive (resistors of 220 Ω or less, red/yellow/green only): each lamp's resistor lead to its pin, all cathodes to GND. That is common cathode, the firmware's default.
  • Common anode signals (the common lead is +) cannot be driven directly: the generated firmware drives lamps common cathode, pin high for on. Put them behind a ULN2003A instead. To the firmware that is still common cathode, whichever way the LEDs themselves are wired.
  • WS2812 strips take three pixels per head, in the order red, yellow, green, on the WS2812 data pin. A strip pauses the Nano's interrupts for about 30 µs per pixel while it updates, so keep the count small on a Nano and test with a long run of throws; an ESP32 has no such limit and is the better choice for a big gantry.

A seven-lamp signal, say two full heads plus a marker lamp, is three signal outputs: head 1, head 2, and a third head with only its red pin wired. Each head is a separate Signal in DEJA with its own aspect; a prototype "yellow over green" is the two heads set together by a route or an automation.

Pulse outputs

A pulse output drives its pin high for a quarter of a second, then low again, whatever direction was asked for. That suits a single-coil uncoupler. It does not suit a twin-coil switch machine such as a Peco solenoid, which needs a separate drive per direction; convert those to a servo or use an external capacitive-discharge unit. Never use a steady output for a solenoid: it holds the coil on and burns it. And never connect a solenoid straight to a GPIO: let the GPIO switch a driver board.

Pins

These are the defaults. deja deploy builds the sketch with the pins you choose in DEJA.

Function ESP32 Nano
DCC input (from the opto) GPIO 34 D2 (interrupt pin)
Servo outputs 1 to 4 GPIO 13, 14, 16, 17 D3, D4, D5, D6
Good lamp pins GPIO 18, 19, 21, 22, 23, 25, 26, 27, 32, 33 D7 to D10, A0 to A5 (enter A0 to A5 as 14 to 19)
WS2812 data GPIO 5 D11
Frog relays the pins you assign the pins you assign

DEJA refuses pins that cannot drive an output: on the ESP32, GPIO 6 to 11 (flash), 34 to 39 (input-only) and the strapping pins 0, 2, 12 and 15; on the Nano, D0 and D1 (USB serial) and A6 and A7 (input-only).

The ESP32 pulses GPIO 14 at boot, so a servo on it can twitch once. GPIO 16 and 17 are used by PSRAM on WROVER modules, so pick other pins there.

4. Set it up in DEJA and flash

  1. Devices → Add device → DCC Accessory Decoder. Command station: your DCC-EX. Decoder: DEJA ESP32 or DEJA Arduino. Base address: the first output of a board, 1, 5, 9, 13, … (4 × n + 1). DEJA will not save another value for these profiles.
  2. Bind your turnouts and signals to its outputs: the output type and pins on the decoder's page, the lamp pins and wiring on each signal.
  3. Open the device's Firmware section and read the generated config.h: output types, pins and DEFAULT_CV1 / DEFAULT_CV9 should match what you wired.
  4. Take the decoder off the track (or switch track power off). USB and track power must never feed the board at the same time.
  5. Run deja deploy <device>. The first run installs the tools and Arduino libraries it needs; see deploying firmware.
  6. Reconnect the track and power up.

Many Nano clones need the older bootloader. If the upload fails, deploy with deja deploy <device> --board arduino:avr:nano:cpu=atmega328old. The board menu calls this "ATmega328P (Old Bootloader)".

5. First test

From the DCC-EX terminal in DEJA, with the decoder at base address 1 (board 1 → linear addresses 1 to 4):

Command Expect
<a 1 0 1> output 1 thrown; <a 1 0 0> closes it
<a 1 1 1> output 2 thrown
<A 1 0> a signal head on output 1 shows red; <A 1 1> yellow, <A 1 2> green, <A 1 3> dark

Then throw the turnout from its card and set the signal's aspect from its card: the same hardware should move. Power-cycle the decoder; the servos should not sweep, and each head should come back as it was.

Extended signal commands (<A>) need DCC-EX 5.2.34 or newer on the command station. Check with <s>.

Configuration variables (CVs)

You can change a lot of the decoder from the programming track, with no re-flash.

CV What it does
1 and 9 The board address (low and high part).
29 Compile-time only. Bit 6 chooses board addressing (0) or output addressing (1), and it is set when the sketch is built. A write to it on the track applies only until the next boot, when the decoder rewrites CV29.
33 + 8 × n Output n (counting from 0): type (1 servo, 2 pulse, 3 steady, 4 signal head), thrown angle, closed angle, speed, frog relay on or off.
161 + 4 × h Signal head h: which of red, yellow and green are lit for each of the four aspects.
238 and 239 Which build of the settings the decoder last applied. The decoder writes these itself. Leave them alone.
240 + n The last position of output n. The decoder writes this itself, after the output has been still for 5 seconds. Leave it alone.

A value of 255 (the blank default) means "use what the sketch was built with". Angles and speed take effect at once. A change of output type or of the frog relay needs a power cycle before it takes effect.

Re-flashing with changed settings resets the address and output/head CVs to the new config.h values; saved servo positions are kept. CV8 = 8 only resets the address.

Changing the address. Put the decoder alone on the programming track and write CV1 and CV9 (<W 1 v> and <W 9 v>), or use the Set decoder address helper described in Programming the address. For a DEJA decoder the helper writes only CV1 and CV9, does not stop on a -1 reply, and reports "Written (no ACK from this decoder)". Never write <W address>: that changes a locomotive's address, not a decoder's. To switch to output addressing, build with it set instead.

This firmware has no ACK circuit, so DCC-EX reports -1 after each <W>. The write still takes effect: power-cycle and test.

Optional ACK circuit. If you build the sketch yourself, set ACK_PIN in config.default.h (or pass -DACK_PIN=<gpio>) to a free output pin. The decoder drives it high for 6 ms to acknowledge each write. Wire that pin through a 1 kΩ resistor to the base of an NPN transistor (a 2N2222, say), and switch a 150 Ω, 2 W resistor across the rectified track supply with it (about 100 mA at 14 V), so the command station sees the extra 60 mA or more it is listening for.

Troubleshooting

Nothing responds.

  • Check the opto's orientation (the dot marks pin 1) and that the 10 kΩ pull-up goes to the board's own logic voltage.
  • Check the output lands on the DCC pin (GPIO 34 or D2).
  • Check the base address in DEJA matches the decoder's CV1 and CV9.
  • For signals, check <s> reports DCC-EX 5.2.34 or newer.

A servo jitters or the board resets. Almost always power. Give the servos their own 5 V rail with the 470 µF capacitor, and join the grounds.

Every lamp is dim. The in-line resistors were sized for a higher voltage; see the table under Signal lamps.

A lamp is on when it should be off. The signal is wired common anode on a direct drive. Move it behind a ULN2003A (see Signal lamps).

It answers four addresses off. The DEJA decoder uses DCC-EX numbering by construction, so there is no ±4 offset to set for it. Check the base address in DEJA matches CV1 and CV9, and that the command station sending the packets is DCC-EX. If you re-programmed the address on the track, program it again, or write CV8 = 8 to go back to the address it was built with.

The Nano upload fails. Try the old bootloader board setting above.