fix stm8loader.py

This commit is contained in:
2025-12-21 02:03:20 +08:00
parent 3a168ac41b
commit 537f8505bb
2 changed files with 247 additions and 223 deletions

BIN
scripts/boot2.bin Normal file

Binary file not shown.

View File

@@ -35,7 +35,7 @@ class STM8BootloaderError(Exception):
pass pass
class STM8Bootloader: class STM8Bootloader:
def __init__(self, port: str, verbose: bool = False, reset_pin: str = 'rts+dtr'): def __init__(self, port: str, verbose: bool = False, reset_pin: str = 'rts+dtr', boot2_file: str = None):
""" """
Initialize STM8 Bootloader Initialize STM8 Bootloader
@@ -43,6 +43,7 @@ class STM8Bootloader:
port: Serial port name port: Serial port name
verbose: Whether to display detailed debug information verbose: Whether to display detailed debug information
reset_pin: Reset pin type ('rts+dtr', 'rts', 'dtr' or 'none') reset_pin: Reset pin type ('rts+dtr', 'rts', 'dtr' or 'none')
boot2_file: boot2 binary file path
""" """
self.port = port self.port = port
self.verbose = verbose self.verbose = verbose
@@ -53,6 +54,9 @@ class STM8Bootloader:
self.in_boot2 = False self.in_boot2 = False
self.script_dir = os.path.dirname(os.path.abspath(__file__)) self.script_dir = os.path.dirname(os.path.abspath(__file__))
# Store boot2 file path
self.default_boot2_file = boot2_file
def log(self, message: str, level: str = "INFO"): def log(self, message: str, level: str = "INFO"):
""" """
Print log information Print log information
@@ -229,8 +233,14 @@ class STM8Bootloader:
True: Send successful, False: Send failed True: Send successful, False: Send failed
""" """
try: try:
# If file path is not absolute, make it relative to script directory # If file path is not absolute, make it relative to current working directory
if not os.path.isabs(bin_file): if not os.path.isabs(bin_file):
# Try to find file in current directory first
current_dir_file = os.path.join(os.getcwd(), bin_file)
if os.path.exists(current_dir_file):
bin_file = current_dir_file
else:
# Fallback to script directory
bin_file = os.path.join(self.script_dir, bin_file) bin_file = os.path.join(self.script_dir, bin_file)
with open(bin_file, 'rb') as f: with open(bin_file, 'rb') as f:
@@ -240,7 +250,7 @@ class STM8Bootloader:
self.log(f"File {bin_file} is empty", "ERROR") self.log(f"File {bin_file} is empty", "ERROR")
return False return False
self.log(f"Read {len(data)} bytes of boot2 program", "DEBUG") self.log(f"Read {len(data)} bytes of boot2 program from {bin_file}", "DEBUG")
# Byte reversal # Byte reversal
reversed_data = bytes(reversed(data)) reversed_data = bytes(reversed(data))
@@ -420,16 +430,25 @@ class STM8Bootloader:
self.in_boot2 = False self.in_boot2 = False
return False return False
def upload_boot2(self, boot2_file: str = "boot2.bin") -> bool: def upload_boot2(self, boot2_file: str = None) -> bool:
""" """
Upload boot2 program to MCU Upload boot2 program to MCU
Args: Args:
boot2_file: boot2 binary file path boot2_file: boot2 binary file path (if None, use default)
Returns: Returns:
True: Upload successful, False: Upload failed True: Upload successful, False: Upload failed
""" """
# Use provided file or default
if boot2_file is None:
if self.default_boot2_file:
boot2_file = self.default_boot2_file
else:
# Fallback to script directory
boot2_file = os.path.join(self.script_dir, "boot2.bin")
self.log("Starting boot2 program upload...", "INFO")
# 1. Switch to 9600 bps # 1. Switch to 9600 bps
self.close() self.close()
@@ -717,9 +736,10 @@ class STM8Bootloader:
self.list_directory(path) self.list_directory(path)
elif cmd == 'reload': elif cmd == 'reload':
# Reset and upload boot2 # Reset and upload boot2 with optional file path
boot2_file = args[1] if len(args) > 1 else None
self.log("Executing reset and to upload boot2...", "INFO") self.log("Executing reset and to upload boot2...", "INFO")
if not self.upload_boot2(): if not self.upload_boot2(boot2_file):
self.log("Reset upload failed", "ERROR") self.log("Reset upload failed", "ERROR")
else: else:
self.log("Reset upload successful", "INFO") self.log("Reset upload successful", "INFO")
@@ -838,7 +858,7 @@ Command List:
ls [path] - List directory contents, files show size, directories only names ls [path] - List directory contents, files show size, directories only names
reload - Reset MCU and upload boot2 program reload [file] - Reset MCU and upload boot2 program
help - Display this help information help - Display this help information
@@ -865,23 +885,23 @@ def main():
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=""" epilog="""
Examples: Examples:
%(prog)s COM3 # Enter interactive mode %(prog)s /dev/ttyUSB0 # Enter interactive mode
%(prog)s COM3 -r 0x8000 256 # Read memory %(prog)s /dev/ttyUSB0 -r 0x8000 256 # Read memory
%(prog)s COM3 -w 0x8000 firmware.bin # Write file %(prog)s /dev/ttyUSB0 -w 0x8000 firmware.bin # Write file
%(prog)s COM3 -w 0x8000 "AABBCC" # Write hex string %(prog)s /dev/ttyUSB0 -w 0x8000 "AABBCC" # Write hex string
%(prog)s COM3 -g 0x8000 # Jump execution %(prog)s /dev/ttyUSB0 -g 0x8000 # Jump execution
%(prog)s --list-ports # List available serial ports %(prog)s --list-ports # List available serial ports
""" """
) )
# Serial port related parameters # Serial port related parameters
parser.add_argument('port', nargs='?', help='Serial port name (e.g., COM3, /dev/ttyUSB0)') parser.add_argument('port', nargs='?', help='Serial port name (e.g., /dev/ttyUSB0, COM3)')
parser.add_argument('-b', '--baudrate', type=int, default=BOOT2_BAUDRATE, parser.add_argument('-b', '--baudrate', type=int, default=BOOT2_BAUDRATE,
help=f'Serial port baud rate (default: {BOOT2_BAUDRATE})') help=f'Serial port baud rate (default: {BOOT2_BAUDRATE})')
# boot2 upload parameters # boot2 upload parameters
parser.add_argument('--boot2', default='boot2.bin', parser.add_argument('--boot2', default='boot2.bin',
help='boot2 program file path (default: boot2.bin in script directory)') help='boot2 program file path (default: boot2.bin in current directory or script directory)')
parser.add_argument('--skip-boot2', action='store_true', parser.add_argument('--skip-boot2', action='store_true',
help='Skip automatic boot2 upload, directly enter interactive mode') help='Skip automatic boot2 upload, directly enter interactive mode')
@@ -922,8 +942,12 @@ Examples:
return 1 return 1
try: try:
# Handle boot2 file path
boot2_file = args.boot2
# Create bootloader instance # Create bootloader instance
loader = STM8Bootloader(args.port, verbose=args.verbose, reset_pin=args.reset_pin) loader = STM8Bootloader(args.port, verbose=args.verbose,
reset_pin=args.reset_pin, boot2_file=boot2_file)
# Open serial port # Open serial port
loader.open(baudrate=args.baudrate) loader.open(baudrate=args.baudrate)
@@ -934,7 +958,7 @@ Examples:
# If not in boot2 and not skipping boot2 upload, must upload boot2 # If not in boot2 and not skipping boot2 upload, must upload boot2
if not in_boot2 and not args.skip_boot2: if not in_boot2 and not args.skip_boot2:
print("[INFO] Not in boot2 mode, starting boot2 program upload...") print("[INFO] Not in boot2 mode, starting boot2 program upload...")
if not loader.upload_boot2(args.boot2): if not loader.upload_boot2():
print("[ERROR] boot2 upload failed") print("[ERROR] boot2 upload failed")
loader.close() loader.close()
return 1 return 1