Diagnose BIN3 LoadPreset failures and add flash bin3 tooling.
Log Flash magic on load failure, expose RTT flash bin3, and document the 0903 pack offset for the universal bank. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
015417dc3d
commit
92e5e32de3
|
|
@ -280,6 +280,12 @@ uint8_t app_log_try_command(const char *cmd)
|
|||
"FLASH_HAITIAN_GO", "FLASH_HAITIAN_OK\n");
|
||||
return 1U;
|
||||
}
|
||||
if (strncmp(cmd, "flash bin3 ", 11) == 0) {
|
||||
uint32_t size = (uint32_t)strtoul(cmd + 11, NULL, 10);
|
||||
app_log_flash_start_at(EXTFLASH_BIN3_UNIVERSAL_ADDR, size,
|
||||
"FLASH_BIN3_GO", "FLASH_BIN3_OK\n");
|
||||
return 1U;
|
||||
}
|
||||
if (strncmp(cmd, "tone status", 11) == 0) {
|
||||
uint8_t hdr[16];
|
||||
uint8_t name[40];
|
||||
|
|
@ -320,6 +326,16 @@ uint8_t app_log_try_command(const char *cmd)
|
|||
(unsigned long)(cur_hdr[12] | (cur_hdr[13] << 8) |
|
||||
(cur_hdr[14] << 16) | (cur_hdr[15] << 24)));
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
|
||||
{
|
||||
uint8_t b3[16];
|
||||
W25Q128_Read(b3, EXTFLASH_BIN3_UNIVERSAL_ADDR, 16);
|
||||
snprintf(line, sizeof(line),
|
||||
"TONE @BIN3 magic=%02X%02X%02X%02X cnt=%lu\n",
|
||||
b3[0], b3[1], b3[2], b3[3],
|
||||
(unsigned long)(b3[12] | (b3[13] << 8) |
|
||||
(b3[14] << 16) | (b3[15] << 24)));
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
|
||||
}
|
||||
snprintf(line, sizeof(line),
|
||||
"TONE @BIN2 magic=%02X%02X%02X%02X max=%lu cnt=%lu name=%.16s\n",
|
||||
hdr[0], hdr[1], hdr[2], hdr[3],
|
||||
|
|
|
|||
|
|
@ -148,8 +148,12 @@ void App_Auto_Init(void)
|
|||
int ret = AutoBandTop1_LoadPresetItemFromFlash(0);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_E("AUTO", "LoadPreset fail ret=%d addr=0x%08X map=%s",
|
||||
ret, (unsigned)ADDRESS, ToneFlashMapBank((uint32_t)ADDRESS));
|
||||
uint8_t hdr[16];
|
||||
W25Q128_Read(hdr, (uint32_t)ADDRESS, 16);
|
||||
LOG_E("AUTO", "LoadPreset fail ret=%d addr=0x%08X map=%s magic=%02X%02X%02X%02X cnt=%lu",
|
||||
ret, (unsigned)ADDRESS, ToneFlashMapBank((uint32_t)ADDRESS),
|
||||
hdr[0], hdr[1], hdr[2], hdr[3],
|
||||
(unsigned long)(hdr[12] | (hdr[13] << 8) | (hdr[14] << 16) | (hdr[15] << 24)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -168,10 +168,23 @@ void UI_ReloadTonePreset(void)
|
|||
if (mGuiData[GUI_TAB_INDEX].Current == 0)
|
||||
{
|
||||
int ret = AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[ALL_MODE_PARAM].Current);
|
||||
if (ret != 0)
|
||||
{
|
||||
uint8_t hdr[16];
|
||||
W25Q128_Read(hdr, (uint32_t)ADDRESS, 16);
|
||||
LOG_E("tone", "load universal idx=%d ret=%d magic=%02X%02X%02X%02X cnt=%lu addr=0x%08X",
|
||||
ParamGuiData[ALL_MODE_PARAM].Current, ret,
|
||||
hdr[0], hdr[1], hdr[2], hdr[3],
|
||||
(unsigned long)(hdr[12] | (hdr[13] << 8) | (hdr[14] << 16) | (hdr[15] << 24)),
|
||||
(unsigned)ADDRESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("tone", "load universal idx=%d ret=%d name=%s addr=0x%08X map=BIN3@0x%08X",
|
||||
ParamGuiData[ALL_MODE_PARAM].Current, ret,
|
||||
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
|
||||
(unsigned)ADDRESS, (unsigned)EXTFLASH_BIN3_UNIVERSAL_ADDR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* 普通/专业:本地曲目或节奏类型 */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Flash Doc/音色文件/0903/3.bin to W25Q128 @ EXTFLASH_BIN3_UNIVERSAL_ADDR via RTT.
|
||||
|
||||
Requires firmware that accepts RTT command: flash bin3 <size>
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import time
|
||||
|
||||
DEFAULT_DEVICES = ("Cortex-M4", "AT32F403AC", "AT32F403A")
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
REPO = os.path.dirname(os.path.dirname(ROOT))
|
||||
DEFAULT_BIN = os.path.join(REPO, "Doc", "音色文件", "0903", "3.bin")
|
||||
EXTFLASH_BIN3_UNIVERSAL_ADDR = 0x000A71AC
|
||||
DAB_MAGIC = bytes((0xAB, 0x44, 0x41, 0x42))
|
||||
|
||||
|
||||
def connect_jlink(device: str):
|
||||
import pylink
|
||||
|
||||
jlink = pylink.JLink()
|
||||
jlink.open()
|
||||
try:
|
||||
jlink.exec_command("HideDeviceSelection = 1")
|
||||
except Exception:
|
||||
pass
|
||||
jlink.set_tif(pylink.enums.JLinkInterfaces.SWD)
|
||||
|
||||
last_error = None
|
||||
for candidate in (device, *DEFAULT_DEVICES):
|
||||
try:
|
||||
try:
|
||||
jlink.exec_command(f"Device = {candidate}")
|
||||
except Exception:
|
||||
pass
|
||||
jlink.connect(candidate)
|
||||
print(f"Connected as {candidate}")
|
||||
return jlink
|
||||
except Exception as exc:
|
||||
last_error = exc
|
||||
jlink.close()
|
||||
raise SystemExit(f"Failed to connect J-Link: {last_error}")
|
||||
|
||||
|
||||
def find_rtt_control_block(jlink, ram_base: int = 0x20000000, ram_size: int = 0x18000):
|
||||
needle = b"SEGGER RTT"
|
||||
chunk = 0x1000
|
||||
was_halted = jlink.halted()
|
||||
if not was_halted:
|
||||
jlink.halt()
|
||||
try:
|
||||
for off in range(0, ram_size, chunk):
|
||||
data = bytes(jlink.memory_read8(ram_base + off, min(chunk, ram_size - off)))
|
||||
idx = data.find(needle)
|
||||
if idx >= 0:
|
||||
return ram_base + off + idx
|
||||
finally:
|
||||
if not was_halted:
|
||||
if hasattr(jlink, "restart"):
|
||||
jlink.restart()
|
||||
else:
|
||||
jlink.go()
|
||||
time.sleep(0.1)
|
||||
return None
|
||||
|
||||
|
||||
def rtt_read_text(jlink, timeout_s: float = 0.2) -> str:
|
||||
deadline = time.time() + timeout_s
|
||||
chunks: list[bytes] = []
|
||||
while time.time() < deadline:
|
||||
try:
|
||||
data = bytes(jlink.rtt_read(0, 512) or [])
|
||||
except Exception:
|
||||
data = b""
|
||||
if data:
|
||||
chunks.append(data)
|
||||
deadline = time.time() + timeout_s
|
||||
else:
|
||||
time.sleep(0.02)
|
||||
return b"".join(chunks).decode("ascii", errors="replace")
|
||||
|
||||
|
||||
def wait_for(jlink, marker: str, timeout_s: float = 30.0) -> str:
|
||||
deadline = time.time() + timeout_s
|
||||
buf = ""
|
||||
while time.time() < deadline:
|
||||
buf += rtt_read_text(jlink, 0.15)
|
||||
if marker in buf:
|
||||
return buf
|
||||
raise SystemExit(f"Timeout waiting for {marker!r}\n--- RTT ---\n{buf[-800:]}")
|
||||
|
||||
|
||||
def send_bytes(jlink, payload: bytes) -> None:
|
||||
off = 0
|
||||
while off < len(payload):
|
||||
try:
|
||||
n = jlink.rtt_write(0, list(payload[off : off + 64]))
|
||||
except Exception:
|
||||
time.sleep(0.05)
|
||||
continue
|
||||
if n is None or n <= 0:
|
||||
time.sleep(0.02)
|
||||
continue
|
||||
off += n
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--bin", default=DEFAULT_BIN)
|
||||
parser.add_argument("--device", default="Cortex-M4")
|
||||
parser.add_argument("--no-reset", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.isfile(args.bin):
|
||||
raise SystemExit(f"missing bin: {args.bin}")
|
||||
|
||||
data = open(args.bin, "rb").read()
|
||||
size = len(data)
|
||||
if size < 16 or data[:4] != DAB_MAGIC:
|
||||
raise SystemExit(f"not a DAB bank (magic={data[:4].hex()})")
|
||||
|
||||
print(f"bin={args.bin} size={size} addr=0x{EXTFLASH_BIN3_UNIVERSAL_ADDR:08X}")
|
||||
|
||||
jlink = connect_jlink(args.device)
|
||||
try:
|
||||
cb = find_rtt_control_block(jlink)
|
||||
if cb is None:
|
||||
raise SystemExit("RTT control block not found")
|
||||
print(f"RTT CB @ 0x{cb:08X}")
|
||||
jlink.rtt_start(cb)
|
||||
time.sleep(0.3)
|
||||
_ = rtt_read_text(jlink, 0.3)
|
||||
|
||||
if not args.no_reset:
|
||||
print("hardware reset...")
|
||||
jlink.reset(halt=False)
|
||||
time.sleep(3.5)
|
||||
try:
|
||||
jlink.rtt_stop()
|
||||
except Exception:
|
||||
pass
|
||||
cb = find_rtt_control_block(jlink)
|
||||
if cb is None:
|
||||
raise SystemExit("RTT CB missing after reset")
|
||||
print(f"RTT CB @ 0x{cb:08X}")
|
||||
jlink.rtt_start(cb)
|
||||
time.sleep(0.5)
|
||||
_ = rtt_read_text(jlink, 0.5)
|
||||
|
||||
cmd = f"flash bin3 {size}\n".encode("ascii")
|
||||
send_bytes(jlink, cmd)
|
||||
print("sent flash command, waiting GO...")
|
||||
try:
|
||||
log = wait_for(jlink, "FLASH_BIN3_GO", 20.0)
|
||||
except SystemExit:
|
||||
raise SystemExit(
|
||||
"Firmware did not accept 'flash bin3'. Rebuild App with app_log.c "
|
||||
"support, or temporarily flash via: concatenate 2.bin+3.bin and "
|
||||
"'flash haitian <combined_size>'."
|
||||
)
|
||||
print(log.strip().splitlines()[-1])
|
||||
time.sleep(0.2)
|
||||
|
||||
chunk = 256
|
||||
sent = 0
|
||||
t0 = time.time()
|
||||
while sent < size:
|
||||
end = min(sent + chunk, size)
|
||||
send_bytes(jlink, data[sent:end])
|
||||
sent = end
|
||||
log = wait_for(jlink, "FLASH_ACK", 60.0)
|
||||
if "FLASH_BIN3_OK" in log:
|
||||
print(log.strip().splitlines()[-1])
|
||||
print("Done. Universal bank (3.bin) updated.")
|
||||
return
|
||||
if sent % (4 * 1024) == 0 or sent == size:
|
||||
elapsed = time.time() - t0
|
||||
print(f" {sent}/{size} ({100.0 * sent / size:.1f}%) {elapsed:.1f}s")
|
||||
|
||||
log = wait_for(jlink, "FLASH_BIN3_OK", 60.0)
|
||||
print(log.strip().splitlines()[-1])
|
||||
print("Done. Universal bank (3.bin) updated.")
|
||||
finally:
|
||||
try:
|
||||
jlink.rtt_stop()
|
||||
except Exception:
|
||||
pass
|
||||
jlink.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -7,7 +7,7 @@ Layout (absolute W25Q128 offsets):
|
|||
0x0000CB70 Charg.bin (legacy pad; charge UI uses UI0902_CHARGE_SCREEN full-screen)
|
||||
0x0001B8F0 1.bin 普通/专业 31 rhythms
|
||||
0x0009D07D 2.bin 海阔天空
|
||||
0x000A8607 3.bin 万能模式
|
||||
0x000A71AC 3.bin 万能模式(紧随 2.bin;具体偏移以打包结果为准)
|
||||
|
||||
Outputs:
|
||||
tools/out/extflash_tone_0903.bin
|
||||
|
|
|
|||
Loading…
Reference in New Issue