Files
gd32e230f8_firmware_merge_tool/FlashTool/src/fw_image.py
T

99 lines
3.4 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
固件镜像处理: 补齐(pad)与拼接(merge) — 纯标准库, GUI 与命令行共用
================================================================
pad - BIN 尾部补 pad_byte 到指定对齐(bootloader 的 Y-Modem 按 1K 整包接收)
merge - Bootloader + APP + 有效标志 拼成一整片 Flash 镜像(初次烧录用)
芯片参数表(CHIP_PROFILES)同时供烧录页(target cfg/Flash 大小)与补齐/拼接
的容量校验使用。
"""
import struct
FLASH_BASE_DEFAULT = 0x08000000
APP_ADDR_DEFAULT = 0x08002000
FLAG_ADDR_DEFAULT = 0x0800FFFC
FLAG_VALUE_DEFAULT = 0xEEEEEEEE
CHIP_PROFILES = {
"GD32E230F4": {"target": "target/gd32e23x.cfg", "flash": 16 * 1024, "ram": 4 * 1024},
"GD32E230F6": {"target": "target/gd32e23x.cfg", "flash": 32 * 1024, "ram": 4 * 1024},
"GD32E230F8": {"target": "target/gd32e23x.cfg", "flash": 64 * 1024, "ram": 8 * 1024},
"GD32E230C8": {"target": "target/gd32e23x.cfg", "flash": 64 * 1024, "ram": 8 * 1024},
}
def parse_int(text):
"""解析 '0x1C' / '4096' / '1k' / '2m' 形式的数值, 非法返回 None"""
s = str(text).strip().lower()
if not s:
return None
mult = 1
if s.endswith("k"):
mult = 1024
s = s[:-1]
elif s.endswith("m"):
mult = 1024 * 1024
s = s[:-1]
try:
if s.startswith("0x"):
return int(s, 16) * mult
return int(s, 10) * mult
except ValueError:
return None
def pad_bin(src_path, dst_path, align, pad_byte=0xFF):
"""把 BIN 补齐到 align 的整数倍, 返回补齐后大小"""
with open(src_path, "rb") as f:
data = f.read()
if align <= 0:
raise ValueError("align must be positive")
remainder = len(data) % align
if remainder:
data += bytes([pad_byte & 0xFF]) * (align - remainder)
with open(dst_path, "wb") as f:
f.write(data)
return len(data)
def merge_firmware(bootloader_path, app_path, output_path, app_addr, flag_addr,
flash_size, flag_value=FLAG_VALUE_DEFAULT):
"""Bootloader + APP + 有效标志 → 整片 Flash 镜像, 返回尺寸信息 dict"""
if app_addr < FLASH_BASE_DEFAULT or app_addr >= FLASH_BASE_DEFAULT + flash_size:
raise ValueError("APP address is outside the flash range")
if flag_addr < FLASH_BASE_DEFAULT or flag_addr + 4 > FLASH_BASE_DEFAULT + flash_size:
raise ValueError("flag address is outside the flash range")
with open(bootloader_path, "rb") as f:
bootloader = f.read()
with open(app_path, "rb") as f:
app = f.read()
app_offset = app_addr - FLASH_BASE_DEFAULT
flag_offset = flag_addr - FLASH_BASE_DEFAULT
if len(bootloader) > app_offset:
raise ValueError("bootloader (%d bytes) exceeds APP offset (%d bytes)"
% (len(bootloader), app_offset))
if app_offset + len(app) > flag_offset:
raise ValueError("APP end address exceeds the flag address")
image = bytearray(b"\xFF" * flash_size)
image[0:len(bootloader)] = bootloader
image[app_offset:app_offset + len(app)] = app
struct.pack_into("<I", image, flag_offset, flag_value & 0xFFFFFFFF)
with open(output_path, "wb") as f:
f.write(image)
return {
"bootloader_size": len(bootloader),
"app_size": len(app),
"output_size": len(image),
"app_addr": app_addr,
"flag_addr": flag_addr,
}