# 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 在此基线上继续完成逻辑代码迁移。