Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

22 KiB

PLSR 2026 重写测试报告

测试日期:2026-08-12

测试分支:codex/plsr-2026-minimal

测试代码基线:bf314a2343002a3df78bce5049badb29d11eae2e

PLSR 实现提交:c7b851659ea26f9af8563e146bf5332c3c8d6dfd

分支起点:e35595aae18690a46a03445865bd6218a166bd89

结论口径:只记录本次 2026 PLSR 最小重写实际执行过的测试

1. 总结

本次重写的 Host 回归、Python 离线自检、IAR 全量构建、固件烧录、真实 Modbus RTU 板测、Y0~Y3 逐路选择、X4/X5 实体回环、硬复位持久化和最终默认状态复核均通过。

类别 最终结果 数量或关键结果
C Host 回归 PASS 44 个测试组,1,694,007 次断言,0 失败
Python 产品测试脚本离线自检 PASS 未打开串口
Python 控制面板离线自检 PASS 未打开 GUI 或串口
IAR EWARM 全量构建 PASS 0 errors,0 warnings
固件烧录和校验 PASS Verification...OK,SHA256 与板测固件一致
Modbus RTU/运动板测 PASS 9 组
X4/X5 实体回环板测 PASS 9 个用例
硬复位持久化 PASS 配置和位置恢复,运动不自动续跑
最终默认状态复核 PASS 位置、配置、输入和夹具输出均恢复
逻辑分析仪测试 未执行 不在本轮验收范围内

这里的“Y0~Y3 验证”是同一个逻辑 PLSR 依次选择 Y0、Y1、Y2、Y3 作为脉冲输出,不是四轴同时运动或四轴联动。

1,694,007 assertions 是逐脉冲检查、边界检查和随机算术比对产生的断言总数,不代表 169 万个独立测试场景。

2. 测试范围和口径

2.1 纳入本报告

  • 本次重写新增的固定产品寄存器区:0x1000~0x11970x2000~0x20060x3000
  • 单个逻辑 PLSR 的配置、状态、控制、运动、短段曲线、动态调频和停止。
  • 单个逻辑 PLSR 对 Y0~Y3 的逐路选择。
  • X4/X5 的 WAIT、EXT 和 EXT_OR_COMPLETE 实体输入回环。
  • 产品配置与逻辑位置的保存、硬复位恢复和默认值恢复。
  • 最小 Modbus RTU 的真实串口访问和异常响应。
  • 当前代码基线的 Host、Python、IAR 和固件产物复核。

2.2 不纳入本报告

旧工程曾做过的四轴并发、双 AB、软限位、长稳、USB CDC 并发和逻辑分析仪波形测试属于另一套实现,不能作为本次重写的通过证据,因此没有合并到本报告。

3. 环境与产物

项目 实际环境或结果
目标板 信捷 XDM-60T4-E,STM32F407IG
RTOS uC/OS-II
串口 COM5,9600 bit/s,8E1,从站 1
Host 编译器 GCC 4.9.2 (tdm64-1)
Host 编译选项 C99,-Wall -Wextra -WerrorPLSR_HOST_TEST
IAR EWARM 8.3.4,配置 Modbus
IAR 工程 EWARM/Modbus.ewp
HEX EWARM/Modbus/Exe/Modbus.hex
HEX 文本文件大小 142,131 B
Intel HEX 有效数据 50,513 B
HEX 地址范围 0x08000000..0x0800C550
SHA256 97956D9EF30A9B274140B9B82F412EDD77F9637F563FCC3F552BB4B140772343

IAR 链接结果:

49,004 bytes of readonly code memory
 1,509 bytes of readonly data memory
18,660 bytes of readwrite data memory
Errors: none
Warnings: none

4. 最终自动化回归

4.1 C Host 回归

执行命令:

powershell.exe -NoProfile -ExecutionPolicy Bypass `
  -File .\tests\plsr_host\run_tests.ps1

最终输出:

SUMMARY tests=44 assertions=1694007 failures=0

44 个测试组全部 PASS:

# 测试组 实际验证内容
1 u64_by_u32_division 用 8 个边界被除数、9 个边界除数和 250,000 组确定性伪随机数据,比对 64 位除 32 位算法与 C 原生除法的商和余数。
2 protocol_boundaries 覆盖区间外、跨区、地址溢出、零长度、空缓冲、只读区、保留字、32 位字段不完整写入、非法值和控制字宽度,并确认失败写入不破坏原值。
3 wait_zero_one_ms 验证 WAIT_TIME=0 按最小 1 ms 处理,先进入 WAITING,1 ms 后才进入下一段。
4 act_zero_no_pulse 验证 ACT_TIME=0 的段不产生脉冲并在下一次 1 ms 调度跳过,后续段正常执行。
5 relative_absolute_zero 验证相对位移 0、相对位移 +5,以及当前位置等于绝对目标时的零位移完成。
6 self_jump_stop 验证单段自跳转可循环运行,并能由 STOP 正常终止。
7 stop_deceleration 验证 STOP 从 1000 Hz 按 1000 ms 减速至 100 Hz 后停止;重复 STOP 不重启减速,最终位置 902。
8 stop_pending_boundary 验证最后脉冲已完成但 Poll 尚未处理时收到 STOP,最终为 STOPPED 而非 COMPLETED。
9 direction_delay_one_ms 验证 1 ms 方向建立延时结束前不输出脉冲,满 1 ms 后启动。
10 ext_edge_at_natural_boundary 验证 EXT 边沿和自然末脉冲同时发生时只处理一次,不重复切段或计数。
11 ext_cut_natural_boundary_interleavings 覆盖 EXT 切断与自然边界的两种临界交错顺序,均正确进入后续 2000 Hz 段。
12 ext_edge_during_direction_delay 验证方向延时期间的 EXT 边沿不会在首脉冲前错误切段。
13 stopped_clears_pending_ext 验证 STOP 清除方向延时期间挂起的 EXT 边沿,重新 START 不消费旧边沿。
14 ext_edge_seamless_epoch 验证上一段的 EXT 竞态不会误切无缝衔接后的下一段。
15 ramp_seamless_epoch 验证上一段遗留的调速更新不会重定向无缝衔接后的下一段。
16 short_profile_boundary_matrix 覆盖直线、平滑、正弦三曲线与 1、2、10、99、100、101 脉冲,检查频率范围、升降趋势、对称性、计数和理论时长。
17 short_final_no_poll 验证三种曲线的 10 脉冲最终短段在脉冲间无 1 ms Poll 时仍逐脉冲减速并准确完成。
18 zero_to_maximum_ramp_duration 验证三种曲线从 0 加速到 100 kHz、1000 脉冲、20 ms 配置的单调性、峰值和总时长。
19 maximum_pulse_ramp_duration 验证三种曲线在 65,535 脉冲和 1311 ms 加速条件下采用可达峰值并准确计数。
20 maximum_single_ramp_no_poll 验证三种曲线的 65,535 脉冲单段在无 Poll 时持续逐脉冲更新并准确完成。
21 short_timer_failure 注入短段频率更新失败,验证立即关闭输出并进入 ERROR/TIMER,位置保留为 1。
22 stop_after_subsequent_handoff 验证无缝切入第二段后立即 STOP 能从新段频率正常减速并停止。
23 short_zero_speed_edges 验证起始/停止速度均为 0 时,1 脉冲和 2 脉冲短段仍以有效非零硬件频率准确执行。
24 short_dynamic_retarget 验证 50 脉冲短段中把目标频率由 1000 改为 2000 Hz 后安全上升,随后 STOP 正常停止。
25 short_ext_cut 验证短段执行 3 脉冲后触发 EXT,在下一脉冲边界切断,最终位置 4。
26 current_frequency_dynamic 验证当前段动态频率按安全脉冲边界生效,状态反映实际输出,运行中改脉冲数不改变启动快照。
27 poll_mailbox_failure 注入动态调频失败,验证 Poll 仅提交更新,失败在脉冲边界转为 ERROR/TIMER
28 future_frequency_on_arrival 普通逐段模式中修改未来第二段频率,当前段不受影响,到达第二段时采用新值。
29 subsequent_future_frequency_handoff 无缝模式中修改未来段频率,验证预装衔接重建并以新频率无缝进入第二段。
30 future_frequency_last_pulse_race 验证未来段调频与当前段最后脉冲竞态时,第二段仍以新频率启动并准确完成。
31 latched_update_before_future_frequency_commit 验证屏蔽中断期间锁存的物理脉冲先消费旧衔接,再提交新的未来频率预装。
32 subsequent_no_poll_gap 验证两段只靠 ISR 无缝衔接,中间不依赖 Poll,输出不停止,最终位置 7。
33 three_single_pulse_no_poll 验证三个各 1 脉冲、1000/2000/3000 Hz 的段在无 Poll 时连续衔接。
34 handoff_queue_failures 两种时序下注入下一段频率排队失败,均关闭输出并转为 ERROR/TIMER
35 command_state_restrictions 验证 IDLE/RUNNING 状态下 START、STOP、CLEAR、静态/动态配置写入及非法组合的限制。
36 command_mailbox_start_snapshot 验证 START 延迟执行与配置快照,后续写入和重复 START 不覆盖首个快照。
37 command_mailbox_stop_clear_deferred 验证重复 STOP/CLEAR 可幂等入队,状态变化延迟到 Poll,冲突命令返回 BUSY。
38 command_mailbox_validation 验证 START 入队前检查起始段和绝对位置有效性,非法配置不启动。
39 command_mailbox_start_failure 注入底层启动失败,验证 Poll 后进入 ERROR/INVALID_RESOURCE,CLEAR 可恢复。
40 wait_signal_positive 验证段后进入 WAITING,选定输入有效后由下一次 Poll 结束等待。
41 persistence_reinit 在 Host 存储模拟中验证输出、方向、2345 Hz 配置和位置 4 跨 PlsrInit() 恢复,CLEAR 后位置保持 0。
42 position_flash_save 验证位置稳定约 1000 ms 后仅保存一次,CLEAR 后延时产生第二次保存。
43 busy_reset_absolute_gate 模拟运动中复位,保留位置但取消绝对位置可信标志;CLEAR 后恢复绝对运动。
44 position_overflow 验证 INT32_MAX 正向溢出时立即停脉冲并进入 ERROR/COUNT

说明:Host 测试直接调用寄存器 API 和平台替身,不能代替真实 RTU 串口板测;真实 RTU 结果见第 7 节。

4.2 Python 产品测试脚本离线自检

执行命令:

py -B HostComputer\plsr_modbus_product_test.py --self-test

结果:

Self-test passed; no serial port was opened

覆盖:

  • Modbus CRC16 参考向量及线上低字节在前的字节序。
  • 6 组有符号 32 位数的双 WORD 拆分与合并。
  • 1200 Hz 请求的 1 Hz 容差边界。
  • ST-LINK GPIO 位读回文本解析。

4.3 Python 控制面板离线自检

执行命令:

py -B HostComputer\plsr_control_panel.py --self-test

结果:

PLSR control panel self-test passed; no GUI or serial port was opened

覆盖 9600 波特率、X4/X5 选项、10 段地址步进、整数解析和越界拒绝、公共区 20 WORD 编码、段区 8 WORD 编码、负脉冲补码及跳转段范围校验。

5. IAR 构建

执行命令:

& 'F:\IAR Systems\Embedded Workbench 8.3\common\bin\IarBuild.exe' `
  'EWARM\Modbus.ewp' -build Modbus -log warnings

最终结果:

Total number of errors: 0
Total number of warnings: 0

EWARM/Modbus/List/Modbus.map 同时报告 Errors: noneWarnings: none,内存数据见第 3 节。

6. 烧录与固件产物校验

6.1 烧录

最终烧录使用 EWARM/Modbus/Exe/Modbus.hex,只擦除并写入应用占用的 Sector 0~3。ST-LINK 最终输出:

Verification...OK

开发过程中还用 STM32CubeProgrammer 执行过两次下载校验,用于确认当时固件可以下载和校验。它们属于中间版本的烧录链路记录,不是功能测试,也不作为最终交付固件的产物证据;最终结论以上述 ST-LINK 烧录、最终 SHA256 和后续完整板测为准。

6.2 持久化区保护

烧录前后均读取并检查 Sector 10/11。应用 HEX 地址上限为 0x0800C550,不覆盖持久化区;烧录流程也没有擦除 Sector 10/11。该检查用于确认后续持久化板测不是由重新烧录清空后伪造出的初始状态。

6.3 产物一致性

板测烧录件和当前分支重新构建产物的 SHA256 均为:

97956D9EF30A9B274140B9B82F412EDD77F9637F563FCC3F552BB4B140772343

7. 真实 Modbus RTU 和运动板测

执行入口:

py -B HostComputer\plsr_modbus_product_test.py `
  --port COM5 --run --phase all --allow-motion

最终 phase=all 的 9 组测试全部 PASS:

# 用例 实际验证内容 结果
1 fixed_map_and_exceptions 真实 FC03/06/10 访问固定配置、段、状态和控制区;检查保留字读零、控制字读零;验证不支持 FC01 返回 0x01,非法/跨区/只读地址返回 0x02,保留字非零、半个 DWORD 和组合控制命令返回 0x03。 PASS
2 positive_negative_absolute_zero 验证正向相对、负向相对、绝对定位及零位移,检查方向、终态和逻辑位置。 PASS
3 all_outputs_100khz 同一个 PLSR 依次选择 Y0、Y1、Y2、Y3,每路请求 100 kHz、执行 1000 个逻辑脉冲并检查完成位置。不是四轴并发。 PASS
4 short_final_profiles 对直线、平滑、正弦三种曲线执行最终 10 脉冲短段,检查终态和准确位置。 PASS
5 wait_time 执行 10 脉冲后进入 WAITING,配置等待 120 ms;检查不会异常提前完成,之后正常完成。 PASS
6 act_time 2000 脉冲目标配合 80 ms ACT,检查时间到后在 0~2000 之间切断并正常完成。 PASS
7 dynamic_frequency_repeated_stop 当前段从 500 Hz 动态改为 1200 Hz;真实状态读回 1199 Hz,在允许的 1 Hz 容差内;运行中静态输出选择写入返回 BUSY;重复 STOP 正常减速停止且未跑满 3000 脉冲。 PASS
8 future_segment_frequency_on_arrival 普通逐段模式运行第一段时修改未来第二段频率,确认当前段仍为 400 Hz,进入第二段后采用 900 Hz。 PASS
9 subsequent_future_frequency_handoff SUBSEQUENT 模式运行第一段时修改未来段频率,确认当前段不变,第二段以 900 Hz 衔接并最终累计 400 脉冲。 PASS

脚本在退出时停止仍在运行的任务,并恢复进入测试前保存的公共配置和前两段配置。

正式烧录后还在完整 phase=all 之前单独执行过一次 --phase smoke,固定映射和异常码检查 PASS。第 9 节恢复默认值并再次硬复位后又执行了一次 smoke,结果仍为 PASS。

8. X4/X5 实体回环板测

8.1 接线和方法

本轮保留的自动化回环接线:

Y4 -> X4
Y5 -> X5

脚本通过 ST-LINK 临时把 Y4/Y5 对应 GPIO 配置为输出,驱动 PLC 输入并直接读回 X4/X5 输入位;产品协议和正式固件没有为测试夹具新增私有寄存器。

开发期夹具最初尝试写 GPIO 的只写 BSRR 寄存器。旧版 ST-LINK_CLI 3.5.0 会在写后回读校验,因 BSRR 不可按普通寄存器回读而返回码 4。夹具随后改用 PI8/PE6 的 ODR 位带地址 0x424402A00x42420298 驱动输出。该失败是调试工具与只写寄存器的校验方式不兼容,不是接线、X4/X5 输入或 PLSR 功能故障。

执行入口:

py -B HostComputer\plsr_modbus_product_test.py `
  --port COM5 --run --phase x45 --allow-motion

8.2 九个用例

# 用例 实际验证内容 结果
1 x45_electrical_scan Y4/Y5 均关闭时 X4/X5 均为低;分别打开 Y4、Y5 时对应输入为高、另一路保持低;关闭后恢复低,验证双路电气扫描和隔离。 PASS
2 X4_wait_signal 选择 X4;50 脉冲后进入 WAITING,X4 低时保持,Y4 拉有效后完成,位置仍为 50。 PASS
3 X4_ext_signal 选择 X4;5000 脉冲运动中由 Y4 触发 EXT_SIGNAL,提前切段并正常完成。 PASS
4 X4_ext_or_complete_natural 选择 X4;不触发输入,50 脉冲自然完成。 PASS
5 X4_ext_or_complete_trigger 选择 X4;5000 脉冲运动中由 Y4 外部触发,提前完成。 PASS
6 X5_wait_signal 选择 X5;50 脉冲后进入 WAITING,X5 低时保持,Y5 拉有效后完成,位置仍为 50。 PASS
7 X5_ext_signal 选择 X5;5000 脉冲运动中由 Y5 触发 EXT_SIGNAL,提前切段并正常完成。 PASS
8 X5_ext_or_complete_natural 选择 X5;不触发输入,50 脉冲自然完成。 PASS
9 X5_ext_or_complete_trigger 选择 X5;5000 脉冲运动中由 Y5 外部触发,提前完成。 PASS

ODR 位带夹具修正后先完成独立电气扫描,再执行完整九项用例。异常清理顺序修正后又执行了第二次完整九项回归,结果仍全部 PASS。

8.3 最终夹具清理状态

测试结束或异常退出均按以下顺序清理:先关闭 Y4/Y5,再停止仍在运行的 PLSR,恢复测试前配置,最后把 PI8/PE6 恢复为输入高阻并清除上下拉。最终复核结果:

  • Y4/Y5 均关闭。
  • PI8/PE6 均为输入高阻、无内部上下拉。
  • X4/X5 读回均为低。

9. 持久化与硬复位板测

持久化测试使用真实目标板和 100 ms 硬复位,不以 Host 内存模拟代替。

9.1 保存准备

执行 persistence-prepare

  • 清零逻辑位置。
  • 写入 500 Hz、7 脉冲的特征配置。
  • 执行运动并确认 COMPLETED、位置为 7。
  • 等待后台保存完成。

9.2 第一次硬复位和恢复检查

执行 100 ms 硬复位后运行 persistence-verify --cleanup,结果:

  • 上电状态为 IDLE,没有自动续跑复位前任务。
  • 逻辑位置恢复为 7。
  • 第一段频率恢复为 500 Hz。
  • 第一段脉冲数恢复为 7。

随后执行 CLEAR,把位置恢复为 0;写回默认配置并等待保存。

9.3 第二次硬复位和默认状态检查

再次执行 100 ms 硬复位后运行 defaults-verify,结果:

  • 状态为 IDLE,逻辑位置为 0。
  • 默认方向建立延时为 10 ms。
  • 默认速度为 1000 Hz,起始速度和停止速度均为 100 Hz。
  • 第 1 段为 1000 Hz、1000 脉冲。
  • 第 2~10 段频率均为 1000 Hz、脉冲数均为 0。

最后又执行一次固定映射 smoke,确认默认配置恢复后 RTU 访问和异常码仍通过。

10. 测试过程中出现的问题和修复回归

本节记录中间失败;这些结果不是最终失败,而是用于说明本轮调试实际发现并关闭了哪些问题。

阶段 中间现象 原因与处理 修复后结果
旧架构 PDU 试验 length == 8UTestStatusAndControl() == 0 失败 试验基于待废弃的旧 PDU 架构。需求复核后没有继续补旧架构,而是按 2026 固定产品接口重写;该试验路线整体废弃。 新固定接口由 Host protocol_boundaries 和真实 fixed_map_and_exceptions 覆盖并通过。
初期 Host 12 tests / 262 assertions / 2 failures 失败项是 wait_zero_rejectedact_zero_rejected。复核明确需求后确认正确语义为 WAIT=0 按 1 ms,ACT=0 零脉冲跳段,代码和测试按正确语义修正。 wait_zero_one_msact_zero_no_pulse 通过;最终 44/1,694,007/0。
扩充 EXT 测试 Host 编译失败,PLSR_EXT_SIGNAL 未声明 测试扩充时枚举和测试引用未同步,补齐枚举/接口后重跑。 Host 编译和完整回归通过。
Modbus 裁剪中间态 IAR 10 errors / 2 warnings 头文件先精简,旧源文件与 main.c 尚未同步清理;不是运动算法失败。随后完成最小 RTU 源文件和入口同步。 IAR 全量构建 0 errors / 0 warnings
Host 脚本启动 Windows 默认策略阻止直接运行 .ps1 改用 powershell.exe -NoProfile -ExecutionPolicy Bypass -File ... Host 脚本正常执行并通过。
X4/X5 夹具初版 ST-LINK_CLI 3.5.0 写 BSRR 返回码 4 BSRR 是只写寄存器,旧 CLI 的写后回读校验不适用。改用 PI8/PE6 的 ODR 位带地址驱动 Y4/Y5。 独立电气扫描和完整 X4/X5 九项通过;判定为夹具工具限制,不计为产品失败。
X4/X5 夹具审查 异常退出清理顺序不够安全 调整为先关闭 Y4/Y5,再停止运动、恢复配置,最后释放 GPIO;保证清理期间不会继续保持输入触发。 完整 X4/X5 九项重新执行并通过,最终 GPIO/输入状态复核通过。

中间失败均保留在本报告中,但最终交付结论以当前基线重新执行的结果为准。

11. 明确未执行和结论边界

以下项目本轮未执行,不得从本报告的 PASS 推导为已验证:

  • 未使用逻辑分析仪,因此没有验证端子真实占空比、每路真实边沿数、毛刺、窄脉冲、方向建立时间或段间物理波形连续性。
  • 未对 MCU 中断最坏响应时间和 100 kHz 下的 ISR 最坏时延做仪器测量。
  • 未做四轴同时运动或四轴联动;本实现只有一个逻辑 PLSR,Y0~Y3 是逐路选择。
  • 未做 USB CDC 与 Modbus/运动并发长稳。
  • 未做本次最小重写的长时间压力、断线重连或坏 CRC 长稳矩阵。
  • 未做真实 VBAT 断主电源测试。本轮实际执行的是调试器控制的 100 ms 硬复位;它能证明复位恢复路径,不能等价证明 VBAT/完全掉电保持。
  • Host 的持久化用例使用内存模拟;真实 Flash/复位结论仅来自第 9 节板测。
  • Host 直接调用寄存器 API,不证明 RTU 物理链路;真实 RTU 覆盖仅限第 7~9 节列出的板测。
  • 未用 IAR 8.40 构建;本轮实际验证版本为 IAR EWARM 8.3.4。

12. 最终状态

测试结束后目标板处于以下状态:

  • 固件为 SHA256 97956D9EF30A9B274140B9B82F412EDD77F9637F563FCC3F552BB4B140772343 对应版本。
  • PLSR 状态为 IDLE,逻辑位置为 0。
  • 固定产品寄存器配置已恢复默认值。
  • Y4/Y5 夹具输出已关闭,PI8/PE6 已释放为输入高阻。
  • X4/X5 均读回低。
  • 最终 defaults-verify 和固定映射 smoke 均 PASS。

本报告没有引用旧实现的四轴、双 AB、长稳或逻辑分析仪结果作为本次重写证据。