7708f12c10
按键召唤答的是按键前的旧帧:uiTask 还没消化键答案就发走了,新画面 只能等下一次周期召唤(280 ms/轮)才带得出——真机反馈 250-450 ms 的 主构成(根因账本 docs/子系统设计/屏板链路设计说明.md §7.1)。 改动(用户批准范围 A+B+C;屏板固件未动,决策三不变): - sb_link:按键召唤改为只入队不起发;uiTask 同拍重绘并组帧成功后交 凭据(sb_link_key_rendered),TIM3 1 kHz 的 sb_link_ms_tick 以 ≤1 ms 放行新帧。140 ms 截止(SB_KEY_RESP_MAX_MS,+59.6 ms 线上 <205 ms 屏板放弃线)保底发旧帧,"一召一答"契约不破;线忙时同旧丢单、 不留扣件。起发两中断源(USART1 IDLE/TIM3)共用 sb_tx_kick, "判忙→占位"在 PRIMASK 临界区原子完成。 - ui_task:排空注键挪到组帧之前,注键→即派即绘→组帧同拍闭环; 组帧返回 BSP_OK 才交重绘凭据(BUSY 拍帧还没反映按键)。 - ui_port:注键单槽改 8 深环(连按不再互相覆盖,满丢最旧+计数); 新增 ui_port_service_keys:同拍 lv_indev_read + lv_refr_now, 省掉 indev ≤20 ms + 刷新 ≤20 ms 两段等待。 - ui_menu_view:菜单移动选中只失效新旧两行带(黄金参考零像素变化), 滚动/异常回退整框失效。 - simulator:窗口循环 sleep 扣除本轮已耗时(原先无条件睡满 lv_timer_handler 返回值,叠加 Windows Sleep 15.6 ms 粒度放大观感)。 - 串口 TX 上报新增 dfok/dfold(凭据放行新帧数/超时保底旧帧数): dfold 连涨 = uiTask 被饿 ≥140 ms 的直接现场证据。 验证:test/host/sb_link 164/164(新增 18 条:不立刻起发/凭据放行/ 140 ms 截止保底/忙时不留扣件/陈旧凭据不放行等边界);菜单 8 状态 + 内容页 66 张黄金像素 PASS;Keil @build 0 错误 0 警告(两次); BOM 99 文件无漂移、代码规范、doc-links 本次文件零问题、cppcheck PASS。 文档:屏板规划文档已被主干收编进设计说明,延迟账本落 docs/子系统设计/屏板链路设计说明.md §7.1,并同步 §4 口径、§8 接口、 §9.1 单测台账 146→164、§10 坑账本补条。 RAM 台账(分支不跑 --write,并行分支提交约定):本笔盖戳行 RW_IRAM1 94,336 B (72.0%) / RW_CCM 57,376 B (87.9%),较上一台账行 +4,400 B——为距上次台账构建以来分支累计差(含批 3 状态灯等未盖戳 提交),非全部本笔引入;本次自身增量按对象计为 ui_port.o +12 B (8 深键环+丢计数+indev 指针)与 sb_link/o 数十字节级。 gate: only mem-budget/mem-numbers pending lead ledger backfill (合并落主干后 Lead 统一 --write 回填受管区)。
112 lines
4.6 KiB
C
112 lines
4.6 KiB
C
/*
|
||
* 模块名称:UI Display Port (LVGL 离屏显示端口)
|
||
* 模块功能:提供 LVGL 1bpp 离屏渲染端口与远程 keypad 输入设备
|
||
* 适用平台:STM32F407ZGTx
|
||
* 作者:王建锋
|
||
* 创建日期:2026-08-29
|
||
* 修改记录:
|
||
* 2026-08-29 王建锋 创建初始版本
|
||
*/
|
||
#ifndef UI_PORT_H
|
||
#define UI_PORT_H
|
||
|
||
#include <stdint.h>
|
||
#include <stddef.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/* 屏幕尺寸与帧缓冲(160x160 1bpp = 3200 字节) */
|
||
#define UI_SCREEN_W 160
|
||
#define UI_SCREEN_H 160
|
||
#define UI_FB_SIZE ((UI_SCREEN_W * UI_SCREEN_H) / 8)
|
||
|
||
/*
|
||
* LVGL 索引色(I1)绘制缓冲布局 = [palette][pixel data](2026-09-21 台架实证;
|
||
* 改本端口或升级 LVGL 版本前必读):
|
||
* - lv_draw_buf_create() : 尺寸 = stride*h + LV_COLOR_INDEXED_PALETTE_SIZE(cf)*4
|
||
* - lv_draw_buf_goto_xy()/lv_draw.c : 取绘制指针时 data += palette(像素不从缓冲首址开始)
|
||
* - lv_refr get_max_row() : 从 data_size 里扣掉 palette 才当可用像素
|
||
* 但 lv_display_set_buffers()/lv_draw_buf_init() 的容量校验**只看 stride*h(不含 palette)**,
|
||
* 故"只给 stride*h"会被静默接受;实测两种后果:
|
||
* 1) 末 palette 个像素字节写到缓冲之外(金丝雀实测越界 8B,曾打脏紧邻 .bss 的
|
||
* s_frame_box[0] 指针 → 野指针 HardFault);
|
||
* 2) flush 回调收到的首地址含 palette,照原样整帧拷贝会让推流画面整体错位 8B。
|
||
* 规则:绘制缓冲按 UI_DRAW_BUF_SIZE 提供、上报 LVGL 的尺寸也用 UI_DRAW_BUF_SIZE;
|
||
* flush 取像素必须 color_p + UI_DRAW_BUF_PALETTE。
|
||
* 注:此处用字面量 8(I1 = 2 色 x 4 字节)以免头文件依赖 lvgl.h;ui_port.c 已按
|
||
* LV_COLOR_INDEXED_PALETTE_SIZE(LV_COLOR_FORMAT_I1)*4 核对一致。
|
||
*/
|
||
#define UI_DRAW_BUF_PALETTE 8u
|
||
#define UI_DRAW_BUF_SIZE (UI_FB_SIZE + UI_DRAW_BUF_PALETTE)
|
||
|
||
/* 远端按键码(与 DTU-HMI key.h 保持一致) */
|
||
#define UI_KEY_UP 0x02
|
||
#define UI_KEY_DOWN 0x40
|
||
#define UI_KEY_LEFT 0x10
|
||
#define UI_KEY_RIGHT 0x08
|
||
#define UI_KEY_ENTER 0x20
|
||
#define UI_KEY_ESC 0x01
|
||
|
||
/*
|
||
* 函数功能:初始化 LVGL 显示端口与按键输入设备
|
||
* 入口参数:无
|
||
* 返回值:0 - 成功,其他 - 失败(显示或输入设备创建失败)
|
||
* 限定条件:无
|
||
* 函数说明:1. 初始化 LVGL 内核并创建 1bpp 离屏显示设备
|
||
* 2. 创建 keypad 输入设备及默认输入组,用于菜单导航
|
||
* 3. 需在 lv_tick_inc/lv_timer_handler 被周期调用后方可刷新
|
||
*/
|
||
int ui_port_init(void);
|
||
|
||
/*
|
||
* 函数功能:获取内存帧缓冲首地址
|
||
* 入口参数:无
|
||
* 返回值:帧缓冲首地址 uint8_t * 固定长度 UI_FB_SIZE 字节
|
||
* 限定条件:ui_port_init() 已成功调用
|
||
* 函数说明:1. 帧缓冲由 flush 回调写入最新渲染结果
|
||
* 2. 供 RemoDispBus 服务端读取并推送至远端
|
||
*/
|
||
uint8_t *ui_port_get_framebuffer(void);
|
||
|
||
/*
|
||
* 函数功能:向输入队列喂入一个远端按键值
|
||
* 入口参数:key_val - 远端键码 uint8_t UI_KEY_* 取值之一
|
||
* 返回值:无
|
||
* 限定条件:无
|
||
* 函数说明:1. 将远端键码映射为 LVGL 按键后缓存
|
||
* 2. 由 keypad 读取回调在下次轮询时上报,驱动菜单导航
|
||
*/
|
||
void ui_port_queue_key(uint8_t key_val);
|
||
|
||
/*
|
||
* 函数功能:UI 周期步进(更新系统节拍并刷新 LVGL)
|
||
* 入口参数:tick_ms - 距上次调用的毫秒数 uint32_t 建议 10
|
||
* 返回值:无
|
||
* 限定条件:ui_port_init() 已成功调用
|
||
* 函数说明:1. 调用 lv_tick_inc 推进 LVGL 内部时钟
|
||
* 2. 调用 lv_timer_handler 处理重绘,结果经 flush 写入帧缓冲
|
||
* 3. 须由任务以固定周期调用,否则界面停止刷新
|
||
*/
|
||
void ui_port_step(uint32_t tick_ms);
|
||
|
||
/*
|
||
* 函数功能:立即消费队列中的待处理按键并让改动落屏(按键提速,2026-10-30)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:ui_port_init() 已成功调用;与 ui_port_step 同一任务上下文
|
||
* 函数说明:1. 队列空 = 空操作(不触发输入读取)
|
||
* 2. 非空则立刻 lv_indev_read 派发键事件 + lv_refr_now 把脏区绘进
|
||
* 帧缓冲——调用方据此可在**同一拍**完成"注键→派发→重绘",
|
||
* 不等下一个 20 ms 输入轮询 / 刷新定时器(按键反馈提速 A 项)
|
||
* 3. 只消费队列头部一个键;连按时其余按键仍由周期轮询逐个派发
|
||
*/
|
||
void ui_port_service_keys(void);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* UI_PORT_H */
|