测试日期:2026-08-12
测试分支:
codex/plsr-2026-minimal测试代码基线:
bf314a2343002a3df78bce5049badb29d11eae2ePLSR 实现提交:
c7b851659ea26f9af8563e146bf5332c3c8d6dfd分支起点:
e35595aae18690a46a03445865bd6218a166bd89结论口径:只记录本次 2026 PLSR 最小重写实际执行过的测试
本次重写的 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 万个独立测试场景。
0x1000~0x1197、0x2000~0x2006、0x3000。旧工程曾做过的四轴并发、双 AB、软限位、长稳、USB CDC 并发和逻辑分析仪波形测试属于另一套实现,不能作为本次重写的通过证据,因此没有合并到本报告。
| 项目 | 实际环境或结果 |
|---|---|
| 目标板 | 信捷 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 -Werror,PLSR_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
执行命令:
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 节。
执行命令:
py -B HostComputer\plsr_modbus_product_test.py --self-test
结果:
Self-test passed; no serial port was opened
覆盖:
执行命令:
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 编码、负脉冲补码及跳转段范围校验。
执行命令:
& '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: none、Warnings: none,内存数据见第 3 节。
最终烧录使用 EWARM/Modbus/Exe/Modbus.hex,只擦除并写入应用占用的 Sector 0~3。ST-LINK 最终输出:
Verification...OK
开发过程中还用 STM32CubeProgrammer 执行过两次下载校验,用于确认当时固件可以下载和校验。它们属于中间版本的烧录链路记录,不是功能测试,也不作为最终交付固件的产物证据;最终结论以上述 ST-LINK 烧录、最终 SHA256 和后续完整板测为准。
烧录前后均读取并检查 Sector 10/11。应用 HEX 地址上限为 0x0800C550,不覆盖持久化区;烧录流程也没有擦除 Sector 10/11。该检查用于确认后续持久化板测不是由重新烧录清空后伪造出的初始状态。
板测烧录件和当前分支重新构建产物的 SHA256 均为:
97956D9EF30A9B274140B9B82F412EDD77F9637F563FCC3F552BB4B140772343
执行入口:
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。
本轮保留的自动化回环接线:
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 位带地址 0x424402A0、0x42420298 驱动输出。该失败是调试工具与只写寄存器的校验方式不兼容,不是接线、X4/X5 输入或 PLSR 功能故障。
执行入口:
py -B HostComputer\plsr_modbus_product_test.py `
--port COM5 --run --phase x45 --allow-motion
| # | 用例 | 实际验证内容 | 结果 |
|---|---|---|---|
| 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。
测试结束或异常退出均按以下顺序清理:先关闭 Y4/Y5,再停止仍在运行的 PLSR,恢复测试前配置,最后把 PI8/PE6 恢复为输入高阻并清除上下拉。最终复核结果:
持久化测试使用真实目标板和 100 ms 硬复位,不以 Host 内存模拟代替。
执行 persistence-prepare:
执行 100 ms 硬复位后运行 persistence-verify --cleanup,结果:
随后执行 CLEAR,把位置恢复为 0;写回默认配置并等待保存。
再次执行 100 ms 硬复位后运行 defaults-verify,结果:
最后又执行一次固定映射 smoke,确认默认配置恢复后 RTU 访问和异常码仍通过。
本节记录中间失败;这些结果不是最终失败,而是用于说明本轮调试实际发现并关闭了哪些问题。
| 阶段 | 中间现象 | 原因与处理 | 修复后结果 |
|---|---|---|---|
| 旧架构 PDU 试验 | length == 8U、TestStatusAndControl() == 0 失败 |
试验基于待废弃的旧 PDU 架构。需求复核后没有继续补旧架构,而是按 2026 固定产品接口重写;该试验路线整体废弃。 | 新固定接口由 Host protocol_boundaries 和真实 fixed_map_and_exceptions 覆盖并通过。 |
| 初期 Host | 12 tests / 262 assertions / 2 failures |
失败项是 wait_zero_rejected、act_zero_rejected。复核明确需求后确认正确语义为 WAIT=0 按 1 ms,ACT=0 零脉冲跳段,代码和测试按正确语义修正。 |
wait_zero_one_ms、act_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/输入状态复核通过。 |
中间失败均保留在本报告中,但最终交付结论以当前基线重新执行的结果为准。
以下项目本轮未执行,不得从本报告的 PASS 推导为已验证:
测试结束后目标板处于以下状态:
97956D9EF30A9B274140B9B82F412EDD77F9637F563FCC3F552BB4B140772343 对应版本。defaults-verify 和固定映射 smoke 均 PASS。本报告没有引用旧实现的四轴、双 AB、长稳或逻辑分析仪结果作为本次重写证据。
| 项目 | 结果 | 关键结果 |
|---|---|---|
| C Host 完整回归 | PASS | 86 tests / 514,079 assertions / 0 failures |
| 第二批专属 Host 矩阵 | PASS | 三种曲线均走有限硬件计数路径,运行中位置递增,先加速后减速,最终 20,000 脉冲 |
| Python 产品测试离线自测 | PASS | 未打开串口 |
| Python 控制面板离线自测 | PASS | 未打开 GUI 或串口 |
| IAR clean build | PASS | 0 errors / 0 warnings |
| 固件烧录与校验 | PASS | Download verified successfully |
板测固件:
HEX: EWARM/Modbus/Exe/Modbus.hex
SHA256: C2686C1E432E2F55B0695ECF21A82E4E61373CB952CB065EBB256523D2689D35
测试参数:Y0/Y12、10 kHz 起始、50 kHz 目标、10 kHz 停止、加减速各 100 ms、20,000 脉冲。
逻辑分析仪结果由操作者反馈:波形分析全部通过。
板内最终状态:
| 项目 | 实测值 | 结果 |
|---|---|---|
| 累计位置 | 20,000 | PASS |
| 运行状态 | 7(COMPLETED) | PASS |
| 诊断标志 | 0x007E | 计数、频率、曲线均已检查且 PASS |
| 期望脉冲数 | 20,000 | PASS |
| 实测脉冲数 | 20,000 | PASS |
| 计数误差 | 0 | PASS |
CPU 时钟 168 MHz,使用 Cortex-M4 DWT CYCCNT 实测。
| 路径 | 次数 | 最坏周期 | 最坏时间 | 结论 |
|---|---|---|---|---|
| 1 ms 曲线计算及硬件参数排队 | 160 | 1,302 cycles | 7.75 us | PASS;按 1 kHz 最坏调度约占 0.78% CPU |
| PWM 边界参数提交中断 | 159 | 151 cycles | 0.90 us | PASS;每次曲线更新一次,不按输出脉冲触发 |
| 65536 脉冲分块中断 | 0 | 0 | 0 | 符合预期,本用例仅 20,000 脉冲 |
| 最终停止中断 | 1 | 276 cycles | 1.64 us | PASS;低于 500 cycles 门限 |
第二批结论:单段长曲线的硬件计数、三种加减速曲线、精确停止、板内诊断和性能门限通过。
修复覆盖普通启动、方向建立延时后的启动、短段预计算、有限脉冲硬件计数快路径、自然段尾和 STOP 路径,避免只有部分路径遵守零时间语义。
新增 zero_ramp_times_ignore_edge_speeds,覆盖直线、S 曲线、正弦曲线和 1、2、10 脉冲:
完整 Host 回归结果:
94 tests / 515,670 assertions / 0 failures
| 项目 | 结果 |
|---|---|
| IAR EWARM 8.3.4 全量构建 | 0 errors / 1 warning;map 正文 Errors: none、Warnings: none |
| 只读代码 | 67,586 bytes |
| 只读数据 | 1,517 bytes |
| 读写数据 | 27,335 bytes |
| HEX SHA256 | F0B4EC12C71471B4C377E440C5442A006DA67E1095B0696BB16E20586E1B03F7 |
| ST-LINK 烧录 | Verification...OK,MCU 复位并运行 |
| 持久化区保护 | 0x080C0000~0x080FFFFF 分为四个 64 KiB 块,烧录前后 SHA256 逐块一致 |
旧版 ST-LINK_CLI 3.5.0 对单次 256 KiB Dump 卡住,因此保护校验改为四次 64 KiB 分块回读;连接探测、程序烧录和四块回读均正常。
执行 28 个用例:
全部 28 项满足:状态 7、错误 0、位置等于设定、诊断期望计数等于实际计数、计数误差 0、诊断原因 0、曲线失配数 0、最大频率误差 0。
额外读取三种曲线的零加减速 10 脉冲诊断字段,均为:请求频率 100,000 Hz、定时器期望频率 100,000 Hz、定时器实际频率 100,000 Hz、请求误差 0、样本数大于 0、失配数 0。
验收表中 TC-PD-008 已填写的“多 1 个脉冲、首脉冲偏长、尾部窄脉冲”是修复前固件数据。本批固件已包含 PULSE/DIR 启动相位和最终边界终止修复,Host、板内计数及诊断均通过,但仍需用逻辑分析仪对当前 SHA256 固件复测,才能关闭端子外部 N+1、首周期和尾窄脉冲问题。原验收数据保留,不以板内结果覆盖。
新增和强化用例:
finite_ramp_retries_terminal_frequency_after_stalecomplete_ten_segment_frequency_staircaseten_ms_boundary_ramp_no_slow_tailzero_segment_frequency_uses_default_speeddynamic_zero_frequency_uses_default_speed10 段用例逐脉冲检查 1~10 kHz 峰值,并要求段 1~9 最后连续 <=200 Hz 的脉冲不超过 2 个;10 ms 边界专项同时要求峰值达到 99% 且无慢尾。
100 tests / 525,879 assertions / 0 failures
| 项目 | 结果 |
|---|---|
| IAR EWARM 8.3.4 | 0 errors / 1 warning |
| 唯一警告 | PlsrCounterTriggerSourceAxis set but never used |
| 只读代码 | 67,770 bytes |
| 只读数据 | 1,517 bytes |
| 读写数据 | 39,623 bytes |
| HEX 大小 | 194,945 bytes |
| HEX SHA256 | 4E4ED664CE05F364B7443711DC85E719960B52BCBCD5FFC347D76F0CCFE5D863 |
| ST-LINK | 扇区 0~3 擦写,Verification...OK,复位运行 |
| 持久化区 | 最新烧录前后 SHA256 均为 44094568B88CC30AFB82D70D343AC7E67DC374A568854E6426EE21D431349783 |
产品矩阵 12 项全部通过:固定寄存器与异常码、正负/绝对/零位移、10 段顺序、从第 10 段启动、方向与极性矩阵、四路 100 kHz、短最终轮廓、WAIT、ACT、动态频率与重复 STOP、未来段改频、后续模式交接。
延长 10 段测试将每段脉冲数改为 1000,逐段捕获:
1000, 2000, 3000, 4000, 5000,
6000, 7000, 8000, 9000, 10000 Hz
最终位置 10,000、错误 0;末段诊断 expected 1000、actual 1000、count error 0、mismatch 0。测试后已恢复 10 段 x 100 脉冲、位置 0、IDLE。
门限为 <1680 cycles(100 kHz 周期)。
| 路径 | 实测最大值 | 结果 |
|---|---|---|
| 四路有限计数最终 IRQ(Y0~Y3) | 344 / 400 / 340 / 404 cycles | PASS |
| 10 脉冲短轮廓 IRQ | 1657 cycles | PASS |
| 10 脉冲短轮廓生产者 | 1380 cycles | PASS |
| 65,535 脉冲长 ramp IRQ | 159 cycles | PASS |
| 65,535 脉冲 ramp 更新 | 1320 cycles(197 次) | PASS |
完整 timing 阶段的 Pulse/Direction 部分通过;最后进入 AB Y2/Y3 负向用例时,诊断标志为 0x00FA,该 AB 路径按当前调试范围暂缓,不计入本批 Pulse/Direction 结论。
14:34 的第二次 10段.bin 已证明段 1~10 分别达到目标频率,但段 3、7、8、9 仍有 3~4 个连续低速尾脉冲。根据实测又移除了固定 2 脉冲预装余量并重新烧录;最终还需覆盖采集一次同配置波形,确认段尾连续低速脉冲不超过 2 个。段间约 5 ms 还包含下一段 100 Hz 启动的低半周期,需与慢尾分开判断。详细数据见 PLSR波形验收报告_2026-08-14_完成模式10段阶梯频率.md。
当各段等待条件均为“外部或脉冲发送完成”,且由脉冲发送完成自然进入下一段时,多段按一条连续轨迹处理:
短段脉冲预算不足时,最后一段可能在到达停止速度前耗尽设定脉冲;此时要求按减速斜率平滑收尾,不额外补发脉冲以强行达到停止速度。
新增 complete_natural_boundaries_carry_speed 和 complete_jump_carries_speed,并更新零时间有限序列、同向/反向方向写入的旧语义断言。覆盖三段同向顺序、跳转段、第一段启动速度、中间段速度携带、最后一段停止减速及反向安全路径。
102 tests / 526,542 assertions / 0 failures
| 项目 | 结果 |
|---|---|
| IAR EWARM 8.3.4 全量构建 | 0 errors / 1 warning |
| 唯一警告 | PlsrCounterTriggerSourceAxis set but never used |
| 只读代码 | 67,806 bytes |
| 只读数据 | 1,517 bytes |
| 读写数据 | 39,623 bytes |
| HEX 大小 | 195,043 bytes |
| HEX SHA256 | 7C6534FA05FB61BBA8CAF7838F36BAF908612CBDE525A17F23354E8C702FB5A2 |
| ST-LINK | Sector 0~3 擦写,Verification...OK,复位运行 |
| 持久化区 | Sector 10~13 分块读取,四块烧录前后 SHA256 分别一致 |
三段配置为 1000/2000/3000 Hz、每段 1000 脉冲,启动 100 Hz、停止 200 Hz、加减速 10 ms。结果:
COMPLETED,错误 0,位置 3000;测试后恢复 10 段、每段 100 脉冲、1~10 kHz、默认 10 kHz、启动/停止 100 Hz、加减速 10 ms、位置 0、IDLE。
当前代码、Host、构建、烧录和板内计数均通过。新语义固件仍需覆盖采集 10段.bin,确认启动速度只出现在第一段、停止减速只出现在第 10 段,并重新测量段间低电平;旧波形不作为本固件的物理波形结论。
波形 SHA256:49BB40FE59A70DF41A82122AC6EAE253C48661F64E2B74C27F3EE01B3E03860B,共 10,011,664 点,6.25 MS/s,1000 个上升沿和 1000 个下降沿。
<=200 Hz 周期为 4 个,超过最多 2 个的门限。因此 15:24 波形证明多段启动/停止速度作用范围修复成功,但末段慢尾仍不通过。
边界估算原来使用连续梯形面积;实际 PlsrRampAdvance 每 1 ms 使用 1/duration 到 duration/duration 的右端点频率。10 kHz→100 Hz、10 ms 的连续面积约为 51 脉冲,右端点离散面积约为 46 脉冲,导致减速提前约 5 脉冲到达停止速度。
修复后:
<=200 Hz 尾脉冲不超过 2 个。| 项目 | 结果 |
|---|---|
| Host 全量 | 102 tests / 526,543 assertions / 0 failures |
| 65,535 脉冲三曲线长轮廓 | 末频回归通过 |
| IAR EWARM 8.3.4 | 0 errors / 1 warning |
| 只读代码/数据、读写数据 | 67,886 / 1,517 / 39,623 bytes |
| HEX 大小 | 195,268 bytes |
| HEX SHA256 | 5851B7714454770DD8EF8A0ED8B01379791F4EF71BDF1B795B36639B18F258AB |
| ST-LINK | Verification...OK;Sector 10~13 烧录前后分块哈希一致 |
| COM5 10×100 | 位置 1000、错误 0、末段 expected/actual 100/100、count error 0、mismatch 0 |
| 末段最终板内诊断频率 | 3071 Hz,未提前进入 100 Hz 慢尾 |
板上已恢复 10 段 x 100 脉冲、位置 0、IDLE。需再覆盖采集一次 10段.bin,确认物理端子的末段连续低速尾脉冲不超过 2 个。
实测发现加减速时间为 0 ms 时段间没有间隔,而加减速时间非 0 ms 时仍有约 250~900 us 低电平。根因是两种配置走了不同硬件路径:
该间隔不是启动/停止速度数值本身造成,而是非零斜坡配置触发了逐段 stop/start 路径。
| 项目 | 结果 |
|---|---|
| Host 全量 | 102 tests / 526,561 assertions / 0 failures |
| 非末段边界 active 断言 | 9 个边界均保持有限序列和脉冲输出 active |
| IAR EWARM 8.3.4 | 0 errors / 1 warning |
| 只读代码/数据、读写数据 | 67,954 / 1,517 / 39,623 bytes |
| HEX 大小 | 195,456 bytes |
| HEX SHA256 | 8778C24D3FDA364DC4B1D6FAD92E69D9090C5B8EC57D1C65DFCAC89EA0B5AC45 |
| ST-LINK | Verification...OK;Sector 10~13 烧录前后分块哈希一致 |
| COM5 10×100 | 位置 1000、错误 0、末段 expected/actual 100/100、count error 0、mismatch 0 |
板上已恢复 10 段 x 100 脉冲、位置 0、IDLE。尚需新逻辑分析仪波形确认 9 个物理段边界不再出现额外低电平;未覆盖的旧 10段.bin 不重复分析。
bbb.bin 原始边沿复核配置为 1 段、默认速度 10000 Hz、启动/停止速度 100 Hz、加减速时间 10 ms、段频率 1000 Hz、脉冲数 100。原始文件 bbb.bin 为 9,708,896 点、6.25 MS/s,共检测到 100 个上升沿和 100 个下降沿。
| 项目 | 原固件实测 |
|---|---|
| 首个上升沿至最后一个下降沿 | 104.001120 ms |
| 首脉冲高/低电平 | 5.000160 / 0.500000 ms |
| 首个上升沿周期 | 5.500160 ms,即 181.8129 Hz |
| 中间可测周期 | 基本为 1.000000 ms,即 1000 Hz |
| 末脉冲高电平 | 0.500000 ms |
原理论/实测图片中的约 526 ms 红色减速尾线不是硬件输出。旧查看器把第 100 个脉冲后的采集空闲低电平当成最后一个周期,从而生成一个接近 0 Hz 的伪频率点并与前一点连线。查看器已改为只使用相邻两个上升沿计算周期;同一文件现在报告 100 个脉冲、99 个可测完整周期,不再绘制伪尾线。
原固件仍有真实的首末脉冲轮廓问题。100→1000 Hz 和 1000→100 Hz 按默认速度 10000 Hz、加减速 10 ms 计算,斜坡持续时间均约 0.9 ms,离散为 1 ms。有限计数路径依赖 1 ms 主循环提交频率,无法在已经开始的 100 Hz 首个高半周期内及时改频,也无法保证末脉冲前提交停止斜坡。
修复后,单段脉冲数不超过 1000 且存在 1 ms 短斜坡时,优先使用整段逐脉冲预计算队列;正常的较长有限斜坡、多段连续硬件序列和零斜坡恒速路径保持不变。该配置的预计算结果为:首脉冲约 550 Hz、中间 98 个脉冲为 1000 Hz、末脉冲约 550 Hz,完整周期累计约 101.64 ms。
| 项目 | 结果 |
|---|---|
| 新增精确回归 | 首/末 549~551 Hz;中间 98 个 1000 Hz;总周期 101.6~101.7 ms |
| Host 全量 | 103 tests / 526,778 assertions / 0 failures |
| IAR EWARM 8.3.4 | 0 errors / 1 warning |
| 只读代码/数据、读写数据 | 68,006 / 1,517 / 39,623 bytes |
| HEX 大小 | 195,612 bytes |
| HEX SHA256 | 068BDC9D417E3C1DEE377BA3053CBB850B32ED3B7EBBB1E9F7653623F29F713A |
| 烧录 | STM32CubeProgrammer 下载、校验、复位成功 |
持久化区 0x080C0000~0x080FFFFF |
烧录前后 SHA256 均为 FC494806B0465476E51678F961A3EC63873C32915A214B31DFB4307048D3949A |
COM5 板测已通过:位置 100、状态 COMPLETED、错误 0;诊断 expected/actual 为 100/100、count error 0、curve mismatch 0,末个诊断请求/定时器频率均为 550 Hz。测试后已清位置并恢复为 IDLE,保留同一单段配置。新逻辑分析仪波形仍待覆盖采集。
第 19 节的单段短轮廓分流仅能覆盖单段样本,不作为最终修复。根因是有限序列曾把一个逻辑段直接等同于一个硬件 step,首段加速和末段减速只能依赖 1 ms 主循环更新;只要斜坡在一个或少数脉冲内完成,单段和多段都会遇到同一问题。
最终实现将“硬件频率 step”和“逻辑段完成边界”拆开:
| 用例 | 覆盖内容 | 结果 |
|---|---|---|
| 单段 100 脉冲 | 100→1000→100 Hz,首末约 550 Hz,中间 98 个 1000 Hz | PASS |
| 3 段无 Poll | 入口斜坡、1000→2000→3000 Hz 硬件边界、最终出口斜坡;300 个脉冲期间不调用 PlsrPoll1ms() |
PASS |
| 10 段无 Poll | 启停 100 Hz、段频率 1000 Hz、默认速度 10000 Hz、加减速 10 ms;9 个边界持续输出 | PASS |
| 既有完整回归 | 有限计数、动态频率、方向反转、短轮廓、AB 相、诊断、持久化和异常路径 | PASS |
最终结果:
104 tests / 527,097 assertions / 0 failures
| 项目 | 结果 |
|---|---|
| IAR EWARM 8.3.4 | 0 errors / 1 个既有未使用变量 warning |
| 只读代码 / 只读数据 / 读写数据 | 69,258 / 1,517 / 87,096 bytes |
| 通用有限 step 缓冲 | 48,240 bytes |
| HEX 大小 | 199,130 bytes |
| HEX SHA256 | 9B296CF02101F78A70F4CCF2BB89DC75AA27E8261F8AED451764854EE2106C4C |
| ST-LINK | 下载、校验、复位和运行成功 |
板上使用 90 kHz→100 kHz、默认速度 10 kHz、加速时间 10 ms、2000 脉冲测试。该轮廓在定时器量化合并后触发 188 次硬件 step IRQ:
| 指标 | 实测 | 100 kHz 门限 |
|---|---|---|
| block IRQ 最大周期 | 396 cycles,约 2.36 us | 1680 cycles,10 us |
| final IRQ 周期 | 410 cycles,约 2.44 us | 1680 cycles,10 us |
| 最小余量 | 约 7.56 us | 必须大于 0 |
性能门限 PASS。IRQ 内无除法、开方或轮廓计算。
同一最坏速率配置板测结果:状态 COMPLETED、位置 2000、错误 0、expected/actual 2000/2000、count error 0、curve mismatch 0、reason 0。
性能测试会按设计写入配置和位置。测试前已备份 0x080C0000~0x080FFFFF,测试后仅恢复 sector 10/11;恢复镜像 SHA256 与测试前均为 7BE5A392BCCB26A510516B80F44FE8FEA287CE58E653325AA7964DDAEC38E4F1。板上最终运行关闭 timing 的 release 固件。