309 lines
8.7 KiB
Markdown
309 lines
8.7 KiB
Markdown
# DCC Programming Track Implementation
|
|
|
|
## Overview
|
|
|
|
The DCC-Bench uses the **LM18200 H-Bridge** for both normal DCC operation AND programming track functionality. Since this is a dedicated test bench with only one locomotive at a time, the same driver can handle both modes without issue.
|
|
|
|
## Why This Works
|
|
|
|
### Traditional DCC Systems
|
|
- **Main Track**: High current (3-5A) for running multiple locomotives
|
|
- **Programming Track**: Limited current (250mA max) with ACK detection
|
|
|
|
### DCC-Bench Approach
|
|
- **Single Track**: Only one locomotive under test
|
|
- **LM18200**: Can handle both operation and programming
|
|
- **Current Limit**: LM18200 has built-in current limiting
|
|
- **ACK Detection**: Monitor current draw through sense resistor
|
|
|
|
## Hardware Requirements
|
|
|
|
### Essential Components
|
|
1. **LM18200 H-Bridge** (already in design)
|
|
- Dual-purpose: DCC signal amplification + programming
|
|
- Built-in current limiting and thermal protection
|
|
- Pins: GPIO 18 (Signal A), GPIO 19 (Signal B), GPIO 23 (Brake)
|
|
|
|
2. **Current Sense Resistor** (0.1Ω, 1W)
|
|
- Monitor programming track current
|
|
- Placed in series with LM18200 output
|
|
- Creates voltage drop proportional to current
|
|
|
|
3. **ADC Input for ACK Detection**
|
|
- ESP32 ADC pin (e.g., GPIO 35)
|
|
- Connected to current sense resistor voltage
|
|
- Detects 60mA+ ACK pulse from decoder
|
|
|
|
### Optional Enhancements
|
|
- **Current Limiter Circuit**: Additional 250mA fuse for extra safety
|
|
- **LED Indicator**: Visual feedback during programming
|
|
- **Isolation**: Optocouplers for additional protection
|
|
|
|
## Wiring Diagram
|
|
|
|
```
|
|
ESP32 GPIO 18 ──────┐
|
|
├──> LM18200 ──> Current Sense ──> TRACK
|
|
ESP32 GPIO 19 ──────┘ │
|
|
│
|
|
ESP32 GPIO 35 (ADC) <──── Voltage Divider ┘
|
|
(for ACK detect)
|
|
|
|
Current Sense Circuit:
|
|
0.1Ω, 1W
|
|
Track+ ────┬──────╱╲╲╲───── LM18200 Output
|
|
│
|
|
├─── 1kΩ ───┬──── GPIO 35 (ADC)
|
|
│ │
|
|
│ 10kΩ
|
|
│ │
|
|
Track- ────┴───────────┴──── GND
|
|
```
|
|
|
|
## DCC Programming Protocol
|
|
|
|
### Service Mode (Programming Track)
|
|
|
|
The DCC-Bench implements NMRA DCC Service Mode:
|
|
|
|
1. **Factory Reset** (CV8 = 8)
|
|
- Resets decoder to factory defaults
|
|
- Standard NMRA reset command
|
|
|
|
2. **Set Address**
|
|
- **Short Address (1-127)**: Write to CV1
|
|
- **Long Address (128-10239)**: Write to CV17 + CV18
|
|
- Automatically updates CV29 for address mode
|
|
|
|
3. **CV Read** (Bit-wise Verify)
|
|
- Tests each bit (0-7) individually
|
|
- More reliable than direct read
|
|
- Requires ACK detection for each bit
|
|
|
|
4. **CV Write** (Write + Verify)
|
|
- Writes value with 3 retry attempts
|
|
- Verifies write with ACK detection
|
|
- NMRA-compliant packet structure
|
|
|
|
### ACK Detection
|
|
|
|
**How It Works:**
|
|
1. Decoder receives programming command
|
|
2. If command is valid and matches, decoder draws 60mA pulse for 6ms
|
|
3. Current sense resistor creates voltage spike
|
|
4. ESP32 ADC detects voltage above threshold
|
|
5. ACK confirmed = command successful
|
|
|
|
**Threshold Values:**
|
|
- **ACK Current**: 60mA minimum (NMRA standard)
|
|
- **ACK Duration**: 6ms typical
|
|
- **Timeout**: 20ms wait for response
|
|
|
|
## Current Implementation Status
|
|
|
|
### ✅ Implemented
|
|
- NMRA-compliant packet encoding
|
|
- Service mode packet structure (22-bit preamble)
|
|
- Factory reset command (CV8 = 8)
|
|
- Address programming (short and long)
|
|
- CV read (bit-wise verify method)
|
|
- CV write (write + verify)
|
|
- Programming screen UI with numeric keypad
|
|
|
|
### ⚠️ Needs Hardware
|
|
- **ACK Detection**: Currently returns `true` (assumed success)
|
|
- **Current Sensing**: ADC reading not yet implemented
|
|
- **Calibration**: Threshold tuning for specific hardware
|
|
|
|
## Adding ACK Detection
|
|
|
|
### Step 1: Wire Current Sense
|
|
```cpp
|
|
// Add current sense resistor (0.1Ω) in series with track output
|
|
// Connect voltage divider to ESP32 GPIO 35 (ADC1_CH7)
|
|
```
|
|
|
|
### Step 2: Update `waitForAck()` Method
|
|
```cpp
|
|
bool DCCGenerator::waitForAck() {
|
|
#define CURRENT_SENSE_PIN 35
|
|
#define ACK_THRESHOLD 100 // Adjust based on calibration
|
|
|
|
unsigned long startTime = millis();
|
|
|
|
// Wait up to 20ms for ACK pulse
|
|
while (millis() - startTime < 20) {
|
|
int adcValue = analogRead(CURRENT_SENSE_PIN);
|
|
|
|
// If current spike detected (60mA+)
|
|
if (adcValue > ACK_THRESHOLD) {
|
|
Serial.println("ACK detected!");
|
|
return true;
|
|
}
|
|
|
|
delayMicroseconds(100);
|
|
}
|
|
|
|
Serial.println("No ACK");
|
|
return false;
|
|
}
|
|
```
|
|
|
|
### Step 3: Calibrate Threshold
|
|
```cpp
|
|
// Test with known-good decoder
|
|
// Measure ADC values during programming
|
|
// Adjust ACK_THRESHOLD to reliably detect 60mA pulse
|
|
```
|
|
|
|
## Safety Features
|
|
|
|
### Built-in Protection
|
|
1. **LM18200 Thermal Shutdown**: Protects against overheating
|
|
2. **Current Limiting**: Prevents excessive current draw
|
|
3. **Brake Pin**: Emergency stop capability (GPIO 23)
|
|
|
|
### Software Safety
|
|
1. **Power-Off on Mode Change**: Prevents accidental high current
|
|
2. **CV Range Validation**: Only allows CV 1-1024
|
|
3. **Address Range Check**: Validates 1-10239
|
|
4. **Write Verification**: Confirms successful programming
|
|
|
|
### Recommended Additions
|
|
1. **250mA Fuse**: Additional protection for programming track
|
|
2. **Timeout Handling**: Abort if no response after retries
|
|
3. **Error Logging**: Track failed programming attempts
|
|
|
|
## Usage
|
|
|
|
### From Touchscreen UI
|
|
|
|
1. **Enter DCC Mode**
|
|
- Press [MODE] button until "DCC" selected
|
|
- Press [POWER] to enable
|
|
|
|
2. **Open Programming Screen**
|
|
- Press [PROG] button (appears in DCC mode)
|
|
|
|
3. **Factory Reset**
|
|
- Press [FACTORY RESET] button
|
|
- Wait for confirmation (or timeout)
|
|
|
|
4. **Set Address**
|
|
- Enter address using keypad (field auto-selected)
|
|
- Press [SET ADDR] button
|
|
- Wait for verification
|
|
|
|
5. **Read CV**
|
|
- Enter CV number (tap CV field, then use keypad)
|
|
- Press [READ] button
|
|
- Value appears in CV Value field
|
|
|
|
6. **Write CV**
|
|
- Enter CV number and value
|
|
- Press [WRITE] button
|
|
- Wait for verification
|
|
|
|
### From Serial Monitor
|
|
|
|
```cpp
|
|
DCCGenerator dcc;
|
|
|
|
// Factory reset
|
|
dcc.factoryReset();
|
|
|
|
// Set address to 42
|
|
dcc.setDecoderAddress(42);
|
|
|
|
// Read CV7 (Version)
|
|
uint8_t version;
|
|
if (dcc.readCV(7, &version)) {
|
|
Serial.printf("Decoder version: %d\n", version);
|
|
}
|
|
|
|
// Write CV3 (Acceleration) = 20
|
|
dcc.writeCV(3, 20);
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### No ACK Detected
|
|
**Possible Causes:**
|
|
- Current sense not connected
|
|
- Threshold too high/low
|
|
- Decoder not responding
|
|
- Wrong CV number/value
|
|
|
|
**Solutions:**
|
|
1. Verify current sense wiring
|
|
2. Test with multimeter (should see 60mA spike)
|
|
3. Calibrate ADC threshold
|
|
4. Try factory-reset decoder first
|
|
5. Check decoder is DCC-compatible
|
|
|
|
### Programming Fails
|
|
**Check:**
|
|
1. Only one locomotive on track
|
|
2. Decoder supports NMRA DCC
|
|
3. Track connections solid
|
|
4. LM18200 powered and enabled
|
|
5. No shorts on track
|
|
|
|
### Inconsistent Results
|
|
**Causes:**
|
|
- Dirty track/wheels
|
|
- Poor electrical contact
|
|
- Noise on current sense line
|
|
- Decoder in bad state
|
|
|
|
**Solutions:**
|
|
1. Clean track and wheels
|
|
2. Verify all connections tight
|
|
3. Add filtering capacitor on ADC input
|
|
4. Factory reset decoder
|
|
5. Check for ground loops
|
|
|
|
## Technical References
|
|
|
|
### NMRA Standards
|
|
- **S-9.2.3**: Service Mode (Programming Track)
|
|
- **RP-9.2.3**: Recommended Practices for Service Mode
|
|
- **CV Definitions**: Standard configuration variables
|
|
|
|
### Service Mode Packet Format
|
|
```
|
|
┌──────────┬───┬──────────┬───┬──────────┬───┬──────────┬───┐
|
|
│ Preamble │ 0 │ Address │ 0 │ Instruction│ 0 │ Checksum│ 1 │
|
|
│ (22 bits)│ │ (1 byte) │ │ (1-2 byte) │ │ (1 byte) │ │
|
|
└──────────┴───┴──────────┴───┴──────────┴───┴──────────┴───┘
|
|
```
|
|
|
|
### CV Addresses
|
|
- **CV1**: Short Address (1-127)
|
|
- **CV7**: Decoder Version
|
|
- **CV8**: Manufacturer ID (8 = Factory Reset)
|
|
- **CV17-18**: Long Address (128-10239)
|
|
- **CV29**: Configuration (address mode, speed steps, etc.)
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Advanced Programming**
|
|
- Operations mode (programming on main track)
|
|
- Read on Main (RailCom support)
|
|
- Indexed CV access
|
|
|
|
2. **Decoder Detection**
|
|
- Auto-detect decoder manufacturer (CV8)
|
|
- Read decoder version (CV7)
|
|
- Capability detection
|
|
|
|
3. **Batch Programming**
|
|
- Save/load decoder configurations
|
|
- Bulk CV programming
|
|
- Profile management
|
|
|
|
4. **Diagnostics**
|
|
- Current monitoring during operation
|
|
- ACK pulse visualization
|
|
- Programming success statistics
|