TC-NET-604 根因闭环:芯片 RX 窗口冻结角(Trap 21),MSS=512 裕量方案证伪回退,缓冲布局与 MSS 解耦 + 超限读金丝雀

- 根因:CH395F 片内 TCP 状态机角(WCH 官方 FAQ 留档,W5500 同类):窗口=接收缓冲剩余空间,
  缓冲恰好填满 + 排空时序交叠后芯片 RX 静默冻结(不 RST、不自恢复),触发模式 = 同连接前序突发 +
  新突发 + 任务负载;驱动超限读丢弃与 L3 pending 均经插桩台架排除
- MSS=512 裕量实验证伪(原序列 10/10 仍停摆,且新连接 4096B 确定性停摆恒剩 64B)→ 维持 1024
- 缓冲块布局(RX 4/TX 2 块)与 SPI DMA 缓冲(接收缓冲+4)与 MSS 解耦,杜绝改 MSS 连带缩小布局
- ch395f_read_recv_buf 超限守卫改为 OVERSIZE 留痕(原静默 return 会把窗口锁死 0 且无从诊断)
- 文档:Trap 21 全记录(含 MSS=512 负结果/64B 残留/FAQ 引文/触发模式);N-1 改写(残留决策项 =
  lftpd 数据通道停摆预算 30s→10-15s 待用户决策);E-02 STOR 预测机制修正;延迟说明基线免重锁注记
- 台架复验:新连接 4096B 31ms PASS(4x1024 粒度)、竞争序列停摆复现(芯片角,已文档化)、
  停摆后重连 520ms 恢复(auto-relisten + 回显正常);芯片行为参数零变化 → M3 基线全部继续有效
This commit is contained in:
2026-09-22 18:57:48 +08:00
parent 7ff2958b3b
commit 93bae35e21
7 changed files with 80 additions and 19 deletions
+5
View File
@@ -1162,6 +1162,11 @@ void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len) {
/* 计算总长度:1字节命令 + 1字节Socket + 2字节长度 + 数据 */
total = 4U + len;
if (total > CH395F_DMA_BUF_SIZE) {
/* 异常金丝雀:接收读不应超过整个接收缓冲(2KB,recv_len 不可能超过缓冲大小);
* 触发即调用方参数异常。静默丢弃会把芯片接收窗口锁死在 0(见 Trap 21),
* 故必须留痕。正常路径不会到达此处。 */
DBG_ERROR("read_recv_buf OVERSIZE: sock %u req %u > max %u, read dropped",
(unsigned)sock, (unsigned)len, (unsigned)(CH395F_DMA_BUF_SIZE - 4U));
return;
}
+22 -9
View File
@@ -112,17 +112,27 @@ extern "C" {
/*
* TCP MSS(CH395F_CMD_SET_TCP_MSS 参数)
* 由 net_init 经 ch395f_set_tcp_mss() 下发;此处作为单一真值源,
* DMA 缓冲大小亦由此推导(见下)。当前选取依据:8 Socket 共享 24KB 缓冲时,
* 各 Socket 接收缓冲 = 2×MSS,故 MSS 取 1024 为最大值(详见 net_socket.c 分配注释)。
* 由 net_init 经 ch395f_set_tcp_mss() 下发(须在 ch395f_init 之前);此处为单一真值源。
* 维持 1024:8 Socket 共享 24KB 缓冲时,单 Socket 接收缓冲 = 2×MSS = 2KB(手册 §9.2.8
* 满足上限的最大值)。TC-NET-604 台架验证(2026-09-22,详见 Trap 21):芯片接收冻结角
* (WCH FAQ:"收不到数据且 TCP 窗口不更新")不受 MSS 裕量影响——降 512 反而更差
* (新连接 4096B 突发即确定性停摆,剩 64B 未达);MSS=1024 时新连接 4096B 正常,
* 仅"同连接前序突发 + 新突发 + 任务负载"模式触发。MSS 裕量假设被证伪,恢复 1024
* (每次满缓冲周期段数少 = 触发概率低)。MSS 只影响芯片分包与窗口动态,
* 与下方缓冲块布局解耦。
*/
#define CH395F_TCP_MSS 1024U
/* 内部缓冲 RAM 每块字节数(手册 §5.45:48 块 × 512B = 24KB) */
#define CH395F_RAM_BLOCK_SIZE 512U
/* 单 Socket 缓冲块数由 MSS 推导:接收 = 2×MSS(满足手册 §9.2.8 接收 ≥ 2×MSS),发送 = 1×MSS;向上取整 */
#define CH395F_RECV_BLOCKS ((2U * CH395F_TCP_MSS + CH395F_RAM_BLOCK_SIZE - 1U) / CH395F_RAM_BLOCK_SIZE)
#define CH395F_SEND_BLOCKS ((CH395F_TCP_MSS + CH395F_RAM_BLOCK_SIZE - 1U) / CH395F_RAM_BLOCK_SIZE)
/* 单 Socket 缓冲块数:固定布局(2026-09-22 与 MSS 解耦;此前由 MSS 推导,改 MSS 会
* 连带静默缩小布局):接收 4 块=2KB、发送 2 块=1KB,8 Socket × 6 块 = 48 块恰好用满。
* 布局满足手册 §9.2.8:接收 2KB = 2×MSS(1024)(建议下沿,零裕量——用满 48 块的代价,
* 其携带的窗口冻结角见 Trap 21)/ ≥ MSS(必须)/ ≤ 6×MSS(建议);
* 发送 1KB = MSS(WCH FAQ 要求"发送缓冲 > MSS",此处取等值——台架实测芯片在
* 缓冲边界可正常成包,验证记录见 Trap 21)。 */
#define CH395F_RECV_BLOCKS 4U
#define CH395F_SEND_BLOCKS 2U
/* 单 Socket 硬件收发缓冲字节数(= 块数 × 块大小)。写入发送 FIFO 的单次长度严禁超过此值,
* 否则会写穿有限的发送缓冲(见 Trap 20)。 */
#define CH395F_SEND_BUF_SIZE_BYTES (CH395F_SEND_BLOCKS * CH395F_RAM_BLOCK_SIZE)
@@ -131,10 +141,13 @@ extern "C" {
/*
* SPI DMA 事务限制
* CH395F_SPI_DMA_MAX_PAYLOAD: 单次 DMA 事务最大有效载荷(总缓冲 - 4 字节命令头)
* 接收方向需一次性读空整个 Socket 接收缓冲(= 2×MSS,避免 Trap 13 部分读导致数据不可见),
* 故总缓冲 = 2×MSS + 4(4 为命令头开销),有效载荷 = 2×MSS。
* 接收方向需一次性读空整个 Socket 接收缓冲(= 接收缓冲大小,避免 Trap 13 部分读
* 导致剩余数据不可见),故总缓冲 = 接收缓冲大小 + 4(4 为命令头开销),
* 有效载荷 = 接收缓冲大小(2KB)。
* 2026-09-22:与 MSS 解耦(此前 = 2×MSS+4,MSS 下调会把 DMA 缓冲缩到装不下整缓冲
* → 整缓冲读被截断丢弃 → 窗口锁死,见 Trap 21)。
*/
#define CH395F_SPI_DMA_BUF_SIZE (CH395F_TCP_MSS * 2U + 4U)
#define CH395F_SPI_DMA_BUF_SIZE (CH395F_RECV_BUF_SIZE_BYTES + 4U)
#define CH395F_SPI_DMA_MAX_PAYLOAD (CH395F_SPI_DMA_BUF_SIZE - 4U)
/* 其他命令 */
+6 -5
View File
@@ -168,10 +168,11 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
* bit3=1: DISCONNECT/TIMEOUT 时不自动清空缓冲区,由软件排空数据后手动关闭 */
ch395f_set_fun_para(0x09);
/* 设置 TCP MSS
/* 设置 TCP MSS(2026-09-22 TC-NET-604:试 512 裕量方案被台架证伪,恢复 1024,见 Trap 21)
* 手册(§5.45):CH395F 内部缓冲共 48 块 × 512B = 24KB。下方为 8 个 Socket 各分配 6 块
* (接收 4 块=2KB + 发送 2 块=1KB),按手册 §9.2.8(接收 ≥ 2×MSS 建议)取 MSS=1024,用满 48 块。
* MSS 真值源为 ch395f.h 的 CH395F_TCP_MSS,DMA 缓冲大小亦由其推导。 */
* (接收 4 块=2KB + 发送 2 块=1KB),块布局固定(与 MSS 解耦,ch395f.h)。
* MSS=1024 为满足布局的最大值(接收=2×MSS);MSS 裕量不能消除芯片窗口冻结角
* (512 方案反使新连接突发也停摆),真值源为 ch395f.h 的 CH395F_TCP_MSS。 */
ch395f_set_tcp_mss(CH395F_TCP_MSS);
/* 设置 TCP 重传参数(必须在 INIT_CH395 之前调用;P0-a:周期 500→200ms。
@@ -223,8 +224,8 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
/* 多 Socket 模式:为 Socket 0~7 各分配独立收发缓冲(必须在 OPEN_SOCKET 之前)
* 手册(§5.45):CH395F 内部缓冲共 48 块 × 512B = 24KB;芯片上电默认仅给 Socket 0~3
* 分配(每 Socket 接收 8 块/发送 4 块),Socket 4~7 为 NULL,故用到 8 个 Socket 必须重分配。
* 单 Socket 块数由 MSS 推导(ch395f.h):接收 CH395F_RECV_BLOCKS(=2×MSS/512=4 块=2KB)、
* 发送 CH395F_SEND_BLOCKS(=1×MSS/512=2 块=1KB),每 Socket 共 6 块,MSS=1024 用满 48 块:
* 单 Socket 块数为固定布局(ch395f.h,2026-09-22 起与 MSS 解耦):接收 CH395F_RECV_BLOCKS(=4 块=2KB)、
* 发送 CH395F_SEND_BLOCKS(=2 块=1KB),每 Socket 共 6 块,用满 48 块:
* blocks_per_socket = CH395F_RECV_BLOCKS + CH395F_SEND_BLOCKS
* recv_start = i * blocks_per_socket, send_start = recv_start + CH395F_RECV_BLOCKS
* Socket 7 占块 42~47,恰好用尽 0~47,互不重叠。