board_test.c
源文件路径:
midware/debug/board_test.c所属模块:midware/debug(设备中间件 - 板级调试/产线测试) 代码行数:638
1. 文件职责
本文件实现 EMS 主控板的单板自检(Single Board Test):把 LED、RTC、SPI Flash/EEPROM、SDRAM、RS485、USART、W5500 以太网、CAN、干接点 DI/DO、DRM 共 10 类外设依次测一遍,把每一项的通过/失败结果按位写进 32 位联合体 u_single_board_test_result,再由 Modbus 从机寄存器对外暴露给产线工装读取。
它处在"产线测试"这条旁路数据流上,不参与正常运行时的能量调度。流程由 Modbus 写寄存器 REG_SINGLE_BOARD_TEST_ENABLE 触发(midware/interface/modbus/modbus.c:6936-6938 把 g_u8_single_board_test_enable 置 TRUE),然后由 task_system_aux(midware/auxiliary/system_aux.c:2083)每 400 ms 轮询一次 board_test();board_test() 自身在入口检查使能标志,测完立刻把标志清回 FALSE,属于"一次性执行"的同步阻塞函数。因为整轮测试内含大量忙等延时,执行期间会长时间占用 task_system_aux,并通过反复调用 IWDG_Feed() 防止看门狗复位。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
BOARD_TEST_U | 联合体(定义在 board_test.h:17-65) | 测试结果容器。u32 u32_all 与 struct { ... } bit 共用同一 4 字节空间,每一位对应一项外设(0=通过,1=失败),初值 0xFFFFFFFF 即全部判失败 |
BOARD_TEST_U.bit.u8_eeprom | 位域 / bit0 | EEPROM(I2C3)测试结果,实际由 flash_test() 与 Flash 一起判定 |
BOARD_TEST_U.bit.u8_rtc | 位域 / bit1 | PCF8563 RTC 测试结果 |
BOARD_TEST_U.bit.u8_flash | 位域 / bit2 | SPI Flash(SPI4)测试结果 |
BOARD_TEST_U.bit.u8_sdram | 位域 / bit3 | 外部 SDRAM 读写测试结果 |
BOARD_TEST_U.bit.u8_rs485 | 位域 / bit4 | RS485 双向测试(USART1 ↔ UART4)结果 |
BOARD_TEST_U.bit.u8_usart2 | 位域 / bit5 | USART2 自发自收测试结果 |
BOARD_TEST_U.bit.u8_usart3 | 位域 / bit6 | 未测试,board_test() 中直接置 0(通过) |
BOARD_TEST_U.bit.u8_usart6 | 位域 / bit7 | 实际由 USART5 自发自收测试写入,见风险点 |
BOARD_TEST_U.bit.u8_w5500 | 位域 / bit8 | W5500 以太网 MAC 回读一致性结果 |
BOARD_TEST_U.bit.u8_can1 | 位域 / bit9 | CAN0 ↔ CAN1 互通测试结果(can_test() 写入) |
BOARD_TEST_U.bit.u8_can2 | 位域 / bit10 | CAN1 ↔ CAN0 互通测试结果 |
BOARD_TEST_U.bit.u8_can3 | 位域 / bit11 | 未测试,直接置 0(通过) |
BOARD_TEST_U.bit.u8_drm | 位域 / bit12 | DRM 4 路信号与 AD 采样测试结果 |
BOARD_TEST_U.bit.u8_dido1 | 位域 / bit13 | 干接点 DO1→DI1 回环测试结果 |
BOARD_TEST_U.bit.u8_dido2 | 位域 / bit14 | 干接点 DO2→DI2 回环测试结果 |
bit15 ~ bit31 | 位域 | 保留位 |
g_u8_usart_buf[16] | 全局 u8 数组 | UART 自发自收测试报文 "USART text"(board_test.c:33) |
g_u8_rs485_buf[16] | 全局 u8 数组 | RS485 自发自收测试报文 "RS485 text"(board_test.c:34) |
g_u8_single_board_test_enable | 全局 u8 | 单板测试使能标志。Modbus 置 1,board_test() 测完清 0;同时被 ate.c 用来禁止串口透传(ate.c:138/172) |
u_single_board_test_result | 全局 BOARD_TEST_U | 测试结果,初值 .u32_all = 0xFFFFFFFF(board_test.c:37) |
FLASH_TEST__LEN | 宏(board_test.h:15,值 32) | 定义为 32,但本文件中从未被引用 |
SDRAM_SDRAM_TEST_ADDR | 宏(hardware/sdram/sdram.h:44) | SDRAM 测试起始地址(SDRAM_BOOT_FILE_ADDR + SDRAM_16K),容量 1 KB |
ADDR_MAX_SDRAM | 宏(hardware/sdram/sdram.h:20) | SDRAM 地址上界 0xC0000000 + CAPACITY_SDRAM - 1,用于越界保护 |
DRY_NODE1_ON/OFF、DRY_NODE2_ON/OFF | 宏(dry_node.h:20-26) | 干接点输出控制,展开为 do0_output_on() / do1_output_off() 等 |
DI_1_ACCESS_POINT、DI_2_ACCESS_POINT | 宏(dry_node.h:24/30) | 干接点回读,展开为 di0_input_bit_get() / di1_input_bit_get() |
结果位与外设对照(按代码实际写入)
| 测试函数 | 写入的位 | 头文件里的 bit 编号注释 |
|---|---|---|
led_test() | 不写任何位 | 调用点注释称 "led bit10" |
rtc_test() | u8_rtc | bit1 ✓ |
flash_test() | u8_flash、u8_eeprom | flash bit2 ✓ |
sdram_test() | u8_sdram | bit3 ✓ |
rs485_test() | u8_rs485 | bit4 ✓ |
usart_test() | u8_usart2、u8_usart6 | usart bit5 ✓ |
w5500_test() | u8_w5500 | 调用点注释称 "w5500 bit6" |
can_test() | u8_can1、u8_can2 | 调用点注释称 "can1 bit7, can2 bit8" |
dry_node_test() | u8_dido1、u8_dido2 | 无注释 |
drm_test() | u8_drm | 无注释 |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
w5500_test | static(board_test.c:49) | 用 ctlnetwork(CN_GET_NETINFO) 回读 W5500 内部 MAC,与软件保存的 IP_Address.u8_mac_addr 比较,一致则 u8_w5500 = 0 |
led_test | static(board_test.c:72) | 依次点亮/熄灭 4 个状态 LED 与 8 个 led_db0~led_db7 面板灯,各保持 1 s,纯目检,不写结果位 |
can_test | static(board_test.c:139) | 构造 8 字节 CAN 数据帧(ID 0xA0),CAN0/CAN1 相互收发各 4 次,比对回读数据判定 u8_can1、u8_can2 |
usart_test | static(board_test.c:212) | USART2 与 USART5 分别自发自收 16 字节 "USART text",strncmp 比对后写 u8_usart2 和 u8_usart6 |
rs485_test | static(board_test.c:287) | 两段测试:① USART1 发 → UART4 收;② UART4 发 → USART1 收。都成功才 u8_rs485 = 0,第一段失败直接返回 |
rtc_test | static(board_test.c:373) | 最多尝试 5 次 PCF8563_GetDateTime() + PCF8563_Check_Time_Is_Valid(),任一次有效即 u8_rtc = 0 |
flash_test | static(board_test.c:397) | 读 SPI Flash ID,命中 C2 20 18/19/1A 则 u8_flash、u8_eeprom 同时置 0,否则同时置 1 |
sdram_test | static(board_test.c:422) | 从 SDRAM_SDRAM_TEST_ADDR 起逐字节写 0x65 再读回,1024 字节全部一致才 u8_sdram = 0,带 ADDR_MAX_SDRAM 越界保护 |
drm_test | static(board_test.c:458) | 读 DRM0 的 AD 中间值与 DRM1~4 的 GPIO 标志,要求 AD 落在 2000~2100 且 4 路标志全为 TRUE;EMS3.6-2 板型直接判通过 |
dry_node_test | static(board_test.c:502) | DO1 拉高/拉低各等 100 ms 回读 DI1 验证 u8_dido1;EMS3.6-1/2/3/4 板型再对 DO2/DI2 做同样验证写 u8_dido2 |
board_test | 全局(board_test.c:613) | 单板测试总入口:检查使能 → 结果清 0xFFFFFFFF → 依次调用 10 个测试子函数 → 无条件补 u8_can3=0、u8_usart3=0 → 清使能标志 |
4. 核心逻辑解析
4.1 总调度与状态机
board_test() 是一个两级触发、单次执行的简单状态机,没有内部状态变量:
Modbus 写 REG_SINGLE_BOARD_TEST_ENABLE (modbus.c:6936)
↓
g_u8_single_board_test_enable = TRUE
↓
task_system_aux 周期 400ms → board_test() (system_aux.c:2083)
↓
if (g_u8_single_board_test_enable == FALSE) return; ← 未使能则立即返回
↓
u_single_board_test_result.u32_all = 0xFFFFFFFF; ← 全部预设为"失败"
↓
led_test → rtc_test → flash_test → sdram_test → rs485_test
→ usart_test → w5500_test → can_test → dry_node_test → drm_test
↓
u8_can3 = 0; u8_usart3 = 0; ← 无对应测试,直接判通过
↓
g_u8_single_board_test_enable = FALSE; ← 回到空闲,测试只跑一次
结果位在进入时被整体置 1(board_test.c:620),各子测试只在通过时清 0,所以"任何异常路径(提前 return / 未覆盖)都表现为失败",这是安全侧设计。
Modbus 侧读寄存器时还有一个互锁(midware/interface/modbus/modbus.c:4212/4223):只有在 g_u8_single_board_test_enable == FALSE(即测试已结束)时才把 u_single_board_test_result.u32_all 的高 16 位 / 低 16 位返回,测试进行中返回的是默认值,避免读到中间态。
4.2 各子测试的算法
flash_test()(board_test.c:397-413) — 唯一的 ID 判定,无算法:
Flash_ReadID(l_u8_buf); // 读 3 字节 JEDEC ID
if ((buf[0]==0xc2) && (buf[1]==0x20) &&
((buf[2]==0x18)||(buf[2]==0x19)||(buf[2]==0x1A)))
u8_flash = 0, u8_eeprom = 0; // 通过
else
u8_flash = 1, u8_eeprom = 1; // 失败
0xC2 是 Macronix 厂商码,0x20 是 SPI 存储类型码,容量字节接受 0x18/0x19/0x1A 三种(对应 16/32/64 Mbit 级别)。EEPROM 与 Flash 共用同一个判据,即一次 SPI Flash 读 ID 成功就同时判定 I2C3 上的 EEPROM 也正常——两者物理上并不相关,这是明显的偷懒写法。
sdram_test()(board_test.c:422-449) — 逐字节写读校验:
memset((u8*)SDRAM_SDRAM_TEST_ADDR, 0xFF, 1024); // 先铺 0xFF
for (i = 0; i < 1024; i++) {
addr = SDRAM_SDRAM_TEST_ADDR + i;
if (addr >= ADDR_MAX_SDRAM) break; // 越界保护
write(addr, 0x65); read(addr, &l_u8_read);
if (l_u8_read != 0x65) { u8_sdram = 1; return; } // 立即判失败
}
u8_sdram = 0;
注意写法差异:memset 用的是 CPU 直接寻址,而写读校验走 FMC_SDRAM_WriteBuffer_02/ReadBuffer_02()。地址粒度为字节(不是字),1024 次单字节访问会有一定耗时。
can_test()(board_test.c:139-203) — 双通道回环。构造固定报文:
| 字节 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| 值 | 0xFF | 0x05 | 0x02 | 0x00 | 0x01 | 0x03 | 0x01 | 0x04 |
frame_id = 0xA0,frame_type = CAN_FT_DATA,frame_len = 8,标准帧(调用的 API 是 *_send_standard_pack)。时序为:
can0_clear_standard_pack(); can1_clear_standard_pack();
for (i = 0; i < 4; i++) {
can0_send_standard_pack(&txMsg); OSTimeDlyHMSM(0,0,0,1); // 1 ms
can1_send_standard_pack(&txMsg); OSTimeDlyHMSM(0,0,0,1);
}
// 判 CAN0 收到的是否等于发出的 → u8_can1
// 判 CAN1 收到的是否等于发出的 → u8_can2
即"自己发、对端收",用 memcmp(rxMsg.frame_data, txMsg.frame_data, 8) 比对数据域。若 get_can*_standard_pack() 返回 FALSE(超时无报文)也直接判失败。注意写入的位名是 u8_can1/u8_can2,但测试对象是 CAN0 与 CAN1 两个控制器。
usart_test()(board_test.c:212-278) — 两段同构的自发自收。以 USART2 段为例:
usart2_clear_buffer();
usart2_send_data(g_u8_usart_buf, 16, 300); // timeout=300
忙等 50 ms(期间 IWDG_Feed)
l_u8_len = usart2_get_data_len(); if (len > 16) len = 16; // 上限钳位
for (i < len) l_u8_receive_buf[i] = usart2_read_data_async();
strncmp(recv, g_u8_usart_buf, 16) == 0 ? u8_usart2 = 0 : u8_usart2 = 1;
USART5 段结构完全相同,只把收发函数换成 usart5_*,超时参数由 300 改为 1000,结果写进 u8_usart6。l_u8_receive_buf 是 16 字节,读之前做了 len > 16 → 16 的钳位,不存在溢出。但 strncmp(..., 16) 在 len < 16 时会比较到 buf 中未写入的位置——由于每次进来都 memset 清零,等价于"长度不足即判失败",行为是安全的。
rs485_test()(board_test.c:287-364) — 双向测试,两次比对同一个结果位:
- 第 1 段(UART4 → USART1):USART1 和 UART4 都先各发一次 16 字节(
usart1_send_data(...,500)与uart4_send_data(...,500)),等 50 ms 后从 USART1 侧读并比对。这里先让两端各发一次是为了"填充无效数据"(代码注释board_test.c:293),即清掉上电残留或回环噪声。若失败则直接u8_rs485 = 1并清缓冲返回。 - 第 2 段(USART1 → UART4):清缓冲后 USART1 再发一次,等 50 ms 后从 UART4 侧读并比对,结果再次写入
u8_rs485(覆盖)。两段都过才最终为 0。
rtc_test()(board_test.c:373-388) — 重试式判定:
for (i = 0; i < 5; i++) {
PCF8563_GetDateTime(PCF_Format_BIN, 0, &tm);
if (PCF8563_Check_Time_Is_Valid(tm) == 0) { u8_rtc = 0; return; } // 有效即通过
}
u8_rtc = 1; // 5 次都无效
tm 在循环外只初始化一次(= {0}),PCF8563_GetDateTime 每次覆盖,无累积问题。
w5500_test()(board_test.c:49-63) — 用 WIZnet 官方 API 把 W5500 芯片内部寄存器的 MAC 读回来,与软件侧保存的 IP_Address.u8_mac_addr[6] 做 strcmp。这里用 strcmp 比较 6 字节二进制 MAC,只要有 0x00 字节就会提前返回相等——MAC 地址出现 0x00 是合法的(例如 00:08:DC:...),存在漏检风险。
drm_test()(board_test.c:458-493) — 板型分流 + 双条件:
if (get_board_type() == BOARD_EMS3_6_2_E) { u8_drm = 0; return; } // 该板型无 DRM,直接通过
ad = get_drm0_data(); // DRM 口 AD 中间值
st[0..3] = get_drm1_flag() ... get_drm4_flag();
if (2000 < ad < 2100 && 四路标志全 TRUE) u8_drm = 0; else u8_drm = 1;
2000 ~ 2100 是硬编码的 ADC 期望窗口(约 2050 ± 50 的中间值,说明 DRM0 被固定在分压中点),无任何宏定义或注释解释。
dry_node_test()(board_test.c:502-593) — 干接点回环,两段 for(;;) 只跑一轮的写法:
- DO1 段:
DRY_NODE1_ON→ 等 100 ms → 读DI_1_ACCESS_POINT,若为 0(导通)则u8_dido1 = 0,否则置 1 并break;再DRY_NODE1_OFF→ 等 100 ms → 要求DI_1_ACCESS_POINT == 1,否则置 1 并break。两段都过才留下 0。 - DO2 段:先判断板型是否为
BOARD_EMS3_6_1_E/2_E/3_E/4_E(四个get_board_type()判断,其中一个漏了括号对齐但语义正确),是则做与 DO1 相同的回环;否则u8_dido2 = 0(该板型无 DO2,判通过)。
4.3 定时与调度时序
本文件没有参与任何 uCOS-II 同步原语(不用信号量、不用消息邮箱),全部靠忙等 + 喂狗:
| 位置 | 等待时长 | 实现方式 | 等价时长 |
|---|---|---|---|
led_test() 各阶段 | abs(OSTimeGet() - tick) < 1000 | 忙等 + IWDG_Feed() ×4 | 4 × 1000 ms |
usart_test() / rs485_test() 等待 | < 50 | 忙等 + IWDG_Feed() | 4 × 50 ms |
can_test() 帧间隔 | OSTimeDlyHMSM(0,0,0,1) | uCOS-II 主动让出 | 8 × 1 ms |
dry_node_test() 电平建立 | < 100 | 忙等 + IWDG_Feed() | 3 × 100 ms |
uCOS-II 的 OS_TICKS_PER_SEC = 1000(UCOSII/uCOS-CONFIG/os_cfg.h:51),所以 OSTimeGet() 的单位就是 1 ms,abs(...) < 1000 即 1 秒。
整轮耗时估算:LED 4 s + RS485/USART 4×50 ms + 干接点 300 ms + 各诊断函数耗时,约 5 秒左右。这段时间内 task_system_aux(优先级见 UCOSII/uCOS-CONFIG/app_cfg.h)无法处理其它工作,因此 board_test() 实际上是对整个系统的一次"停顿",只有反复 IWDG_Feed() 保证不被看门狗打断。
4.4 关键全局变量读写
| 变量 | 写者 | 读者 | 触发条件 |
|---|---|---|---|
g_u8_single_board_test_enable | board_test() 清 0(board_test.c:636);Modbus 置 1(modbus.c:6937) | board_test()(board_test.c:615)、ate.c:138/172、modbus.c:4212/4223 | Modbus 工装写寄存器 |
u_single_board_test_result | 除 led_test() 外所有子测试 | Modbus 寄存器高低 16 位(modbus.c:4214/4225) | 测试结束且使能标志为 0 时可读 |
g_u8_usart_buf / g_u8_rs485_buf | 编译期常量初始化 | usart_test()、rs485_test() | 仅本文件内部使用 |
5. 对外接口
本文件导出
| 名称 | 类型 | 供谁使用 |
|---|---|---|
board_test(void) | 函数(声明在 board_test.h:70) | midware/auxiliary/system_aux.c:2083 |
g_u8_single_board_test_enable | 全局变量(board_test.h:67) | midware/debug/ate.c:138/172、midware/interface/modbus/modbus.c:4212/4223/6937 |
u_single_board_test_result | 全局变量(board_test.h:68) | midware/interface/modbus/modbus.c:4214/4225 |
本文件调用的外部函数/变量
| 来源模块 | 使用内容 |
|---|---|
hardware/led(hmi/led 体系) | LED_Green_ON/OFF、LED_Red_ON/OFF、LED_Yellow_ON/OFF、LED_Blue_ON/OFF |
hardware/gpio/gpio.h | led_db0_on()~led_db7_on() 及对应 _off、get_drm0_data()、get_drm1_flag()~get_drm4_flag() |
midware/interface/dry_node/dry_node.h | 宏 DRY_NODE1_ON/OFF、DRY_NODE2_ON/OFF、DI_1_ACCESS_POINT、DI_2_ACCESS_POINT |
hardware/pcf8563 | PCF8563_GetDateTime()、PCF8563_Check_Time_Is_Valid()、_PCF8563_DateTime_Typedef |
hardware/flash | Flash_ReadID() |
hardware/sdram | FMC_SDRAM_WriteBuffer_02()、FMC_SDRAM_ReadBuffer_02()、SDRAM_SDRAM_TEST_ADDR、ADDR_MAX_SDRAM |
hardware/usart0/1/2/5、hardware/usart4 | usart2_send_data/clear_buffer/get_data_len/read_data_async、usart5_*、usart1_*、uart4_* |
hardware/can0、hardware/can1 | can0_send_standard_pack()、can1_send_standard_pack()、get_can0_standard_pack()、get_can1_standard_pack()、can0_clear_standard_pack()、can1_clear_standard_pack()、类型 CAN_MSG_TYPEDEF_T |
midware/ethernt/lan/wizchip_conf.h | ctlnetwork(CN_GET_NETINFO, ...)、类型 wiz_NetInfo |
midware/ethernt/ethernet.h | IP_Address.u8_mac_addr |
system/board_init/board_init.h | get_board_type()、BOARD_EMS3_6_1_E/2_E/3_E/4_E |
hardware/iwdg | IWDG_Feed() |
| uCOS-II | OSTimeGet()、OSTimeDlyHMSM() |
| 标准库 | strcmp、strncmp、memcmp、memset |
6. 依赖关系
依赖
board_test.h、can0.h、can1.h、flash.h、led.h、debug.h、usart0.h、usart1.h、usart2.h、usart3.h、usart4.h、usart5.h、lcd.h、spi1.h、spi2.h、w5500.h、pcf8563.h、sdram.h、ethernet.h、system_config.h、board_init.h、gpio.h、dry_node.h、iwdg.h(board_test.c:8-31)。
其中
usart3.h、lcd.h、spi1.h、spi2.h、system_config.h在本文件中被包含但没有任何符号被实际使用,属于历史遗留包含。
被依赖
midware/auxiliary/system_aux.c(includeboard_test.h,调用board_test())midware/interface/modbus/modbus.c(读写g_u8_single_board_test_enable、u_single_board_test_result)midware/debug/ate.c(读g_u8_single_board_test_enable,在单板测试期间禁止串口透传)
7. 备注与风险点
board_test()内注释与实际位号全部错位(board_test.c:622-631):注释写w5500 bit6(实际 bit8)、can1 bit7, can2 bit8(实际 bit9/bit10)、led bit10(LED 根本不写位,而 bit10 恰是u8_can2)。按注释理解结果字会得到完全错误的结论。led_test()不产生任何结果位,是纯目检项;但board_test()调用点给它标了个 "led bit10",容易让上位机以为 LED 有自动判定。u8_usart3与u8_can3被无条件置 0(通过)(board_test.c:633-634),没有做任何测试——即这两项对工装永远显示"通过"。- USART5 的测试结果写进了名为
u8_usart6的位(board_test.c:271-275)。hardware/usart5/usart5.c用的是USART5(PC6/PC7,usart5.c:24-29),所以位名与实际外设不符。 w5500_test()用strcmp比较 6 字节二进制 MAC(board_test.c:55):MAC 中出现0x00时strcmp提前返回相等,会漏判。正确做法是memcmp(..., 6)。flash_test()用一次 SPI Flash 读 ID 同时判定 Flash 与 EEPROM(board_test.c:405-406),EEPROM(I2C3)实际上从未被访问,"EEPROM 测试"名不副实。drm_test()的 AD 窗口2000 ~ 2100是硬编码魔法数字(board_test.c:475),无宏、无注释、未随板型区分。- 整轮测试是长时间忙等:
led_test()单次就忙等 4 秒,加上其它项总共约 5 秒。期间task_system_aux被独占,系统其它业务停摆,只靠IWDG_Feed()续命;若测试中途死循环(例如 CAN 收发 API 阻塞在更长超时里),看门狗仍会被喂住,无法复位。 dry_node_test()用for(;;) { ... break; }实现"只跑一次"(board_test.c:506、board_test.c:547),是goto/do-while的绕写;DO1 段末尾的break位于while延时循环之后,可读性差但语义正确。sdram_test()的越界保护只在读取循环内(board_test.c:432),而memset((u8*)SDRAM_SDRAM_TEST_ADDR, 0xFF, 1024)(board_test.c:428)在保护之前无条件执行 1024 字节写入;如果测试区紧贴地址上界,memset 仍可能越界。dry_node_test()对 DO2 的板型判断写成|| get_board_type() == BOARD_EMS3_6_4_E(board_test.c:549),前三个条件都带括号、最后一个没带,虽运算符优先级正确(==高于||),但风格不一致。FLASH_TEST__LEN宏(=32)在board_test.h:15定义后从未使用,是死宏。g_u8_usart_buf/g_u8_rs485_buf声明为全局但只在本文件使用,没有static,符号被外部可见;board_test.h也未extern它们,属于"泄漏的非 static 内部数据"。rs485_test()第一段失败时提前 return(board_test.c:328-331),此时u8_rs485已是 1,但其余测试项(USART/W5500/CAN/干接点等)仍会被board_test()继续调用——只在rs485_test()内部提前结束,不会跳过后续项。memset((u8*)SDRAM_SDRAM_TEST_ADDR, 0xFF, 1024)绕过FMC_SDRAM_WriteBuffer_02(),直接按 CPU 地址写;如果 SDRAM 尚未完成SystemInit中的控制器初始化,这一句会直接产生总线错误,而后续的写读校验才走正规 API,风格不统一。board_test.c的文件头注释写的是@file :singleboardtest.c(board_test.c:2),文件名与注释不符。