Files
TCP2UART/项目技术实现.md
T
gaoro-xiao c21d85a9da refactor: 适配STM32F103RCT6 + FreeRTOS工程框架,同步baremetal-r8协议手册
- IOC: MCU切换为STM32F103RCTx,添加FREERTOS+TIM4中间件,HAL时间基准改为TIM4
- Keil uvprojx: 目标器件RC,Flash 256KB/48KB SRAM,宏xE,HD Flash算法,启动文件xe.s
- EWARM ewp: 宏xE,ICF/启动文件切换为xe版本
- 启动文件: Stack_Size 0x400→0x800适配FreeRTOS
- 重写项目需求说明/技术实现文档,描述FreeRTOS 5任务架构+lwIP NO_SYS=0
- 新增AT固件使用手册(MUX/NET/LINK协议)和工程调试指南(FreeRTOS专项)
2026-04-09 20:22:48 +08:00

454 lines
13 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 项目技术实现
## 一、文档目的
本文档描述 `TCP2UART` 项目基于 `STM32F103RCT6 + FreeRTOS` 的最终内部实现口径。
本文档只围绕最终协议模型展开:
- `MUX`:串口承载层
- `NET`:全局网络配置层
- `LINK[idx]`:实例配置与连接管理层
不再保留历史 `S1... / C1...` 外部字段模型。
## 二、当前工程基础
当前工程基础约束如下:
1. MCU`STM32F103RCT6`256KB Flash / 48KB SRAM
2. 网络芯片:`CH390D`
3. 软件架构:`FreeRTOS + lwIP NO_SYS=0`
4. 协议栈:`lwIP socket/netconn API`
5. 调试输出:`SEGGER RTT`
6. 使用 `FreeRTOS` 任务调度
7. 不实现 DHCP
## 三、总体架构
```text
+--------------------------------------------------+
| AT / Control Plane |
| USART1 AT parser + MUX control frame parser |
+--------------------------------------------------+
| Configuration Model |
| MUX / NET / LINK[idx] |
+--------------------------------------------------+
| FreeRTOS Tasks |
| NetworkTask / UartTask / ConfigTask / RouteTask |
+--------------------------------------------------+
| Inter-Task Communication |
| Queue / Semaphore / Mutex / StreamBuffer |
+--------------------------------------------------+
| lwIP TCP/IP Stack (NO_SYS=0) |
| tcpip_thread + socket/netconn + sys_arch |
+--------------------------------------------------+
| Driver Layer |
| CH390 / lwIP netif / UART DMA+IDLE / HAL |
+--------------------------------------------------+
```
## 四、FreeRTOS 任务设计
### 4.1 任务列表
| 任务名 | 优先级 | 栈大小 | 周期 | 职责 |
|--------|--------|--------|------|------|
| `NetworkTask` | osPriorityHigh (4) | 512 words | 事件驱动 | CH390 事件消费 + lwIP 超时处理 |
| `UartTask` | osPriorityHigh (4) | 512 words | 事件驱动 | UART DMA/IDLE 接收 + MUX 帧提取 |
| `ConfigTask` | osPriorityNormal (3) | 256 words | 事件驱动 | AT 命令解析与响应 |
| `RouteTask` | osPriorityNormal (3) | 512 words | 事件驱动 | SRCID/DSTMASK 数据路由分发 |
| `DefaultTask` | osPriorityLow (1) | 128 words | 1000ms 周期 | LED 心跳 + IWDG 喂狗 |
### 4.2 任务间通信机制
```text
UART ISR --[Semaphore]--> UartTask --[Queue]--> RouteTask --[Queue]--> NetworkTask
|
ConfigTask <--[Queue]-- RouteTask <--[Queue]-- NetworkTask <--------+
|
+--> UART TX (Direct DMA send)
```
具体通信对象:
| 对象 | 类型 | 生产者 | 消费者 | 用途 |
|------|------|--------|--------|------|
| `xUartRxQueue` | Queue (64 items) | UartTask | RouteTask | UART 接收帧传递 |
| `xTcpRxQueue` | Queue (32 items) | NetworkTask | RouteTask | TCP 接收数据传递 |
| `xConfigQueue` | Queue (16 items) | RouteTask | ConfigTask | AT 命令文本传递 |
| `xCh390Semaphore` | Binary Semaphore | EXTI0 ISR | NetworkTask | CH390 中断通知 |
| `xSpiMutex` | Mutex | NetworkTask | 多任务 | SPI/CH390 访问保护 |
| `xUart2TxStream` | StreamBuffer (1024) | RouteTask | UartTask | UART2 发送数据 |
| `xUart3TxStream` | StreamBuffer (1024) | RouteTask | UartTask | UART3 发送数据 |
### 4.3 NetworkTask 实现方向
```c
void NetworkTask(void *argument)
{
/* 初始化 CH390 + lwIP netif */
/* 创建 TCP Server/Client 实例 */
for (;;) {
/* 等待 CH390 中断信号量 */
xSemaphoreTake(xCh390Semaphore, pdMS_TO_TICKS(10));
/* 处理 CH390 事件 */
ethernetif_poll();
ethernetif_check_link();
/* lwIP 超时处理由 tcpip_thread 自动完成 */
/* TCP 数据收发 */
tcp_link_process();
}
}
```
### 4.4 UartTask 实现方向
```c
void UartTask(void *argument)
{
for (;;) {
/* 等待 UART IDLE 中断通知 */
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10));
/* 处理 UART2/UART3 DMA 接收数据 */
/* MUX=0: 直接投递到路由队列 */
/* MUX=1: 提取 MUX 帧,分流控制帧与数据帧 */
/* 检查 StreamBuffer,发送 UART TX 数据 */
}
}
```
### 4.5 ConfigTask 实现方向
```c
void ConfigTask(void *argument)
{
for (;;) {
/* 从配置队列接收 AT 命令文本 */
xQueueReceive(xConfigQueue, &cmd, portMAX_DELAY);
/* 解析并执行 AT 命令 */
config_process_at_cmd(cmd);
/* 通过 UART1 发送响应 */
}
}
```
### 4.6 RouteTask 实现方向
```c
void RouteTask(void *argument)
{
for (;;) {
/* 从 UART 队列和 TCP 队列读取数据帧 */
/* 根据 SRCID/DSTMASK 决定路由目标 */
/* 控制帧 (DSTMASK=0x00) -> ConfigTask */
/* 数据帧 -> TCP 实例或 UART TX */
}
}
```
## 五、最终协议实现模型
### 5.1 MUX 帧承载层
数据口启用 MUX 后,统一处理如下帧:
```text
SYNC | LEN_H | LEN_L | SRCID | DSTMASK | PAYLOAD | TAIL
```
实现职责:
1. 识别帧边界
2. 解析长度字段
3. 提取 `SRCID`
4. 解析 `DSTMASK`
5. 按控制帧或数据帧分流
### 5.2 控制帧与数据帧分离
控制规则固定如下:
- `DSTMASK = 0x00`:系统控制帧
- `DSTMASK != 0x00`:业务数据帧
系统控制帧处理要求:
1. `PAYLOAD` 解释为 AT 文本
2. AT 文本必须以 `\r\n` 结束
3. 控制帧投递到 `ConfigTask`
业务数据帧处理要求:
1. `SRCID` 表示单一源端点
2. `DSTMASK` 表示目标端点集合
3. `RouteTask` 根据 `DSTMASK` 做多目标分发
### 5.3 统一端点编码
内部与外部文档统一使用以下端点编码:
| 端点 | 编码 |
|------|------|
| `C1` | `0x01` |
| `C2` | `0x02` |
| `UART2` | `0x04` |
| `UART3` | `0x08` |
| `S1` | `0x10` |
| `S2` | `0x20` |
实现要求:
- `SRCID` 为单值
- `DSTMASK` 为位图
- `DSTMASK=0x00` 仅保留为控制帧
## 六、配置层设计
### 6.1 MUX 记录
`MUX` 为全局记录,仅控制设备数据口是否进入 MUX 承载模式。
取值:
- `0`:普通透传
- `1`MUX 透传
### 6.2 NET 记录
`NET` 为全局静态网络记录:
```text
IP,MASK,GW,MAC
```
说明:
- 设备只有一张网卡,因此不为每个实例单独配置本地 IP
- 当前实现目标中不包含 DHCP
### 6.3 LINK 记录
`LINK[idx]` 为统一实例记录:
```text
EN,LPORT,RIP,RPORT,UART
```
固定索引映射:
- `0 = S1`
- `1 = S2`
- `2 = C1`
- `3 = C2`
字段职责:
- `EN`:实例启用状态
- `LPORT`:本地端口
- `RIP / RPORT`:对端地址与端口
- `UART`:对应业务数据口
说明:
- `Server``Client` 共享同一记录结构
- `Server``RIP / RPORT` 可作为对端约束或预设
- `Client``RIP / RPORT` 表示远端目标
## 七、模块职责
### 7.1 配置模块 `config.c/.h`
最终职责:
1. 解析 `AT+MUX`
2. 解析 `AT+NET`
3. 解析 `AT+LINK`
4. 加载与保存配置
5. 处理 `SAVE / RESET / DEFAULT`
### 7.2 UART 透传模块 `uart_trans.c/.h`
最终职责:
1. 保持 `USART2 / USART3``DMA + IDLE` 接收发送基线
2.`MUX=0` 时执行普通透传
3.`MUX=1` 时执行 MUX 帧收发
4. 将控制帧与业务数据帧分流
### 7.3 TCP Server / Client 模块
最终职责:
1. 不再从外部协议角度区分不同字段模型
2. 统一受 `LINK[idx]` 配置驱动
3. 由调度层决定实例与 UART 的数据交换路径
### 7.4 FreeRTOS 初始化 `freertos.c`
CubeMX 生成的 FreeRTOS 初始化文件,职责:
1. 定义默认任务 `StartDefaultTask`
2. 用户在 `MX_FREERTOS_Init` 中创建自定义任务
### 7.5 FreeRTOS 配置 `FreeRTOSConfig.h`
关键配置项:
| 配置项 | 值 | 说明 |
|--------|-----|------|
| `configUSE_PREEMPTION` | 1 | 抢占式调度 |
| `configTICK_RATE_HZ` | 1000 | 1ms tick |
| `configMINIMAL_STACK_SIZE` | 128 | 最小栈(words |
| `configTOTAL_HEAP_SIZE` | 10240 | FreeRTOS 堆大小 |
| `configMAX_PRIORITIES` | 7 | 最大优先级数 |
| `configUSE_MUTEXES` | 1 | 启用互斥锁 |
| `configUSE_COUNTING_SEMAPHORES` | 1 | 启用计数信号量 |
| `configUSE_RECURSIVE_MUTEXES` | 1 | 启用递归互斥锁 |
| `configCHECK_FOR_STACK_OVERFLOW` | 2 | 栈溢出检测方式 2 |
| `configUSE_MALLOC_FAILED_HOOK` | 1 | 内存分配失败钩子 |
| `configSUPPORT_DYNAMIC_ALLOCATION` | 1 | 动态内存分配 |
## 八、lwIP 配置方向
### 8.1 lwIP 线程模型
由于采用 `NO_SYS=0`lwIP 将运行以下线程:
1. `tcpip_thread`:lwIP 核心线程,处理所有协议栈内部事件
2. 应用任务通过 `netconn` / `socket` API 与 lwIP 交互
### 8.2 lwIP 内存配置建议
| 配置项 | 建议值 | 说明 |
|--------|--------|------|
| `MEM_SIZE` | 8192 | lwIP 堆大小 |
| `MEMP_NUM_NETCONN` | 6 | netconn 连接数 |
| `MEMP_NUM_TCP_PCB` | 6 | TCP 控制块数 |
| `PBUF_POOL_SIZE` | 8 | pbuf 池大小 |
| `PBUF_POOL_BUFSIZE` | 1524 | pbuf 缓冲大小 |
| `TCP_WND` | 2048 | TCP 窗口大小 |
| `TCP_MSS` | 1460 | TCP 最大段大小 |
### 8.3 sys_arch 移植层
`Drivers/LwIP/port/sys_arch.c` 提供 lwIP 到 FreeRTOS 的适配:
1. `sys_thread_new`:创建 lwIP 线程
2. `sys_mbox_*`:消息邮箱(基于 FreeRTOS Queue
3. `sys_sem_*`:信号量(基于 FreeRTOS Semaphore
4. `sys_mutex_*`:互斥锁(基于 FreeRTOS Mutex
5. `sys_arch_protect / unprotect`:临界区保护
## 九、中断与 HAL 时间基准
### 9.1 HAL 时间基准
FreeRTOS 下 `SysTick` 被 FreeRTOS 占用,HAL 时间基准改用 `TIM4`
- `TIM4` 配置为 1ms 中断(72MHz / (71+1) / (999+1) = 1kHz
- `HAL_InitTick` 使用 `TIM4` 而非 `SysTick`
- `uwTick``TIM4_IRQHandler` 中递增
### 9.2 中断优先级规划
| 中断 | 优先级 | 说明 |
|------|--------|------|
| `SysTick` | 15(最低) | FreeRTOS tick |
| `PendSV` | 15(最低) | FreeRTOS 上下文切换 |
| `SVCall` | 0 | FreeRTOS 服务调用 |
| `TIM4` | 0 | HAL 时间基准 |
| `EXTI0` | 5 | CH390 中断 |
| `DMA1_Ch2~7` | 5 | UART DMA |
| `USART1/2/3` | 5 | UART 中断 |
| `SPI1` | 5 | SPI 中断 |
FreeRTOS 可管理的中断优先级必须 >= `configMAX_SYSCALL_INTERRUPT_PRIORITY`(本工程为 5)。
## 十、内存预算
`STM32F103RCT6` 为目标(48KB SRAM):
### 10.1 RAM 预算
| 项目 | 建议值 | 说明 |
|------|--------|------|
| 启动栈 (MSP) | 2 KB | startup_stm32f103xe.s 中定义 |
| FreeRTOS 堆 | 10 KB | heap_4.c 管理 |
| 任务栈合计 | ~6 KB | 5 个任务 |
| lwIP 堆 | 8 KB | MEM_SIZE |
| UART 缓冲 | 4 KB | RX/TX DMA 缓冲 |
| Queue/StreamBuffer | 4 KB | 任务间通信 |
| 参数/状态 | 2 KB | 配置结构 |
| 空闲栈 | 1 KB | 系统预留 |
| **合计** | ~37 KB | 预留约 11 KB 余量 |
### 10.2 Flash 预算
| 项目 | 估计值 | 说明 |
|------|--------|------|
| FreeRTOS 内核 | ~8 KB | 含 CMSIS-RTOS V2 |
| HAL 驱动 | ~20 KB | GPIO/UART/SPI/DMA/IWDG/TIM |
| lwIP 协议栈 | ~40 KB | core + api + ipv4 + netif |
| CH390 驱动 | ~4 KB | |
| 应用代码 | ~20 KB | config/uart_trans/tcp/route |
| **合计** | ~92 KB | 预留约 164 KB 余量 |
## 十一、硬件资源
### 11.1 MCU
- 型号:`STM32F103RCT6`
- Flash`256 KB`
- SRAM`48 KB`
- 主频:`72 MHz`
### 11.2 主要外设
- `SPI1`:连接 `CH390D`
- `USART1`:配置串口
- `USART2`:数据透传串口
- `USART3`:数据透传串口
- `DMA1`3 路 UART 收发 DMA
- `EXTI0`CH390 中断输入
- `IWDG`:独立看门狗
- `TIM4`HAL 时间基准(替代 SysTick
### 11.3 引脚分配
| 引脚 | 功能 | 用途 |
|------|------|------|
| PA2 | USART2_TX | 数据透传串口 |
| PA3 | USART2_RX | 数据透传串口 |
| PA4 | SPI1_NSS | CH390D 片选 |
| PA5 | SPI1_SCK | CH390D SPI 时钟 |
| PA6 | SPI1_MISO | CH390D SPI 数据输入 |
| PA7 | SPI1_MOSI | CH390D SPI 数据输出 |
| PA9 | USART1_TX | 配置串口 |
| PA10 | USART1_RX | 配置串口 |
| PB0 | EXTI0 | CH390D INT |
| PB1 | GPIO_Output | CH390D RESET |
| PB10 | USART3_TX | 数据透传串口 |
| PB11 | USART3_RX | 数据透传串口 |
| PC13 | GPIO_Output | 状态 LED |
| PD0/PD1 | HSE | 8MHz 外部晶振 |
## 十二、实现边界
1. 保持单网卡静态网络模型
2. 不实现 DHCP
3. 不实现旧 `S1... / C1...` 外部协议字段
4. 不在文档中保留兼容层描述
5. 所有 AT 文本控制统一要求 `\r\n` 结束
6. FreeRTOS 堆管理使用 `heap_4.c`
7. HAL 时间基准使用 `TIM4` 而非 `SysTick`
## 十三、文档一致性要求
后续实现、联调、测试与代码注释必须遵守以下统一口径:
1. 对外协议只使用 `MUX / NET / LINK`
2. 控制帧只使用 `DSTMASK=0x00`
3. MUX 帧格式固定为 `SYNC | LEN_H | LEN_L | SRCID | DSTMASK | PAYLOAD | TAIL`
4. AT 手册、需求说明、技术实现三份文档不得再出现历史展开式字段