docs(屏板链路): 规划文档收编为设计说明事实源,全仓引用与端口口径同步
- 重写 docs/子系统设计/屏板链路设计说明.md:链路角色、串口与端口配置、 物理接线、协议实现口径、键值与状态灯映射、资源与耗时、对外接口、 已验证/未闭环、坑账本——只写现状事实,演进过程查 git 历史 - 删除 docs/任务规划/屏板链路.md(内容已全部沉淀进上述设计说明, 登记簿「完成即销项」;docs/任务规划/README.md 相应两行一并移除) - 代码与主机侧测试的文档指针改指设计说明对应章节: sb_link.h/.c、sb_proto.h/.c、sb_led_map.h、console_log.c、ui_task.c、 test/host 的 sb_link/sb_proto/sb_led_map 三套与两个台架脚本 - docs/README.md:设计文档索引行与设计说明描述更新,任务规划目录 7→6 文件 - docs/产品需求/产品需求设计文档.md:串口通道现状口径同步——第 11/12/13 条 已交付(4208 B 应答/状态灯掩码/键上行/双出口并发)、LOGO 下发出局不实现、 帧长实测固化、调试日志口 UART5/RS232#1(§4.2/§5.16/§6.6/§9.12/§9.13) - docs/子系统设计/控制台单写者日志设计说明.md v1.8:全文端口口径由 USART1 同步为 UART5/RS232#1(CON_UART* 单点宏),ORE 机理标注跨端口 同因,时间线补端口迁移行;头部修订指针改为实际章节名 说明:本任务经用户显式授权在任务树内编辑 docs/任务规划/ 与产品需求基线 (铁律「单写者」豁免一次);主树合并后统一跑全量 check_doc_links --all。
This commit is contained in:
@@ -7,8 +7,8 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-29
|
||||
* 修改记录:
|
||||
* 2026-10-29 王建锋 创建初始版本(批 1 的 1-2 / 1-3)
|
||||
* 2026-10-29 王建锋 批 2:组帧入口 + 中断起发 + TxCplt 收尾 + 按键队列 + 离线判定
|
||||
* 2026-10-29 王建锋 创建初始版本(收中断 + 帧 A 校验)
|
||||
* 2026-10-29 王建锋 增加:组帧入口 + 中断起发 + TxCplt 收尾 + 按键队列 + 离线判定
|
||||
*
|
||||
* 四个容易踩的点(改之前先读,前三条都已在台架上被别的东西咬过一次):
|
||||
*
|
||||
@@ -291,7 +291,7 @@ void sb_link_on_rx_event(UART_HandleTypeDef *p_huart, uint16_t size)
|
||||
if (frame.cmd == SB_CMD_KEY)
|
||||
{
|
||||
s_stats.key_events++;
|
||||
/* 只入队,不注键:注键会走 ui_port 的输入队列,属业务动作(决策三)。
|
||||
/* 只入队,不注键:注键会走 ui_port 的输入队列,属业务动作。
|
||||
* key == 0 是"无键",屏板自己的语义就是没有事件,不必占队列。 */
|
||||
if (frame.key != 0U)
|
||||
{
|
||||
@@ -299,7 +299,7 @@ void sb_link_on_rx_event(UART_HandleTypeDef *p_huart, uint16_t size)
|
||||
}
|
||||
}
|
||||
|
||||
/* 决策三:起发就在这儿,不在任务里轮询。一召唤 → 一答 4208 B,绝不叠发。
|
||||
/* 起发就在这儿,不在任务里轮询。一召唤 → 一答 4208 B,绝不叠发。
|
||||
* 上一帧还没发完(屏板自己超时重问过)就丢这一轮:多发一帧会让屏板把
|
||||
* 两帧粘成一帧撕裂,而且它接收溢出后会永久收不到东西(见 §4.4 的警示)。 */
|
||||
if (s_frame_ready == 0U)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* 模块功能:把主机与屏板之间那条 700 kbaud 链路完整地管起来:
|
||||
* - 收:IDLE 空闲中断断帧、6 B 帧 A 校验、错误中断里清 ORE 并重挂接收;
|
||||
* - 发:任务侧组一帧 B(4208 B)进静态缓冲,中断侧收到召唤帧**直接点 TX DMA**,
|
||||
* TxCplt 里收尾(决策三:不排队、不攒批、不在任务里逐字节轮询);
|
||||
* TxCplt 里收尾(不排队、不攒批、不在任务里逐字节轮询);
|
||||
* - 按键上行:中断只入队,注键由任务侧取走(**注键不能在中断里做**);
|
||||
* - 链路监视:连续 >=10 s 无召唤帧才判离线;CRC 错帧静默丢弃并计数。
|
||||
* 协议字节级编解码(CRC / 帧 A 解析 / 帧 B 组帧)在 sb_proto,本层只做搬运与时序。
|
||||
@@ -11,8 +11,8 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-29
|
||||
* 修改记录:
|
||||
* 2026-10-29 王建锋 创建初始版本(批 1 的 1-2 / 1-3:700 kbaud + 收中断)
|
||||
* 2026-10-29 王建锋 批 2:帧 B 组帧入口、中断起发、TxCplt 收尾、按键队列、离线判定
|
||||
* 2026-10-29 王建锋 创建初始版本(700 kbaud + 收中断)
|
||||
* 2026-10-29 王建锋 增加:帧 B 组帧入口、中断起发、TxCplt 收尾、按键队列、离线判定
|
||||
*
|
||||
* 为什么单独一层、不并进 sb_proto:
|
||||
* sb_proto 是纯逻辑(CRC / 组帧 / 解析),能在 test/host 里原样 include 跑单测;
|
||||
@@ -55,13 +55,13 @@ extern "C" {
|
||||
* 接收缓冲:16 B 足够。
|
||||
* 屏板只发 6 B 的帧 A(周期召唤 / 按键召唤),16 B 留出一次噪声冲击的余量。
|
||||
* ⚠ 不要照抄屏板侧的 4208 B——那是帧 B 的长度,方向相反(主机发、屏板收),
|
||||
* 放进接收侧白占 SRAM(判据见 docs/任务规划/屏板链路.md §1.3)。
|
||||
* 放进接收侧白占 SRAM(判据见 docs/子系统设计/屏板链路设计说明.md §2)。
|
||||
*/
|
||||
#define SB_LINK_RX_BUF_SIZE (16U)
|
||||
|
||||
/*
|
||||
* 统计上报周期(ms)。只在计数有变化时才打一行,链路空闲不刷屏;
|
||||
* 台架验收靠的就是这一行里的累计值(判据见 docs/任务规划/屏板链路.md §3 的 1-3)。
|
||||
* 台架验收靠的就是这一行里的累计值(判据见 docs/子系统设计/屏板链路设计说明.md §9)。
|
||||
*/
|
||||
#define SB_LINK_REPORT_MS (5000U)
|
||||
|
||||
@@ -70,7 +70,7 @@ extern "C" {
|
||||
* 复位期间约 1 s 不召唤;再叠上主机的重挂/噪声恢复,短窗口会把"屏板活着但歇了口气"
|
||||
* 误判成离线,然后在下一次召唤时又"恢复"——现场看到的是离线标志反复跳。
|
||||
* 10 s 的取法:比 1 s 自复位空窗大一个数量级,又远小于"人发现屏板黑屏"的时间。
|
||||
* 出处 docs/任务规划/屏板链路.md §3 的 2-5。
|
||||
* 出处 docs/子系统设计/屏板链路设计说明.md §2 链路监视。
|
||||
*/
|
||||
#define SB_LINK_OFFLINE_MS (10000U)
|
||||
|
||||
@@ -105,7 +105,7 @@ typedef struct
|
||||
uint32_t rx_crc_err; /* CRC 不符 */
|
||||
uint32_t rx_len_err; /* 长度不是 SB_FRAME_A_LEN */
|
||||
uint32_t rx_fmt_err; /* 地址/功能码/命令字不符 */
|
||||
uint32_t key_events; /* 其中 cmd == SB_CMD_KEY 的帧数(按键召唤,2-3 的消费源) */
|
||||
uint32_t key_events; /* 其中 cmd == SB_CMD_KEY 的帧数(按键召唤,按键队列的消费源) */
|
||||
uint32_t err_irq; /* 错误中断次数(ORE/NE/FE/PE) */
|
||||
uint32_t err_bits; /* 错误中断里见过哪些位(HAL_UART_ERROR_* 的并集,见下) */
|
||||
uint32_t rearm_fail; /* 重挂接收失败次数(正常应恒 0,非 0 说明链路已静默) */
|
||||
@@ -113,7 +113,7 @@ typedef struct
|
||||
uint8_t last_cmd; /* 最近一帧有效帧的命令类型(SB_CMD_*) */
|
||||
uint8_t last_key; /* 最近一帧有效帧的键值(无键为 0) */
|
||||
|
||||
/* ---- 批 2:发送侧(帧 B 组帧 + TX DMA 起发 + 收尾) ---- */
|
||||
/* ---- 发送侧(帧 B 组帧 + TX DMA 起发 + 收尾) ---- */
|
||||
uint32_t tx_kick; /* 起发成功次数(每次有效召唤帧 +1) */
|
||||
uint32_t tx_done; /* TxCplt 次数(链路正常时应恒等于 tx_kick) */
|
||||
uint32_t tx_busy_drop; /* 召唤到了但上一帧还在发 → 本次不答(屏板 280 ms 后会再问) */
|
||||
@@ -122,9 +122,9 @@ typedef struct
|
||||
uint32_t frame_build; /* 组帧次数(只有内容/掩码变化才 +1) */
|
||||
uint32_t frame_bad; /* 组完自校验失败次数(正常恒 0) */
|
||||
uint32_t frame_us; /* 最近一次组帧耗时(µs,DWT 实测) */
|
||||
uint32_t frame_us_max; /* 组帧耗时峰值(µs)——2-1 的"≤0.3 ms"就看这一列 */
|
||||
uint32_t frame_us_max; /* 组帧耗时峰值(µs),预算 ≤1 ms(docs/子系统设计/屏板链路设计说明.md §7) */
|
||||
|
||||
/* ---- 批 2:按键上行与链路监视 ---- */
|
||||
/* ---- 按键上行与链路监视 ---- */
|
||||
uint32_t key_drop; /* 按键队列满导致的丢弃次数 */
|
||||
uint8_t offline; /* 1 = 连续 >= SB_LINK_OFFLINE_MS 无有效召唤帧 */
|
||||
} sb_link_stats_t;
|
||||
@@ -180,7 +180,7 @@ bsp_err_t sb_link_receive_start(void);
|
||||
* 返回值:无
|
||||
* 限定条件:**中断上下文**,只做 CRC 与计数(4 B 校验约 1 µs),不得打日志、不得阻塞。
|
||||
* 函数说明:长度不是 6 就直接记 rx_len_err 并丢弃;是 6 才解析。解析通过后**直接点 TX DMA**
|
||||
* 把已经组好的帧 B 发出去(决策三:起发必须在中断里,不能在任务里轮询——屏板按
|
||||
* 把已经组好的帧 B 发出去(起发必须在中断里,不能在任务里轮询——屏板按
|
||||
* "总线空闲 1 个字符"断帧,一次几十 µs 的任务抢占就能把帧切断,而屏板不报超时)。
|
||||
* 业务动作仍然不做:按键只入队,注键由任务侧 sb_link_key_take() 取走后做。
|
||||
* 末尾无条件重挂接收。
|
||||
@@ -223,7 +223,7 @@ void sb_link_poll(uint32_t now_ms);
|
||||
* BSP_ERR_CRC 组完自校验失败(已计数 frame_bad,帧不会发出去)
|
||||
* 限定条件:**任务上下文**,且必须与 ui_port_step() 同一个任务(显存是单写者)。
|
||||
* 变化帧实测 ≈0.5 ms(典型)/ 0.8 ms(峰值),没变只付 memcmp(≈20 µs);
|
||||
* 判据口径见 docs/任务规划/屏板链路.md §3 的 2-1。
|
||||
* 判据口径见 docs/子系统设计/屏板链路设计说明.md §7。
|
||||
* 函数说明:1. **不持有显存副本**——直接拿 p_live_bmp 与帧缓冲里的点阵段 memcmp,
|
||||
* 没变就立刻返回(约 20 µs)。省掉 3200 B 影子缓冲,也省掉每拍重算 CRC。
|
||||
* 2. **TX 占用期间绝不写帧缓冲**(那会让 DMA 发出半新半旧的"脏帧"):
|
||||
@@ -235,12 +235,13 @@ bsp_err_t sb_link_frame_update(const uint8_t *p_live_bmp, uint32_t led_mask);
|
||||
/*
|
||||
* 函数功能:取走一个待注的屏板按键(任务侧)
|
||||
* 入口参数:无
|
||||
* 返回值:屏板 key 字节(1~10,语义见 docs/任务规划/屏板链路.md §4.3);
|
||||
* 返回值:屏板 key 字节(1~10,语义见 docs/子系统设计/屏板链路设计说明.md §5);
|
||||
* 0 = 队列空(屏板自己的 0 就是"无键",两者同义,不必再分)
|
||||
* 限定条件:任务上下文;中断侧在入队,本函数出队。单生产者单消费者,不需要关中断。
|
||||
* 函数说明:只吐**屏板原始键号**,不映射 UI_KEY_*——键号是协议语义,UI 键码是 UI 语义,
|
||||
* 两者在 uiTask 里汇合(那一层才知道当前是哪个页面在接键)。
|
||||
* key == 9/10(RESET/FACTORY)照原样吐出,丢不丢由调用方按决策四裁定。
|
||||
* key == 9/10(RESET/FACTORY)照原样吐出,丢不丢由调用方定(当前口径见
|
||||
* docs/子系统设计/屏板链路设计说明.md §5)。
|
||||
*/
|
||||
uint8_t sb_link_key_take(void);
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ uint16_t sb_crc16(const uint8_t *p_data, uint16_t len)
|
||||
uint16_t crc = 0xFFFFU;
|
||||
/* 32 位计数:用 uint16_t 循环变量时 ARMCC 每轮会多生成一条 UXTH(实测见
|
||||
* fromelf 反汇编),4206 B 一轮就是 4206 条无用指令。帧 B 每帧都要算满 4206 B,
|
||||
* 这条值得省(组帧预算见 docs/任务规划/屏板链路.md §3 的 2-1)。 */
|
||||
* 这条值得省(组帧预算见 docs/子系统设计/屏板链路设计说明.md §7)。 */
|
||||
uint32_t n = (uint32_t)len;
|
||||
|
||||
while (n > 0U)
|
||||
@@ -176,7 +176,7 @@ bsp_err_t sb_frame_a_parse(const uint8_t *p_buf, uint16_t len, sb_frame_a_t *p_o
|
||||
* led_mask - 状态灯位掩码,小端填进 info[0..3]
|
||||
* 返回值:BSP_OK / BSP_ERR_PARAM(指针为空)
|
||||
* 限定条件:整帧重写(含 998 B 填充与 CRC),调用方不必预先清零。
|
||||
* 函数说明:掩码的位语义不归本模块管(见任务规划批 3)。
|
||||
* 函数说明:掩码的位语义不归本模块管(见 App/algo/sb_led_map.h)。
|
||||
*/
|
||||
bsp_err_t sb_frame_b_build_image(uint8_t *p_frame, const uint8_t *p_bmp, uint32_t led_mask)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* - 帧 B(主机 → 屏板,固定 4208 B)组帧:普通图(LED 掩码)/ LOGO(宽高 + 魔数)
|
||||
* - 帧 B 自校验(组完立刻能验,供组帧路径自查)
|
||||
* 本模块**不碰寄存器、不碰 DMA、不碰任务**:串口怎么配、谁来发、什么时候发都不归它管
|
||||
* (那是批 1 的 1-2 / 1-3 与批 2 的事)。
|
||||
* (那是 sb_link 与传输层的事)。
|
||||
* 适用平台:STM32F4 系列(ARMCC v5);不依赖 HAL,主机侧可直接编译(故可主机单测)。
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-29
|
||||
|
||||
Reference in New Issue
Block a user