14 KiB
DCC Locomotive Decoder
ESP32-H2 based DCC locomotive decoder with advanced features for model railroading.
Features
- DCC Signal Decoding: Full NMRA-compliant DCC decoder supporting short (1-127) and long (128-10239) addresses
- Motor Control: TB67H450FNG H-bridge motor driver with:
- 128-step speed control
- Configurable acceleration/deceleration
- Load compensation with PID control
- Current sensing
- LED Control: WS2812 addressable LED support
- Multiple lighting effects (solid, blink, pulse, directional)
- Function-mapped lighting
- Adjustable brightness
- RailCom Feedback: Bidirectional communication with command station
- Accessory Outputs: 2x N-channel MOSFET outputs for accessories
- Smoke generators
- Sound modules
- Other low-side switched loads
- Configuration: WiFi/Bluetooth configuration via WebSocket
- Web-based interface
- CV (Configuration Variable) management
- Real-time status monitoring
Hardware Requirements
Components
- ESP32-H2 Development Board (e.g., ESP32-H2-DevKitM-1)
- TB67H450FNG Motor Driver IC
- WS2812 or compatible addressable LEDs
- N-channel MOSFETs (2x) for accessory outputs (e.g., IRLZ44N)
- Optocoupler for DCC signal isolation (e.g., 6N137 or PC817)
- Current sense resistor (0.1Ω - 0.5Ω, 1W or higher)
- Capacitors: 100µF electrolytic, 0.1µF ceramic
- Resistors: Pull-ups/pull-downs as needed
- Push button for configuration mode
Power Supply
- Track Power: 12-18V DC from DCC track
- Logic Power: 3.3V for ESP32-H2 (use onboard regulator or external LDO)
- Motor Power: Same as track power (filtered)
Wiring Diagram
DCC Input
DCC Track Signal
|
+---[1kΩ]---+---[Optocoupler Anode]
| |
[10kΩ] [0.1µF]
| |
GND GND
Optocoupler Cathode ---[470Ω]--- 3.3V
Optocoupler Output --- GPIO4 (PIN_DCC_INPUT)
Optocoupler Ground --- GND
TB67H450FNG Motor Driver
ESP32-H2 TB67H450FNG Motor
GPIO5 ----------- IN1
GPIO6 ----------- IN2
GPIO7 ----------- PWM
OUT1 --------------- M+
OUT2 --------------- M-
VM ---------------- Track+ (12-18V)
VCC ---------------- 3.3V
GND ---------------- GND
Current Sensing:
IPROPI ------------- GPIO8 (via voltage divider)
[0.1Ω Rs between OUT2 and GND]
TB67H450FNG Pin Configuration:
| Pin | Connection | Description |
|---|---|---|
| VM | Track Power (12-18V) | Motor power supply |
| VCC | 3.3V | Logic power supply |
| IN1 | GPIO5 | Input 1 (phase A) |
| IN2 | GPIO6 | Input 2 (phase B) |
| PWM | GPIO7 | PWM speed control |
| OUT1 | Motor+ | Motor output 1 |
| OUT2 | Motor- | Motor output 2 |
| IPROPI | GPIO8 | Current monitor output |
| GND | GND | Ground |
Motor Control Truth Table:
| IN1 | IN2 | PWM | Operation |
|---|---|---|---|
| L | L | X | Brake (standby) |
| H | L | PWM | Forward |
| L | H | PWM | Reverse |
| H | H | X | Brake (active) |
WS2812 LED Strip
ESP32-H2 WS2812
GPIO9 ----------- DIN (Data In)
3.3V/5V --------- VCC (check LED voltage requirements)
GND ------------- GND
Note: Add a 330-470Ω resistor in series with DIN
Add a 100-1000µF capacitor across VCC and GND near LEDs
RailCom
ESP32-H2 Circuit
GPIO10 ---------- UART TX (to RailCom transmitter)
GPIO11 ---------- DCC Cutout Detection (optional)
RailCom Transmitter Circuit:
UART TX --- [Transistor Driver] --- Track Signal
(Sends during DCC cutout window)
Accessory Outputs (N-FETs)
ESP32-H2 N-FET (IRLZ44N) Load
GPIO12 ---------- Gate 1
Source 1 ---------- GND
Drain 1 ----------- Load 1 (-)
GPIO13 ---------- Gate 2
Source 2 ---------- GND
Drain 2 ----------- Load 2 (-)
Load (+) connects to positive supply
Add 10kΩ pull-down resistor from Gate to Source on each FET
Configuration Button
GPIO14 ---------- Button ---------- GND
(Internal pull-up enabled)
Complete Pin Assignment Table
| Pin | Function | Connection | Notes |
|---|---|---|---|
| GPIO4 | DCC Input | Optocoupler output | DCC signal from track |
| GPIO5 | Motor IN1 | TB67H450FNG IN1 | Motor phase A |
| GPIO6 | Motor IN2 | TB67H450FNG IN2 | Motor phase B |
| GPIO7 | Motor PWM | TB67H450FNG PWM | Speed control |
| GPIO8 | Current Sense | TB67H450FNG IPROPI | ADC input |
| GPIO9 | LED Data | WS2812 DIN | LED control |
| GPIO10 | RailCom TX | UART1 TX | RailCom feedback |
| GPIO11 | Cutout Detect | DCC cutout circuit | Optional |
| GPIO12 | Accessory 1 | N-FET Gate | Output 1 |
| GPIO13 | Accessory 2 | N-FET Gate | Output 2 |
| GPIO14 | Config Button | Push button to GND | Enter config mode |
Note: Pin assignments can be modified in src/main.cpp (PIN DEFINITIONS section).
Software Setup
Prerequisites
- PlatformIO installed
- Git (optional)
Installation
- Clone or download this repository
- Open the
DCC-Locofolder in PlatformIO (VS Code with PlatformIO extension) - Build the project:
pio run - Upload to ESP32-H2:
pio run --target upload - Monitor serial output:
pio device monitor
Configuration
Initial Setup
On first boot, the decoder initializes with default values:
- Address: 3 (short address)
- Acceleration: 10
- Deceleration: 10
- LED Brightness: 128 (50%)
- RailCom: Enabled
- Load Compensation: Enabled
Configuration Mode
To enter configuration mode:
- Hold the configuration button (GPIO14) for 3 seconds
- The decoder creates a WiFi Access Point:
- SSID:
DCC-Loco-XXXXXX(XXXXXX = device ID) - Password:
dcc12345
- SSID:
- Connect to the WiFi AP
- Open a web browser and navigate to
http://192.168.4.1 - Use the web interface to:
- Read/Write Configuration Variables (CVs)
- Test outputs
- Monitor decoder status
- Reset to defaults
- Press the configuration button again to exit config mode
Configuration Variables (CVs)
Standard NMRA CVs:
| CV | Name | Default | Description |
|---|---|---|---|
| 1 | Primary Address | 3 | Short address (1-127) |
| 2 | Vstart | 1 | Start voltage |
| 3 | Acceleration Rate | 10 | Acceleration rate (0-255) |
| 4 | Deceleration Rate | 10 | Deceleration rate (0-255) |
| 5 | Vhigh | 255 | Maximum voltage |
| 6 | Vmid | 128 | Mid voltage |
| 7 | Version ID | 1 | Decoder version |
| 8 | Manufacturer ID | 13 | Manufacturer ID (DIY) |
| 17-18 | Extended Address | - | Long address (128-10239) |
| 29 | Configuration Data | 6 | Config bits (address mode, speed steps) |
Custom CVs:
| CV | Name | Default | Description |
|---|---|---|---|
| 50 | Motor Kp | 50 | PID proportional gain (value/10) |
| 51 | Motor Ki | 5 | PID integral gain (value/10) |
| 52 | Motor Kd | 10 | PID derivative gain (value/10) |
| 53 | RailCom Enable | 1 | Enable RailCom (0=off, 1=on) |
| 54 | Load Comp Enable | 1 | Enable load compensation (0=off, 1=on) |
| 55 | LED Brightness | 128 | LED brightness (0-255) |
| 56 | Accessory 1 Mode | 2 | Accessory output 1 mode |
| 57 | Accessory 2 Mode | 2 | Accessory output 2 mode |
Accessory Modes:
- 0 = Always off
- 1 = Always on
- 2 = Function controlled
- 3 = PWM control
- 4 = Blinking
- 5 = Speed dependent
WebSocket Protocol
The configuration server uses WebSocket for real-time communication.
Connect: ws://<decoder-ip>/ws
Commands:
Read CV:
{
"command": "read_cv",
"cv": 1
}
Write CV:
{
"command": "write_cv",
"cv": 1,
"value": 5
}
Get Status:
{
"command": "get_status"
}
Reset to Defaults:
{
"command": "reset"
}
Responses:
CV Read:
{
"type": "cv_read",
"cv": 1,
"value": 3
}
Status:
{
"type": "status",
"address": 3,
"speed": 0,
"direction": true,
"signal": true,
"current": 150,
"functions": [false, false, true, ...]
}
Code Structure
DCC-Loco/
├── platformio.ini # PlatformIO configuration
├── README.md # This file
├── include/ # Header files
│ ├── DCCDecoder.h # DCC signal decoding
│ ├── CVManager.h # Configuration variable management
│ ├── LEDController.h # WS2812 LED control
│ ├── MotorDriver.h # TB67H450FNG motor control
│ ├── RailCom.h # RailCom feedback
│ ├── AccessoryOutputs.h # Accessory output control
│ └── ConfigServer.h # WiFi/Bluetooth config server
├── src/ # Implementation files
│ ├── main.cpp # Main application
│ ├── DCCDecoder.cpp
│ ├── CVManager.cpp
│ ├── LEDController.cpp
│ ├── MotorDriver.cpp
│ ├── RailCom.cpp
│ ├── AccessoryOutputs.cpp
│ └── ConfigServer.cpp
├── lib/ # Custom libraries (if any)
├── data/ # Web files (future use)
└── Hardware/ # KiCad project files (future)
Module Descriptions
DCCDecoder
Decodes DCC packets using interrupt-driven bit detection. Supports:
- Short and long addresses
- 128-step speed control
- Functions F0-F28
- Emergency stop
- Signal quality monitoring
CVManager
Manages Configuration Variables in non-volatile storage using ESP32 Preferences:
- NMRA-compliant CV storage
- Factory reset functionality
- Address management (short/long)
LEDController
Controls WS2812 addressable LEDs with FastLED:
- Multiple light modes (solid, blink, pulse, directional)
- Function mapping to LEDs
- Brightness control
- Up to 16 LEDs
MotorDriver
Controls TB67H450FNG motor driver:
- Forward/reverse control
- PWM speed control
- Acceleration/deceleration curves
- Load compensation with PID
- Current monitoring
RailCom
Implements RailCom feedback protocol:
- Channel 1: Address broadcast
- Channel 2: Status information
- 250kbaud communication
- Cutout detection
AccessoryOutputs
Controls 2x N-FET outputs:
- Multiple modes (on/off, function, PWM, blink, speed-dependent)
- Function mapping
- Independent control
ConfigServer
Web-based configuration interface:
- WiFi Access Point mode
- WebSocket real-time communication
- CV read/write
- Status monitoring
- Reset functionality
Testing
Basic Test Procedure
-
Power Up Test
- Connect decoder to track power (12-18V DC)
- Verify ESP32-H2 boots (check serial output)
- Verify no smoke or excessive heat
-
DCC Signal Test
- Apply DCC signal to track
- Check serial monitor for "DCC OK" messages
- Verify correct address detection
-
Motor Test
- Send speed commands via DCC controller
- Verify smooth acceleration/deceleration
- Test forward and reverse
- Check emergency stop
-
LED Test
- Verify headlights change with direction
- Test function-controlled LEDs (F1, F2, etc.)
- Check brightness adjustment
-
Accessory Test
- Activate mapped functions (F3, F4)
- Verify N-FET outputs switch correctly
- Test different output modes
-
Configuration Test
- Enter configuration mode (hold button 3s)
- Connect to WiFi AP
- Read/write CVs via web interface
- Verify changes take effect after exit
Troubleshooting
No DCC Signal:
- Check optocoupler wiring
- Verify GPIO4 receives signal
- Check for proper DCC track voltage
Motor doesn't run:
- Verify TB67H450FNG connections
- Check motor power supply (VM)
- Verify PWM signal on GPIO7
- Check motor connections
LEDs don't light:
- Verify WS2812 data line connection
- Check LED power supply voltage
- Ensure correct NUM_LEDS setting
- Check for loose connections
Can't enter config mode:
- Verify button wiring (GPIO14 to GND)
- Check serial monitor for messages
- Try holding button longer (>3s)
WiFi AP not visible:
- Check ESP32-H2 WiFi support
- Verify sufficient power supply
- Check for WiFi interference
- Review serial output for errors
Advanced Features
Load Compensation
The decoder includes PID-based load compensation to maintain consistent speed under varying loads:
- Monitors motor current
- Adjusts PWM duty cycle
- Tunable via CVs 50-52
- Can be disabled via CV54
Custom Function Mapping
Edit src/main.cpp to customize LED and accessory mappings:
// Example: Map F5 to LED 2 with pulse effect
ledController.mapFunctionToLED(5, 2, LIGHT_PULSE);
// Example: Map F6 to accessory output 1
accessories.mapFunction(1, 6);
RailCom Customization
Extend RailCom data transmission in src/RailCom.cpp:
- Add more status information in Channel 2
- Implement CV read-back
- Add custom data fields
Future Enhancements
- Sound decoder support
- SUSI interface for external sound modules
- Bluetooth configuration
- Advanced lighting effects (mars light, ditch lights)
- Function remapping via CV
- Dual motor support
- ABC brake support
- Servo outputs
Hardware Design Files
KiCad schematic and PCB files will be added to the Hardware/ folder in future releases.
License
This project is open-source and available under the MIT License.
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Commit your changes
- Submit a pull request
Support
For issues, questions, or suggestions:
- Open an issue on GitHub
- Check documentation in
doc/folder - Review source code comments
Credits
- NMRA DCC specifications
- ESP32-H2 Arduino core
- FastLED library
- AsyncWebServer library
Version History
- v1.0 (2026-01-15): Initial release
- DCC decoding
- Motor control with load compensation
- WS2812 LED support
- RailCom feedback
- Accessory outputs
- WiFi configuration
Happy Model Railroading! 🚂