Fix mode-row asset pairing and add RTT external UI flash path.
- Map 0902 rows as 16/19 universal, 17/20 normal, 18/21 expert - Add flash ui0902 RTT writer; avoid LCD dump stealing down bytes - Restore UI_ReturnToModeSelect; shrink flash-trans RAM use - Disable mode-select debug touch crosses Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
f8675e3529
commit
e62c2270af
|
|
@ -14,11 +14,95 @@ static char s_debug_level = 'D';
|
|||
static char s_cmd_buf[48];
|
||||
static uint8_t s_cmd_len;
|
||||
|
||||
/* RTT 二进制烧录:将 ui0902_res.bin 写到 W25Q128 @ UI0902_RES_BASE */
|
||||
static uint8_t s_flash_mode;
|
||||
static uint32_t s_flash_addr;
|
||||
static uint32_t s_flash_remain;
|
||||
static uint32_t s_flash_last_sector;
|
||||
static uint16_t s_flash_page_len;
|
||||
static uint8_t s_flash_page[256];
|
||||
|
||||
uint8_t app_log_flash_busy(void)
|
||||
{
|
||||
return s_flash_mode;
|
||||
}
|
||||
|
||||
static uint32_t app_log_ms(void)
|
||||
{
|
||||
return (uint32_t)(rt_tick_get() * 1000U / RT_TICK_PER_SECOND);
|
||||
}
|
||||
|
||||
static void app_log_flash_flush_page(void)
|
||||
{
|
||||
uint32_t sector;
|
||||
char ack[40];
|
||||
|
||||
if (s_flash_page_len == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
sector = s_flash_addr & ~0xFFFU;
|
||||
if (sector != s_flash_last_sector) {
|
||||
W25Q128_Erase_Sector(sector);
|
||||
s_flash_last_sector = sector;
|
||||
}
|
||||
W25Q128_Write(s_flash_page, s_flash_addr, s_flash_page_len);
|
||||
s_flash_addr += s_flash_page_len;
|
||||
s_flash_remain -= s_flash_page_len;
|
||||
s_flash_page_len = 0U;
|
||||
|
||||
/* 扇区边界或结束时 ACK,主机据此节流 */
|
||||
if ((s_flash_addr & 0xFFFU) == 0U || s_flash_remain == 0U) {
|
||||
snprintf(ack, sizeof(ack), "FLASH_ACK %lu\n", (unsigned long)s_flash_addr);
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, ack);
|
||||
}
|
||||
}
|
||||
|
||||
static void app_log_flash_feed(const uint8_t *data, unsigned len)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len && s_flash_remain > 0U; i++) {
|
||||
if (s_flash_page_len == 0U && s_flash_addr == UI0902_RES_BASE && i == 0U) {
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_RX\n");
|
||||
}
|
||||
s_flash_page[s_flash_page_len++] = data[i];
|
||||
if (s_flash_page_len >= sizeof(s_flash_page) ||
|
||||
s_flash_page_len >= s_flash_remain) {
|
||||
app_log_flash_flush_page();
|
||||
}
|
||||
}
|
||||
|
||||
if (s_flash_remain == 0U && s_flash_mode) {
|
||||
s_flash_mode = 0U;
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_UI0902_OK\n");
|
||||
UI_DrawModeSelectScreen();
|
||||
}
|
||||
}
|
||||
|
||||
static void app_log_flash_start(uint32_t size)
|
||||
{
|
||||
char msg[64];
|
||||
|
||||
if (size == 0U || size > (2U * 1024U * 1024U)) {
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_UI0902_ERR size\n");
|
||||
return;
|
||||
}
|
||||
|
||||
s_flash_mode = 1U;
|
||||
s_flash_addr = UI0902_RES_BASE;
|
||||
s_flash_remain = size;
|
||||
s_flash_last_sector = 0xFFFFFFFFUL;
|
||||
s_flash_page_len = 0U;
|
||||
s_cmd_len = 0U;
|
||||
s_cmd_buf[0] = '\0';
|
||||
|
||||
snprintf(msg, sizeof(msg),
|
||||
"FLASH_UI0902_GO base=0x%08lX size=%lu\n",
|
||||
(unsigned long)UI0902_RES_BASE, (unsigned long)size);
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, msg);
|
||||
}
|
||||
|
||||
static void app_log_slot_store(const char *line)
|
||||
{
|
||||
uint16_t idx = s_head;
|
||||
|
|
@ -177,6 +261,11 @@ uint8_t app_log_try_command(const char *cmd)
|
|||
app_log_sys_reset();
|
||||
return 1U;
|
||||
}
|
||||
if (strncmp(cmd, "flash ui0902 ", 13) == 0) {
|
||||
uint32_t size = (uint32_t)strtoul(cmd + 13, NULL, 10);
|
||||
app_log_flash_start(size);
|
||||
return 1U;
|
||||
}
|
||||
return 0U;
|
||||
}
|
||||
|
||||
|
|
@ -207,7 +296,7 @@ static void app_log_feed_char(char c)
|
|||
|
||||
void app_log_poll(void)
|
||||
{
|
||||
char rx[16];
|
||||
uint8_t rx[64];
|
||||
unsigned read_len;
|
||||
unsigned i;
|
||||
|
||||
|
|
@ -216,8 +305,13 @@ void app_log_poll(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (s_flash_mode) {
|
||||
app_log_flash_feed(rx, read_len);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < read_len; i++) {
|
||||
app_log_feed_char(rx[i]);
|
||||
app_log_feed_char((char)rx[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -234,5 +328,6 @@ void app_log_write(char level, const char *cat, const char *fmt, ...) { (void)le
|
|||
void app_log_poll(void) {}
|
||||
uint8_t app_log_try_command(const char *cmd) { (void)cmd; return 0U; }
|
||||
void app_log_set_ui_page(const char *name) { (void)name; }
|
||||
uint8_t app_log_flash_busy(void) { return 0U; }
|
||||
|
||||
#endif /* APP_LOG_ENABLE */
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ void app_log_write(char level, const char *cat, const char *fmt, ...);
|
|||
void app_log_poll(void);
|
||||
uint8_t app_log_try_command(const char *cmd);
|
||||
void app_log_set_ui_page(const char *name);
|
||||
uint8_t app_log_flash_busy(void);
|
||||
|
||||
#if APP_LOG_ENABLE
|
||||
|
||||
|
|
|
|||
13
UI/UI_Idle.c
13
UI/UI_Idle.c
|
|
@ -71,6 +71,16 @@ static void UI_ModeSelect_DrawButtons(void)
|
|||
UI_ModeSelect_DrawButtonAt(2);
|
||||
}
|
||||
|
||||
void UI_ReturnToModeSelect(void)
|
||||
{
|
||||
StartFlag = 0;
|
||||
InModeFlag = false;
|
||||
AutoBandTop1_Stop();
|
||||
s_mode_select_focus = 0;
|
||||
CallUI_Idle();
|
||||
UI_DrawModeSelectScreen();
|
||||
}
|
||||
|
||||
void UI_DrawModeSelectScreen(void)
|
||||
{
|
||||
UI_ClearFocus();
|
||||
|
|
@ -230,8 +240,6 @@ void IdleProcess(DisplayTaskMessage_Type msg)
|
|||
LOG_I("UI", "mode_select hit area=%u row=%u focus=%u x=%u y=%u",
|
||||
(unsigned)k, (unsigned)row, (unsigned)s_mode_select_focus,
|
||||
(unsigned)msg.HiByte, (unsigned)msg.LoByte);
|
||||
/* 调试十字:确认触点是否落在按钮上 */
|
||||
TP_Drow_Touch_Point(msg.HiByte, msg.LoByte, RED);
|
||||
/* 已聚焦 → 进入;未聚焦 → 切蓝焦点,再点一次进入 */
|
||||
if (row == s_mode_select_focus) {
|
||||
if (now - s_last_enter_ms < 300U)
|
||||
|
|
@ -248,7 +256,6 @@ void IdleProcess(DisplayTaskMessage_Type msg)
|
|||
if (!hit) {
|
||||
LOG_I("UI", "mode_select miss x=%u y=%u",
|
||||
(unsigned)msg.HiByte, (unsigned)msg.LoByte);
|
||||
TP_Drow_Touch_Point(msg.HiByte, msg.LoByte, YELLOW);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -236,24 +236,26 @@ void LCD_WR_PIC_ClipX(uint16_t x, uint16_t y, uint16_t full_w, uint16_t h,
|
|||
}
|
||||
}
|
||||
|
||||
/* 从W25Q128读小图到RAM后透明显示(跳过近黑像素),仅用于 <=4KB 小图 */
|
||||
#define PIC_TRANS_BUF_SIZE 4096
|
||||
/* 从 W25Q128 按行读取并透明显示(跳过近黑像素),复用 pic_batch_buf,无大块静态 RAM */
|
||||
void LCD_WR_PIC_FROM_FLASH_Trans(uint16_t x, uint16_t y, uint16_t length, uint16_t width, uint32_t flash_addr)
|
||||
{
|
||||
static uint8_t s_trans_buf[PIC_TRANS_BUF_SIZE];
|
||||
uint32_t total_bytes = (uint32_t)length * width * 2;
|
||||
uint32_t i;
|
||||
if (total_bytes == 0 || total_bytes > PIC_TRANS_BUF_SIZE) return;
|
||||
W25Q128_Read(s_trans_buf, flash_addr, (uint16_t)total_bytes);
|
||||
for (i = 0; i < total_bytes / 2; i++)
|
||||
uint16_t row, col;
|
||||
uint32_t row_bytes = (uint32_t)length * 2U;
|
||||
if (length == 0 || width == 0 || row_bytes > PIC_BATCH_SIZE) return;
|
||||
|
||||
for (row = 0; row < width; row++)
|
||||
{
|
||||
uint16_t c = (uint16_t)((s_trans_buf[i * 2] << 8) | s_trans_buf[i * 2 + 1]);
|
||||
uint8_t r5 = (uint8_t)((c >> 11) & 0x1F);
|
||||
uint8_t g6 = (uint8_t)((c >> 5) & 0x3F);
|
||||
uint8_t b5 = (uint8_t)(c & 0x1F);
|
||||
if (r5 <= 1 && g6 <= 2 && b5 <= 2)
|
||||
continue;
|
||||
LCD_DrawPoint((uint16_t)(x + (i % length)), (uint16_t)(y + (i / length)), c);
|
||||
W25Q128_Read(pic_batch_buf, flash_addr + row * row_bytes, (uint16_t)row_bytes);
|
||||
for (col = 0; col < length; col++)
|
||||
{
|
||||
uint16_t c = (uint16_t)((pic_batch_buf[col * 2U] << 8) | pic_batch_buf[col * 2U + 1U]);
|
||||
uint8_t r5 = (uint8_t)((c >> 11) & 0x1F);
|
||||
uint8_t g6 = (uint8_t)((c >> 5) & 0x3F);
|
||||
uint8_t b5 = (uint8_t)(c & 0x1F);
|
||||
if (r5 <= 1 && g6 <= 2 && b5 <= 2)
|
||||
continue;
|
||||
LCD_DrawPoint((uint16_t)(x + col), (uint16_t)(y + row), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,6 +190,11 @@ static uint8_t LCD_Dump_CommandPending(void)
|
|||
unsigned read_len;
|
||||
unsigned i;
|
||||
|
||||
/* 烧录外部 UI 资源时占用 RTT0 down,禁止此处吞字节 */
|
||||
if (app_log_flash_busy()) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
read_len = SEGGER_RTT_Read(LCD_DUMP_RTT_DOWN_CH, rx, sizeof(rx));
|
||||
if (read_len == 0U) {
|
||||
return 0U;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFED
|
|||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy with packing = none { readwrite };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
|
||||
|
|
|
|||
|
|
@ -0,0 +1,183 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Flash tools/out/ui0902_res.bin to W25Q128 @ 0x00100000 via RTT."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
DEFAULT_DEVICES = ("Cortex-M4", "AT32F403AC", "AT32F403A")
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
DEFAULT_BIN = os.path.join(ROOT, "tools", "out", "ui0902_res.bin")
|
||||
|
||||
|
||||
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):
|
||||
n = jlink.rtt_write(0, list(payload[off : off + 128]))
|
||||
if n <= 0:
|
||||
time.sleep(0.01)
|
||||
continue
|
||||
off += n
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--bin", default=DEFAULT_BIN)
|
||||
parser.add_argument("--device", default="Cortex-M4")
|
||||
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)
|
||||
print(f"bin={args.bin} size={size}")
|
||||
|
||||
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)
|
||||
|
||||
# Hardware reset clears any stuck flash_mode from a previous attempt
|
||||
print("hardware reset...")
|
||||
jlink.reset(halt=False)
|
||||
time.sleep(3.5)
|
||||
# RTT CB may move after reboot — re-find
|
||||
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 ui0902 {size}\n".encode("ascii")
|
||||
send_bytes(jlink, cmd)
|
||||
print("sent flash command, waiting GO...")
|
||||
log = wait_for(jlink, "FLASH_UI0902_GO", 15.0)
|
||||
print(log.strip().splitlines()[-1])
|
||||
time.sleep(0.2)
|
||||
|
||||
# wait for first byte confirmation after starting transfer
|
||||
chunk = 256
|
||||
sent = 0
|
||||
t0 = time.time()
|
||||
# prime first page then expect FLASH_RX
|
||||
send_bytes(jlink, data[0:256])
|
||||
sent = 256
|
||||
wait_for(jlink, "FLASH_RX", 15.0)
|
||||
print("device receiving...")
|
||||
while sent < size:
|
||||
end = min(sent + chunk, size)
|
||||
send_bytes(jlink, data[sent:end])
|
||||
sent = end
|
||||
if sent % 4096 == 0 or sent == size:
|
||||
log = wait_for(jlink, "FLASH_ACK", 30.0)
|
||||
if "FLASH_UI0902_OK" in log:
|
||||
print(log.strip().splitlines()[-1])
|
||||
print("Done. Mode-select should redraw with new assets.")
|
||||
return
|
||||
if sent % (64 * 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_UI0902_OK", 30.0)
|
||||
print(log.strip().splitlines()[-1])
|
||||
print("Done. Mode-select should redraw with new assets.")
|
||||
finally:
|
||||
try:
|
||||
jlink.rtt_stop()
|
||||
except Exception:
|
||||
pass
|
||||
jlink.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -103,11 +103,12 @@ INTERNAL = [
|
|||
|
||||
# ---------------- external flash (big images / text strips) ----------------
|
||||
EXTERNAL = [
|
||||
# Art numbering: 16/19=universal, 17/20=normal, 18/21=expert (not consecutive pairs)
|
||||
("ROW_UNIVERSAL_NOT", "04_模式图标/完整版/模式界面栏背景-16.png"),
|
||||
("ROW_UNIVERSAL_SEL", "04_模式图标/完整版/模式界面栏背景-17.png"),
|
||||
("ROW_NORMAL_NOT", "04_模式图标/完整版/模式界面栏背景-18.png"),
|
||||
("ROW_NORMAL_SEL", "04_模式图标/完整版/模式界面栏背景-19.png"),
|
||||
("ROW_EXPERT_NOT", "04_模式图标/完整版/模式界面栏背景-20.png"),
|
||||
("ROW_UNIVERSAL_SEL", "04_模式图标/完整版/模式界面栏背景-19.png"),
|
||||
("ROW_NORMAL_NOT", "04_模式图标/完整版/模式界面栏背景-17.png"),
|
||||
("ROW_NORMAL_SEL", "04_模式图标/完整版/模式界面栏背景-20.png"),
|
||||
("ROW_EXPERT_NOT", "04_模式图标/完整版/模式界面栏背景-18.png"),
|
||||
("ROW_EXPERT_SEL", "04_模式图标/完整版/模式界面栏背景-21.png"),
|
||||
("ICON_UNIVERSAL_SEL", "04_模式图标/万能模式图标-1.png"),
|
||||
("ICON_UNIVERSAL_NOT", "04_模式图标/万能模式图标-2.png"),
|
||||
|
|
|
|||
Loading…
Reference in New Issue