项目架构
super_agent_bot edited this page 2026-11-02 07:55:38 +08:00

项目架构

一页看清: 分层、任务、启动顺序、线程间通信与数据流。细节以 docs/架构设计/项目架构总览.md、docs/架构设计/项目启动顺序管理.md 和源码为准。

本页基于 2026-11-01 的 master 分支整理; 当前任务表以 Src/freertos.c 为准(9 个任务)。

1. 分层架构

项目分层架构: 应用层到硬件七层单向依赖

图: 七层单向依赖 - 上层只依赖相邻下层.

设计原则: 上层只依赖相邻下层, 单向依赖; UI 层与基础服务层同级并列; 业务层(net_cfg)是顶层共享配置。

层 目录 职责 关键模块
① 业务层 Drivers/BSP/NETCFG/ 顶层共享配置, 被 UI 与基础服务共用 net_cfg
② UI 层 Drivers/BSP/UI/ LVGL 界面, 与 PC 模拟器共用源码 ui_menu / ui_content_page / ui_page_* / ui_net_sink
③ 基础服务层 App/、Drivers/BSP/NET/lftpd/ 应用编排、任务、日志、对时、FTP app_main / sys_events / task/* / lftpd / time_sync
④ 中间件层 Drivers/BSP/NET/、Lib/、App/util/ 通用库与协议栈 net_socket / net_select / FatFs / dhara FTL / LVGL / sys_clock
⑤ 驱动层 Drivers/BSP/{CH395F,GD5F2GQ5UE,TPAFE5160,SD2506,RS485}/ 芯片寄存器、时序、中断 ch395f / gd5f2gq5ue / tpafe5160 / sd2506 / rs485
⑥ 内核 / HAL Middlewares/、Drivers/STM32F4xx_HAL_Driver/、Drivers/CMSIS/ 调度、外设 HAL、启动 FreeRTOS V10.3.1 · STM32 HAL · CMSIS
⑦ 硬件 — STM32F407ZGTx @168 MHz SPI1/SPI2/I2C1/UART4/USART1/DMA/GPIO/TIM7/TIM3

关键跨层调用: UI 的网口设置页只读写 net_cfg 的 RAM 副本, 不直接触 CH395F; FTP / 对时 / 远程显示 / 104 都经 net_socket; 所有 CH395F 操作最终串行化到 netTask。

2. 运行时任务(9 个)

九个 FreeRTOS 任务的栈预算

图: 任务栈预算 - 栈从 CCM 的 FreeRTOS 堆分配.

任务由 Src/freertos.c 创建, 任务体在 App/task/、App/sync/ 与 App/algo/。栈单位为 words(x4 = 字节)。

任务 栈(words) 优先级 职责
defaultTask 1280 Normal FatFS 挂载/自愈、配置引擎属主、syslog 唯一写者、控制台唯一发送者、LED、栈水位、看门狗唯一喂狗者
netTask 960 Normal 网络 bring-up、CH395F 轮询、socket 消息串行执行、网络重建
ftpTask 1024 Normal 等网络 + 存储双就绪后启动 FTP(21), 单客户端会话循环
testTask 2048 BelowNormal 板端测试套件入口; 产品构建不选套件时立即删除回收 8 KB 栈
uiTask 4096 BelowNormal LVGL 初始化、菜单/内容页、待机屏、10 ms 刷新、远程推流
timeSyncTask 640 Normal TCP 8888 接收 PC 推送时间并写 RTC
adcTask 640 AboveNormal 1 kHz 采样节拍消费者: TPAFE 原子快照 + STM32 ADC1 DMA; 喂 TASK_WD_ADC
iec104Task 640 Normal IEC 60870-5-104 被控站服务(TCP 2404); 喂 TASK_WD_IEC104
protectTask 512 Normal 20 ms 保护判据节拍: prot_elm_run()、采样故障闭锁、定值校验; 喂 TASK_WD_PROTECT

idle / timer 由 FreeRTOS 内核创建。任务栈从 CCM 中的 FreeRTOS heap 分配, 不占主 SRAM。 改栈或加大局部变量前后必须重跑 scripts/stack_report.py; 新增任务前先核算 RAM 预算(见开发指南)。

3. 就绪屏障(Event Flags)

Event Flags 就绪屏障: 生产者置位, 消费者等待

图: 就绪屏障 - 状态位 NoClear, 命令位消费.

任务启动顺序不靠魔法延时, 而靠 CMSIS-RTOS2 Event Flags(sys_evtHandle)。生产者置位, 消费者等待。

bit 名称 类型 语义
0 SYS_EVT_NET_READY 状态位 netTask: 网络初始化 + PHY 稳定完成
1 SYS_EVT_STORAGE_READY 状态位 defaultTask: FTL/FatFS 挂载 + 配置就绪
2 SYS_EVT_FTP_READY 状态位 ftpTask: FTP 启动完成(预留)
3 SYS_EVT_TIMESYNC_READY 状态位 首次对时完成(预留)
4 SYS_EVT_NET_RECONFIG 命令位 UI 请求立即应用新网口配置
5 SYS_EVT_CFG_SAVE 命令位 UI 请求保存配置(defaultTask 消费)
6 SYS_EVT_CONSOLE_TX 命令位 控制台环形缓冲有数据待发送
7 SYS_EVT_PROT_SET_SAVE 命令位 保护定值脏, 请求落盘

两条铁律:

  • 状态位必须 osFlagsNoClear: 就绪位表达持久状态, 任何消费者都不许消费它。曾因默认消费导致 ftpTask 的 WaitAll 永不成立、21 端口静默不监听。
  • 命令位必须消费型: 命令位要恰好被消费一次, 否则会反复写盘或反复重建网络。

4. 启动时序

sequenceDiagram
    participant M as 复位 / main.c
    participant A as app_main_init
    participant K as FreeRTOS
    participant T as 任务
    M->>M: HAL_Init + 时钟 + 外设
    M->>A: fault_handler_enable
    A->>A: syslog + 复位原因
    A->>A: SD2506 + sys_clock
    A->>A: RS-485 / NAND / TPAFE
    A->>A: 采集处理 / 相量 / 测频 / 保护判据
    A->>A: SD2506 诊断 + TIM3 1 kHz
    A->>K: osKernelInitialize / MX_FREERTOS_Init
    K->>T: osKernelStart
    T-->>T: 就绪屏障 + 节拍运行

osKernelStart 之前是“内核前模式”: 禁止任何 FreeRTOS/CMSIS-RTOS 创建类 API; 只能用纯寄存器/HAL 轮询、无锁静态缓冲, 内核启动后再惰性创建真正的队列。详见 docs/架构设计/项目启动顺序管理.md。

5. 数据流

5.1 采集与保护

flowchart TB
    TIM["TIM3 更新事件<br/>1 kHz"] -->|CONVST| T["TPAFE5160<br/>8 路电气量<br/>并行 16 位"]
    TIM -->|TRGO| A["STM32 ADC1<br/>9 路<br/>DMA 连续请求"]
    T --> S["原子快照"]
    A --> S
    S --> TASK["adcTask<br/>纯消费者<br/>每拍 poll"]
    TASK --> L1["采集处理层<br/>adc_input / adc_health"]
    L1 --> L2["相量层<br/>sample_ring / phasor"]
    L2 --> F["测频<br/>freq"]
    L2 --> L3["保护判据层<br/>prot_set / prot_elm"]
    L3 --> P["protectTask<br/>20 ms"]
    F --> M["遥测快照<br/>meas 200 ms"]
    M --> I["IEC 60870-5-104<br/>TCP 2404"]
    P --> I

详见采集与算法。

5.2 存储

flowchart TB
    APP["应用 / FTP / 配置 / 日志"] --> FF["FatFs FAT32"]
    FF --> D["diskio"]
    D --> FTL["dhara FTL"]
    FTL --> N["GD5F2GQ5UE NAND"]

defaultTask 是配置引擎属主与 syslog 唯一写者; ftpTask 通过 FatFs 读写, FatFs 打开 FF_FS_REENTRANT 做卷级互斥。详见存储子系统。

5.3 网络

flowchart TB
    CH["CH395F SPI2"] --> NS["net_socket + net_select"]
    NS --> Q["netMsgQueue 深度 8"]
    Q --> NT["netTask 串行执行"]
    NT --> FTP["FTP :21"]
    NT --> TS["对时 :8888"]
    NT --> UI["远程显示 :7003"]
    NT --> IEC["IEC 104 :2404"]

CH395F 是单连接模型: Socket 0 复用监听与数据通道, 四个 TCP 服务串行占用连接, 断开后自动回 LISTEN。详见网络子系统。

5.4 UI 与日志

  • UI: uiTask 把 LVGL 渲染到 160x160、1bpp 的 g_ui_fbuf(3200 B), 经 ui_net_sink 在 TCP 7003 推流; 远端按键回注。
  • 日志: syslog_post() 写定长 64 B 记录到 /log/run.log / /log/selftest.log; 实时调试流走 USART1, 由 defaultTask 单写者发送。
  • 看门狗: 各任务置心跳位, defaultTask 每 100 ms 采样, 连续 800 ms 不达标就停止喂 IWDG, 约 2.5 s 后复位。

6. 线程间通信与单写者

机制 对象 用途
Event Flags sys_evtHandle 启动屏障、配置保存、网络重建、控制台、定值落盘
Message Queue netMsgQueue(深度 8) 所有 CH395F 操作串行化到 netTask
任务通知 xTaskNotify() net_* 公开 API 的错误码回传(net_msg_t 按值拷贝, 改副本调用方看不到)
环形缓冲 控制台 4 KB 多任务日志入队, defaultTask 唯一发送

单写者纪律: 配置文件属主 = defaultTask; syslog 唯一写者 = defaultTask; 控制台唯一发送者 = defaultTask。netTask/uiTask 不得直接触碰配置引擎。

7. 目录地图

目录 职责 可改性
Src/ Inc/ CubeMX 生成: main.c、freertos.c、HAL 外设、中断、时基 只写 USER CODE 区
App/ 应用层: app/ 启动与就绪事件、task/ 任务、algo/ 采集与算法、cfg/ 配置、log/ 日志、fs/ 卷锁、sync/ 对时、util/ 工具 手写
Drivers/BSP/ 手写驱动与服务: TPAFE5160 / CH395F / NET(socket + lftpd)/ NETCFG / GD5F2GQ5UE / SD2506 / RS485 / UI 手写
Drivers/STM32F4xx_HAL_Driver/ Drivers/CMSIS/ Middlewares/ ST HAL / CMSIS / FreeRTOS 第三方, 只读
Lib/ LVGL、FatFs、dhara + MCU 端 lv_conf.h 只读(本地补丁须登记)
MDK-ARM/ Keil 工程、scatter、下载脚本 工程配置手改; UV4 抖动不入库
simulator/ LVGL PC 模拟器(CMake + SDL2), 与固件同标准受检 手写
test/ board/ 板级套件、host/ 主机侧单测与脚本 手写
scripts/ tools/ 门禁与报告脚本、配图/字体/菜单生成器 手写
docs/ 全量设计/测试/规范文档(入口 docs/README.md) 手写, 受 doc-links 门禁
.dsh/skills/ .gitea/ .serialtest/ agent skills、CI 工作流、串口/烧录配置 手写

8. 延伸阅读

主题 文档
全景架构(图 + 跨层依赖) docs/架构设计/项目架构总览.md
启动顺序与内核前模式 docs/架构设计/项目启动顺序管理.md
存储栈 docs/架构设计/STM32F4-Base存储架构说明.md
产品需求基线 docs/产品需求/产品需求设计文档.md
看门狗 docs/子系统设计/看门狗设计说明.md
ADC 采样节拍 docs/子系统设计/ADC采样节拍设计说明.md
IEC 104 docs/子系统设计/IEC104上行设计说明.md
内存预算 docs/内存管理/RAM使用分析与优化方案.md