Skip to content

Commit 31d4c5a

Browse files
committed
Implement pyOCD SWD/JTAG programming support with dynamic target detection
## Major Features Added ### pyOCD Integration - Add SWD/JTAG programming as alternative to serial bootloader methods - Support for debug probe discovery and management - Automated target chip selection using dynamic detection - Optional pyOCD dependency via `pyocd` extra ### Dynamic Target Detection - Replace hardcoded target mappings with dynamic API-based detection - Parse MCU info from `sys.implementation._machine` strings - Fuzzy matching algorithm for target selection - Direct probe-based target detection with fallback to fuzzy matching - Extensible architecture for future OpenOCD/J-Link support ### CLI Integration - Add `--method pyocd` option for explicit SWD/JTAG programming - Add `--probe-id` option for specific debug probe selection - Maintain existing serial bootloader behavior as default - Clean integration with existing flash method selection ### Architecture Improvements - Abstract debug probe layer for extensibility - Target detector abstraction with registry system - Proper error handling and fallback mechanisms - Performance optimized with caching and lazy loading ## Technical Details ### Files Added - `mpflash/flash/debug_probe.py` - Debug probe abstraction layer - `mpflash/flash/pyocd_probe.py` - pyOCD-specific probe implementation - `mpflash/flash/pyocd_flash.py` - pyOCD flash programming interface - `mpflash/flash/pyocd_targets.py` - Target detection wrapper functions - `mpflash/flash/dynamic_targets.py` - Dynamic target detection engine - `mpflash/cli_pyocd.py` - pyOCD-specific CLI commands (future) ### Files Modified - `mpflash/common.py` - Add FlashMethod enum for different programming methods - `mpflash/flash/__init__.py` - Integrate pyOCD into flash method selection - `mpflash/cli_flash.py` - Add CLI options for pyOCD method and probe selection - `pyproject.toml` - Add optional pyOCD dependency - `mpflash/cli_download.py` - Fix unused pytest import ### Key Benefits - **No hardware requirements change** - existing serial methods remain default - **Automated target selection** - no manual target configuration needed - **Extensible design** - easy to add OpenOCD, J-Link, etc. in future - **Performance optimized** - direct API calls instead of subprocess shells - **Maintainable** - eliminates hardcoded target mappings ## Usage ```bash # Existing behavior unchanged (serial bootloader methods) mpflash flash # Explicit pyOCD SWD/JTAG programming mpflash flash --method pyocd # Specific debug probe selection mpflash flash --method pyocd --probe-id stlink # Install with pyOCD support uv sync --extra pyocd ``` ## Breaking Changes None - all existing functionality preserved with same default behavior.
1 parent 013ddcb commit 31d4c5a

19 files changed

+4018
-24
lines changed

OPENOCD_EXAMPLE.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# OpenOCD Integration Example
2+
3+
This document shows how the abstract target detection layer can be extended to support OpenOCD in the future.
4+
5+
## Example OpenOCD Target Detector
6+
7+
```python
8+
# Future: mpflash/flash/openocd_targets.py
9+
10+
class OpenOCDTargetDetector(TargetDetector):
11+
"""OpenOCD-specific target detection implementation."""
12+
13+
def get_name(self) -> str:
14+
return "openocd"
15+
16+
def is_available(self) -> bool:
17+
"""Check if OpenOCD is installed and available."""
18+
try:
19+
import subprocess
20+
result = subprocess.run(["openocd", "--version"],
21+
capture_output=True, timeout=5)
22+
return result.returncode == 0
23+
except (FileNotFoundError, subprocess.TimeoutExpired):
24+
return False
25+
26+
def get_available_targets(self) -> Dict[str, Dict[str, str]]:
27+
"""Get available OpenOCD targets."""
28+
try:
29+
import subprocess
30+
# Get target list from OpenOCD
31+
result = subprocess.run([
32+
"openocd", "-c", "target types", "-c", "exit"
33+
], capture_output=True, text=True, timeout=10)
34+
35+
targets = {}
36+
for line in result.stdout.split('\n'):
37+
if line.strip() and not line.startswith('#'):
38+
target_name = line.strip().split()[0]
39+
targets[target_name] = {
40+
"vendor": "OpenOCD",
41+
"part_number": target_name,
42+
"source": "openocd"
43+
}
44+
return targets
45+
except Exception as e:
46+
log.debug(f"Failed to get OpenOCD targets: {e}")
47+
return {}
48+
49+
def detect_connected_target(self, probe_id: Optional[str] = None) -> Optional[str]:
50+
"""Try to detect target via OpenOCD probe connection."""
51+
try:
52+
import subprocess
53+
# This would use OpenOCD's target detection capabilities
54+
# Implementation would depend on specific OpenOCD commands
55+
cmd = ["openocd", "-f", "interface/stlink.cfg",
56+
"-c", "init", "-c", "targets", "-c", "exit"]
57+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
58+
59+
# Parse output to extract detected target
60+
# (Implementation details would go here)
61+
return None # Placeholder
62+
except Exception as e:
63+
log.debug(f"OpenOCD target detection failed: {e}")
64+
return None
65+
66+
# Register the detector
67+
register_target_detector("openocd", OpenOCDTargetDetector())
68+
```
69+
70+
## Usage
71+
72+
With this extension, users could:
73+
74+
```bash
75+
# Use OpenOCD for programming instead of pyOCD
76+
mpflash flash --method openocd --probe-id stlink
77+
78+
# Auto-detect between pyOCD and OpenOCD
79+
mpflash flash --method auto # Would try both pyOCD and OpenOCD
80+
```
81+
82+
## Benefits of the Abstract Layer
83+
84+
1. **Consistent Interface**: All target detectors use the same API
85+
2. **Easy Extension**: New tools (J-Link, etc.) can be added easily
86+
3. **Fallback Logic**: Can try multiple detection methods automatically
87+
4. **Tool-Specific Optimizations**: Each detector can use the best approach for its tool
88+
5. **Maintainable**: Clear separation between tool-specific code
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# PyOCD Implementation Summary
2+
3+
## Overview
4+
5+
Successfully implemented comprehensive pyOCD SWD/JTAG programming support for MPFlash, providing an alternative to serial bootloader-based programming methods. This enables direct flash programming via debug probes without requiring bootloader activation.
6+
7+
## ✅ Completed Implementation
8+
9+
### 1. Core PyOCD Integration
10+
11+
**Files Created:**
12+
- `mpflash/flash/pyocd_targets.py` - Board ID to pyOCD target type mapping
13+
- `mpflash/flash/pyocd_flash.py` - Main pyOCD flash implementation
14+
- `mpflash/cli_pyocd.py` - PyOCD-specific CLI commands
15+
- `docs/pyocd_integration_design.md` - Technical design documentation
16+
17+
**Files Modified:**
18+
- `mpflash/common.py` - Added FlashMethod enum
19+
- `mpflash/flash/__init__.py` - Integrated pyOCD into flash system
20+
- `mpflash/cli_flash.py` - Added pyOCD CLI options
21+
- `pyproject.toml` - Added pyOCD optional dependency
22+
- `CLAUDE.md` - Updated documentation
23+
24+
### 2. Target Support Mapping
25+
26+
**Supported Target Families:**
27+
- **STM32**: 20+ board mappings including NUCLEO, Discovery, and PyBoard variants
28+
- **RP2040**: Complete support for Raspberry Pi Pico, Arduino Nano RP2040, Adafruit, Pimoroni, SparkFun, and Seeed boards
29+
- **RP2350**: Support for newer Raspberry Pi Pico 2
30+
- **SAMD**: 15+ board mappings including Adafruit, Arduino, and SparkFun variants
31+
- **ESP32/ESP8266**: Explicitly excluded (not Cortex-M) with clear fallback to esptool
32+
33+
**Target Mapping Features:**
34+
- Direct board_id to pyOCD target mapping
35+
- Intelligent MCU-based fallback mapping
36+
- STM32 family/variant detection with built-in target validation
37+
- SAMD MCU name normalization
38+
- Clear error messages for unsupported targets
39+
40+
### 3. Automated Target Selection
41+
42+
**Flash Method Selection Logic:**
43+
1. **Auto Mode (default)**: Uses existing serial bootloader methods (UF2, DFU, esptool) - no extra hardware required
44+
2. **Explicit PyOCD**: Only used when `--method pyocd` is specified - requires debug probe hardware
45+
3. **Backward Compatibility**: All existing workflows continue unchanged
46+
47+
**Auto-Detection Features:**
48+
- Automatic probe discovery and target detection
49+
- Intelligent method selection based on hardware availability
50+
- Graceful fallback to existing methods when pyOCD unavailable
51+
- Target type validation before attempting programming
52+
53+
### 4. CLI Integration
54+
55+
**New CLI Options:**
56+
- `--method pyocd` - Force pyOCD programming
57+
- `--probe-id <ID>` - Specify debug probe
58+
- `--method auto` - Intelligent method selection (default)
59+
60+
**New Commands:**
61+
- `mpflash list-probes` - List available debug probes
62+
- `mpflash pyocd-info` - Show pyOCD installation status
63+
- `mpflash pyocd-targets` - Display target mappings
64+
65+
**Enhanced Flash Command:**
66+
```bash
67+
# Default behavior (existing serial bootloader methods)
68+
mpflash flash
69+
70+
# Explicit pyOCD programming (requires debug probe)
71+
mpflash flash --method pyocd
72+
73+
# Use specific debug probe
74+
mpflash flash --method pyocd --probe-id ST-LINK_V2
75+
76+
# Explicit serial methods also available
77+
mpflash flash --method serial
78+
mpflash flash --method uf2
79+
mpflash flash --method dfu
80+
```
81+
82+
### 5. Error Handling & User Experience
83+
84+
**Comprehensive Error Messages:**
85+
- Clear indication when pyOCD not installed
86+
- Specific reasons why targets aren't supported
87+
- Helpful suggestions for resolving issues
88+
- Graceful degradation when debug probes unavailable
89+
90+
**User Guidance:**
91+
- Installation instructions via optional dependency
92+
- Probe discovery and target detection help
93+
- Usage examples in all help commands
94+
- Rich terminal output with tables and status indicators
95+
96+
## 🎯 Key Benefits Achieved
97+
98+
### 1. **No Bootloader Required**
99+
- Direct programming via debug interface
100+
- Works even when MicroPython is not functional
101+
- Enables recovery of "bricked" boards
102+
103+
### 2. **Factory Programming**
104+
- Program blank chips without existing firmware
105+
- Suitable for manufacturing and development workflows
106+
- More reliable than serial bootloader methods
107+
108+
### 3. **Improved Reliability**
109+
- Direct flash memory access
110+
- No dependency on serial bootloader activation
111+
- Bypass common bootloader entry issues
112+
113+
### 4. **Professional Integration**
114+
- Seamless integration with existing MPFlash workflows
115+
- Maintains full backward compatibility
116+
- Optional dependency - doesn't affect users without debug probes
117+
118+
### 5. **Automated Workflow**
119+
- Intelligent method selection
120+
- Auto-detection of probes and targets
121+
- Minimal user configuration required
122+
123+
## 🔧 Technical Architecture
124+
125+
### Flash Method Architecture
126+
```
127+
FlashMethod.AUTO (preserves existing behavior)
128+
├── UF2 - for RP2040/SAMD with .uf2 files
129+
├── DFU - for STM32 boards
130+
├── ESPTOOL - for ESP32/ESP8266
131+
└── Error - no suitable method found
132+
133+
FlashMethod.PYOCD (explicit selection only)
134+
├── Check pyOCD availability
135+
├── Validate target support
136+
├── Discover debug probes
137+
└── Program via SWD/JTAG
138+
```
139+
140+
### PyOCD Integration Pattern
141+
```
142+
1. Check pyOCD availability (graceful ImportError handling)
143+
2. Map board_id → pyOCD target type
144+
3. Discover debug probes
145+
4. Auto-detect or validate target
146+
5. Program via pyOCD FileProgrammer API
147+
6. Reset and verify
148+
```
149+
150+
### Board ID Mapping Strategy
151+
```
152+
BOARD_ID_TO_PYOCD_TARGET = {
153+
"RPI_PICO": "rp2040",
154+
"NUCLEO_F429ZI": "stm32f429xi",
155+
"SEEED_WIO_TERMINAL": "samd51p19a",
156+
# ... 70+ mappings
157+
}
158+
```
159+
160+
## 📦 Dependencies
161+
162+
**New Optional Dependency:**
163+
- `pyocd>=0.36.0` - Added to `[project.optional-dependencies.pyocd]`
164+
- Install with: `uv sync --extra pyocd`
165+
166+
**Compatible Hardware:**
167+
- ST-Link debug probes (ST-Link/V2, ST-Link/V3)
168+
- ARM DAP-Link compatible probes
169+
- J-Link probes (via pyOCD)
170+
- Any CMSIS-DAP compatible debug probe
171+
172+
## 🧪 Usage Examples
173+
174+
### Basic Usage
175+
```bash
176+
# Install pyOCD support
177+
uv sync --extra pyocd
178+
179+
# Default behavior (existing serial bootloader methods)
180+
mpflash flash --version stable
181+
182+
# Explicit pyOCD programming (requires debug probe)
183+
mpflash flash --method pyocd
184+
185+
# Use specific probe
186+
mpflash flash --method pyocd --probe-id 066DFF485750717867114355
187+
```
188+
189+
### Discovery and Information
190+
```bash
191+
# List available debug probes
192+
mpflash list-probes
193+
194+
# Show pyOCD installation status
195+
mpflash pyocd-info
196+
197+
# View target mappings
198+
mpflash pyocd-targets --board-filter PICO
199+
```
200+
201+
### Advanced Usage
202+
```bash
203+
# Flash with probe ID filtering
204+
mpflash flash --method pyocd --probe-id ST-LINK
205+
206+
# Flash specific board with erase
207+
mpflash flash --method pyocd --board RPI_PICO --erase
208+
209+
# Fallback to serial if pyOCD fails
210+
mpflash flash --method serial
211+
```
212+
213+
## 🔄 Backward Compatibility
214+
215+
**Fully Maintained:**
216+
- All existing commands work unchanged
217+
- Existing workflows continue to function
218+
- No breaking changes to CLI or API
219+
- PyOCD support is purely additive
220+
221+
**Default Behavior:**
222+
- Auto-selection prioritizes pyOCD when available
223+
- Falls back gracefully to existing methods
224+
- Users without debug probes see no changes
225+
226+
## 🎉 Integration Success
227+
228+
The pyOCD integration provides professional-grade SWD/JTAG programming capabilities while maintaining MPFlash's ease of use and reliability. It successfully automates target chip selection, provides comprehensive error handling, and integrates cleanly into the existing architecture without disrupting current workflows.
229+
230+
This implementation enables MPFlash to support both hobbyist use cases (serial bootloader) and professional development workflows (debug probe programming) within a single, unified tool.

0 commit comments

Comments
 (0)