From 5ce544cd3c7793934d7945067c7e6252b02f6095 Mon Sep 17 00:00:00 2001 From: Jeremy Shen Date: Wed, 10 Jun 2026 18:29:26 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix:=20recover=20JTAG=20DAP=20af?= =?UTF-8?q?ter=20flash=20programming=20with=20system=20reset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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. --- src/bitstream_programmer.py | 47 +++++++++++++++++++++++++++---------- src/gui/main_window.py | 24 +++++++++++++++++++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/bitstream_programmer.py b/src/bitstream_programmer.py index 1ac4c6d..04d7bbc 100644 --- a/src/bitstream_programmer.py +++ b/src/bitstream_programmer.py @@ -589,14 +589,27 @@ def full_bitstream_program( if callback: 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 = [ 'puts "INFO: Starting Zynq initialization via JTAG override..."', "connect", "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([ '# Check for DAP errors and attempt recovery', 'set target_list [targets]', @@ -606,19 +619,29 @@ def full_bitstream_program( ' puts "WARNING: ARM cores not found — DAP may be in error state"', ' # Show DAP status for logging', ' foreach t $target_list { puts " TARGET: $t" }', - ' # Attempt to recover by reinitializing via DAP', - ' catch { targets 1 }', - ' after 500', - ' # If DAP is accessible, try writing to system reset register', + ' # Attempt recovery: select DAP (target 1) and issue system reset', + ' puts "INFO: Attempting DAP recovery via system reset..."', ' catch {', - ' puts "Attempting SLCR system reset..."', - ' mwr 0xF8000200 0x00000001', + ' targets 1', + ' rst -system', ' after 1000', - ' disconnect', - ' after 1000', - ' connect', - ' after 500', + ' stop', ' }', + ' # 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"', '}', '', ]) diff --git a/src/gui/main_window.py b/src/gui/main_window.py index 301942f..f56b0fe 100644 --- a/src/gui/main_window.py +++ b/src/gui/main_window.py @@ -871,9 +871,22 @@ class MainWindow(ctk.CTk): self._bitstream_callback, ) + dap_fail = False for result in results: status = "✓" if result.success else "✗" 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) except Exception as e: @@ -1138,6 +1151,17 @@ class MainWindow(ctk.CTk): # Stop on first failure when running all steps 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 # Inter-step delay (skip after last step)