Files
STM32F4-Base/AGENTS.md
T

14 KiB
Raw Blame History

STM32F4-Base

编译验证:所有代码修改后必须执行 @build 验证编译通过(0 错误 0 警告),否则不要提交。

构建

  • 仅支持 Keil MDK-ARM v5 (ARMCC),无其他工具链
  • 命令行编译:@build(执行 MDK-ARM/build.bat,从仓库根目录用相对路径调用)
  • build.bat 硬编码 Keil 路径 C:\Keil_v5\UV4\UV4.exe(本机已验证存在;换机器需改)
  • 退出码:0 = 0 错误 0 警告 | 1 = 有警告或错误(查看 MDK-ARM/build_log.txt)
  • ⚠️ 旧绝对路径陷阱:仓库曾位于 D:\Code\DTU 程序\STM32F4-Base,.opencode/command/*.md 与 test/run_boot_test.ps1 中若出现该路径一律视为失效,改用仓库相对路径(如 & "MDK-ARM\build.bat")

Python 环境(跑脚本用)

  • 统一入口:仓库内 .venv\Scripts\python.exe(Python 3.12.4,fontTools + Pillow 已装),所有依赖第三方库的脚本一律用它;依赖清单 requirements.txt(仓库根目录)
  • 重建/换机:& 'C:\ProgramData\anaconda3\python.exe' -m venv .venv; & '.venv\Scripts\python.exe' -m pip install -r requirements.txt(种子解释器可用任意带 venv 的 python ≥3.10;.venv/ 已 gitignore,不入库)
  • requirements.txt 必须纯 ASCII:Windows 下 pip 按系统代码页(GBK)解码该文件,中文注释会 UnicodeDecodeError(2026-09-09 实测)
  • PATH 默认 python 是 msys64 的(C:\msys64\ucrt64\bin\python.exe),不要用它跑依赖第三方库的脚本;纯标准库脚本(回归测试、extract_cn.py、gen_menu.py)任意 python3 均可
  • 字体生成:& '.venv\Scripts\python.exe' tools/font_gen/make_font.py

硬件

外设 接口 引脚
CH395F 以太网 SPI2 PB12 CS, PB13 SCK, PB14 SDO, PB15 SDI
GD5F2GQ5UE NAND SPI1 PE0 CS, PB3 SCK, PB4 MISO, PB5 MOSI, PB8 WP, PE1 HOLD
TPAFE5160 ADC 并行16位 PG0-PG15 数据, PD3 RD, PD4 CONVST, PD7 BUSY
USART1 串口 PA9 TX, PA10 RX (115200bps)
RS-485 UART5 PC12 TX, PD2 RX, PD0 DE(半双工)
6x LED GPIO PC4, PC5, PB1, PB2, PF11, PF12(低电平点亮)

MCU: STM32F407ZGTx @ 168MHz (HSE 8MHz → PLL M=4/N=168/P=2,见 *.ioc/stm32f4xx_hal_conf.h)

架构

Src/main.c → CubeMX 外设初始化 → app_main_init → osKernelStart
  → [FreeRTOS tasks: defaultTask, netTask, ftpTask, testTask, uiTask, timeSyncTask]
  • app_main_init 顺序(时间子系统优先,使后续日志带时间戳):sd2506_init → sys_clock_init(墙钟基准)→ rs485_init → gd5f2gq5ue_init → tpafe5160_init → SD2506 诊断 → tpafe5160_start_conv_irq
  • 就绪屏障(App/sys_events.h Event Flags,取代魔法延时/全局轮询):SYS_EVT_NET_READY(bit0, netTask 置位) / SYS_EVT_STORAGE_READY(bit1, defaultTask 置位) / SYS_EVT_FTP_READY(bit2) / SYS_EVT_TIMESYNC_READY(bit3);消费者用 osEventFlagsWait 阻塞等待
  • defaultTask:FatFS 挂载(f_mount forced,无卷自动 f_mkfs FAT32)→ 置 SYS_EVT_STORAGE_READY → LED 闪烁循环
  • netTask:等 SYS_EVT_STORAGE_READY(≤10s)→ net_stack_bring_up()(net_cfg_load 读 Flash 网口配置 → net_init(ip,mask,gw,mac) + PHY 强制 100M 全双工 + 等链路 ≤3s → 回写芯片实际 MAC 影子 → 递增网络代次号)→ 置 SYS_EVT_NET_READY → 循环 net_poll() + net_process_messages() + osDelay(1)(tick=1ms);循环内消费 SYS_EVT_NET_RECONFIG(UI 保存网口配置后请求)→ 立即重建网络(新 IP 生效,无需重启;各 TCP 服务据代次号重建监听)
  • ftpTask:osEventFlagsWait(NET_READY | STORAGE_READY, WaitAll) 后 lftpd_start("/", 21, &ftp)(已无 7s 魔法延时)
  • testTask:测试套件入口(test/test_config.h 选择;产品构建下空转)
  • uiTask:等 SYS_EVT_NET_READY 后 ui_port_init → ui_menu_init → 启动 UI net sink
  • timeSyncTask:TCP 墙钟时间同步(PC 推送)
  • 功能编译开关:App/app_cfg.h(APP_NET_ENABLE / APP_ADC_ENABLE / APP_RS485_ENABLE)
  • 全景架构图:docs/项目架构总览.md(六层分层 / 任务与就绪屏障 / 启动时序 / 存储·网络·UI 栈 / 目录组织)

任务栈

Task 栈大小(words) 优先级
defaultTask 2048 Normal
netTask 4096 Normal
ftpTask 4096 Normal
testTask 4096 BelowNormal
uiTask 16384 BelowNormal
timeSyncTask 2048 Normal

CH395F 设计原则

  • 单连接 socket:Socket 0 复用监听和数据通道,收到 CONNECT 后切换为数据通道,DISCONNECT/TIMEOUT 后重新 OPEN → LISTEN
  • 中断统一处理:所有 CH395F 中断在 net_poll() 中通过 GET_GLOB_INT_STATUS 集中读取并清除,不得在 ISR 或其他地方单独处理

NET 网络层

  • net_socket.h/c — BSD Socket API;单连接模式(ch395f_set_fun_para(0x09):多 Socket + TCP Server 单连接 + 手动关闭),连接停留在 Socket 0
  • net_select.h/c — select/poll I/O 多路复用
  • 线程安全通过消息队列(netMsgQueue)实现,所有 CH395F 操作在 netTask 中串行处理
  • net_init 顺序:check_exist → reset → set_fun_para(0x09) → MSS/重传/KeepAlive → IP → ch395f_init() → ch395f_set_mac_addr()(mac 非空且非全零时)→ Socket 0~7 缓冲分配 → ping 使能
  • 网口参数(IP/掩码/网关/MAC)取自 Flash 配置(Drivers/BSP/NETCFG/:magic 'NCFG' + ver + CRC-16/MODBUS;工厂默认 192.168.1.100/24、gw .1,MAC 全零 = 芯片内置),保存后下次上电生效;PHY 强制 100M 全双工
  • 新文件需手动添加到 Keil MDK 工程才能编译

测试构建模式

  • test/test_config.h:TEST_SUITE_CH395F / TEST_SUITE_STORAGE / TEST_SUITE_GD5F / TEST_SUITE_RTC 互斥(一次构建只能启用一个,#error);全部注释 = 正常产品构建
  • CH395F 套件沿用 test/ch395f_test.h 阶段宏:硬件层 Phase 15 与 NET 层 Phase 611 互斥(#error);硬件层模式下 netTask 不创建,testTask 独占 CH395F
  • 各模块测试指南见 docs/测试说明/(CH395F / GD5F / SD2506 / FTP)

关键文件

路径 说明
Src/main.c 入口,CubeMX 生成 + USER CODE 区域
Src/freertos.c FreeRTOS task 创建,CubeMX 生成 + USER CODE 区域
App/app_main.c 应用初始化流程编排
App/sys_events.h 系统就绪事件(Event Flags 就绪屏障)
App/app_cfg.h 功能模块编译开关
App/task/net_task.c netTask 主循环(网络初始化 + 轮询)
test/test_config.h 测试套件选择(互斥开关)
Drivers/BSP/NET/ BSD Socket API 网络抽象层 + lftpd
Drivers/BSP/NETCFG/ 网口配置(Flash 持久化 + CRC,网口设置内容页数据源)
Drivers/BSP/CH395F/ CH395F SPI 驱动
Drivers/BSP/GD5F2GQ5UE/ NAND Flash 驱动 + dhara FTL + FatFS diskio
Drivers/BSP/TPAFE5160/ ADC 并行接口驱动
Drivers/BSP/SD2506/ RTC 驱动
Drivers/BSP/RS485/ RS-485 通信(UART5 + PD0 DE)
Drivers/BSP/UI/ LVGL UI 组件(与 PC 模拟器共用源码)

驱动关键点

详见 docs/ 目录:

  • docs/项目架构总览.md — 六层全景架构(分层/任务/启动时序/存储·网络·UI 栈)
  • docs/网络配置说明.md — 网口设置页配置(UI 可改的 IP/掩码/网关/MAC:持久化 / 立即生效 / 页面操作)
  • docs/问题记录/CH395F_Trap_Records.md — CH395F 已知陷阱
  • docs/问题记录/GD5F2GQ5UE_Trap_Records.md — GD5F2GQ5UE 已知陷阱
  • docs/问题记录/SD2506_Trap_Records.md — SD2506 RTC 已知陷阱
  • docs/测试说明/CH395F_Test_Guide.md — 网络测试说明(含构建模式与执行顺序)

串口调试(serial-mcp-server MCP/CLI)

通过 Adancurusul/serial-mcp-server 自主读取/控制 USART1 串口(PA9 TX / PA10 RX,115200bps)的打印流。

  • 串口端口单一配置源:.opencode/serial_config.json(当前本机为 COM6)。端口变化只改这个文件。
  • 用法、采集窗口模式、已知陷阱等详见 docs/测试说明/serial-mcp-server_串口调试.md

自动化测试(AI 迭代闭环)

改完代码后运行 @test 可自动执行完整闭环:构建验证 → 串口捕获武装(serial-mcp-server 采集窗口)→ 烧录(MDK-ARM/download.bat,下载后 Reset & Run)→ 解析捕获 JSON → test/verify_log.ps1 标记校验 → PASS/FAIL 判定并迭代。

  • 推荐一键命令:test/run_boot_test.ps1 = 采集(含 EOF 重试)→ 烧录 → 提取日志 → verify 全流程,退出码 0=PASS / 1=FAIL / 2=采集或烧录错误 / 3=日志文件错误
  • 判定标准:@test 内部先 @build(0 错误 0 警告),再 @download(退出码 0),日志用 verify_log.ps1 校验(默认 Required:App init OK/Network Init/net init: OK;Forbidden:FAIL/ERROR/HardFault)
  • 采集必须在烧录前武装(采集进程先打开 COM 等 first-byte,烧录触发复位后才抓得到开机日志);run_boot_test.ps1 的 -FlashCmd 分支已保证顺序
  • 每次按模块定制标记(网络/存储/RTC/ADC/RS485)见 docs/测试说明/自动化测试流程.md
  • UI 已有 DBG 打印(UI port init: OK / UI menu init: OK / UI net sink: started),可用 -Required "UI port init: OK;UI menu init: OK" 自动回归 UI 初始化;屏幕内容仍需人工目检

代码规范与 pre-commit

  • 提交被 pre-commit 钩子门禁,任一失败即拦截:cppcheck 静态分析(warning/performance/portability/style)+ 代码规范机械检查 + U+FFFD 乱码检查 + gitlint commit message
  • 代码规范 V1.0(docs/代码规范/嵌入式C语言代码规范(V1.0).md):命名小写下划线(g_/s_/p_/a_ 前缀)、头文件保护宏 XXX_H、常量在右、文件头模块注释块等;可机械校验项由 scripts/check_coding_standard.py 强制
  • 检查范围仅项目自有代码;第三方(Lib/、Middlewares/、CMSIS/HAL、lftpd、Drivers/BSP/UI、test/)被排除
  • 新机器启用:pre-commit install;全库扫描:pre-commit run --all-files
  • 详见 docs/代码规范/pre-commit使用说明.md、docs/代码规范/cppcheck使用说明.md

LVGL PC 模拟器

simulator/(CMake + SDL2 2.32.10 预编译库)可在 PC 上开发调试 UI,与 MCU 端共用 UI 源码(Drivers/BSP/UI/ui_menu.c、ui_font_cn_12.c),无需烧录:

cd simulator
cmake -B build -G "Visual Studio 16 2019" -A x64
cmake --build build --config Debug
# 运行 simulator\build\Debug\lvgl_sim.exe
  • 详见 docs/UI 设计/LVGL模拟器部署与使用说明.md
  • 中文字体:ui_cn_chars.txt(字符集)+ tools/font_gen/ 生成 Drivers/BSP/UI/ui_font_cn_12.c,见 docs/UI 设计/UI_中文字体生成与配置.md

图形绘制(文档配图)

文档里的技术图形统一用 SVG 生成器(tools/arch_diagram/,纯标准库)或 Mermaid,勿手绘 ASCII 框图:

  • 精确布局图(协议帧 / 分层架构 / 依赖 / 就绪屏障)→ tools/arch_diagram/gen_*.py:改脚本顶部数据 → & '.venv\Scripts\python.exe' tools/arch_diagram/gen_xxx.py 重新生成 docs/images/*.svg(脚本内置 XML 自检)。
  • 拓扑类图(流程 / 时序 / 状态机)→ Markdown 内嵌 mermaid 代码块。
  • 全流程 / 选型 / 约定 / 检查清单见 docs/图形绘制流程.md(已沉淀为 draw-diagram skill);产物统一放 docs/images/ 专门目录;脚本与生成的 .svg 一并提交。

注意

  • Inc/ 和 Src/ 中 CubeMX 生成的文件带有 USER CODE BEGIN/END 标记,自定义代码写在这些区域之间
  • Drivers/BSP/ 下的驱动文件为纯手工代码,不受 CubeMX 保护
  • CH395F 每次 SPI 事务需用 ch395f_spi_begin() / ch395f_spi_end() 包裹
  • CH395F SPI PCB 设计问题,分频系数必须为 8,速度相对较低
  • FreeRTOS V10.3.1 via CMSIS-RTOS V2,HAL 时基用 TIM7(非 SysTick),tick = 1ms
  • NVIC 优先级分组 4 位,外设中断优先级 ≥ 5(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY)
  • 内存预算紧张:任务栈目前普遍偏大(见 待处理内容.md),新增任务/缓冲/栈前必须先核算 RAM 余量

源码编辑与编码安全(铁律)

本工程源码含大量中文注释,曾因错误的文本重写方式导致整文件乱码(U+FFFD 替换符,不可逆)。以下规则必须遵守:

  • 绝不用 Get-Content / Set-Content / cmd 文本重写含中文的源码文件。这类"整文件重写"会按系统默认编码重新解码再写回,多字节中文必被 U+FFFD 替换且不可逆。
  • 改代码只用 Edit 工具(精确子串替换,不重新编解码整个文件,安全);批量替换用 Edit 的 replaceAll。
  • 必须脚本级替换时,使用显式且一致的编码(工程源码为 UTF-8:多数文件无 BOM,但 UI 相关文件 Drivers/BSP/UI/*、App/task/ui_task.c、Lib/lv_conf.h 为 UTF-8 带 BOM——如 Python open(p, encoding="utf-8"/"utf-8-sig") 按原样同编码回写,保持 BOM 状态不变)——但最稳的是别碰,只用 Edit / git。
  • 发现乱码先别急着 git checkout:git checkout 会丢弃所有未提交工作,使损失扩大。先评估能否用 Edit 仅改坏掉的那几行。
  • 验证是否真损坏用字节级检查(统计 EF BF BD 出现次数),不要依赖终端/Read 渲染判断。