Files
STM32F4-Base/docs/架构设计/系统架构与硬件规格.md
T
wandering1 4a4ad6bc5f chore(全仓): @build/@test 旧文档别名清退为技能调用名
现状口径:/keil-build 与 /serial-boot-test 是 DSH 会话的技能调用名,
不是 shell 命令;「名 + 命令行参数」的命令形态改为可执行体
run_boot_test.py 的真实调用。

- AGENTS.md:别名说明重写为「技能调用名不是 shell 命令」,两条目改
  「编译(/keil-build)」「串口回归(/serial-boot-test)」
- keil-build / serial-boot-test 两 skill 调用名与示例同步;task-worktree
  方案文档去掉 @build/@test 惯例从句;@task 保留(不在点名范围)
- 123 文件现状陈述全改;台架捕获、变更记录/时间线、rename 映射输入
  等 41 行历史证据保留旧名
- gen_memory_svg.py 6 处措辞随改,3 张 SVG 产物同批重跑
- 顺手补并行方案同行漏网计数 51→52 钩子

验证:提交期快钩子对 123 文件实跑全 Passed;check_doc_links --all
rc=0(3038 处、无法判定 0);check_mermaid --all rc=0;YAML 解析 52
钩子不变;skill-size rc=0;py_compile 全过;字节卫生零漂移。
2026-10-30 13:03:12 +08:00

17 KiB
Raw Blame History

STM32F4-Base 系统架构与硬件规格

文档定位:全仓系统运行时架构与硬件规格(V0.1)的权威表档——自 docs/产品需求/产品需求设计文档.md v1.9 的原 §3/§4 拆出(需求与验收口径仍在需求档)。 与 docs/架构设计/项目架构总览.md 的分工:总览是叙述性全景, 本档是完整口径表——就绪屏障位表(bit0~8)、线程间通信机制表、启动时序图、 引脚分配表、硬件能力边界表以本档为准,两处冲突以本档为准并回改总览。 硬件口径:V0.1(docs/硬件平台/V0.1_网表详细分析报告.md + Inc/main.h)。

1. 系统运行时架构

1.1 六层分层架构

STM32F4-Base 项目分层架构

上图由 tools/arch_diagram/gen_arch_svg.py 生成(手绘 SVG,零连线交叉);改架构后编辑脚本顶部 ROWS 数据重跑即可,源数据与下表一致。

分层原则:上层只依赖相邻下层(单向);① 业务层为顶层(仅 net_cfg,被 UI 与基础服务共用), ② UI 层与 ③ 基础服务层同级并列。

层 目录 职责 关键模块
① 业务层 Drivers/BSP/NETCFG/ 顶层共享配置(被 UI 与基础服务共用) net_cfg
② UI 层 Drivers/BSP/UI/ LVGL 界面(与 PC 模拟器共用源码) ui_port ui_menu ui_menu_view ui_menu_tab ui_content_page ui_page_* ui_net_sink ui_font_cn_12 ui_deco
③ 基础服务层 App/、Drivers/BSP/NET/lftpd/ 应用侧服务、采集算法与协议编排 app_main sys_events app_cfg task/* algo/*(语义取数与有效性~保护判据)protocol/iec104/* log/soe_store lftpd time_sync
④ 中间件层 Drivers/BSP/NET/、Lib/、App/util/ 通用库 / 协议栈 net_socket net_select FatFs nand_ftl(dhara) 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 @168MHz SPI1 / SPI2 / I2C1 / UART4 / USART1 / DMA / GPIO / TIM7

1.2 运行时任务模型

九个 FreeRTOS 任务(Src/freertos.c 创建,任务体在 App/task/、App/sync/):

任务 栈(words / B) 优先级 职责
defaultTask 1280 / 5120 Normal FatFS 挂载(无卷 f_mkfs)→ 卷健康探针/自愈 → net_cfg_load + 定值/运行参数/通讯参数装载(配置引擎属主)→ 置 STORAGE_READY → 日志落盘(唯一写者)+ 2 s 配置轮询 + 各模块脏位落盘(prot_set / run_par / comm)+ SOE 排空 + LED 闪烁 + 栈水位观测 + 看门狗唯一喂狗者
netTask 960 / 3840 Normal 等存储 → net_stack_bring_up() → 置 NET_READY → net_poll 轮询 + CH395F 操作串行化(消息队列执行者)
ftpTask 1024 / 4096 Normal 等网络且存储(WaitAll)→ lftpd_start("/", 21) → 单客户端会话循环
testTask 2048 / 8192 BelowNormal 测试套件入口(test/board/test_config.h 选择)。产品构建不创建(未选套件时立即 vTaskDelete 回收其 8 KB CCM 栈)
uiTask 4096 / 16384 BelowNormal 等网络 → ui_port_init/ui_menu_init/ui_standby_init(空闲 60 s 切待机屏)/ui_net_sink → 10 ms 刷新 + 数据注入
timeSyncTask 640 / 2560 Normal 等网络 → TCP :8888 收 PC 推送时间 → 写 RTC
adcTask 640 / 2560 AboveNormal 采集主线唯一消费者:每拍 adc_input_poll()(TPAFE 快照 + ADC1 DMA 帧)→ adc_health 有效性 → phasor_run() 相量 → freq_run() 测频 → 每 200 ms meas_tick() 发布遥测快照
iec104Task 640 / 2560 Normal 等网络 → TCP :2404 监听 → 104 链路状态机(总召/变位/周期/遥控/定值/对时)+ 断链重听 + 网络代次自愈
protectTask 512 / 2048 Normal 20 ms 判据节拍:采样故障闭锁判定 → 定值校验和巡检 → prot_elm_run() 元件判据 → 动作边沿投递 SOE(不做 NAND I/O)

idle(128 words)/ timer(256 words)由 FreeRTOS 内核创建。所有任务栈从 56 KB heap_4 堆 (CCM)分配;CCM 水位 87.9%(<92% 门禁)。 任务表与 Src/freertos.c 的 osThreadAttr_t 一致,由 scripts/gen_task_table.py 生成并门禁校验; 栈配置与实测余量见 ../产品需求/产品需求设计文档.md §7.3,改栈前后必须重跑 scripts/stack_report.py。

⚠ 节拍同源:TIM3 更新事件(1 kHz)同时触发 TPAFE CONVST 与(经 TRGO)ADC1 一轮 9 通道扫描, 并在 ISR 内唤醒 adcTask——采集节拍与任务唤醒不允许各自计时。 ⚠ ADC1 必须在挂 DMA 的瞬间处于关闭态:app_main_init() 步骤 4b-pre 的 adc1_disable() 不可删、不可后移, 否则 DMA 乒乓缓冲整体旋转 2 格(表象与"映射表写错"一致)。证据见 docs/子系统设计/ADC采样节拍设计说明.md §4.5。

1.3 就绪屏障(Event Flags)

就绪屏障(Event Flags)

用 CMSIS-RTOS2 Event Flags(sys_evtHandle)表达"子系统就绪",取代魔法延时与全局标志轮询。 生产者与消费者互不知晓,只经事件组解耦;新增子系统只需定义新 bit + 各自 wait/set。

位 名称 类型 语义
bit0 SYS_EVT_NET_READY 状态位 netTask:net_init + PHY 稳定完成
bit1 SYS_EVT_STORAGE_READY 状态位 defaultTask:FTL/FatFS 挂载 + 配置就绪
bit2 SYS_EVT_FTP_READY 状态位 ftpTask:lftpd_start 完成
bit3 SYS_EVT_TIMESYNC_READY 状态位 timeSyncTask:首次时间同步完成
bit4 SYS_EVT_NET_RECONFIG 命令位 UI:请求立即应用新网口配置
bit5 SYS_EVT_CFG_SAVE 命令位 UI:网口配置保存请求(defaultTask 消费并写盘)
bit6 SYS_EVT_CONSOLE_TX 命令位 控制台单写者:生产者入环形缓冲后置位
bit7 SYS_EVT_PROT_SET_SAVE 命令位 保护定值落盘请求:104 检测到定值脏后置位,defaultTask 原子写 /prot_set.bin
bit8 SYS_EVT_RUN_PAR_SAVE 命令位 运行参数段落盘请求:104 写运行参数后置位,defaultTask 整档外科保存

⚠️ 铁律:状态位(bit03)表达持久状态,任何消费者都不许消费——必须 osFlagsWaitAny|osFlagsNoClear。命令位(bit48)表达"请做一件事",必须恰好被消费一次(消费型等待)。 历史事故:就绪位被先到的等待者消费,导致 ftpTask 的 WaitAll(bit0|bit1) 永不成立、21 端口从未监听(静默)。

1.4 启动时序

sequenceDiagram
    autonumber
    participant M as main
    participant A as app_main_init
    participant K as osKernelStart
    participant D as defaultTask
    participant N as netTask
    participant S as adcTask / protectTask
    participant F as ftpTask
    participant U as uiTask
    participant I as iec104Task / timeSyncTask

    M->>M: HAL_Init + CubeMX 外设初始化<br/>(SPI1/SPI2/I2C1/UART4/USART1/DMA/GPIO/TIM3/TIM7)
    M->>A: app_main_init()
    Note over A: 时间子系统优先,使后续日志带时间戳
    A->>A: sd2506_init() → sys_clock_init()(墙钟基准)
    A->>A: rs485_init() → gd5f2gq5ue_init()(BBT 扫描)
    A->>A: tpafe5160_init() → adc_input_init()(语义映射自检)
    A->>A: 配置段注册(adc_cal / run_par / prot_set / comm)→ 定值/元件初始化
    A->>A: adc1_disable() → ADC1 挂 DMA(4b-pre,顺序不可变)→ 启动 TIM3 1 kHz 节拍
    A-->>M: "App init OK"
    M->>K: osKernelStart()
    K->>D: 调度
    D->>D: f_mount(无卷则 f_mkfs FAT32)→ 卷探针/自愈 → 配置装载<br/>→ 定值整表原子装载(损坏则保出厂默认 + 自检留痕)
    D-->>N: set SYS_EVT_STORAGE_READY
    S->>S: adcTask:等 TIM3 节拍 → 采集 → 相量/测频 → 200 ms 遥测快照
    S->>S: protectTask:20 ms 判据(未标定/采样故障则停走)
    N->>N: wait STORAGE_READY(Any|NoClear)→ net_init(ip,mask,gw,mac)<br/>→ PHY 强制 100M 全双工 → 等链路 ≤3s
    N-->>F: set SYS_EVT_NET_READY
    F->>F: wait NET_READY|STORAGE_READY(All|NoClear)→ lftpd_start("/", 21)
    U->>U: wait NET_READY(Any|NoClear)→ ui_port_init → ui_menu_init → ui_net_sink_start(7003)
    I->>I: wait NET_READY(Any|NoClear)→ TCP listen :2404 / :8888

顺序铁律:① 配置段注册必须先于 cfg_file_load(否则 FTP 上传的段不生效); ② adc1_disable() 必须在挂 DMA 之前;③ osKernelStart 之前禁调任何内核 API(含 osDelay / 队列)。

1.5 线程间通信

机制 对象 用途
Event Flags sys_evtHandle 启动就绪屏障 + 命令位(§1.3)
Message Queue netMsgQueue(深度 8,net_msg_t) 所有 CH395F 操作经队列串行化到 netTask 执行,保证 SPI 单线程访问
双区 + 序号(无锁) phasor 相量区、meas 遥测快照 写侧填满计算区后单字节翻转活跃索引;读者先取索引再整份拷贝,seq 判"是否换帧"
SPSC 环(无锁) soe_store(深度 8) protectTask 只投递动作边沿,defaultTask 排空落盘——保护路径零 NAND I/O
脏位 + 事件位 prot_set / run_par / comm 写入方置脏;104 侧 peek 后投递事件位,配置属主(defaultTask)落盘,失败保留脏位下轮重试
单字请求标志 prot_elm_request_reset() 跨上下文复归请求(104 遥控 YK11 在 iec104Task 落请求,protectTask 下一拍消费)

2. 硬件规格

2.1 主控与内存

项 值 说明
MCU STM32F407ZGTx Cortex-M4(FPU),LQFP144
主频 168 MHz HSE 8 MHz → PLL M=4 / N=168 / P=2
Flash 1 MB(0x08000000) 片内
SRAM 192 KB(128 KB 主 SRAM1+SRAM2 + 64 KB CCM) 链接器映射 128 KB 主 SRAM;CCM 用于 FreeRTOS 堆(任务栈)
RTOS FreeRTOS V10.3.1(CMSIS-RTOS2) HAL 时基 TIM7,tick = 1 ms;NVIC 4 位抢占,外设中断优先级 ≥5
工具链 Keil MDK-ARM v5(ARMCC v5) 工程锁 uAC6=0,不支持 armclang
CubeMX 6.17.0 + STM32Cube FW_F4 V1.28.3 与 .ioc 记录一致,再生成须用此组合

2.2 外设与引脚分配

权威来源:V0.1 网表分析报告 + Inc/main.h(代码已迁移至 V0.1)。下表为 V0.1 硬件的引脚。

外设 接口 引脚 说明
CH395F 以太网 SPI2 PB12 CS / PB13 SCK / PB14 SDO / PB15 SDI 10/100M 以太网控制器;PHY 强制 100M 全双工;SPI 分频系数必须为 8(PCB 设计约束)
GD5F2GQ5UE NAND SPI1 PE0 CS / PB3 SCK / PB4 MISO / PB5 MOSI / PB8 WP / PE1 HOLD 256 MB SPI NAND(2 Gbit)
TPAFE5160 ADC 并行 16 位 PG0~PG15 数据 / PC6 FRSTDATA / PC7 BUSY(EXTI) / PC8 RD / PC9 CONVST / PA8 OS2 / PA11 OS1 / PA12 OS0 高精度多通道 ADC
SD2506 RTC I2C1 PB6 SCL / PB7 SDA 提供墙钟基准与日志时间戳
USART1(U5 直连 TTL) UART PA9 TX / PA10 RX 700000 8N1 → 屏板链路(TTL 直连、无 DE,../产品需求/产品需求设计文档.md §5.16.2);PA10 双向均已接线;日志已迁 UART5
UART4(RS-485) UART PC10 TX / PC11 RX / PA15 DE 半双工通信(V0.1 轮换后 RS485#4 = UART4,../硬件平台/V0.1_网表详细分析报告.md §4.2)
USART2(RS-232 #3) UART PD5 TX / PD6 RX 经 U10 隔离 → U13 TPT3232E → CN1;固件目前未占用(日志实际走 UART5/RS232#1)
UART5(RS-232 #1) UART PC12 TX / PD2 RX 经 U9 隔离 → U13 → CN1;日志口(115200,/serial-boot-test 采集通道;台架端子 ../子系统设计/屏板链路设计说明.md §3.2)
状态 LED ×6 GPIO PC5 / PB0 / PB1 / PB2 / PF11 / PF12 低电平点亮
SWD — PA13 SWDIO / PA14 SWCLK V0.1 已修复 V0.0 的 SWCLK 引脚缺陷
调试口 — CN2(XH-3A,1=SWDIO/2=SWCLK/3=GND) V0.1 由 H2 排针改为 XH 端子

⚠️ V0.0 / V0.1 差异:V0.1 相比 V0.0 做了接口裁剪(删 8080 LCD 与 8 键)+ U17 大面积引脚重排 + ADC 前端通道置换(17 路中 13 路变化)+ 调试口改型。固件 BSP 与 ADC 通道映射表必须按 V0.1 重映射; 详见 docs/硬件平台/V0.1_网表详细分析报告.md。

2.3 存储器件

器件 容量 组织 软件栈
GD5F2GQ5UE 2 Gbit(256 MB) 2048 块 × 64 页 × 2048 B FatFS(FAT32)→ dhara FTL(磨损均衡 / 坏块管理 / GC)→ NAND 驱动
SD2506 — I2C1 RTC(时间/温度/电池诊断)
  • BBT 持久化:坏块表存于保留块池(顶部 4 块),不交给 dhara 管理。
  • 单写者纪律:defaultTask 拥有存储;netTask 只读 RAM 配置副本,不触卷。
  • FatFs 约束:FF_USE_LFN=0(严格 8.3 文件名);FF_FS_REENTRANT=1 + ffsystem.c 互斥钩子(超时 1 s);FF_FS_NORTC=0(get_fattime 直引用墙钟)。

2.4 硬件版本与兼容性

版本 状态 说明
V0.0 历史 含 8080 LCD、8 按键;存在 2 处设计缺陷(SWCLK 引脚错误致 SWD 不通、ADC17 落在非 ADC 引脚)
V0.1 当前 架构与 V0.0 一致;裁剪 LCD/按键、U17 引脚重排、修复上述 2 处缺陷;固件已迁移
V0.2 规划关注 新增关注项:VCAP 电容值未标注、PC13/14/15 子板 LED 3 mA 限流、SPI1 无法双落点

2.5 平台约束

约束 内容
CubeMX 生成文件 Inc/、Src/ 中带 USER CODE BEGIN/END 标记;自定义代码只能写标记区内
生成区外的定制 仅限 Src/iwdg.c 延后启动、4 个 Fault Handler 实体(scripts/check_cubemx_survival.py 审计兜底)
osKernelStart 前 禁止任何 FreeRTOS / CMSIS-RTOS API 调用
BOM / 编码 部分源文件带 BOM(Drivers/BSP/UI/*、App/task/ui_task.c、App/cfg/cfg_file.c、Lib/lv_conf.h),被工具改写丢 BOM 会导致 ARMCC 按 CP936 解码、中文字面量编译失败
SDIO V0.1 主板 SDIO 固定引脚组被 TPAFE/UART 全部占用 → 无 SDIO 能力(当前设计不受影响,FatFs 卷在 SPI NAND 上)
新源文件 必须双端注册(Keil .uvprojx + simulator/CMakeLists.txt),否则不参与编译

2.6 V0.1 硬件能力边界(对产品的硬约束)

下列五条是硬件事实,不是软件缺陷;需求档 §5 的功能范围与 需求档 §9 的"等条件"项均由它们推导:

# 约束 具体内容 产品影响 解除条件
H1 双转换器无共同采样触发 8 路电气量分属 TPAFE5160(16 位、8 通道同步、±5 V 双极性)与 STM32 ADC1(12 位、顺序扫描、0~3.3 V 单极性)两片;两片无共同触发,STM32 侧 9 通道一轮约 67 µs 跨转换器的相位 / 功率 / 功率因数 / 对称分量 / 三相同时刻判据一律不成立 → 方向元件、PT/CT 断线、三相过流、零序过流延后 V0.2 硬件:8 路电气量全部接 TPAFE(与备用路对调串联电阻,料号不变,走线级改动);固件只改映射表内容
H2 STM32 侧无中点偏置 单极性 0~3.3 V,交流量负半周削顶 UB/UC/IB/IC/IN 无有效值/相量,只能读码值监视;104 对应点恒置 IV V0.2 补偏置
H3 无出口继电器与开入回路 无跳闸/告警出口、无硬压板与开入遥信 保护动作只体现为遥信 + 日志 + SOE;104 遥控 YK1~4/13/14 否定确认 开入开出独立立项 + 硬件
H4 无本地屏与按键 160×160 单色屏仅存在于远端客户端 UI 以 TCP :7003 推流 + 远端按键回注(../产品需求/产品需求设计文档.md §8) 产品形态即如此,不解除
H5 无 SDIO SDIO 固定引脚组被 TPAFE/UART 占用 FatFs 卷只能落 SPI NAND(当前设计不受影响) 不解除

量纲口径(由 H1/H2 派生):在端子/子板变比确认与两点标定完成前,遥测与保护读数的单位是 ADC 引脚电压(eng=0),不是二次值;此时 ADC_CAL_F_VALID 未置位, 保护判据整体停走(../产品需求/产品需求设计文档.md §5.12)。这是刻意设计,不是"保护不动作"的缺陷。