11 KiB
11 KiB
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")
硬件
| 外设 | 接口 | 引脚 |
|---|---|---|
| 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.hEvent 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_mountforced,无卷自动f_mkfsFAT32)→ 置SYS_EVT_STORAGE_READY→ LED 闪烁循环 - netTask:延时 2s →
net_stack_bring_up()(net_init + MAC + PHY 强制 100M 全双工 + 等链路 ≤3s)→ 置SYS_EVT_NET_READY→ 循环net_poll()+net_process_messages()+osDelay(1)(tick=1ms) - 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)
任务栈
| 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 0net_select.h/c— select/poll I/O 多路复用- 线程安全通过消息队列(
netMsgQueue)实现,所有 CH395F 操作在 netTask 中串行处理 net_init顺序:check_exist → reset →set_fun_para(0x09)→ MSS/重传/KeepAlive → IP →ch395f_init()→ Socket 0~7 缓冲分配 → ping 使能- 静态 IP 192.168.1.100/24(gw 192.168.1.1),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/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/问题记录/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
注意
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,如 Python
open(p, encoding="utf-8")同编码回写)——但最稳的是别碰,只用 Edit / git。 - 发现乱码先别急着
git checkout:git checkout会丢弃所有未提交工作,使损失扩大。先评估能否用 Edit 仅改坏掉的那几行。 - 验证是否真损坏用字节级检查(统计
EF BF BD出现次数),不要依赖终端/Read 渲染判断。