Files
TCP2UART/项目技术实现.md
T

376 lines
10 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 项目技术实现(裸机迁移基线)
## 一、目标
当前分支 `baremetal-r8` 的目标不是一次性完成全部业务逻辑重写,而是先把工程基线切换到适合 `STM32F103R8T6` 的裸机方向,为后续继续开发提供统一入口。
本阶段已经完成或约束如下:
1. MCU 目标统一为 `STM32F103R8T6 / STM32F103xB`
2. `CubeMX IOC` 中已移除 `FreeRTOS` 中间件声明
3. 工程规划转为裸机轮询 + 中断驱动模型
4. 暂不在本阶段重写 TCP/串口业务逻辑
5. 保留现有源码作为迁移参考,后续由其他 Agent/开发者继续接力实现
## 二、硬件与资源约束
### 2.1 MCU
- 型号:`STM32F103R8T6`
- Flash`64 KB`
- SRAM`20 KB`
- 主频:`72 MHz`
### 2.2 主要外设
- `SPI1`:连接 `CH390D`
- `USART1`:配置串口
- `USART2`Server 透传串口
- `USART3`Client 透传串口
- `DMA1`3 路 UART 收发 DMA
- `EXTI0`CH390 中断输入
- `IWDG`:独立看门狗
### 2.3 当前引脚分配
| 引脚 | 功能 | 用途 |
|------|------|------|
| PA2 | USART2_TX | Server 透传串口 |
| PA3 | USART2_RX | Server 透传串口 |
| 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 | Client 透传串口 |
| PB11 | USART3_RX | Client 透传串口 |
| PC13 | GPIO_Output | 状态 LED |
| PD0/PD1 | HSE | 8MHz 外部晶振 |
## 三、为何从 FreeRTOS 迁移到裸机
`STM32F103R8T6` 的 RAM 只有 `20KB`。当前工程在引入如下组件后,链接空间明显不足:
1. `FreeRTOS` 内核
2. `CMSIS-RTOS V2` 包装层
3. 多任务栈
4. `lwIP + socket/netconn` OS 抽象层
5. 多路 `StreamBuffer / Semaphore / Mutex`
此前编译已经证明:
1. 源码层报错可修复
2. 统一 `R8` 型号后仍然在链接阶段失败
3. 主要瓶颈是 `RAM + Flash` 同时偏紧
因此本项目后续建议的主方向为:
1. 去掉 `FreeRTOS`
2. 去掉 `CMSIS-RTOS V2`
3. 避免依赖 `lwIP socket/netconn`
4. 采用裸机主循环 + DMA/IDLE/EXTI 中断驱动
5. 网络侧改为更贴近资源受限场景的实现模型
## 四、裸机架构目标
### 4.1 总体分层
```text
+--------------------------------------------------+
| Application State Machine |
| config / server link / client link / watchdog |
+--------------------------------------------------+
| Transport Scheduler |
| main loop polling + event flags + timeout scan |
+--------------------------------------------------+
| Network Interface |
| CH390 event polling / packet rx-tx dispatch |
+--------------------------------------------------+
| Peripheral Drivers |
| UART DMA+IDLE / SPI / GPIO / EXTI / Flash |
+--------------------------------------------------+
| STM32 HAL / CMSIS |
+--------------------------------------------------+
```
### 4.2 执行模型
不再使用任务调度器,改为以下模型:
1. `ISR` 只做最小事件置位与 DMA 状态更新
2. 主循环统一处理事件、超时、状态机推进
3. UART RX 继续依赖 `DMA + IDLE`
4. UART TX 可保留 `DMA`
5. CH390 中断只置位 `netif_pending`
6. 网络协议处理在主循环中推进
### 4.3 事件源
建议保留以下裸机事件位:
```c
typedef enum {
EVENT_NONE = 0x00000000u,
EVENT_CH390_INT = 0x00000001u,
EVENT_UART1_RX_IDLE = 0x00000002u,
EVENT_UART2_RX_IDLE = 0x00000004u,
EVENT_UART3_RX_IDLE = 0x00000008u,
EVENT_UART2_TX_DONE = 0x00000010u,
EVENT_UART3_TX_DONE = 0x00000020u,
EVENT_NET_TIMER_1MS = 0x00000040u,
EVENT_LINK_RETRY = 0x00000080u,
EVENT_CONFIG_PENDING = 0x00000100u,
} app_event_t;
```
这些事件位建议通过 `volatile uint32_t g_app_events` 或一个轻量原子位图维护。
## 五、建议的软件模块拆分
### 5.1 保留模块
以下模块可继续保留,但需要去除 RTOS 依赖:
1. `App/config.c`
2. `App/flash_param.c`
3. `App/tcp_server.*`
4. `App/tcp_client.*`
5. `App/uart_trans.*`
6. `Drivers/CH390/*`
7. `Drivers/LwIP/*` 或后续替代网络栈
### 5.2 需要改造的核心模块
1. `Core/Src/main.c`
2. `Core/Src/stm32f1xx_it.c`
3. `Core/Src/usart.c`
4. `Core/Src/dma.c`
5. `Core/Src/freertos.c`:后续应移除出构建或清空为兼容壳
6. `Core/Inc/FreeRTOSConfig.h`:后续可移除出工程
7. `Drivers/LwIP/port/sys_arch.c`:若完全去 OS,应停止使用该移植层
8. `Drivers/LwIP/src/include/arch/sys_arch.h`
### 5.3 建议新增的裸机模块
建议后续新增:
1. `App/app_scheduler.c/.h`
- 统一处理事件位
- 驱动周期任务
- 执行状态机推进
2. `App/app_net.c/.h`
- 网络初始化
- CH390 事件分发
- 链路保活/重连
3. `App/app_uart.c/.h`
- UART DMA/IDLE 收发整合
- 与网络方向的缓冲协调
4. `App/app_time.c/.h`
- 基于 `SysTick` 的毫秒计时
- 软件超时管理
## 六、裸机下的关键技术决策
### 6.1 延时与时间基准
建议统一使用:
1. `SysTick 1ms` 全局时基
2. 禁止在主业务路径使用长阻塞 `HAL_Delay`
3. 超时逻辑统一基于 `tick_now - tick_start`
示例:
```c
uint32_t app_now_ms(void);
bool app_is_timeout(uint32_t start, uint32_t timeout_ms);
```
### 6.2 UART 接收模型
保持 `DMA + IDLE` 是合理的,原因:
1. 可降低 CPU 占用
2. 适合串口透传场景
3. 便于在裸机下维持较高吞吐
建议 UART RX 流程:
1. DMA 持续接收至环形或双缓冲
2. IDLE 中断触发“本帧结束”
3. ISR 只记录长度与事件位
4. 主循环消费数据并决定转发方向
### 6.3 UART 发送模型
建议继续使用 `DMA TX`
1. 发送启动在主循环中执行
2. DMA 完成中断只清 busy 标志并置 `TX_DONE` 事件
3. 发送缓冲统一由应用层管理
### 6.4 CH390 访问模型
裸机下不再需要 `mutex`,但仍需保证上下文一致性:
1. ISR 内不要执行复杂 SPI 事务
2. EXTI 仅置位 `EVENT_CH390_INT`
3. 所有 CH390 SPI 读写都在主循环中完成
4. 若必须与 DMA 回调共享状态,使用短临界区保护
### 6.5 网络栈路线
这里需要后续 Agent 决定最终实现路线,建议二选一:
1. `lwIP RAW API + NO_SYS=1`
- 优点:仍保留成熟 TCP/IP 栈
- 缺点:迁移复杂度较高,需要重写当前 `socket/netconn` 依赖
2. 基于现有 CH390 资料,评估是否存在更轻的直接 socket/简化协议接口
- 优点:可能进一步减小资源占用
- 缺点:功能边界和维护成本需重新评估
当前更推荐的长期路线是:
`lwIP RAW API + NO_SYS=1`
因为这条路线与现有 CH390 + 以太网驱动结构更连续。
## 七、主循环设计建议
建议采用固定骨架:
```c
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_IWDG_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_USART3_UART_Init();
MX_SPI1_Init();
app_time_init();
app_uart_init();
app_net_init();
app_config_init();
while (1)
{
app_poll_events();
app_process_config();
app_process_uart_links();
app_process_network();
app_process_timeouts();
app_feed_watchdog();
}
}
```
设计原则:
1. 所有步骤可重入或幂等
2. 每轮主循环不可长时间阻塞
3. 网络与串口处理都要支持“分段推进”
## 八、建议的状态机拆分
### 8.1 TCP Server 链路
```text
IDLE -> LISTEN -> CONNECTED -> CLOSING -> LISTEN
```
### 8.2 TCP Client 链路
```text
IDLE -> RESOLVE/CONFIG -> CONNECTING -> CONNECTED -> RETRY_WAIT -> CONNECTING
```
### 8.3 配置口
```text
IDLE -> RX_FRAME_READY -> PARSE -> EXECUTE -> RESPOND -> IDLE
```
### 8.4 CH390 网口
```text
RESET -> INIT -> LINK_CHECK -> RUNNING -> ERROR_RECOVER -> INIT
```
## 九、内存预算建议
`STM32F103R8T6` 为目标,后续实现应尽量遵循:
### 9.1 推荐 RAM 预算
| 项目 | 建议值 | 说明 |
|------|--------|------|
| 启动栈 | 1 KB | `startup` 保留 |
| C Heap | 0 | 默认关闭 |
| UART1 RX/TX | 384 B | 配置口 |
| UART2 RX/TX | 1 KB | 透传链路 |
| UART3 RX/TX | 1 KB | 透传链路 |
| 网络收发缓存 | 2-4 KB | 视协议栈路线而定 |
| 参数/状态结构 | < 2 KB | 控制状态 |
### 9.2 原则
1. 避免动态分配
2. 优先静态缓冲 + 明确大小
3. 单向链路缓冲优先复用
4. 所有大缓冲区要在文档中登记
## 十、当前已完成的工程侧修改
本分支当前已经完成:
1. `R8/xB` 型号统一
2. MDK 启动文件切换到 `startup_stm32f103xb.s`
3. `IOC` 中移除 `FREERTOS` 中间件声明
4. `PendSV/SVCall` 不再作为 RTOS 中断入口保留
5. `Heap/Stack` 的工程默认值收缩到更适合 `R8`
## 十一、后续 Agent 接手时应优先处理的事项
### 11.1 工程配置层
1.`MDK-ARM/TCP2UART.uvprojx` 中移除 `FreeRTOS` 源文件组
2. 从包含路径中移除 `CMSIS_RTOS_V2``FreeRTOS` 路径
3. 视需要移除 `Core/Src/freertos.c`
4. 视需要移除 `Core/Inc/FreeRTOSConfig.h`
### 11.2 代码层
1. 将所有 `osThreadNew``vTaskDelay``xStreamBuffer*``xSemaphore*``xMutex*` 调用替换为裸机实现
2.`lwIP``NO_SYS=0` 路线迁移到裸机可用路线
3. 重写 `CH390` 事件处理为主循环驱动
4. 重写 UART 透传调度逻辑为状态机
### 11.3 风险点
1. 当前 `socket/netconn` 方案不能直接脱离 OS 使用
2. `sys_arch` 相关移植层最终应被清退
3. 原来依赖任务切换“自然解耦”的路径,迁移到裸机后必须明确状态和时序边界
## 十二、交接说明
当前分支适合作为“裸机迁移起点”,但不是最终可编译成品。它的价值在于:
1. 目标器件与工程元数据已经统一
2. `CubeMX` 方向已经从 `FreeRTOS` 转向裸机
3. 技术实现文档已明确后续重构路线
接下来的工作重点应由后续 Agent 在此基线上继续完成逻辑代码迁移。