From 29edad34378168da47a13139b830a844fd10a76a Mon Sep 17 00:00:00 2001 From: kicer Date: Sat, 20 Dec 2025 19:16:13 +0800 Subject: [PATCH] fix boot2.s --- scripts/boot1.opt | 23 +- scripts/boot2.s | 114 ++----- scripts/stm8_bootloader_test.py | 523 -------------------------------- src/main.c | 5 +- 4 files changed, 37 insertions(+), 628 deletions(-) delete mode 100644 scripts/stm8_bootloader_test.py diff --git a/scripts/boot1.opt b/scripts/boot1.opt index 57421ce..28b60e0 100644 --- a/scripts/boot1.opt +++ b/scripts/boot1.opt @@ -1,9 +1,9 @@ ;; M Code ;; option O0 O1 N1 O2 N2 O3 N3 O4 N4 O5 N5 ;; 4800 00 00 ff 00 ff 00 ff 00 ff 00 ff -- -- 00 03 d0 -;; 03D0|4810 a6 0d c7 52 32 c7 52 35 c7 52 31 a6 80 5f 5c 27 -;; 03E0|4820 17 72 0b 52 30 f8 3b 52 31 4c 26 f1 c7 52 31 96 -;; 03F0|4830 5c 5c 5c 13 01 26 e4 81 fe 94 72 cc 48 3e 80 04 +;; 03D0|4810 a6 0d c7 52 32 c7 52 35 c7 52 31 4f 5f 5c 27 0b +;; 03E0|4820 72 0b 52 30 f8 3b 52 31 4c 20 f1 4d 27 09 96 5c +;; 03F0|4830 5c 5c 13 01 26 01 81 5f fe 94 72 cc 48 3e 80 04 ;; UART1 register address definitions UART1_SR = 0x5230 ; Status register @@ -33,14 +33,12 @@ _boot_start: ;; Send BREAK signal and version number $0D ld UART1_DR, A ; [C7 52 31] Send version number 0x0D - ;; Receive 128-byte data block and push onto stack -_boot_rx_block: - ld A, #0x80 ; [A6 80] + clr A _boot_rx_byte: clrw X ; [5F] Reset X (for timeout detection) _boot_rx_wait: incw X ; [5C] Increment X, check for overflow (timeout detection) - jreq _boot_exit ; [27 14] If X overflows (receive timeout), exit + jreq _boot_timeout ; [27 14] If X overflows (receive timeout), exit ;; Wait for data reception btjf UART1_SR, #5, _boot_rx_wait ;[72 0B 52 30 F8] @@ -48,23 +46,24 @@ _boot_rx_wait: ;; Data received, push onto stack push UART1_DR ; [3B 52 31] inc A ; [4C] Increment A, used as receive counter - jrne _boot_rx_byte ; [26 F1] If A is not 0, continue receiving - - ;; Receive 128 bytes success - ld UART1_DR, A ; [C7 52 31] Send Ack 0x00 + jra _boot_rx_byte ; [26 F1] If A is not 0, continue receiving +_boot_timeout: + tnz A + jreq _boot_exit ;; Check address ldw X, SP ; [96] incw X ; [5c] incw X ; [5c] incw X ; [5c] cpw X, (1, SP) ; [13 01] - jrne _boot_rx_block ; [26 E7] + jrne _boot_exit ; [26 E7] ;; Reception complete, jump to received code ret ; [81] Jump to address at top of stack via ret instruction _boot_exit: ;; Timeout exit, jump to user program + clrw X ldw X, (X) ; [FE] ldw SP, X ; [94] jp [_boot_go_adr] ; [72 CC 48 3E] Indirect jump diff --git a/scripts/boot2.s b/scripts/boot2.s index dc8d17c..234fcba 100644 --- a/scripts/boot2.s +++ b/scripts/boot2.s @@ -10,7 +10,7 @@ ; 字节69: 校验和 (所有字节XOR) ; ================================================ -BOOT2_SP = 0x03CF ; start of boot1 ram address +BOOT2_SP = 0x03CD ; start of boot1 ram address ;; Register address definitions UART1_SR = 0x5230 ; Status register @@ -31,9 +31,7 @@ WWDG_CR = 0x50D1 ; WWDG control register ;; Const vars CMD_READ = 0xF1 ; 读内存命令 CMD_WRITE = 0xF2 ; 写内存命令 -CMD_ERASE = 0xF3 ; 整片擦除命令 -CMD_RESET = 0xF4 ; 复位命令 -CMD_GO = 0xF5 ; 跳转执行命令 +CMD_GO = 0xF3 ; 跳转执行命令 CMD_HEADER = 0x5A ; 帧头 ACK_HEADER = 0xA5 ; 应答帧头 @@ -50,16 +48,16 @@ DEFAULT_SP_H = 0x0000 ; ram top address DEFAULT_SP_L = 0x0000 ; ram top address tx_buffer = 0x0002 ; protocol tx buffer rx_buffer = 0x0002 ; protocol rx buffer -rx_state = 72 ; 接收状态 -rx_length = 73 ; 接收长度 -tx_state = 74 ; 发送状态 -tx_data_length = 75 ; 待发送的数据长度 -calc_checksum = 76 ; 计算的校验和 -temp_var1 = 77 ; 临时变量 -temp_var2 = 78 ; 临时变量 -temp_var3 = 79 ; 临时变量 +rx_state = 72 ; 接收状态 +rx_length = 73 ; 接收长度 +tx_state = 74 ; 发送状态 +tx_data_length = 75 ; 待发送的数据长度 +calc_checksum = 76 ; 计算的校验和 +temp_var1 = 77 ; 临时变量 +temp_var2 = 78 ; 临时变量 +temp_var3 = 79 ; 临时变量 -;; Bootloader body (load in ram ?-0x03D2) +;; Bootloader body (load in ram ?-0x03D0) .area RAM_BOOT .db (BOOT2_SP-(_end-_start)+1)>>8 @@ -67,16 +65,15 @@ temp_var3 = 79 ; 临时变量 _start: ; 配置UART1: 128000波特率, 8N1, 启用TX/RX - mov UART1_BRR2, #0 mov UART1_BRR1, #1 - mov UART1_CR2, #0x0C ; TEN=1, REN=1 - + ;mov UART1_BRR2, #0 + ;mov UART1_CR2, #0x0C ; TEN=1, REN=1 _main_loop: ; 接收命令帧 - call receive_frame + callr receive_frame ; 验证校验和 - call verify_checksum + callr verify_checksum jrne _checksum_error ; 根据命令类型跳转 @@ -88,12 +85,6 @@ _main_loop: cp A, #CMD_WRITE jreq _cmd_write - cp A, #CMD_ERASE - jreq _cmd_erase - - cp A, #CMD_RESET - jreq _cmd_reset - cp A, #CMD_GO jreq _cmd_go @@ -119,19 +110,10 @@ _cmd_write: call write_memory jra _main_loop -_cmd_erase: - ; 擦除命令 - call erase_memory - jra _main_loop - -_cmd_reset: - ; 复位命令 - 软件复位 - call software_reset - ; 注意: software_reset 不返回 - _cmd_go: ; 跳转执行命令 - call jump_to_address + ldw X, rx_buffer+2 + jp (X) ; 注意: jump_to_address 不返回 receive_frame: @@ -252,7 +234,7 @@ send_ack_state_response: ld A, tx_state ld (X), A - call send_response_pkg + callr send_response_pkg ret ; 发送应答数据帧 @@ -269,7 +251,7 @@ send_ack_data_response: ; already set data - call send_response_pkg + callr send_response_pkg ret read_memory: @@ -296,7 +278,7 @@ _read_loop: dec temp_var1 jrne _read_loop - call send_ack_data_response + callr send_ack_data_response ret ; temp_var1: 待写入长度 @@ -337,12 +319,12 @@ _mem_write: incw Y dec temp_var1 jrne _mem_write - call send_ack_state_response + callr send_ack_state_response ret _flash_write: ; unlock FLASH/DATA - call unlock_flash + callr unlock_flash ; Word Program mov FLASH_CR2, #0xC0 @@ -381,7 +363,7 @@ _write_end: mov FLASH_CR2, #0x00 mov FLASH_NCR2, #0xFF ; lock FLASH/DATA - call lock_flash + callr lock_flash call send_ack_state_response ret @@ -411,54 +393,4 @@ _do_lock_data: bres FLASH_IAPSR, #3 ret -; 两个字节长度 -erase_memory: - ; unlock option byte - mov FLASH_CR2, #0xC0 - mov FLASH_NCR2, #0x3F - - ld A, #0xAA ; lock chip -_write_rop: - ld OPT0_ROP, A -_erase_loop: - mov temp_var1, FLASH_IAPSR - btjt temp_var1, #0, _lock_opt - btjf temp_var1, #2, _erase_loop - - cp A, #0 - jreq _lock_opt - ld A, #0 ; unlock chip - jra _write_rop - -_lock_opt: - ; lock option byte - mov FLASH_CR2, #0x00 - mov FLASH_NCR2, #0xFF - ret - -software_reset: - ; STM8软件复位: 写0x80到WWDG_CR - mov WWDG_CR, #0x80 - ; 复位需要时间,这里无限循环 - jra software_reset - -jump_to_address: - mov tx_state, #SUCCESS_CODE - call send_ack_state_response - - ; 使用X作为延时计数器 - ldw X, #1000 -_delay_loop: - decw X - jrne _delay_loop - - ; 读取跳转地址 - ld A, rx_buffer+2 - ld XH, A - ld A, rx_buffer+3 - ld XL, A - - ; 跳转到指定地址 - jp (X) - _end: diff --git a/scripts/stm8_bootloader_test.py b/scripts/stm8_bootloader_test.py deleted file mode 100644 index 59c439a..0000000 --- a/scripts/stm8_bootloader_test.py +++ /dev/null @@ -1,523 +0,0 @@ -#!/usr/bin/env python3 -""" -STM8 RAM Bootloader测试脚本 -用于测试bootloader功能 - -工作流程: -1. 默认加载同级目录下的boot2.bin发送,可通过选项指定 -2. 执行后,等待用户按下开发板的复位键 -3. MCU复位后,会以波特率9600发送0x00 0x0D到python -4. 收到后开始发送boot2.bin,从最后一块开始向前发送,每发送128字节后,MCU会应答一个0x01 -5. 发送完成后进入交互shell,用户可以输入命令执行响应的操作(先不实现) - -用法: -python3 stm8_bootloader_test.py [-p PORT] [-b BAUDRATE] [--bin BIN_FILE] -""" - -import sys -import os -import time -import argparse -import serial -import struct -import colorama -from colorama import Fore, Style -from typing import Optional, List - -colorama.init(autoreset=True) - -class STM8BootloaderTester: - def __init__(self, port: str, baudrate: int = 9600, bin_file: str = None): - self.port = port - self.baudrate = baudrate - - # 如果未指定bin文件,使用脚本同级目录下的boot2.bin - if bin_file is None: - script_dir = os.path.dirname(os.path.abspath(__file__)) - self.bin_file = os.path.join(script_dir, "boot2.bin") - else: - self.bin_file = bin_file - - self.ser = None - self.bootloader_size = 0 - - def open_serial(self) -> bool: - """打开串口""" - try: - print(f"{Fore.CYAN}打开串口 {self.port}, 波特率 {self.baudrate}...") - self.ser = serial.Serial( - port=self.port, - baudrate=self.baudrate, - bytesize=serial.EIGHTBITS, - parity=serial.PARITY_NONE, - stopbits=serial.STOPBITS_ONE, - timeout=1.0, # 读取超时1秒 - write_timeout=1.0 # 写入超时1秒 - ) - - if self.ser.is_open: - print(f"{Fore.GREEN}串口打开成功!") - return True - else: - print(f"{Fore.RED}串口打开失败!") - return False - - except serial.SerialException as e: - print(f"{Fore.RED}串口错误: {e}") - return False - - def close_serial(self): - """关闭串口""" - if self.ser and self.ser.is_open: - self.ser.close() - print(f"{Fore.YELLOW}串口已关闭") - - def check_file_size(self, file_size: int, chunk_size: int = 128) -> bool: - """检查文件大小是否为chunk_size的整数倍""" - if file_size % chunk_size != 0: - print(f"{Fore.RED}错误: 文件大小 {file_size} 不是 {chunk_size} 的整数倍!") - print(f"{Fore.YELLOW}请确保bootloader大小为 {chunk_size} 字节的整数倍") - return False - return True - - def read_bin_file(self) -> Optional[bytes]: - """读取bin文件""" - try: - if not os.path.exists(self.bin_file): - print(f"{Fore.RED}错误: 文件 {self.bin_file} 不存在!") - return None - - with open(self.bin_file, 'rb') as f: - data = f.read() - - self.bootloader_size = len(data) - print(f"{Fore.GREEN}读取 {self.bootloader_size} 字节来自 {self.bin_file}") - - # 检查文件大小是否为128的整数倍 - if not self.check_file_size(self.bootloader_size): - return None - - # 显示文件信息 - if self.bootloader_size > 0: - print(f"{Fore.CYAN}文件首16字节: {data[:16].hex(' ')}") - if self.bootloader_size > 16: - print(f"{Fore.CYAN}文件尾16字节: {data[-16:].hex(' ')}") - - return data - - except Exception as e: - print(f"{Fore.RED}读取文件错误: {e}") - return None - - def wait_for_mcu_ready(self, timeout: int = 30) -> bool: - """等待MCU发送就绪信号 0x00 0x0D""" - print(f"\n{Fore.YELLOW}等待MCU就绪信号...") - print(f"{Fore.YELLOW}请按下开发板上的复位键!") - print(f"{Fore.YELLOW}等待超时: {timeout} 秒") - - start_time = time.time() - last_print_time = start_time - expected_bytes = b'\x00\x0D' - buffer = b'' - - try: - while time.time() - start_time < timeout: - current_time = time.time() - elapsed = int(current_time - start_time) - - # 每5秒打印一次状态 - if current_time - last_print_time >= 5: - print(f"{Fore.YELLOW}已等待 {elapsed} 秒...") - last_print_time = current_time - - # 检查串口是否有数据 - if self.ser.in_waiting > 0: - # 读取一个字节 - byte = self.ser.read(self.ser.in_waiting) - if byte: - buffer += byte - - # 检查是否匹配就绪信号 - if buffer[-2:] == expected_bytes: - print(f"{Fore.GREEN}收到MCU就绪信号: {buffer.hex(' ')}") - return True - - # 显示接收到的数据(调试用) - if buffer: - print(f"{Fore.CYAN}[调试] 接收缓冲区: {buffer.hex(' ')}") - # 保留缓冲区最后一个字节 - buffer = buffer[-1:] - - - time.sleep(0.01) - - except Exception as e: - print(f"{Fore.RED}等待MCU就绪时出错: {e}") - - print(f"{Fore.RED}超时! 未收到MCU就绪信号") - return False - - def reverse_bytes_within_chunks(self, data: bytes, chunk_size: int = 128) -> bytes: - """在每个128字节块内反转字节顺序""" - if len(data) % chunk_size != 0: - raise ValueError(f"数据长度({len(data)})必须是{chunk_size}的整数倍") - - result = bytearray() - num_chunks = len(data) // chunk_size - - for i in range(num_chunks): - start_idx = i * chunk_size - end_idx = start_idx + chunk_size - chunk = data[start_idx:end_idx] - # 反转块内字节顺序 - reversed_chunk = bytes(reversed(chunk)) - result.extend(reversed_chunk) - - return bytes(result) - - def send_bootloader_reverse(self, data: bytes, chunk_size: int = 128) -> bool: - """反向发送bootloader数据(从最后一块开始,每块内字节也反转)""" - if not data: - print(f"{Fore.RED}错误: 没有数据可发送") - return False - - # 首先在每个128字节块内反转字节顺序 - reversed_data = self.reverse_bytes_within_chunks(data, chunk_size) - - total_size = len(reversed_data) - num_chunks = total_size // chunk_size - - print(f"\n{Fore.CYAN}开始反向发送bootloader...") - print(f"{Fore.CYAN}总大小: {total_size} 字节") - print(f"{Fore.CYAN}分块大小: {chunk_size} 字节") - print(f"{Fore.CYAN}总块数: {num_chunks}") - print(f"{Fore.CYAN}发送顺序: 从最后一块到第一块,每块内字节顺序已反转") - - success_count = 0 - fail_count = 0 - - try: - # 从最后一块开始发送 - for i in range(num_chunks - 1, -1, -1): - start_idx = i * chunk_size - end_idx = start_idx + chunk_size - chunk = reversed_data[start_idx:end_idx] - - # 原始块索引(反转前) - original_chunk_index = i - original_start_addr = original_chunk_index * chunk_size - - print(f"\n{Fore.YELLOW}[块 {num_chunks-i}/{num_chunks}]") - print(f"{Fore.CYAN} 原始位置: 0x{original_start_addr:04X}-0x{original_start_addr+chunk_size-1:04X}") - print(f"{Fore.CYAN} 发送大小: {len(chunk)} 字节") - print(f"{Fore.CYAN} 数据(已反转): {chunk[:16].hex(' ')}" + - ("..." if len(chunk) > 16 else "")) - - # 发送数据块 - bytes_sent = self.ser.write(chunk) - - if bytes_sent != len(chunk): - print(f"{Fore.RED} 发送失败! 期望 {len(chunk)} 字节, 实际 {bytes_sent} 字节") - fail_count += 1 - continue - - print(f"{Fore.GREEN} 发送成功: {bytes_sent} 字节") - - # 等待MCU应答 - print(f"{Fore.YELLOW} 等待MCU应答...") - - try: - # 读取应答 - ack = self.ser.read(1) - if ack == b'\x00': - print(f"{Fore.GREEN} 收到确认: 0x00") - success_count += 1 - elif ack: - print(f"{Fore.RED} 收到错误应答: {ack.hex()}") - fail_count += 1 - else: - print(f"{Fore.RED} 应答超时!") - fail_count += 1 - - except Exception as e: - print(f"{Fore.RED} 读取应答时出错: {e}") - fail_count += 1 - - # 显示进度 - progress = (num_chunks - i) / num_chunks * 100 - print(f"{Fore.CYAN} 进度: {progress:.1f}% ({num_chunks-i}/{num_chunks})") - - except Exception as e: - print(f"{Fore.RED}发送过程中出错: {e}") - return False - - print(f"\n{Fore.CYAN}=== 发送完成 ===") - print(f"{Fore.GREEN}成功块数: {success_count}") - print(f"{Fore.RED}失败块数: {fail_count}") - - return fail_count == 0 - - def interactive_shell(self): - """交互式命令行""" - print(f"\n{Fore.CYAN}{'='*60}") - print(f"{Fore.CYAN}进入交互模式") - print(f"{Fore.CYAN}输入 'help' 查看可用命令") - print(f"{Fore.CYAN}输入 'exit' 退出") - print(f"{Fore.CYAN}{'='*60}") - - commands = { - 'help': self._cmd_help, - 'read': self._cmd_read, - 'write': self._cmd_write, - 'erase': self._cmd_erase, - 'reset': self._cmd_reset, - 'go': self._cmd_go, - 'echo': self._cmd_echo, - 'info': self._cmd_info, - } - - while True: - try: - # 获取用户输入 - cmd_input = input(f"\n{Fore.GREEN}boot> ").strip() - - if not cmd_input: - continue - - # 检查是否为退出命令 - if cmd_input.lower() in ['exit', 'quit', 'q']: - print(f"{Fore.YELLOW}退出交互模式") - break - - # 分割命令和参数 - parts = cmd_input.split() - cmd = parts[0].lower() - args = parts[1:] if len(parts) > 1 else [] - - # 执行命令 - if cmd in commands: - commands[cmd](args) - else: - print(f"{Fore.RED}未知命令: {cmd}") - print(f"{Fore.YELLOW}输入 'help' 查看可用命令") - - except KeyboardInterrupt: - print(f"\n{Fore.YELLOW}检测到Ctrl+C,退出交互模式") - break - except Exception as e: - print(f"{Fore.RED}命令执行错误: {e}") - - def _cmd_help(self, args): - """显示帮助""" - print(f"{Fore.CYAN}可用命令:") - print(f"{Fore.YELLOW} help 显示此帮助信息") - print(f"{Fore.YELLOW} read 读取内存") - print(f"{Fore.YELLOW} write 写入内存") - print(f"{Fore.YELLOW} erase 擦除Flash") - print(f"{Fore.YELLOW} reset 复位MCU") - print(f"{Fore.YELLOW} go 跳转到指定地址执行") - print(f"{Fore.YELLOW} echo 回显文本") - print(f"{Fore.YELLOW} info 显示信息") - print(f"{Fore.YELLOW} exit 退出交互模式") - - def _cmd_read(self, args): - """读取内存命令""" - if len(args) < 2: - print(f"{Fore.RED}用法: read <地址> <长度>") - print(f"{Fore.YELLOW}示例: read 0x8000 16") - return - - try: - addr = int(args[0], 0) - length = int(args[1], 0) - - print(f"{Fore.CYAN}读取内存:") - print(f"{Fore.CYAN} 地址: 0x{addr:04X}") - print(f"{Fore.CYAN} 长度: {length} 字节") - - # TODO: 实现读取命令 - print(f"{Fore.YELLOW}[待实现] 读取功能") - - except ValueError as e: - print(f"{Fore.RED}参数错误: {e}") - - def _cmd_write(self, args): - """写入内存命令""" - if len(args) < 2: - print(f"{Fore.RED}用法: write <地址> <数据>") - print(f"{Fore.YELLOW}示例: write 0x8000 0x01 0x02 0x03") - return - - try: - addr = int(args[0], 0) - data = [int(x, 0) for x in args[1:]] - - print(f"{Fore.CYAN}写入内存:") - print(f"{Fore.CYAN} 地址: 0x{addr:04X}") - print(f"{Fore.CYAN} 数据: {bytes(data).hex(' ')}") - print(f"{Fore.CYAN} 长度: {len(data)} 字节") - - # TODO: 实现写入命令 - print(f"{Fore.YELLOW}[待实现] 写入功能") - - except ValueError as e: - print(f"{Fore.RED}参数错误: {e}") - - def _cmd_erase(self, args): - """擦除Flash命令""" - print(f"{Fore.YELLOW}擦除Flash...") - # TODO: 实现擦除命令 - print(f"{Fore.YELLOW}[待实现] 擦除功能") - - def _cmd_reset(self, args): - """复位命令""" - print(f"{Fore.YELLOW}复位MCU...") - # TODO: 实现复位命令 - print(f"{Fore.YELLOW}[待实现] 复位功能") - - def _cmd_go(self, args): - """跳转执行命令""" - if len(args) < 1: - print(f"{Fore.RED}用法: go <地址>") - print(f"{Fore.YELLOW}示例: go 0x8000") - return - - try: - addr = int(args[0], 0) - print(f"{Fore.YELLOW}跳转到地址: 0x{addr:04X}") - # TODO: 实现跳转命令 - print(f"{Fore.YELLOW}[待实现] 跳转功能") - - except ValueError as e: - print(f"{Fore.RED}参数错误: {e}") - - def _cmd_echo(self, args): - """回显命令""" - if args: - text = ' '.join(args) - print(f"{Fore.CYAN}回显: {text}") - else: - print(f"{Fore.RED}用法: echo <文本>") - - def _cmd_info(self, args): - """显示信息命令""" - print(f"{Fore.CYAN}Bootloader测试工具信息:") - print(f"{Fore.CYAN} 串口: {self.port}") - print(f"{Fore.CYAN} 波特率: {self.baudrate}") - print(f"{Fore.CYAN} Bootloader文件: {self.bin_file}") - print(f"{Fore.CYAN} Bootloader大小: {self.bootloader_size} 字节") - - def run(self): - """运行测试""" - print(f"{Fore.CYAN}{'='*60}") - print(f"{Fore.CYAN}STM8 RAM Bootloader 测试工具") - print(f"{Fore.CYAN}{'='*60}") - - # 1. 打开串口 - if not self.open_serial(): - return False - - try: - # 2. 读取bin文件 - bin_data = self.read_bin_file() - if not bin_data: - return False - - # 3. 等待MCU就绪 - if not self.wait_for_mcu_ready(): - return False - - # 4. 发送bootloader(反向发送) - if not self.send_bootloader_reverse(bin_data): - print(f"{Fore.RED}Bootloader发送失败!") - return False - - # 5. 进入交互模式 - self.interactive_shell() - - return True - - except KeyboardInterrupt: - print(f"\n{Fore.YELLOW}用户中断!") - return False - - except Exception as e: - print(f"{Fore.RED}运行时错误: {e}") - import traceback - traceback.print_exc() - return False - - finally: - self.close_serial() - -def list_serial_ports(): - """列出可用串口""" - import serial.tools.list_ports - - ports = serial.tools.list_ports.comports() - - if not ports: - print(f"{Fore.YELLOW}未找到可用串口!") - return [] - - print(f"{Fore.CYAN}可用串口:") - for i, port in enumerate(ports): - print(f"{Fore.GREEN} [{i}] {port.device}: {port.description}") - - return ports - -def main(): - parser = argparse.ArgumentParser(description="STM8 RAM Bootloader测试工具") - parser.add_argument("-p", "--port", help="串口号 (如 COM3, /dev/ttyUSB0)") - parser.add_argument("-b", "--baudrate", type=int, default=9600, - help="串口波特率 (默认: 9600)") - parser.add_argument("--bin", default=None, - help="Bootloader bin文件路径 (默认: 脚本目录下的boot2.bin)") - parser.add_argument("--list", action="store_true", - help="列出可用串口") - - args = parser.parse_args() - - # 如果指定了--list,列出串口后退出 - if args.list: - list_serial_ports() - return - - # 如果没有指定串口,列出并让用户选择 - if not args.port: - ports = list_serial_ports() - if not ports: - print(f"{Fore.RED}请使用 -p 参数指定串口!") - return - - try: - choice = input(f"\n{Fore.CYAN}请选择串口号 [0-{len(ports)-1}]: ") - idx = int(choice) - if 0 <= idx < len(ports): - args.port = ports[idx].device - else: - print(f"{Fore.RED}无效的选择!") - return - except (ValueError, IndexError): - print(f"{Fore.RED}无效的输入!") - return - - # 创建测试器并运行 - tester = STM8BootloaderTester( - port=args.port, - baudrate=args.baudrate, - bin_file=args.bin - ) - - success = tester.run() - - if success: - print(f"\n{Fore.GREEN}测试完成!") - else: - print(f"\n{Fore.RED}测试失败!") - - # 等待用户按键退出 - input(f"\n{Fore.YELLOW}按Enter键退出...") - -if __name__ == "__main__": - main() diff --git a/src/main.c b/src/main.c index 941dddc..e1c3c70 100644 --- a/src/main.c +++ b/src/main.c @@ -9,13 +9,14 @@ void main(void) { PB_DDR |= (1 << LED_PIN); PB_CR1 |= (1 << LED_PIN); + /* 9600bps, 8N1, TEN, REN */ UART1_BRR1 = 0x0D; UART1_BRR2 = 0x00; - UART1_CR2 = 0x0D; + UART1_CR2 = 0x0C; while(1) { PB_ODR ^= (1 << LED_PIN); - UART1_DR = *ptr++; + UART1_DR = PB_ODR; delay_ms(500); } }