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

10 KiB
Raw Blame History

TCP2UART 项目技术实现(裸机迁移基线)

一、目标

当前分支 baremetal-r8 的目标不是一次性完成全部业务逻辑重写,而是先把工程基线切换到适合 STM32F103R8T6 的裸机方向,为后续继续开发提供统一入口。

本阶段已经完成或约束如下:

  1. MCU 目标统一为 STM32F103R8T6 / STM32F103xB
  2. CubeMX IOC 中已移除 FreeRTOS 中间件声明
  3. 工程规划转为裸机轮询 + 中断驱动模型
  4. 暂不在本阶段重写 TCP/串口业务逻辑
  5. 保留现有源码作为迁移参考,后续由其他 Agent/开发者继续接力实现

二、硬件与资源约束

2.1 MCU

  • 型号:STM32F103R8T6
  • Flash64 KB
  • SRAM20 KB
  • 主频:72 MHz

2.2 主要外设

  • SPI1:连接 CH390D
  • USART1:配置串口
  • USART2Server 透传串口
  • USART3Client 透传串口
  • DMA13 路 UART 收发 DMA
  • EXTI0CH390 中断输入
  • 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 总体分层

+--------------------------------------------------+
| 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 事件源

建议保留以下裸机事件位:

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

示例:

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 + 以太网驱动结构更连续。

七、主循环设计建议

建议采用固定骨架:

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 链路

IDLE -> LISTEN -> CONNECTED -> CLOSING -> LISTEN

8.2 TCP Client 链路

IDLE -> RESOLVE/CONFIG -> CONNECTING -> CONNECTED -> RETRY_WAIT -> CONNECTING

8.3 配置口

IDLE -> RX_FRAME_READY -> PARSE -> EXECUTE -> RESPOND -> IDLE

8.4 CH390 网口

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_V2FreeRTOS 路径
  3. 视需要移除 Core/Src/freertos.c
  4. 视需要移除 Core/Inc/FreeRTOSConfig.h

11.2 代码层

  1. 将所有 osThreadNewvTaskDelayxStreamBuffer*xSemaphore*xMutex* 调用替换为裸机实现
  2. lwIPNO_SYS=0 路线迁移到裸机可用路线
  3. 重写 CH390 事件处理为主循环驱动
  4. 重写 UART 透传调度逻辑为状态机

11.3 风险点

  1. 当前 socket/netconn 方案不能直接脱离 OS 使用
  2. sys_arch 相关移植层最终应被清退
  3. 原来依赖任务切换“自然解耦”的路径,迁移到裸机后必须明确状态和时序边界

十二、交接说明

当前分支适合作为“裸机迁移起点”,但不是最终可编译成品。它的价值在于:

  1. 目标器件与工程元数据已经统一
  2. CubeMX 方向已经从 FreeRTOS 转向裸机
  3. 技术实现文档已明确后续重构路线

接下来的工作重点应由后续 Agent 在此基线上继续完成逻辑代码迁移。