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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
/* 其他命令 */
|
||||
|
||||
@@ -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,互不重叠。
|
||||
|
||||
Reference in New Issue
Block a user