Files
lishanpi/tools/flash.py
T

305 lines
9.3 KiB
Python
Raw Normal View History

2026-04-26 16:24:42 +08:00
#!/usr/bin/env python3
"""
LSPi Project Flash Script
Support OpenOCD, J-Link, PyOCD and other programming tools
"""
import os
import sys
import subprocess
import shutil
import argparse
# Project configuration
PROJECT_NAME = "LSPi_Project"
ELF_FILE = f"build/{PROJECT_NAME}.elf"
BIN_FILE = f"build/{PROJECT_NAME}.bin"
HEX_FILE = f"build/{PROJECT_NAME}.hex"
# GD32F470 target configuration
TARGET_DEVICE = "gd32f470zg"
TARGET_CPU = "cortex-m4"
# Tool detection
def detect_tools():
"""Detect available programming tools in system"""
tools = {}
# Detect OpenOCD
if shutil.which("openocd"):
tools["openocd"] = "openocd"
elif shutil.which("openocd.exe"):
tools["openocd"] = "openocd.exe"
# Detect J-Link
if shutil.which("jlink"):
tools["jlink"] = "jlink"
elif shutil.which("jlink.exe"):
tools["jlink"] = "jlink.exe"
elif shutil.which("JLink.exe"):
tools["jlink"] = "JLink.exe"
# Detect PyOCD
if shutil.which("pyocd"):
tools["pyocd"] = "pyocd"
elif shutil.which("pyocd.exe"):
tools["pyocd"] = "pyocd.exe"
return tools
def check_build_files(args):
"""Check if build files exist"""
if not os.path.exists(args.elf):
print(f"Error: ELF file not found: {args.elf}")
print("Please run build command first: cmake -B build && cmake --build build")
return False
print(f"Found ELF file: {args.elf}")
# Check if BIN and HEX files are generated
if os.path.exists(args.bin):
print(f"Found BIN file: {args.bin}")
else:
print(f"Warning: BIN file not found: {args.bin}")
if os.path.exists(args.hex):
print(f"Found HEX file: {args.hex}")
else:
print(f"Warning: HEX file not found: {args.hex}")
return True
def flash_with_openocd(elf_path):
"""Flash using OpenOCD"""
print("Flashing with OpenOCD...")
# OpenOCD configuration script
# Note: need to adjust interface and target config files based on actual hardware
openocd_script = f"""
# Configuration for CMSIS-DAP debugger
source [find interface/cmsis-dap.cfg]
# Configuration for ST-Link debugger
# source [find interface/stlink.cfg]
# Configuration for J-Link debugger
# source [find interface/jlink.cfg]
# GD32F4xx target configuration (using STM32F4xx config as OpenOCD may not have GD32 specific config)
source [find target/stm32f4x.cfg]
# Reset configuration for GD32
# Try different reset configurations if one doesn't work
# reset_config srst_only
# reset_config srst_nogate
reset_config connect_assert_srst
# Program and verify
program {elf_path} verify reset exit
"""
# Write script to temporary file
with open("openocd_temp.cfg", "w") as f:
f.write(openocd_script)
try:
cmd = ["openocd", "-f", "openocd_temp.cfg"]
print(f"Executing: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print("Flash successful!")
else:
print(f"Flash failed, return code: {result.returncode}")
print(f"Stderr: {result.stderr}")
return result.returncode == 0
except Exception as e:
print(f"Error executing OpenOCD: {e}")
return False
finally:
# Cleanup temporary file
if os.path.exists("openocd_temp.cfg"):
os.remove("openocd_temp.cfg")
def flash_with_jlink(hex_path):
"""Flash using J-Link"""
print("Flashing with J-Link...")
# J-Link command script
jlink_script = f"""
device {TARGET_DEVICE}
speed 4000
erase
loadfile {hex_path}
r
g
exit
"""
# Write script to temporary file
script_file = "jlink_temp.jlink"
with open(script_file, "w") as f:
f.write(jlink_script)
try:
cmd = ["JLink.exe", "-CommanderScript", script_file]
print(f"Executing: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print("Flash successful!")
else:
print(f"Flash failed, return code: {result.returncode}")
print(f"Stderr: {result.stderr}")
return result.returncode == 0
except Exception as e:
print(f"Error executing J-Link: {e}")
return False
finally:
# Cleanup temporary file
if os.path.exists(script_file):
os.remove(script_file)
def flash_with_pyocd(hex_path):
"""Flash using PyOCD"""
print("Flashing with PyOCD...")
try:
# Erase chip
print("Erasing chip...")
erase_cmd = ["pyocd", "erase", "-c", "-t", TARGET_DEVICE]
erase_result = subprocess.run(erase_cmd, capture_output=True, text=True)
if erase_result.returncode != 0:
print(f"Erase failed: {erase_result.stderr}")
# Flash HEX file
print(f"Flashing HEX file: {hex_path}")
flash_cmd = ["pyocd", "load", hex_path, "-t", TARGET_DEVICE]
result = subprocess.run(flash_cmd, capture_output=True, text=True)
if result.returncode == 0:
print("Flash successful!")
else:
print(f"Flash failed, return code: {result.returncode}")
print(f"Stderr: {result.stderr}")
return result.returncode == 0
except Exception as e:
print(f"Error executing PyOCD: {e}")
return False
def generate_bin_hex(args):
"""Generate BIN and HEX files"""
print("Generating BIN and HEX files...")
# Use arm-none-eabi-objcopy tool
objcopy = "arm-none-eabi-objcopy"
if shutil.which(objcopy):
try:
# Generate HEX file
hex_cmd = [objcopy, "-O", "ihex", args.elf, args.hex]
subprocess.run(hex_cmd, check=True)
print(f"Generated HEX file: {args.hex}")
# Generate BIN file
bin_cmd = [objcopy, "-O", "binary", "-S", args.elf, args.bin]
subprocess.run(bin_cmd, check=True)
print(f"Generated BIN file: {args.bin}")
return True
except subprocess.CalledProcessError as e:
print(f"Failed to generate files: {e}")
return False
else:
print(f"Tool not found: {objcopy}, cannot generate BIN/HEX files")
return False
def main():
parser = argparse.ArgumentParser(description="LSPi Project Flash Script")
parser.add_argument("--tool", choices=["openocd", "jlink", "pyocd", "auto"],
default="auto", help="Select programming tool (default: auto)")
parser.add_argument("--elf", default=ELF_FILE, help="ELF file path")
parser.add_argument("--hex", default=HEX_FILE, help="HEX file path")
parser.add_argument("--bin", default=BIN_FILE, help="BIN file path")
parser.add_argument("--generate", action="store_true", help="Generate BIN/HEX files")
parser.add_argument("--list-tools", action="store_true", help="List available programming tools")
args = parser.parse_args()
# List available tools
if args.list_tools:
tools = detect_tools()
print("Available programming tools:")
for tool, path in tools.items():
print(f" {tool}: {path}")
if not tools:
print(" No programming tools found")
return
# Check build files
if not check_build_files(args):
sys.exit(1)
# Generate BIN/HEX files
if args.generate or not os.path.exists(HEX_FILE):
if not generate_bin_hex(args):
print("Warning: Could not generate BIN/HEX files, continuing...")
# Detect available tools
available_tools = detect_tools()
if not available_tools:
print("Error: No programming tools found")
print("Please install one of the following:")
print(" - OpenOCD (recommended)")
print(" - SEGGER J-Link")
print(" - PyOCD")
sys.exit(1)
print("Available programming tools:")
for tool in available_tools:
print(f" - {tool}")
# Select programming tool
tool_to_use = args.tool
if tool_to_use == "auto":
# Select by priority
if "openocd" in available_tools:
tool_to_use = "openocd"
elif "jlink" in available_tools:
tool_to_use = "jlink"
elif "pyocd" in available_tools:
tool_to_use = "pyocd"
else:
print("Error: No available programming tools")
sys.exit(1)
print(f"Selected programming tool: {tool_to_use}")
# Execute flash
success = False
if tool_to_use == "openocd":
success = flash_with_openocd(args.elf)
elif tool_to_use == "jlink":
if not os.path.exists(args.hex):
print(f"Error: HEX file not found: {args.hex}")
print("Please use --generate to generate HEX file")
sys.exit(1)
success = flash_with_jlink(args.hex)
elif tool_to_use == "pyocd":
if not os.path.exists(args.hex):
print(f"Error: HEX file not found: {args.hex}")
print("Please use --generate to generate HEX file")
sys.exit(1)
success = flash_with_pyocd(args.hex)
if success:
print("Flash completed!")
sys.exit(0)
else:
print("Flash failed!")
sys.exit(1)
if __name__ == "__main__":
main()