🐛 fix: recover JTAG DAP after flash programming with system reset

- Add preemptive rst -system at Step 3 start to clean post-flash DAP state
- Replace ineffective SLCR write with targets 1 → rst -system recovery
- Exit with clear power-cycle instructions when DAP recovery fails
- Show prominent DAP error guidance in GUI for Step 3 and Run All mode

Verified: Step 1→2→3 now passes end-to-end (340s) without board power cycle.
This commit is contained in:
Jeremy Shen
2026-06-10 18:29:26 +08:00
parent 73b8225a27
commit 5ce544cd3c
2 changed files with 59 additions and 12 deletions
+35 -12
View File
@@ -589,14 +589,27 @@ def full_bitstream_program(
if callback: if callback:
callback("start", "Initializing Zynq via JTAG (FSBL override)...") callback("start", "Initializing Zynq via JTAG (FSBL override)...")
# Build TCL with DAP error recovery # Build TCL with preemptive system reset + DAP error recovery
tcl_lines = [ tcl_lines = [
'puts "INFO: Starting Zynq initialization via JTAG override..."', 'puts "INFO: Starting Zynq initialization via JTAG override..."',
"connect", "connect",
"after 500", "after 500",
] ]
# DAP error check — if ARM cores not visible, try recovery # Preemptive system reset (safe on clean board; may help after flash)
tcl_lines.extend([
'# Preemptive system reset to clean up any leftover state',
'if {[catch {',
' targets -set -nocase -filter {name =~ "arm*#0"}',
' rst -system',
' after 1000',
' stop',
' puts "INFO: Preemptive system reset OK"',
'}]} { puts "INFO: Preemptive system reset skipped (no ARM target)" }',
'',
])
# DAP error check — if ARM cores not visible, try recovery via DAP
tcl_lines.extend([ tcl_lines.extend([
'# Check for DAP errors and attempt recovery', '# Check for DAP errors and attempt recovery',
'set target_list [targets]', 'set target_list [targets]',
@@ -606,19 +619,29 @@ def full_bitstream_program(
' puts "WARNING: ARM cores not found — DAP may be in error state"', ' puts "WARNING: ARM cores not found — DAP may be in error state"',
' # Show DAP status for logging', ' # Show DAP status for logging',
' foreach t $target_list { puts " TARGET: $t" }', ' foreach t $target_list { puts " TARGET: $t" }',
' # Attempt to recover by reinitializing via DAP', ' # Attempt recovery: select DAP (target 1) and issue system reset',
' catch { targets 1 }', ' puts "INFO: Attempting DAP recovery via system reset..."',
' after 500',
' # If DAP is accessible, try writing to system reset register',
' catch {', ' catch {',
' puts "Attempting SLCR system reset..."', ' targets 1',
' mwr 0xF8000200 0x00000001', ' rst -system',
' after 1000', ' after 1000',
' disconnect', ' stop',
' after 1000',
' connect',
' after 500',
' }', ' }',
' # Disconnect and reconnect to refresh JTAG chain',
' catch { disconnect; after 1000; connect; after 500 }',
' # Check if ARM cores reappeared',
' set target_list2 [targets]',
' set has_arm2 0',
' foreach t $target_list2 {',
' puts " AFTER RECOVERY: $t"',
' if {[regexp -nocase {arm|cortex} $t]} { set has_arm2 1 }',
' }',
' if {!$has_arm2} {',
' puts "FATAL: DAP recovery failed — board requires power cycle"',
' puts "FATAL: Unplug/replug power, then retry Step 3"',
' exit 1',
' }',
' puts "INFO: ARM cores recovered after DAP reset"',
'}', '}',
'', '',
]) ])
+24
View File
@@ -871,9 +871,22 @@ class MainWindow(ctk.CTk):
self._bitstream_callback, self._bitstream_callback,
) )
dap_fail = False
for result in results: for result in results:
status = "" if result.success else "" status = "" if result.success else ""
self._log_message(f" {status} {result.step}: {result.message}") self._log_message(f" {status} {result.step}: {result.message}")
if "DAP" in result.message and not result.success:
dap_fail = True
if dap_fail:
self._log_message("")
self._log_message(" ╔══════════════════════════════════════════╗")
self._log_message(" ║ DAP ERROR — JTAG debug port hung ║")
self._log_message(" ║ This is caused by prior flash programming║")
self._log_message(" ║ → Power-cycle the board (unplug/replug) ║")
self._log_message(" ║ → Then re-run Step 3 ║")
self._log_message(" ╚══════════════════════════════════════════╝")
self._log_message("")
return all(r.success for r in results) return all(r.success for r in results)
except Exception as e: except Exception as e:
@@ -1138,6 +1151,17 @@ class MainWindow(ctk.CTk):
# Stop on first failure when running all steps # Stop on first failure when running all steps
if not single_step and not success: if not single_step and not success:
# Special case: Step 2 pass → Step 3 DAP fail = board needs power cycle
if i == 2 and results[0] and not success:
self._log_message("")
self._log_message(" ┌─────────────────────────────────────────┐")
self._log_message(" │ Step 3 failed after flash programming. │")
self._log_message(" │ This is normal — program_flash leaves │")
self._log_message(" │ the JTAG DAP in error state. │")
self._log_message(" │ → Power-cycle the board, then re-run │")
self._log_message(" │ Step 3 (Load Bootloader) alone. │")
self._log_message(" └─────────────────────────────────────────┘")
self._log_message("")
break break
# Inter-step delay (skip after last step) # Inter-step delay (skip after last step)