Files
STM32F4-Base/AGENTS.md
T

14 KiB
Raw Blame History

STM32F4-Base

STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2);仅 Keil MDK-ARM v5 (ARMCC, C99) 工具链;FreeRTOS V10.3.1 / CMSIS-RTOS2;192KB SRAM / 1MB Flash。

任何代码修改后必须先 @build 验证(0 错误 0 警告)再提交;硬件闭环用 @test。

铁律:源码编辑与编码

  • 改代码只用 Edit 工具(精确子串替换);批量替换用 Edit 的 replaceAll。绝不用 Get-Content/Set-Content/cmd 重写含中文的文件——整文件重写会按系统默认编码重解码 → U+FFFD 乱码且不可逆
  • 字符串字面量必须纯 ASCII(2026-09-15 实测):本机 ARMCC 对无 BOM 源文件按 CP936 解读,字符串内含奇数个汉字时末尾高字节吞掉结束引号 → 编译错(偶数个汉字侥幸通过);中文只写注释(注释不参与解析)。带 BOM 的文件(Drivers/BSP/UI/*、App/task/ui_task.c、App/cfg_file.c、Lib/lv_conf.h)经 BOM 按 UTF-8 解码,不受此条限制
  • 确需脚本级重写:工程源码为 UTF-8(多数文件无 BOM,UI 系带 BOM),按原样同编码回写、保持 BOM 状态;拿不准就别碰
  • 发现乱码:先统计 EF BF BD 字节数确认真损坏(勿信终端/Read 渲染);不要急著 git checkout(会丢弃全部未提交工作)——先用 Edit 只修坏行
  • Edit 工具会剥掉文件原有的 UTF-8 BOM(2026-09-18 实测):带 BOM 文件(如 App/cfg_file.c)被 Edit 后 BOM 静默消失 → ARMCC 改按 CP936 解码 → 中文字符串字面量报 #870-D: invalid multibyte character sequence(只有重编译该文件才暴露,历史"0 警告"不代表安全)。改完带中文字面量的文件须核对 BOM 并按原样补回(只在文件头前缀 3 字节 EF BB BF,勿整文件重写)

构建与验证

  • @build = & "MDK-ARM\build.bat"(仓库根目录用相对路径);退出码 0 = 0 错误 0 警告,1 = 有警告或错误(查 MDK-ARM/build_log.txt);build.bat 硬编码本机 Keil 路径 C:\Keil_v5\UV4\UV4.exe(换机需改)
  • @test / test/run_boot_test.ps1 一键闭环:开串口+清日志 → 烧录(MDK-ARM/download.bat,下载后 Reset&Run)→ wait-idle(等 RX 静默 8s,超时 30s)→ test/verify_log.ps1 标记校验;退出码 0=PASS / 1=FAIL / 2=采集或烧录错误 / 3=用法/预检错误
  • 默认校验标记:Required App init OK / Network Init / net init: OK;Forbidden FAIL / ERROR / HardFault;按模块定制标记(网络/存储/RTC/ADC/RS485/UI)见 docs/测试说明/自动化测试流程.md
  • ⚠️ 旧绝对路径 D:\Code\DTU 程序\... 出现即失效(仓库已搬迁),一律改用仓库相对路径
  • 下载/烧录铁律(2026-09-20 实测):走 & "MDK-ARM\reset.bat" flash [文件](= ST-LINK_CLI -c SWD -P <文件> -Rst -Run),烧后 -Rst -Run 不可省略——裸 -P 会报 Programming Complete,但目标核处于死循环/异常状态时写入并不落地(芯片内容不变;这就是 09/19~09/20 "反复重下载、芯片一直是旧镜像、二分法失效" 的根因);.hex/.bin 均可直烧(1MB ≈ 6.5s,快于 UV4 路径);只重启不烧录用 reset.bat 无参(= -c SWD -Rst -Run,本机 3 线接线唯一复位手段:nRST 未接、-HardRst/RM= 不可用)
  • 烧录后必须回读校验:ST-LINK_CLI -c SWD -CmpFile <文件> 0x08000000(全片逐字节比对,No difference found 才算真正写入);CLI = C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe(v3.5.0.0,探针 SN 0B250D12A218303030303032)→ 完整用法/复位语义/故障排查 docs/测试说明/ST-LINK_CLI_复位使用说明.md

Python 环境

  • 统一入口 & '.venv\Scripts\python.exe'(3.12,fontTools/Pillow 已装);PATH 默认 python 是 msys64 的,不要用它跑依赖第三方库的脚本;纯标准库脚本任意 python3 均可
  • 重建/换机:& 'C:\ProgramData\anaconda3\python.exe' -m venv .venv + pip install -r requirements.txt(.venv/ 已 gitignore)
  • requirements.txt 必须纯 ASCII(Windows 下 pip 按 GBK 代码页解码,中文注释会 UnicodeDecodeError)

提交门禁(pre-commit)

  • 任一失败即拦截:cppcheck(warning/performance/portability/style)+ C 代码规范机械检查 + U+FFFD 乱码检查 + gitlint;范围仅项目代码(第三方 Lib//Middlewares//CMSIS/HAL/lftpd/dhara/MDK-ARM/test/ 排除;规范检查另排除 CubeMX 生成的 Src//Inc/)
  • trailing-whitespace 钩子另排除 Drivers/CMSIS/、Drivers/STM32F4xx_HAL_Driver/、Middlewares/(2026-09-20:CubeMX 6.18 重生成带回行尾空白,每次重生成产生提交抖动;Drivers/BSP/ 自研代码仍受检)
  • 提交信息:单行中文标题 <100 字符(gitlint),UTF-8 无 BOM + git commit -F <文件>(防终端转码破坏)
  • 代码规范 V1.0:小写下划线命名(g_/s_/p_/a_ 前缀)、头文件保护宏 XXX_H、常量在右、文件头模块注释块 → docs/代码规范/
  • 全库扫描 pre-commit run --all-files;详见 docs/代码规范/pre-commit使用说明.md

平台约束

  • Inc//Src/ 中 CubeMX 生成文件带 USER CODE BEGIN/END 标记:自定义代码只写标记区之间;Drivers/BSP/ 为纯手工代码
  • FreeRTOS V10.3.1(CMSIS-RTOS V2);HAL 时基 = TIM7(非 SysTick),tick = 1ms;NVIC 4 位优先级分组,外设中断优先级 ≥ 5
  • 内核启动(osKernelStart)前禁止任何 FreeRTOS/CMSIS-RTOS API 调用(2026-09-20 启动失败实证根因,修复 82411cf):osMessageQueueNew/osMessageQueuePut/osMutexNew/osSemaphoreNew 等在内核启动前调用会杀死启动(09/19~09/20 "每次必死" 的代码层根因 = syslog_mcu_init 在内核启动前调用 osMessageQueueNew)。内核启动前代码的标准模式:纯寄存器/HAL 轮询操作 + 无锁静态缓冲(如 s_preboot[8] 暂存内核前日志)+ 内核启动后惰性创建真队列(任务上下文首次使用时,见 syslog_drain);凡在内核启动前执行的初始化函数里不得创建任何 CMSIS 对象
  • CH395F SPI:每次事务须 ch395f_spi_begin()/end() 包裹;分频系数必须为 8(PCB 约束,勿"优化")
  • 内存预算紧张:新增任何任务/缓冲/栈前必须先核算 RAM 余量(docs/内存管理/、待处理内容.md)
  • 自研代码禁用 C 库堆分配(2026-09-18,P0-1):禁止 malloc/calloc/realloc/strdup/free——本机工具链 MicroLIB 的 C 堆由 startup_stm32f407xx.s 的 Heap_Size EQU 0x200 限定为 512 B,KB 级分配必然返回 NULL 且模拟器(宿主 CRT 堆)完全正常、照不出来。需要动态内存只用 pvPortMalloc/vPortFree(FreeRTOS 堆 configTOTAL_HEAP_SIZE),或像配置引擎那样把分配收进平台后端(cfg_store_alloc/free/heap_free:MCU=FreeRTOS 堆、模拟器=宿主堆,共享核心零分配符号);分配失败必须有 FAIL 日志 + 自检上报,暂态峰值要写编译期预算
Task 栈 (words) 优先级
defaultTask 512 Normal
netTask 1024 Normal
ftpTask 1024 Normal
testTask 1024 BelowNormal
uiTask 4096 BelowNormal
timeSyncTask 512 Normal

(实际值以 Src/freertos.c 为准,六任务栈合计 32KB;改动栈/缓冲前先核对此表与实测)

架构要点

Src/main.c(CubeMX 初始化)→ app_main_init → osKernelStart → 6 任务(osKernelStart 之前全是内核启动前代码:禁调任何 FreeRTOS/CMSIS-RTOS API,见「平台约束」)

  • app_main_init(时间子系统优先,使后续日志带时间戳):sd2506_init → sys_clock_init(墙钟;RTC 故障时降级默认时间基准并返回 -1 触发"时钟芯片异常"自检;sys_clock_get 每 30 天惰性再基准化防 49.7 天 tick 回绕)→ rs485_init → gd5f2gq5ue_init → tpafe5160_init → SD2506 诊断 → tpafe5160_start_conv_irq
  • 就绪屏障(App/sys_events.h Event Flags,取代魔法延时):SYS_EVT_NET_READY(netTask 置位)/ STORAGE_READY(defaultTask:卷挂载 + 网络配置加载完成)/ FTP_READY / TIMESYNC_READY;消费者用 osEventFlagsWait 阻塞等待
  • netTask:net_stack_bring_up(配置已由 defaultTask 在屏障前加载,本任务只读 RAM 副本 → net_init + PHY 强制 100M 全双工 → 递增网络代次号)→ 置 NET_READY → 循环 net_poll + net_process_messages;消费 SYS_EVT_NET_RECONFIG → 立即重建网络(新 IP 免重启生效,各 TCP 服务据代次号重建监听)
  • defaultTask:f_mount forced(无卷自动 f_mkfs FAT32)→ 网络配置加载(net_cfg_load,首启含旧档迁移)→ STORAGE_READY → LED 闪烁;同时是 syslog(/log/run.log·selftest.log,定长 64B 记录)的唯一写者与配置引擎属主(cfg_file 静态态单任务收敛于此:UI 保存请求执行 net_cfg_save_run + 2s cfg_file_poll,经 SYS_EVT_CFG_SAVE 事件唤醒;netTask/uiTask 不得直接触碰配置引擎,见 P1-3)
  • 全景 docs/项目架构总览.md(六层分层 / 启动时序 / 存储·网络·UI 栈 / 目录组织)

硬件引脚

外设 接口 引脚
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 调试串口 UART PA9 TX, PA10 RX (115200)
RS-485 UART4 PC10 TX, PC11 RX, PA15 DE(半双工)
6x LED GPIO PC5, PB0, PB1, PB2, PF11, PF12(低电平点亮)

模块约定

  • CH395F 单连接 socket:监听与数据通道复用同一 Socket(CONNECT 后转数据通道,DISCONNECT/TIMEOUT 后重开 → LISTEN);所有 CH395F 中断在 net_poll() 内经 GET_GLOB_INT_STATUS 集中读取并清除,不得在 ISR 或其他地方单独处理
  • 所有 net_* socket 操作经 netMsgQueue 消息队列在 netTask 串行执行(线程安全);非 netTask 任务直接调 net_* API,勿直接碰 CH395F 驱动
  • 网口配置:/config.ini [network] 段(工厂默认 192.168.1.100/24、gw .1;MAC 全零 = 芯片内置;UI 保存立即生效;旧档 /cfg/netcfg.bin 首启自动迁移)→ docs/网络配置说明.md
  • 新 .c 文件必须手动注册到两处才能双端编译:MDK-ARM/STM32F407-Demo.uvprojx + simulator/CMakeLists.txt(用 new-source-file skill)
  • 测试构建:test/test_config.h 的 TEST_SUITE_CH395F/STORAGE/GD5F/RTC 互斥(一次只能启用一个,#error);全部注释 = 产品构建;CH395F 套件 test/ch395f_test.h:硬件层 Phase 15 与 NET 层 Phase 611 互斥;CH395F 硬件层模式下 netTask(基础线程:无条件创建、全构建唯一实例)入口自挂起(不运行),testTask 独占 CH395F
  • 改驱动前先读对应 docs/问题记录/*_Trap_Records.md(CH395F / GD5F2GQ5UE / SD2506);各模块测试指南见 docs/测试说明/

串口助手 serial_tool

  • 入口:& '.venv\Scripts\python.exe' tools/serial_tool/serial_tool.py <命令>(daemon 自动拉起;全部命令 5s 超时、JSON 输出、exit 0/1/2/3)
  • 全量历史 = 日志文件 tools/serial_tool/state/serial.log(RX/TX/SYS 时间戳行);agent 直接 Read/Grep 文件,无采集窗口仪式;20MB 上限自动截头保尾 10MB
  • 常用:open(幂等)/ send <文本>(或 --hex 0D0A)/ log --tail N --grep P / clear(代际+1)/ wait-idle --settle-ms 8000 --max-ms 30000 / status / close
  • 串口端口单一配置源:.opencode/serial_config.json(当前 COM7);端口变化只改这个文件
  • 命令/工作流/故障排查 docs/测试说明/串口助手使用指南.md;契约/daemon 行为/陷阱 docs/测试说明/串口助手设计说明.md
  • 抓开机日志铁律(2026-09-20 实测):① 顺序 open → clear → 烧录/复位 → wait-idle → 读日志校验标记(采集必须先于烧录,否则错过开机头几行);② wait-idle 必须带 --timeout <秒>(CLI→daemon 默认 5s 硬超时会掐断长等待:wait-idle --timeout 90 --settle-ms 8000 --max-ms 45000);③ 标记校验直接 Read/Grep/Select-String state/serial.log 文件最可靠(log --grep 子命令实测不可信,勿作判定依据)
  • open 报"拒绝访问/端口被占用"时:先查残留旧 daemon(上一会话遗留的 serial_tool.py --serve python 进程——口句柄已死但进程仍占着串口与 HTTP 口 18765)→ taskkill /F /PID <旧PID> → 重新 open(自动拉起新 daemon,系统自动释放口);改 serial_config.json 后同样必须先杀旧 daemon 再 open(daemon 启动时缓存配置)

LVGL PC 模拟器

  • simulator/(CMake + SDL2 预编译库)与 MCU 端共用 UI 源码(ui_menu.c、ui_font_cn_12.c),免烧录开发 UI:cmake -B build -G "Visual Studio 16 2019" -A x64; cmake --build build --config Debug → 运行 simulator\build\Debug\lvgl_sim.exe
  • 自检:--cfgtest(配置闭环)/ --logtest(日志引擎)/ --standby shot.bin(待机屏截图)/ --idle <秒>
  • UI 改动一律走 ui-verify skill 五步门禁;含新汉字的 UI 文案提交前先跑 font-regen skill 重生成中文字体

文档与图形

  • 配置文件 docs/配置文件设计说明.md;墙钟 docs/系统墙钟时间维护说明.md;代码规范 docs/代码规范/;测试说明 docs/测试说明/;审计发现 docs/项目审计改进清单.md;已知待办 待处理内容.md(内存预算);引用关系图 docs/引用关系图说明.md
  • 图形走 draw-diagram skill:精确布局图(协议帧/分层/屏障)用 tools/arch_diagram/gen_*.py 生成器(产物放 docs/images/,脚本与 .svg 一并提交);拓扑图(流程/时序/状态机)用 Mermaid;勿手绘 ASCII 框图
  • 文件引用关系图走 tools/refgraph:& 'tools\refgraph\gen_refgraph.bat' 生成文件级 + 模块级引用图(产物 docs/images/引用关系图.*,脚本与 .dot/.svg/.json 一并提交,PNG 本地预览不提交);项目文件变化后重跑更新;渲染依赖 Graphviz(winget 可装)