Files
TCP2UART/工程调试指南.md
T
gaoro-xiao 31a3da48fa fix(tcp): MUX模式网口失联 — 对端关闭时用tcp_abort替代tcp_close避免TIME_WAIT耗尽pcb池
根因: tcp_close()将对端关闭的pcb推入TIME_WAIT(120s), 占用MEMP_TCP_PCB池(仅4个),
多连接同时断开后pcb池耗尽, tcp_new()返回NULL, 新连接无法建立直到120s超时释放。

核心修复:
- tcp_server/client: 对端关闭(p=NULL)时tcp_abort替代tcp_close, pcb立即释放
- ch390_runtime: PKT_ERR恢复强制OR上RCR_RXEN(与WCH官方一致)
- ch390_runtime: TX连续超时3次自动emergency reset
- ch390_runtime: 每5秒health_check读VID验证芯片存活
- main: App_StartLinksIfNeeded失败时不标记g_links_started, 允许重试
- main: MUX逐帧RTT printf改为#if DEBUG门控, 减少主循环延迟
- uart_trans: MUX帧解析改为先搜0x7E再消费header, 非法帧只丢1字节
2026-04-14 03:44:26 +08:00

524 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TCP2UART 调试指导
## 1. 适用范围
本指导面向当前 `TCP2UART` 工程,覆盖以下四类调试场景:
1. `STM32F103R8T6 + CH390D` 的基础 bring-up
2. `SEGGER RTT`、异常陷阱与主循环运行状态确认
3. `USART1` 配置口、`USART2/USART3` 数据口与 `MUX / NET / LINK[idx]` 协议联调
4. `TCP Server / TCP Client / UART` 三层数据通路联调与问题隔离
本指导默认基线如下:
1. 当前工程采用裸机主循环架构,未使用 FreeRTOS 参与主业务调度
2. `CH390` 运行时访问统一由 `ch390_runtime` 持有
3. 调试输出统一使用 `SEGGER RTT`
4. 当前应用层协议模型已经收敛到 `MUX / NET / LINK[idx]`
5. 当前代码应以 `MDK-ARM` 工程构建结果为准,而不是 `CMake + MSVC` 结果
---
## 2. 当前工程边界与真实状态
在进入现场调试前,先统一以下工程边界,避免沿用过时结论:
1. 当前项目的主要软件路径已经切换为:
- `NET`:网络基础参数
- `LINK[idx]`:链路配置记录
- `MUX`:数据口承载模式
2. 对外 AT 配置面应只围绕以下命令展开:
- `AT`
- `AT+?`
- `AT+QUERY`
- `AT+MUX`
- `AT+NET`
- `AT+LINK`
- `AT+SAVE`
- `AT+RESET`
- `AT+DEFAULT`
3. 当前 `CH390D` 的历史“全 `0xFF` / 全 `0x0000`”结论不应再直接沿用。
4. 已有结论表明:
- MCU 启动、RTT、主循环、TIM4 心跳路径可工作
- `CH390D` 基础寄存器读写与 `lwIP netif` 基本链路已经打通过一次
- 真实硬件侧曾定位到 `CH390D` 供电滤波电容虚焊问题
5. 因此,当前调试重点不再是“CH390 是否完全不通”,而是:
- 启动阶段是否稳定
- `MUX / NET / LINK[idx]` 协议是否与代码一致
- UART / TCP / CH390 三层通路是否协同稳定
- 参数保存、复位和恢复流程是否可靠
---
## 3. 代码入口与调试责任边界
### 3.1 启动与主循环入口
以下代码路径是 bring-up 的第一现场:
1. `Core/Src/main.c`
- `main()`:总启动入口
- `SystemClock_Config()`:时钟初始化
- `App_Init()`:应用层初始化
- `App_Poll()`:主循环核心路径
- `BootDiag_ReportCh390()`:启动阶段 CH390 诊断输出
2. `Core/Src/stm32f1xx_it.c`
- 故障与中断入口
- `USART1/2/3``EXTI0`、DMA 回调等联调关键入口
### 3.2 CH390 责任边界
当前 CH390 调试必须遵守以下责任边界:
1. `Drivers/CH390/CH390_Interface.c`
- 只负责 GPIO / SPI / 寄存器与内存事务
2. `Drivers/CH390/CH390.c`
- 只负责芯片级 helper,例如默认配置、PHY、MAC 读写
3. `Drivers/CH390/ch390_runtime.c`
- 唯一的运行时拥有者
- 负责初始化、链路检查、IRQ 消费、RX/TX 服务与诊断快照
4. `Drivers/LwIP/src/netif/ethernetif.c`
- 只承担 netif glue 与轮询桥接,不应重新下沉复杂 CH390 运行时事务
5. `Core/Src/main.c`
- 启动后只通过 runtime 对外暴露的诊断与轮询接口工作
调试时不要把原始 CH390 寄存器访问重新散回 `main.c`、中断或多个业务层。
### 3.3 配置口与业务口边界
1. `USART1`
- 配置口
- 负责接收 `AT` 命令
- 当前接收逻辑在:
- `Core/Src/main.c``App_PollUart1ConfigRx()`
- `Core/Src/stm32f1xx_it.c``HAL_UART_RxCpltCallback()`
- `App/config.c``config_uart_rx_byte()` / `config_process_at_cmd()`
2. `USART2 / USART3`
- 数据口
- 负责普通透传或 MUX 承载
- 当前入口在 `App/uart_trans.c`
---
## 4. 当前硬件与调试工具基线
### 4.1 核心硬件对象
1. MCU`STM32F103R8T6`
2. 以太网芯片:`CH390D`
3. 配置串口:`USART1`
4. 数据串口:`USART2 / USART3`
5. 调试输出:`SEGGER RTT`
### 4.2 构建与下载基线
当前建议优先使用以下工程与产物:
1. `MDK-ARM/TCP2UART.uvprojx`
2. `MDK-ARM/TCP2UART/TCP2UART.axf`
3. `MDK-ARM/TCP2UART/TCP2UART.hex`
4. `MDK-ARM/TCP2UART/TCP2UART.map`
5. `MDK-ARM/TCP2UART/TCP2UART.build_log.htm`
6. `build_keil.log`
说明:
1. 当前 `CMake configure` 可以完成,但 `CMake + MSVC` 不适合作为 STM32/CMSIS 的最终构建验收依据。
2. 若需要验证“当前代码是否真实可编译”,优先看 `MDK-ARM` 构建产物与日志。
### 4.3 常用调试工具
1. `Keil MDK-ARM`
2. `ST-Link / J-Link`
3. `SEGGER RTT Viewer`
4. `PowerShell`
5. `tools/start_tcp_debug_server.ps1`
6. `tools/tcp_debug_server.py`
---
## 5. 启动阶段调试顺序
建议按 P0 ~ P5 顺序推进,不要跳层。
### 5.1 P0:确认最小基础条件
每次现场调试前,先确认:
1. `MDK-ARM` 可构建并产出新的 `axf/hex/map`
2. 板卡可正常下载与复位
3. RTT 可连接并看到启动输出
4. LED 心跳可工作
5. `App_Poll()` 已经进入稳定轮询
这一层若失败,不要进入网络或协议调试。
### 5.2 P1:确认启动日志与 trap 状态
上电或复位后,优先看 RTT 输出中是否出现:
1. `TCP2UART boot`
2. 若 HSE 启动失败,则会出现:
- `WARN: HSE start failed, fallback to HSI PLL`
3. `BootDiag_ReportCh390()` 输出的 CH390 诊断与网络配置快照
若发生异常,优先观察是否打印:
1. `TRAP: Error_Handler`
2. `TRAP: HardFault_Handler`
3. `TRAP: MemManage_Handler`
4. `TRAP: BusFault_Handler`
5. `TRAP: UsageFault_Handler`
当前 trap 统一收敛到:
1. `Core/Src/main.c``Debug_TrapWithRttHint()`
2. 它会打印 RTT、执行 `__BKPT(0)` 并停住
因此,若 RTT 中出现 `TRAP:`,应立即接调试器看断点现场,而不是继续盲猜高层逻辑。
### 5.3 P2:确认 CH390 初始化链路
启动阶段应重点关注 `Drivers/CH390/ch390_runtime.c` 中初始化阶段日志,理想情况下应能依次看到:
1. `ETH init: gpio`
2. `ETH init: spi`
3. `ETH init: reset`
4. `ETH init: probe`
5. `ETH init: default`
6. `ETH init: mac`
7. `ETH init: getmac`
8. `ETH init: irq`
9. `ETH init: done`
此阶段重点判定:
1. `VID / PID / REV` 是否可信
2. PHY 寄存器是否稳定可读
3. MAC 写入与回读是否一致
4. `link_up` 是否与真实网线状态一致
若这一层失败,优先做硬件侧量测,而不是先改业务层:
1. `RSTB`
2. `CS`
3. `SCK`
4. `MOSI`
5. `MISO`
6. `INT`
7. `VDDK`
8. `AVDD33 / VDDIO / AVDD33`
9. `XI / XO`
---
## 6. USART1 配置口调试
### 6.1 当前命令面
根据当前代码与手册,配置口应围绕以下命令验证:
1. `AT`
2. `AT+?`
3. `AT+QUERY`
4. `AT+MUX=...`
5. `AT+MUX?`
6. `AT+NET=...`
7. `AT+NET?`
8. `AT+LINK=...`
9. `AT+LINK?`
10. `AT+SAVE`
11. `AT+RESET`
12. `AT+DEFAULT`
### 6.2 现场关键规则
根据已有联调记录,配置口最关键的 bench 规则是:
1. 当前现场验证时,配置命令必须保证以换行完成帧。
2. 若主机侧发送方式不对,现象会很像“配置口完全无响应”。
3. 因此,配置口不响应时,第一优先级不是改 parser,而是先验证主机端发送格式与接线。
### 6.3 最小验证步骤
建议按以下顺序验证:
1. 连接 `USART1`
2. 先发 `AT`
3. 再发 `AT+QUERY`
4. 再发 `AT+NET?`
5. 再发 `AT+LINK?`
6. 修改一个最小参数,例如:
- `AT+MUX=1`
7. 执行:
- `AT+SAVE`
- `AT+RESET`
8. 复位后再次查询,确认配置是否保留
### 6.4 持久化失败时怎么查
优先检查以下路径:
1. `App/config.c`
- `config_save()`
- `config_load()`
- `config_set_defaults()`
2. `App/flash_param.c`
- Flash 解锁
- 页擦除
- 半字编程
- 写后校验
3. 参数页地址:
- `0x0800FC00`
不要在还没证明 `AT+SAVE` 已真正被接受之前,就直接把 `Flash 全 FFFFFFFF` 归因到 Flash 驱动错误。
---
## 7. MUX / NET / LINK[idx] 联调指导
### 7.1 协议总则
当前协议必须按以下模型理解:
1. `MUX`:全局数据承载模式开关
2. `NET`IP / Mask / GW / MAC
3. `LINK[idx]`:链路配置项
固定链路索引映射为:
1. `LINK[0] = S1`
2. `LINK[1] = S2`
3. `LINK[2] = C1`
4. `LINK[3] = C2`
固定端点编码为:
1. `C1 = 0x01`
2. `C2 = 0x02`
3. `UART2 = 0x04`
4. `UART3 = 0x08`
5. `S1 = 0x10`
6. `S2 = 0x20`
### 7.2 MUX 数据口规则
`MUX=1` 时,数据口应使用 MUX 帧。
重点规则:
1. `DSTMASK=0x00` 表示系统控制帧
2. 控制帧中的 AT 文本必须严格按手册要求结束
3. 普通数据帧走业务转发路径,不应进入配置解析器
### 7.3 调试时重点检查什么
若怀疑 `MUX` 模式不工作,优先检查:
1. `App/uart_trans.c`
- `uart_mux_try_extract_frame()`
- `uart_mux_encode_frame()`
2. `Core/Src/main.c`
- `App_RouteMuxUartTraffic()`
- `App_RouteRawUartTraffic()`
- `App_RouteTcpTraffic()`
3. `App/config.c`
- `config_build_response_frame()`
- `config_process_at_cmd()`
推荐最小 MUX 联调顺序:
1. 先在 `MUX=0` 下跑通原始透传
2. 再切换 `MUX=1`
3. 先发一个控制帧,确认 `DSTMASK=0x00` 路径可通
4. 再发一个单目标数据帧,例如只打到 `S1`
5. 最后验证多目标位图转发
---
## 8. TCP / UART / CH390 联调顺序
### 8.1 先做链路,再做业务
`CH390` 初始化、链路和 IRQ 未被证明稳定前,不要先调高层 TCP/UART 业务。
### 8.2 推荐顺序
建议按以下顺序推进:
1. RTT 启动与 trap 状态正常
2. CH390 启动日志完整
3. 链路检测可信
4. `TCP server` / `TCP client` 建链可信
5. UART 原始透传可信
6. 再切入 `MUX` 模式联调
### 8.3 最小 TCP 调试工具
当需要验证板子是否真的把 payload 发到主机时,优先使用仓库内置最小工具:
1. `tools/tcp_debug_server.py`
- 打印连接、收包、文本视图和十六进制视图
2. `tools/start_tcp_debug_server.ps1`
- 会先清理冲突监听,再启动 Python 服务端
推荐命令:
```powershell
powershell -ExecutionPolicy Bypass -File ".\tools\start_tcp_debug_server.ps1" -Port 8081 -NoStdin
```
如需回显:
```powershell
powershell -ExecutionPolicy Bypass -File ".\tools\start_tcp_debug_server.ps1" -Port 8081 -Echo
```
直接运行 Python 服务端也可以:
```powershell
python .\tools\tcp_debug_server.py --host 0.0.0.0 --port 8081 --no-stdin
```
### 8.4 推荐验证方法
1. 先关闭 VOFA、`ncat` 和其它可能占用 `8081` 的进程
2. 启动 `start_tcp_debug_server.ps1`
3. 让板子连接主机 `TCP client` 目标端口
4. 再从主机连接板子的 `TCP server` 端口发送固定测试文本
5. 同时观察:
- Python 工具是否收到连接与 payload
- 板子 RTT 是否出现连接或错误信息
若板子 RTT 显示已连接,但主机工具无数据,优先检查本机端口占用而不是先改板端逻辑。
---
## 9. 异常、卡死与假死排查
### 9.1 看到 `TRAP:` 时怎么做
1. 先记录 RTT 中的 trap 标签
2. 立刻用调试器查看当前 PC / LR / 调用栈
3. 结合 `Core/Src/stm32f1xx_it.c` 中对应 handler 定位异常类型
### 9.2 没有 `TRAP:` 但系统不工作时怎么做
若没有 `TRAP:`,但系统表现异常,应优先区分以下情况:
1. 主循环仍在跑,只是业务路径没反应
2. 中断未到或链路未更新
3. 发生了阻塞式等待或超时问题
4. 上层工具接错端口或被错误进程抢占
### 9.3 历史上已经确认过的典型软件问题
以下问题在历史排查中已经出现过,应优先复核,不要重复踩坑:
1. PHY 访问无超时,导致永久卡死
2. 刷新未初始化的 IWDG 句柄导致 HardFault
3. 在长耗时 SPI 路径中错误扩大临界区,导致看似"系统假死"
4. 在多个层次同时触达 CH390 / SPI,导致运行时边界混乱
5. 配置口命令结束方式不对,导致误判为 parser 无响应
### 9.4 2026-04-14 MUX 模式网口失联修复记录
#### 现象
MUX 模式启动后,一段时间后网口失联。重新插拔网线无法恢复,重启后恢复正常。对端主动关闭 TCP 连接后,120 秒内无法重新建立连接。
#### 根因
对端主动关闭 TCP 连接时,`tcp_server_on_recv(p=NULL)``tcp_client_on_recv(p=NULL)` 调用 `tcp_close()` 关闭本地 pcb。`tcp_close()` 发送 FIN 后将 pcb 推入 TIME_WAIT 状态,持续 `2 × TCP_MSL = 120 秒`。在此期间 pcb 占用 `MEMP_TCP_PCB` 池(总量仅 4 个)。当多条连接同时断开后,pcb 池耗尽,新连接的 `tcp_new()` 返回 NULL。
#### 修复内容
| 文件 | 修改 | 说明 |
|------|------|------|
| `App/tcp_server.c` | `tcp_close(pcb)``tcp_abort(pcb)` | 对端关闭时立即释放 pcb,不进入 TIME_WAIT |
| `App/tcp_client.c` | `tcp_close(pcb)``tcp_abort(pcb)` | 同上 |
| `Drivers/CH390/ch390_runtime.c` | PKT_ERR 恢复时 `rcr``rcr \| RCR_RXEN` | 确保 RX 重新使能,与 WCH 官方参考一致 |
| `Drivers/CH390/ch390_runtime.c` | TX 连续超时 3 次触发 `ch390_runtime_emergency_reset()` | CH390 TX 引擎卡死时自动复位芯片 |
| `Drivers/CH390/ch390_runtime.c` | 新增 `ch390_runtime_health_check()` | 每 5 秒读 VID 验证芯片存活 |
| `Core/Src/main.c` | `App_StartLinksIfNeeded` 失败时不标记 `g_links_started` | 允许下次 poll 自动重试 |
| `Core/Src/main.c` | MUX 逐帧 RTT printf 改为 `#if DEBUG` 门控 | 生产固件不输出,减少主循环延迟 |
| `App/uart_trans.c` | `uart_mux_try_extract_frame` 先搜 0x7E 再消费 header | 非法帧只丢 1 字节而非 5 字节 |
#### 构建验证
Keil MDK-ARM 构建 0 Error(s), 0 Warning(s)。Flash 52.7 KB / 64.0 KB (82.5%)RAM 20.0 KB / 20.0 KB (100%)。
---
## 10. 常见误区
调试当前工程时,应避免以下误区:
1. 不要继续沿用“CH390 恒为全 `0xFF`”这一过时结论
2. 不要在 `main.c`、IRQ、netif 多处重新插入原始 CH390 访问
3. 不要在没有芯片脚侧证据前,只凭 MCU 侧 GPIO 判断总线正常
4. 不要在基础寄存器读写尚不可信时,直接调高层 `TCP/UART/MUX` 业务逻辑
5. 不要把一次性 bring-up 实验代码长期留在正式路径中
6. 不要让多个本机进程同时监听板子要连接的 TCP 端口
7. 不要在尚未证明命令已真正进入 parser 之前,直接归因到 Flash、协议或网络层
---
## 11. 推荐的现场记录模板
建议每次现场调试至少记录以下信息:
1. 日期时间
2. 板卡编号
3. 固件产物路径
4. 下载方式
5. RTT 关键日志
6. 串口发送内容
7. TCP 调试工具输出
8. 关键波形或电压量测点
9. 结论
10. 下一步动作
建议记录格式:
```text
时间:
板卡:
固件:
下载方式:
操作步骤:
RTT输出:
串口/TCP现象:
硬件量测:
结论:
下一步:
```
---
## 12. 当前推荐的结论表达方式
若需要向项目成员同步当前状态,建议采用以下口径:
1. 当前工程软件架构已稳定在 `bare-metal + lwIP RAW + ch390_runtime 单一拥有者`
2. 当前调试重点已经从“CH390 是否完全无响应”转移到协议、链路和系统级联调
3. 当前对外协议和配置模型应以 `MUX / NET / LINK[idx]` 为准
4. `USART1` 配置口、`USART2/3` 数据口与 TCP 路由必须按最新代码路径调试,不应再参照历史 `IP/MASK/GW/PORT/RIP/RPORT` 公开接口模型
5. 硬件验证仍必须以 CH390 芯片脚侧波形和供电域量测为准
---
## 13. 建议配套阅读
建议与本指导配套阅读:
1. `AT固件使用手册.md`
2. `项目技术实现.md`
3. `项目需求说明.md`
4. `uart-ch390-debug-handoff.md`
5. `CH390_最终结论报告.md`
6. `build_keil.log`
7. `PCB/SCH_Schematic1_2026-03-26.pdf`
8. `tools/tcp_debug_server.py`
9. `tools/start_tcp_debug_server.ps1`