# PLSR 方案设计书 > 文档版本:V1.0 Rev.C > 需求基线:[PLSR需求规格统计_V1.3.md](./PLSR需求规格统计_V1.3.md) Rev.B > 目标平台:XDM-60T4-E / STM32F407IG / uC/OS-II > 编制日期:2026-08-10 > 文档状态:设计基线;标记为“待上板验证”的项目在验证完成前不得关闭 ## 目录 1. [概述](#1-概述) 1. [项目背景](#11-项目背景) 2. [定义](#12-定义) 2. [系统概述](#2-系统概述) 1. [需求概述](#21-需求概述) 2. [系统结构图](#22-系统结构图) 3. [功能模块列表](#23-功能模块列表) 3. [功能模块设计](#3-功能模块设计) 1. [PLSR运动控制核心模块设计](#31-plsr运动控制核心模块设计) 2. [参数解析与任务提交模块设计](#32-参数解析与任务提交模块设计) 3. [路径解释与段调度模块设计](#33-路径解释与段调度模块设计) 4. [速度规划模块设计](#34-速度规划模块设计) 5. [高速脉冲输出模块设计](#35-高速脉冲输出模块设计) 6. [状态机与命令模块设计](#36-状态机与命令模块设计) 7. [输出资源管理模块设计](#37-输出资源管理模块设计) 8. [软元件与通信适配模块设计](#38-软元件与通信适配模块设计) 9. [位置、当量与持久化模块设计](#39-位置当量与持久化模块设计) 10. [诊断与自测模块设计](#310-诊断与自测模块设计) 4. [数据结构设计](#4-数据结构设计) 1. [数据结构设计](#41-数据结构设计) 2. [数据结构与程序的关系](#42-数据结构与程序的关系) 5. [错误处理设计](#5-错误处理设计) 1. [错误处理设计描述](#51-错误处理设计描述) 2. [错误输出信息](#52-错误输出信息) 6. [参考资料](#6-参考资料) ## 1 概述 ### 1.1 项目背景 本项目在现有 XDM-60T4-E 控制器工程中实现 PLSR 定位控制功能。控制器采用 STM32F407IG、12 MHz 外部晶振、168 MHz 系统时钟和 uC/OS-II,现有工程已经具备 USART1 Modbus RTU、USB Device、Backup SRAM 和基本任务调度能力,但尚未实现高速脉冲、 路径解释、速度规划及轴状态管理。 PLSR V1.0 对标信捷 XD/XL 系列 PLC 的 PLSR 逻辑模型,保留 `PLSR S0 S1 S2 D`、 S0 多段数据、S1 用户参数、S2 K0~K4 参数组、D 输出端口以及固定 HSD/SFD/SM/SD/I 软元件语义。在此基础上增加四轴独立运行、CW/CCW、64 位内部位置、参数原子提交、命令防重、 诊断和 Backup SRAM 检查点等能力。 本文说明系统如何实现需求,重点覆盖: - 总体软硬件架构; - OS 任务与硬件中断的职责边界; - PULSE/DIR、AB 相和 CW/CCW 输出; - S0/S1/S2/D 解析与运行快照; - 多段路径、等待、跳转和段事件; - 加减速、动态调频、位置及累计; - 固定软元件、保存、错误和诊断。 V1.0 不实现多轴直线或圆弧插补、闭环位置修正、电子凸轮、龙门同步、完整机械回零和 安全认证急停。 ### 1.2 定义 | 名称 | 定义 | | --- | --- | | PLSR | 多段脉冲定位指令,逻辑调用形式为 `PLSR S0 S1 S2 D` | | S0 | 动态首地址指定的路径数据块,保存总段数及各段频率、脉冲数、等待和跳转 | | S1 | 动态首地址指定的用户参数块,保存相对/绝对模式和起始段 | | S2 | K0~K4 运动参数套组,保存默认速度、速度限制、曲线、补偿、刷新周期及与独立FOLLOW指令共用的字段 | | D | 输出资源操作数,兼容语义下选择 Y0~Y3,本项目对应 Q0~Q3 高速资源 | | PULSE/DIR | 一个端口输出脉冲,另一个端口输出方向电平 | | AB 相 | 两路相差四分之一周期的正交输出,通过相位先后表示方向 | | CW/CCW | 正向和反向分别使用独立脉冲端口,两个端口不得同时输出 | | 指令脉冲 | PULSE/DIR 的一个上升沿、CW/CCW 的一个完整脉冲或 AB 相的一个完整四状态周期 | | 控制刷新周期 | 速度规划器更新目标频率的周期,只允许 0.1 ms 或 1 ms | | 脉冲周期 | 由当前输出频率决定的物理波形周期,与 OS Tick 和控制刷新周期不同 | | 运行快照 | START 接受后为轴生成的不可变 S0/S1/S2/D 执行副本 | | BUSY | 轴存在已接受但尚未终止的任务,包括运动、WAIT和PAUSED | | PULSE_ACTIVE | 当前物理脉冲正在输出 | | DONE | 当前任务正常完成并锁存;STOP或ERROR不得置位 | | 当量 | 通过每转脉冲数和每转移动量将工程单位换算为指令脉冲 | | 固定软元件 | 信捷规定地址和含义的 HSD、SFD、SM、SD、I 数据 | | 动态数据地址 | 调用者在允许数据区内为 S0、S1 选择的连续首地址 | ## 2 系统概述 ### 2.1 需求概述 #### 2.1.1 功能范围 系统应实现四个独立逻辑轴。PULSE/DIR 可同时运行四轴;AB 相和 CW/CCW 使用 Q0/Q1、 Q2/Q3 固定点对,最多同时运行两轴。四轴之间不做插补,各轴独立启动、停止、调频、定位和查询。 主要功能如下: | 类别 | V1.0功能 | | --- | --- | | 输出方式 | PULSE/DIR、AB相、CW/CCW | | 轴数 | 四轴独立;AB/CW/CCW最多两轴 | | 频率 | 1~100 kHz保证范围;100001~200000 Hz经板测后作为非保证扩展 | | 脉冲数量 | 完整有符号32位;0表示跳过当前段 | | 定位 | 相对定位、绝对定位、设置/清零当前位置 | | 路径 | 1~100段,支持等待、ACT、EXT和动态跳转 | | 曲线 | 无加减速、直线、S形、正弦 | | 段衔接 | 完成方式、后续方式 | | 控制 | START、STOP、PAUSE、RESUME、保存、清零、自测 | | 刷新周期 | S2配置0.1 ms或1 ms,OS Tick保持1 ms | | 保存 | Flash固定配置、Backup SRAM动态检查点 | | 对标 | 固定HSD/SFD/SM/SD/I地址及S0/S1动态首地址语义 | #### 2.1.2 性能和安全目标 - 正常完成时脉冲数量误差为 0; - 输出目标占空比为 50%; - 当前段目标频率修改应在配置的控制刷新周期内开始应用; - 四轴 100 kHz 并发时不得丢脉冲、重复脉冲或串轴; - Modbus和USB压力不得改变运动结果; - 上电、复位、HardFault和看门狗复位期间输出保持安全无效; - 运行参数使用快照或原子访问,禁止读取半更新数据; - 异常复位后不得自动续跑,并清除绝对位置有效标志; - 软件急停没有独立硬件切断回路,不得宣称安全认证急停。 #### 2.1.3 工程基线与约束 | 项目 | 现状/约束 | 方案处理 | | --- | --- | --- | | MCU | STM32F407IG,168 MHz | 保持现有时钟配置 | | OS | uC/OS-II,Tick为1 ms | 不提高OS Tick | | Modbus | USART1+DMA,任务轮询 | 作为调用与监控适配层 | | USB | OTG FS中断优先级已设为4 | 低于输出/计数中断优先级1和TIM6优先级2,仍需长稳并发板测 | | PLSR定时器 | TIM6、TIM9/TIM12及TIM10/11/13/14已接入 | 保持固定资源映射并通过租约隔离冲突 | | Modbus历史 | 1000起始历史区写入已删除 | S0/S1动态数据池不得恢复旧历史映射 | | Backup SRAM | 已完成基础初始化 | 扩展为带版本和CRC的双检查点 | | 急停 | 无外部硬件切断 | 仅实现软件立即关闭和状态锁存 | ### 2.2 系统结构图 ![PLSR系统结构图](./PLSR系统结构图.svg) **图 2-1 PLSR系统结构图** 图中蓝色表示控制与数据流,橙色表示硬实时及物理输出路径,绿色表示固定软元件、持久化和诊断等 数据服务。为方便纯文本环境阅读,结构关系同时保留如下文字版本。 ```text ┌──────────────────────────────────────────────────────────┐ │ PLC调用 / Modbus RTU / 内部测试接口 │ └───────────────────────────┬──────────────────────────────┘ │ ┌───────────────────────────▼──────────────────────────────┐ │ 命令与软元件适配:调用上升沿、命令序号、状态快照 │ └───────────────────────────┬──────────────────────────────┘ │ ┌───────────────────────────▼──────────────────────────────┐ │ 参数提交:读取S0/S1/S2/D、完整校验、资源申请、运行快照 │ └───────────────────────────┬──────────────────────────────┘ │ ┌───────────────────────────▼──────────────────────────────┐ │ 四轴运动内核:状态机、路径解释、速度规划、位置与段事件 │ └───────────────┬───────────────────────────┬──────────────┘ │ │ ┌───────────────▼──────────────┐ ┌─────────▼──────────────┐ │ OS任务控制面 │ │ 定时器/EXTI实时面 │ │ 命令、段切换、等待、保存 │ │ 脉冲、调频、尾停、限位 │ └───────────────┬──────────────┘ └─────────┬──────────────┘ │ │ └─────────────┬─────────────┘ │ ┌─────────────────────────────▼────────────────────────────┐ │ STM32F407板级层:TIM6、TIM9/12、TIM10/11/13/14、GPIO、EXTI│ └─────────────────────────────┬────────────────────────────┘ │ Q0~Q3 / DIR │ 伺服驱动器 ``` 系统划分为控制面和实时面: | 执行域 | 运行位置 | 负责内容 | 禁止内容 | | --- | --- | --- | --- | | 控制面 | `PlsrTask` | 命令、校验、快照、状态机慢路径、等待、段切换、保存和发布 | 逐脉冲翻转GPIO | | 实时面 | TIM/EXTI中断 | 硬件累计、软件兜底计数、尾脉冲、速度刷新、限位和EXT锁存 | 阻塞、动态内存、Flash、通信解析、OS等待 | ### 2.3 功能模块列表 | 编号 | 模块 | 建议源文件 | 主要职责 | | --- | --- | --- | --- | | M01 | PLSR运动控制核心 | `plsr_core.c` | 四轴对象、任务入口、事件分派和模块协调 | | M02 | 参数解析与任务提交 | `plsr_parser.c` | S0/S1/S2/D读取、校验、快照和提交 | | M03 | 路径解释与段调度 | `plsr_path.c` | 段进入、等待、跳转、零段和段事件 | | M04 | 速度规划 | `plsr_profile.c` | 三种曲线、短距离、衔接和动态调频 | | M05 | 高速脉冲输出 | `plsr_hal_f407.c` | PWM、TIM9/TIM12硬件累计、软件计数兜底、AB配对和安全关闭 | | M06 | 状态机与命令 | `plsr_state.c`、`plsr_command.c` | 合法状态转换、命令幂等和优先级 | | M07 | 输出资源管理 | `plsr_resource.c` | 高速点、DIR点及TIM9/TIM12计数资源的原子申请和释放 | | M08 | 软元件与通信适配 | `plsr_device.c` | HSD/SFD/SM/SD/I、S0/S1及Modbus边界 | | M09 | 位置、当量与持久化 | `plsr_position.c`、`plsr_persist.c` | 64位位置、换算、限位、Flash和Backup SRAM | | M10 | 诊断与自测 | `plsr_diag.c` | 错误映射、分频记录、性能统计和自测 | 建议工程目录: ```text PLSR/ Inc/ plsr.h plsr_types.h plsr_device.h plsr_hal.h Src/ plsr_core.c plsr_parser.c plsr_path.c plsr_profile.c plsr_hal_f407.c plsr_state.c plsr_command.c plsr_resource.c plsr_device.c plsr_position.c plsr_persist.c plsr_diag.c ``` ## 3 功能模块设计 ### 3.1 PLSR运动控制核心模块设计 #### 3.1.1 模块功能描述 运动控制核心静态创建四个 `PlsrAxis` 对象,负责初始化各子模块、运行 `PlsrTask`、接收中断事件、 调用状态机、协调段调度和发布状态。模块不直接解释 Modbus 帧,也不直接操作 Flash 或具体 GPIO。 OS任务建议如下: | 任务 | 建议优先级 | 触发方式 | 职责 | | --- | ---: | --- | --- | | `PlsrTask` | 4 | 事件唤醒,最长1 ms巡检 | 命令、路径慢处理、等待、状态发布和保存请求 | | 现有Modbus任务 | 5 | 1 ms轮询 | 通信收发和协议解析 | | 测试任务 | 6及以后 | 按需 | 非实时测试和日志 | 中断优先级首次配置建议如下,最终值通过 uC/OS-II 端口约束和上板测试冻结: | 抢占优先级 | 中断 | 用途 | | ---: | --- | --- | | 1 | 硬限位EXTI | 锁存限位并禁止继续越界输出 | | 2 | TIM9/TIM12、TIM10/11/13/14 | 硬件计数完成、软件兜底计数、参数边界和尾脉冲关闭 | | 3 | TIM6 | 0.1 ms速度控制基准 | | 4 | EXT输入EXTI | 路径切段边沿锁存 | | 5 | USART1、DMA2 | 现有Modbus通信 | | 6 | USB OTG FS | 从当前优先级0调低 | | 15 | SysTick | 现有1 ms OS Tick | 实时中断不调用 OS API,只设置原子事件位。`PlsrTask` 获取事件后按急停、限位、立即停止、 减速停止、暂停和正常事件的顺序处理。 #### 3.1.2 模块输入输出接口说明 ```c PlsrResult Plsr_Init(void); void Plsr_Task(void *argument); PlsrResult Plsr_Submit(const PlsrCall *call, uint32_t sequence); PlsrResult Plsr_Command(const PlsrCommand *command); bool Plsr_GetStatus(uint8_t axis, PlsrStatus *status); void Plsr_IsrPost(uint8_t axis, uint32_t event_mask); ``` 输入为调用参数、控制命令和硬件事件;输出为提交结果、状态快照、固定软元件状态和持久化请求。 #### 3.1.3 流程图 ![PLSR单轴完整执行流程图](./PLSR单轴完整执行流程图.png) **图 3-1 PLSR单轴完整执行流程图** ```text 系统启动 -> 输出置安全状态 -> 初始化设备访问、资源和持久化 -> 初始化四轴对象 -> 初始化定时器和EXTI -> 自检 -> 全部成功:进入IDLE -> 任一失败:保持输出关闭并发布初始化错误 PlsrTask循环 -> 读取ISR事件 -> 按优先级处理停止和限位 -> 处理命令 -> 推进各轴状态机 -> 处理等待和段跳转 -> 发布一致状态 -> 执行非实时保存请求 ``` ### 3.2 参数解析与任务提交模块设计 #### 3.2.1 模块功能描述 该模块把 `PLSR S0 S1 S2 D` 转换为可执行任务。START 只在启动信号上升沿或新命令序号时接受。 模块先完整校验,再原子申请资源,最后生成运行快照;任何失败都不得影响正在运行的合法任务。 S0校验内容: - 总段数为1~100; - 末地址 `S0 + N*10 + 9` 使用检查过的64位运算; - 保留字为0; - 双字低字在低地址、高字在下一地址; - 频率、脉冲数、等待编码、变量来源和跳转来源合法; - 数据块位于允许的数据区; - S0与S1不重叠。 S1只包含定位模式和起始段。S2只允许K0~K4,并校验默认速度、最高速度、起止频率、曲线、 补偿、刷新周期及FOLLOW共用字段的合法范围;FOLLOW共用字段不参与PLSR运算。D按输出模式检查 Y0~Y3或Y0/Y2固定点对。 #### 3.2.2 模块输入输出接口说明 ```c PlsrResult PlsrParser_BuildSnapshot( const PlsrCall *call, PlsrJobSnapshot *snapshot, PlsrErrorDetail *detail); PlsrResult PlsrParser_ReadLiveFrequency( const PlsrJobSnapshot *snapshot, uint16_t segment, uint32_t *frequency_hz); ``` 输入为 S0/S1 首地址、S2选择值、D及输出配置;输出为完整快照或带错误数据块号的失败结果。 #### 3.2.3 流程图 ```text 收到START -> 检查上升沿/命令序号 -> 检查轴状态 -> 读取S0总段数并计算边界 -> 读取并校验全部S0段 -> 读取并校验S1 -> 读取并校验S2和D -> 检查绝对位置、限位和组合参数 -> 原子申请输出资源 -> 生成不可变运行快照 -> 成功返回运动核心 任一步失败 -> 回滚已申请资源 -> 保持输出无效 -> 返回兼容码和增强错误 ``` 运行期间仅允许重新读取当前段目标频率。S0其它字段、S1、S2、D和资源绑定均使用快照;非法动态 频率写入被忽略,继续使用最近合法值并发布诊断。 ### 3.3 路径解释与段调度模块设计 #### 3.3.1 模块功能描述 路径模块负责1~100段的进入、执行完成条件、等待、动态跳转和段事件。相对模式把段脉冲数解释为 本段位移;绝对模式把它解释为目标坐标,并用目标坐标减当前逻辑位置求实际输出位移。 零值判断顺序固定为: 1. 先检查脉冲数量; 2. 脉冲数为0时不输出,产生零段事件并跳转; 3. 脉冲数非0且频率为0时才使用S2默认速度; 4. 默认速度不合法时拒绝执行。 等待条件处理如下: | 编码 | 条件 | 模块处理 | | --- | --- | --- | | H00 | 脉冲完成 | 输出完成后立即跳转 | | H01 | Wait时间 | 完成后计时;0按1 ms | | H02 | Wait信号 | 完成后判断X/M/HM,未有效则保持WAIT | | H03 | ACT时间 | 段开始计时;时间到放弃剩余脉冲,脉冲先完则等到时间 | | H04 | EXT信号 | 新上升沿到达时放弃剩余脉冲;脉冲先完仍等待新边沿 | | H05 | EXT或脉冲完成 | 原子锁存先到原因,先到者决定跳转 | 快照保存变量来源类型和编号,Wait/ACT数值、Wait信号和动态跳转值在实际求值时读取,以保留信捷 动态变量语义。跳转值0表示顺序执行,1~N表示指定段,自跳表示有意无限循环。 PULSE/DIR运行中由ACT/EXT提前结束时,控制面只冻结profile并保存待执行路径动作;HAL在下一次自然 update(端子完整下降沿)锁存硬件计数并停止PWM,再用段完成事件推进路径。不得在1 ms路径tick中 直接关闭CC1E,以免截断已经产生上升沿的末脉冲。 #### 3.3.2 模块输入输出接口说明 ```c PlsrResult PlsrPath_Enter(PlsrAxis *axis, uint16_t segment); PlsrResult PlsrPath_OnOutputDone(PlsrAxis *axis); PlsrResult PlsrPath_OnExt(PlsrAxis *axis, uint32_t edge_sequence); PlsrResult PlsrPath_PollWait(PlsrAxis *axis, uint64_t now_ms); ``` 输出包括下一段请求、正常完成请求、停止剩余脉冲请求和段事件。 #### 3.3.3 流程图 ```text 进入段 -> 检查段号 -> 计算相对位移或绝对位移 -> 位移为0:不输出并生成段事件 -> 位移非0:解析方向和目标频率 -> 启动输出/ACT/EXT监视 -> 等待脉冲完成或条件事件 -> 锁存段结束原因 -> 产生I6000~I6399对应事件 -> 求动态跳转值 -> 下一段 / WAIT / COMPLETED / ERROR ``` 每次任务调度最多连续处理100次无脉冲跳转,达到上限后主动让出CPU,避免无限循环阻塞系统。 ### 3.4 速度规划模块设计 #### 3.4.1 模块功能描述 速度规划模块根据S2、段目标、剩余脉冲和下一段速度生成当前控制频率。TIM6提供10 kHz控制基准; 0.1 ms轴每次更新,1 ms轴每10次更新。无运行轴时关闭TIM6。 内部采用定点数:频率使用Q32.32,归一化曲线进度使用Q1.31,时间使用整数微秒,禁止在控制中断 使用浮点三角函数。 三种曲线定义为: ```text 直线:g(u) = u S形: g(u) = 3u² - 2u³ 正弦:g(u) = (1 - cos(πu)) / 2 f(u) = f_start + (f_end - f_start) * g(u) ``` 正弦函数使用只读查找表和线性插值。距离不足时通过有界二分求解峰值频率,自动形成三角或短距离 曲线;无法满足起止速度和脉冲数时返回参数冲突。 完成方式在当前段脉冲结束后再改变到下一段速度;后续方式在当前段内预留变速脉冲,使段边界时已达到 下一段入口速度。反向段必须先减速到0再切换方向或相序。 S2最高速度为0或超出硬件开放范围时拒绝启动。起始、目标和终止速度超过合法最高速度时限幅并发布 `SPEED_CLAMPED`。FOLLOW性能范围为1~100,前馈补偿范围为0~100;两者属于信捷独立 FOLLOW/FOLLOW_AB指令使用的共用S2字段。本PLSR模块保留存储、快照和范围校验,但不把它们 代入PLSR速度曲线,也不自行定义FOLLOW运算公式。 #### 3.4.2 模块输入输出接口说明 ```c PlsrResult PlsrProfile_Prepare( const PlsrSegmentRuntime *segment, const PlsrS2Snapshot *s2, PlsrProfile *profile); void PlsrProfile_ControlTick(PlsrProfile *profile, uint32_t elapsed_us); void PlsrProfile_SetTarget(PlsrProfile *profile, uint32_t target_hz); ``` 输入为当前频率、目标频率、起止频率、加减速时间、曲线、剩余脉冲和衔接方式;输出为当前命令频率 和待提交的定时器分频参数。 #### 3.4.3 流程图 ```text 准备段曲线 -> 校验S2和目标速度 -> 计算加速/减速所需脉冲 -> 距离足够:生成完整曲线 -> 距离不足:求解短距离峰值 -> 每0.1/1 ms推进定点曲线 -> 计算当前命令频率 -> 限幅并生成诊断 -> 计算待提交PSC/ARR/CCR -> 脉冲模块在安全周期边界应用 ``` 运行中目标频率修改不改变剩余脉冲数。规划器在配置刷新周期内接收并开始过渡,物理周期参数在最近的 安全周期边界切换;低频时不得为了刷新指标截断一个完整脉冲。 ### 3.5 高速脉冲输出模块设计 #### 3.5.1 模块功能描述 高速输出模块使用硬件定时器维持脉冲边沿,OS不参与逐脉冲翻转。 ![PLSR高速脉冲与硬件计数架构图](./PLSR高速脉冲与硬件计数架构图.svg) **图 3-2 PLSR高速脉冲与硬件计数架构图** | 逻辑点 | MCU引脚 | 定时器通道 | 定时器时钟 | | --- | --- | --- | ---: | | Q0/Y0 | PF6 | TIM10_CH1 | 168 MHz | | Q1/Y1 | PF8 | TIM13_CH1 | 84 MHz | | Q2/Y2 | PF7 | TIM11_CH1 | 168 MHz | | Q3/Y3 | PF9 | TIM14_CH1 | 84 MHz | ##### 3.5.1.1 混合计数架构 RM0090 Rev.22 第19.4.2节表101的TIM9/TIM12内部触发连接提供以下通路: | 硬件计数器 | 触发选择 | 内部计数来源 | 对应输出 | | --- | --- | --- | --- | | TIM9 | ITR2 | TIM10_OC | Q0 | | TIM9 | ITR3 | TIM11_OC | Q2 | | TIM12 | ITR2 | TIM13_OC | Q1 | | TIM12 | ITR3 | TIM14_OC | Q3 | TIM9在同一时刻只能选择Q0或Q2中的一路,TIM12只能选择Q1或Q3中的一路。因此V1.0采用: ```text 优先:TIM9/TIM12内部硬件累计 ↓ 计数器不可达或已被其它轴占用 兜底:对应输出定时器的周期中断软件累计 ``` 计数方式在每段开始前确定并锁存到该段结束,不在脉冲活动期间切换。最多同时提供两套内部硬件 计数;四轴PULSE/DIR并发时,至少两轴硬件计数、其余轴软件计数。资源分配优先级依次为: 1. 已运行轴持有的计数器租约不得被新任务抢占; 2. 同一批待启动段发生竞争时,优先AB相,其次按预计软件中断负载从高到低选择; 3. 条件仍相同时,按命令提交顺序选择; 4. 无可用硬件计数器时自动使用软件计数,不因计数器不足拒绝合法运动。 可同时硬件计数的PULSE/DIR组合为Q0+Q1、Q0+Q3、Q2+Q1或Q2+Q3。Q0与Q2竞争TIM9, Q1与Q3竞争TIM12。 AB相每个相位通道每完整正交周期只产生一次同类内部比较事件,因此一组AB轴只需选择其中一个相位 作为周期计数基准。两组AB轴应通过匹配分配分别使用TIM9和TIM12,例如Q0/Q1轴选Q0→TIM9, Q2/Q3轴选Q3→TIM12。 CW/CCW只对当前实际发脉冲的方向通道计数。发生方向切换时,在完全停止的段边界重新申请相应的 TIM9或TIM12;申请失败则该段切换为软件计数,不能在脉冲活动期间改源。 定时器采用向上计数和PWM输出: ```text f_actual = f_timer / ((PSC + 1) * (ARR + 1)) CCR1 = (ARR + 1) / 2 ``` 分频算法选择能容纳16位ARR的最小预分频,并比较相邻合法候选,取绝对频率误差最小者;误差相同时 选择更大的ARR以保留分辨率。记录目标频率、实际频率、PSC、ARR、CCR和误差。 硬件计数模式下不为每个PWM周期开启更新中断。TIM6控制刷新先短暂禁止输出定时器的更新装载,依次 写入PSC、ARR和CCR预装载值,再恢复更新装载;完整的新参数在随后自然更新事件一次性生效。若更新 边界在短暂禁止期间到达,则延后一个完整周期生效,不能出现混合分频值或截断周期。 PULSE/DIR先设置DIR,再等待默认10 ms或配置的方向建立时间,随后启动PWM。物理上升沿计1个指令 脉冲。硬件计数时由TIM9/TIM12在外部时钟模式1下累计每周期一次的内部OC事件;软件计数时由输出 定时器自然更新事件累计。进入目标脉冲时只武装一次尾边沿处理,最后一个脉冲下降沿到达后关闭通道, 防止出现下一个多余上升沿。 CW/CCW正向只启动CW端,反向只启动CCW端,另一路始终无效。检测到双通道同时活动时立即关闭配对 输出并进入ERROR。 AB相固定配对如下: | 轴归属 | A相 | B相 | 正向状态顺序 | | --- | --- | --- | --- | | Y0 | Q0/TIM10 | Q1/TIM13 | `00→10→11→01→00` | | Y2 | Q2/TIM11 | Q3/TIM14 | `00→10→11→01→00` | 反向交换A、B领先关系。两个定时器预装四分之一周期相位差;从已分配的一个相位内部OC事件累计 完整AB周期,落后相第四次跳变完成后关闭最后一周期。一个完整四状态周期只计1个指令脉冲,四次 相位跳变不得分别计数。 AB启动必须在GPIO仍持有安全低电平时完成以下顺序:停止两个定时器、强制OC无效并UG、把两个CNT 装入严格大于CCR且保持四分之一周期差的位置、使能通道、切回AF、切入PWM1后再同时开放计数。 禁止在运行中重写CNT维持相位。双AB分别以Q0→TIM9和Q3→TIM12作为完整周期计数源;到达目标前 武装落后相的`00`边界快速门控,并通过D1468~D1469记录该快速路径最大周期数。上述新序列和门控 代码已完成Host/IAR验证。PAUSE同样只在下一真实`00`边界停表,已经开始的周期计入完成数;双组 近同时完成时,ISR只快速gate并锁存,GPIO、计数器释放和事件发布延后到任务态;异常返回前再次 扫描另一组已武装的`00`标志,消除首轮扫描后到达的等优先级竞争。D1468取实际停表门控扫描与 返回前最终安全扫描的最大值,必须小于一个100kHz四分之一周期;整个输出ISR仍由独立ISR WCET 窗口约束。在四通道真机确认严格边沿数、 2.5us首相位间隔、变频及PAUSE/RESUME波形前仍标记为待上板验证。 ##### 3.5.1.2 16位硬件计数扩展 TIM9和TIM12均为16位计数器。计数器配置为外部时钟模式1,ARR保持为`0xFFFF`,每收到一次选定的 内部OC事件,CNT自动加1。软件使用“16位硬件CNT + 64位块累计”扩展完整INT32脉冲范围: ```text 每65536个指令脉冲 -> TIM9/TIM12产生一次更新中断 -> 软件块累计加65536 最终低16位到达比较值 -> 检查块累计是否已到目标高位 -> 是:武装最终完整脉冲/AB周期的尾边沿关闭 -> 否:清比较标志并继续硬件累计 ``` 目标低16位不为0时使用捕获比较事件判断最终余数;目标恰为65536的整数倍时,使用更新事件和块累计 判断完成,禁止把比较值0解释成启动瞬间已经完成。 100 kHz连续输出时,每个硬件计数轴的块中断频率约为`100000/65536=1.53次/秒`;除块中断、最终 比较和异常外,不产生逐脉冲计数中断。零脉冲段在进入硬件层前处理,绝对值计算使用64位,避免 INT32_MIN取反溢出。 TIM10/11/13/14的SMCR在寄存器表中为保留项,因此硬件计数器只能通知CPU达到目标,不能反向门控 输出定时器。最终比较事件到达后不得立即截断 活动波形,而应根据模式武装输出定时器的最终边沿:PULSE/DIR和CW/CCW在最后下降沿关闭,AB相在 第四次状态跳变后同时关闭配对通道。`N=1`时在启动前直接武装尾边沿。内部OC事件相位、同步延迟和 最终关闭窗口必须用逻辑分析仪确认。 四个高速定时器对应共享中断向量: | 定时器 | 中断向量 | | --- | --- | | TIM10 | `TIM1_UP_TIM10_IRQn` | | TIM11 | `TIM1_TRG_COM_TIM11_IRQn` | | TIM13 | `TIM8_UP_TIM13_IRQn` | | TIM14 | `TIM8_TRG_COM_TIM14_IRQn` | 两个硬件计数器的中断向量为: | 计数器 | 中断向量 | 用途 | | --- | --- | --- | | TIM9 | `TIM1_BRK_TIM9_IRQn` | Q0/Q2硬件块计数和最终比较 | | TIM12 | `TIM8_BRK_TIM12_IRQn` | Q1/Q3硬件块计数和最终比较 | 热路径采用直接寄存器访问,不调用通用 `HAL_TIM_IRQHandler()`。共享中断入口先检查本定时器标志, 并为TIM1/TIM8未来用途保留分派能力。硬件计数轴关闭输出定时器的周期更新中断;软件计数轴才启用 周期更新中断。 #### 3.5.2 模块输入输出接口说明 ```c PlsrResult PlsrHw_Init(void); PlsrResult PlsrHw_Configure(const PlsrHwRequest *request); PlsrResult PlsrHw_Start(uint8_t axis, uint64_t pulses); PlsrResult PlsrHwCounter_Configure(const PlsrCounterLease *lease, uint64_t target_pulses); void PlsrHwCounter_Stop(const PlsrCounterLease *lease); void PlsrHw_SetPendingDivider(uint8_t axis, const PlsrDivider *divider); void PlsrHw_RequestTailStop(uint8_t axis); void PlsrHw_ForceSafe(uint32_t resource_mask); ``` 输入为模式、方向、频率、脉冲数量、方向点和极性;输出为周期完成事件、实际计数、分频诊断和硬件错误。 #### 3.5.3 流程图 ```text 启动硬件输出 -> 输出保持无效 -> 配置GPIO复用和安全电平 -> 装载PSC/ARR/CCR并清状态标志 -> PULSE/DIR设置方向并等待建立时间 -> AB装载配对相位 / CW选择单通道 -> 尝试申请并配置TIM9/TIM12硬件计数 成功:关闭逐周期计数中断 失败:启用输出定时器软件周期计数 -> 使能通道和定时器 -> 硬件持续输出 -> 硬件模式:每65536脉冲更新块累计 软件模式:周期ISR更新剩余量 -> TIM6通过预装载安全更新分频 -> 进入最后一个脉冲/AB周期 -> 比较事件完成尾边沿 -> 关闭输出并通知运动核心 ``` TIM10/11/13/14没有重复计数寄存器,TIM9/TIM12内部连接又只能覆盖两路。四轴100 kHz时,若两路 硬件计数、两路软件计数,最坏约为每秒200,000次软件周期事件,加TIM6的10,000次控制事件和少量 硬件块中断。完整功能开发前必须完成两种计数模式原型,测量ISR最坏执行时间、CPU占用、计数模式 切换、USB/Modbus压力、尾脉冲和AB相位;未通过不得宣称四轴100 kHz验收完成。 ### 3.6 状态机与命令模块设计 #### 3.6.1 模块功能描述 每轴状态固定为: ```text UNINITIALIZED、IDLE、ACCEL、RUN、DECEL、WAIT、PAUSED、 COMPLETED、STOPPED、ERROR ``` ![PLSR单轴状态机与命令优先级图](./PLSR单轴状态机与命令优先级图.svg) **图 3-3 PLSR单轴状态机与命令优先级图** 主要合法转换如下: | 当前状态 | 事件 | 下一状态 | | --- | --- | --- | | UNINITIALIZED | 初始化成功 | IDLE | | IDLE/COMPLETED/STOPPED | START成功 | ACCEL、RUN、WAIT或COMPLETED | | ACCEL/RUN | 需要减速 | DECEL | | 运动状态 | 等待条件未满足 | WAIT | | 运动状态 | PAUSE且减速完成 | PAUSED | | PAUSED | RESUME | ACCEL或RUN | | 运行类状态 | 路径正常结束 | COMPLETED | | 非终止状态 | STOP完成 | STOPPED | | 可运行状态 | 不可恢复错误 | ERROR | | ERROR | RESET_ERROR成功 | IDLE | 未列出的转换由统一入口拒绝并记录非法转换。DONE只在正常完成时置1,下一次START成功接受时清零; STOP和ERROR不得置DONE。WAIT和PAUSED期间BUSY为1、PULSE_ACTIVE为0。 支持START、STOP_DECEL、STOP_IMMEDIATE、PAUSE、RESUME、SET_POSITION、CLEAR_POSITION、 CLEAR_TOTAL、SAVE_CONFIG、LOAD_CONFIG、RESET_ERROR和SELF_TEST。每轴保存最近命令序号与结果, 相同序号重发只返回上次结果,不重复执行。 #### 3.6.2 模块输入输出接口说明 ```c PlsrResult PlsrState_Transition( PlsrAxis *axis, PlsrState target, PlsrTransitionReason reason); PlsrResult PlsrCommand_Execute( PlsrAxis *axis, const PlsrCommand *command); ``` #### 3.6.3 流程图 ```text 收到命令 -> 比较命令序号 -> 重复序号:返回上次结果 -> 检查当前状态是否允许 -> 按命令执行动作 -> 通过唯一状态转换入口改变状态 -> 保存序号、结果和停止原因 -> 发布BUSY/PULSE_ACTIVE/DONE/WAIT/ERROR ``` 事件优先级固定为:软件急停 > 硬限位 > STOP_IMMEDIATE > STOP_DECEL > PAUSE > 正常运行。 高优先级原因锁存后,低优先级命令不得覆盖。 ### 3.7 输出资源管理模块设计 #### 3.7.1 模块功能描述 资源管理器维护高速资源Q0~Q3、普通输出资源Q0~Q7/Q10~Q17/Q20,以及内部硬件计数器 TIM9/TIM12的占用位图。高速输出和DIR资源属于运动必需资源;硬件计数器属于优化资源,申请失败时 允许使用软件计数兜底。 | 模式 | D允许值 | 高速资源 | DIR资源 | | --- | --- | --- | --- | | PULSE/DIR | Y0~Y3 | D对应的一个Q点 | 一个未占用有效输出点 | | AB相 | Y0或Y2 | Q0/Q1或Q2/Q3 | 无 | | CW/CCW | Y0或Y2 | Q0/Q1或Q2/Q3 | 无 | 硬件计数资源规则: | 脉冲来源 | 可申请计数器 | 冲突组 | | --- | --- | --- | | Q0/TIM10 | TIM9 ITR2 | 与Q2互斥 | | Q2/TIM11 | TIM9 ITR3 | 与Q0互斥 | | Q1/TIM13 | TIM12 ITR2 | 与Q3互斥 | | Q3/TIM14 | TIM12 ITR3 | 与Q1互斥 | 单轴或两轴运行时优先选择能全部硬件计数的组合。四轴运行时,资源管理器分别从Q0/Q2组和Q1/Q3组 选择一个轴使用硬件计数。既有运行租约不被抢占;同批竞争时按AB模式、预计中断负载和提交顺序选择。 计数器租约只在段停止边界申请或释放;任务运行期间如果某段不能获得计数器,则该段使用软件计数。 方向点板级映射如下: | PLC点 | MCU引脚 | PLC点 | MCU引脚 | | --- | --- | --- | --- | | Q0 | PF6 | Q10 | PG7 | | Q1 | PF8 | Q11 | PG6 | | Q2 | PF7 | Q12 | PH9 | | Q3 | PF9 | Q13 | PH8 | | Q4 | PI8 | Q14 | PH7 | | Q5 | PE6 | Q15 | PH6 | | Q6 | PE5 | Q16 | PF11 | | Q7 | PE4 | Q17 | PB0 | | Q20 | PH5 | | | 完整申请掩码在短临界区内一次判断和占用,禁止逐点申请后失败而留下半组资源。运行期间模式、D、 配对关系、方向点和极性锁定。正常完成、STOP和ERROR统一通过幂等清理入口释放资源。 #### 3.7.2 模块输入输出接口说明 ```c PlsrResult PlsrResource_Reserve( uint8_t owner_axis, const PlsrResourceRequest *request, PlsrResourceLease *lease); void PlsrResource_Release(PlsrResourceLease *lease); PlsrCountMode PlsrResource_SelectCounter( uint8_t owner_axis, uint8_t pulse_source, PlsrCounterLease *counter_lease); ``` #### 3.7.3 流程图 ```text 构造完整资源掩码 -> 检查模式与D -> 检查高速点和DIR点合法性 -> 进入短临界区 -> 任一冲突:退出并返回RESOURCE_CONFLICT -> 无冲突:一次性占用全部资源 -> 尝试申请TIM9/TIM12计数优化资源 成功:锁存硬件计数租约 失败:锁存软件计数模式 -> 配置硬件 -> 配置失败:安全关闭并回滚 -> 任务终止:安全关闭并幂等释放 ``` ### 3.8 软元件与通信适配模块设计 #### 3.8.1 模块功能描述 HSD、SFD、SM、SD、I、S0和S1是逻辑软元件命名空间,不等同于“Modbus通信地址表”。 PLSR内核通过统一设备接口访问逻辑软元件,Modbus只负责字节序、影子写入、命令序号和提交响应。 固定地址只采用 [PLSR地址映射.md](./PLSR地址映射.md): | 类别 | 固定范围 | | --- | --- | | K0配置 | HSD460~539 | | 公共参数及K1~K4 | SFD900~1419 | | 累计状态 | HSD0~15 | | 运行/方向标志 | SM1000/1001、1020/1021、1040/1041、1060/1061 | | 实时状态 | SD1000~1011、1020~1031、1040~1051、1060~1071 | | 段事件 | I6000~6399 | | 动态数据 | S0、S1 | 固定字段使用显式描述表保存地址、位宽、有符号性、读写属性、合法范围、所属轴和持久化类别,不得通过 自拟轴块改变信捷地址。保留字段仍占原地址,未实现字段不得挪作项目扩展。 32/64位状态采用版本化快照发布。Modbus断开不产生STOP;非法通信参数不得改变正在运行的任务。 本设计书不新增PLSR全局通信地址区,也不恢复已删除的Modbus历史功能。 Modbus数据存储提供相互隔离的X、M、HM三套10000位映像。FC01/FC05/FC0F访问M,FC02只读访问X; `PlsrModbusDataSourceInit()`把PLSR `readBit`连接到对应映像。依据《实现PLSR指令.pdf》已建立 X0~X12、X14~X17、X20 的 GPIO 输入扫描映射;X13/PA14 因承担 SWDCLK,在调试构建中保留不用。 P19 初测由 Y4~Y7 回接 X0~X3;为同步观察 Y0 脉冲与四路触发,当前验证夹具改为 Y1~Y4 回接 X0~X3。真实 WAIT、EXT 和正/负硬限位链路已关闭。HM 映像尚未接入经板测的 保持介质,因此 HM 掉电保持不得宣称关闭。 #### 3.8.2 模块输入输出接口说明 ```c bool PlsrDevice_Read(DeviceRef ref, int64_t *value); bool PlsrDevice_Write(DeviceRef ref, int64_t value); bool PlsrDevice_ReadBlock(DeviceRef first, uint16_t words, uint16_t *buffer); void PlsrDevice_PublishAxis(uint8_t axis, const PlsrStatus *status); void PlsrDevice_TriggerSegmentEvent(uint8_t axis, uint16_t segment); ``` #### 3.8.3 流程图 ```text 外部读写请求 -> 解析逻辑软元件类型和地址 -> 检查位宽、权限和范围 -> 参数写入影子区 -> COMMIT时调用PLSR业务校验 -> 成功:切换版本并返回序号/结果 -> 失败:保持原有效参数 状态读取 -> 读取版本号 -> 复制完整状态 -> 再读版本号 -> 前后相同且为稳定版本:返回 -> 否则重试 ``` ### 3.9 位置、当量与持久化模块设计 #### 3.9.1 模块功能描述 每轴内部维护64位逻辑位置、本次任务累计、总累计和物理输出诊断计数,以及独立的 `position_valid`。高速ISR只更新当前块计数;任务在块边界、段边界或检查点时合并64位数据。 发布HSD固定32位累计前检查INT32范围。超出范围时保持最近合法发布值,锁存 `COUNTER_OVERFLOW`,不得回绕或静默截断。HSD记录只有一个全局位置有效元数据位,因此检查点按 四轴`position_valid`且无发布溢出的保守AND写入;单独校准一轴不得把其他未校准轴一起标为可信, 任何轴超出32位发布范围时也不得让旧HSD位置在重启后冒充当前可信坐标。 当量换算按每转指令脉冲数和每转移动量形成有理数比例,计算前约分并检查溢出,每轴保存换算余数, 避免连续多段累计舍入漂移。任一分母为0时返回兼容错误码2。 软限位按逻辑位置和预计停止距离判断:禁止向越界方向启动,允许运动离开已触发限位;运动中触发默认 减速停止。方向反转时插入内部齿隙补偿子段,补偿脉冲不计入用户段、逻辑位置或HSD,但计入物理输出 诊断。 固定配置使用Flash A/B双槽: ```text magic | format_version | payload_length | sequence | payload | CRC32 ``` 动态K0、64位位置、累计、有效标志和最近诊断保存到有VBAT维持的Backup SRAM双检查点。 正常完成、正常停止、设置/清零位置和清累计后立即保存;运行中初始按10 ms及段边界保存诊断检查点。 异常复位或上次BUSY时清除 `position_valid`,任何情况都不自动恢复未完成路径。 #### 3.9.2 模块输入输出接口说明 ```c PlsrResult PlsrPosition_Set(uint8_t axis, int64_t position); PlsrResult PlsrPosition_Clear(uint8_t axis); PlsrResult PlsrPosition_ConvertToPulse(uint8_t axis, int64_t value, int64_t *pulse); PlsrResult PlsrPersist_SaveConfig(void); PlsrResult PlsrPersist_LoadConfig(void); void PlsrPersist_SaveCheckpoint(uint32_t reason); ``` #### 3.9.3 流程图 ```text 脉冲块完成 -> 原子交换当前块计数 -> 检查64位加法溢出 -> 更新逻辑位置和累计 -> 检查软限位 -> 检查HSD32位发布范围 -> 更新状态快照 -> 达到检查点条件:更新Backup SRAM 上电恢复 -> 输出保持安全 -> 读取复位原因 -> 校验Flash和Backup SRAM版本/CRC -> 恢复允许的配置与诊断 -> 异常复位或上次BUSY:清position_valid -> 清全部运行资源 -> 禁止自动启动 ``` ### 3.10 诊断与自测模块设计 #### 3.10.1 模块功能描述 诊断模块记录每轴目标/实际频率、PSC/ARR/CCR、当前计数模式、TIM9/TIM12块累计、软件脉冲数、 物理边沿诊断值、当前段、停止原因、状态机非法转换、资源冲突和ISR执行周期。 P16诊断协议V7使用D1256~D1263发布整体/ISR最大周期,D1456~D1467发布六个任务阶段独立最大值, D1468~D1469发布AB末周期快速门控最大值,D1470~D1515发布缓存的持久化诊断与受控验证应答, D1516~D1537使用首尾generation发布USB CDC initialized及八个32位收发/错误统计。 Modbus只读功能码0x47提供40 WORD运行诊断;各32位字段不会撕裂,整组字段允许跨相邻通信事件; USB CDC另记录收发、BUSY、失败和重挂统计。USB OTG FS优先级为4,长稳脚本可并发施加Modbus轮询、 原子动态频率写入、坏CRC、计划断线及可选USB OUT流量。 `SELF_TEST` 分为两级: - 默认不输出自测:地址表、S0/S1边界、跳转、分频、状态机、计数和CRC; - 输出自测:需要明确测试授权,仅在断开执行机构或采取防护后输出指定低频波形。 #### 3.10.2 模块输入输出接口说明 ```c void PlsrDiag_RecordError(uint8_t axis, PlsrError error, const PlsrErrorDetail *detail); void PlsrDiag_RecordDivider(uint8_t axis, const PlsrDivider *divider); void PlsrDiag_RecordIsrCycles(uint8_t axis, uint32_t cycles); PlsrResult PlsrDiag_SelfTest(uint32_t test_mask, bool allow_output); ``` #### 3.10.3 流程图 ```text 收到SELF_TEST -> 检查所有轴非BUSY -> 执行静态地址和配置检查 -> 执行分频、路径、计数和状态机检查 -> 是否请求输出测试 否:汇总结果 是:检查显式授权和安全条件 -> 输出受限测试波形 -> 自动安全关闭 -> 发布逐项结果和首个失败原因 ``` ## 4 数据结构设计 ### 4.1 数据结构设计 #### 4.1.1 基本枚举 ```c typedef enum { PLSR_STATE_UNINITIALIZED, PLSR_STATE_IDLE, PLSR_STATE_ACCEL, PLSR_STATE_RUN, PLSR_STATE_DECEL, PLSR_STATE_WAIT, PLSR_STATE_PAUSED, PLSR_STATE_COMPLETED, PLSR_STATE_STOPPED, PLSR_STATE_ERROR } PlsrState; typedef enum { PLSR_OUTPUT_PULSE_DIR = 0, PLSR_OUTPUT_AB = 1, PLSR_OUTPUT_CW_CCW = 2 } PlsrOutputMode; typedef enum { PLSR_POSITION_RELATIVE = 0, PLSR_POSITION_ABSOLUTE = 1 } PlsrPositionMode; typedef enum { PLSR_COUNT_SOFTWARE = 0, PLSR_COUNT_TIM9 = 1, PLSR_COUNT_TIM12 = 2 } PlsrCountMode; ``` #### 4.1.2 调用与命令 ```c typedef struct { DeviceRef s0; DeviceRef s1; DeviceRef s2; uint8_t d_axis; } PlsrCall; typedef struct { uint32_t sequence; uint16_t axis; uint16_t opcode; int64_t argument; } PlsrCommand; ``` #### 4.1.3 段快照 ```c typedef struct { uint32_t target_frequency_hz; int32_t pulse_or_position; uint16_t wait_word; int32_t wait_argument; uint16_t jump_word; int32_t jump_argument; } PlsrSegmentSnapshot; ``` 四轴各保留最多100段的紧凑快照。快照同时保存当前段频率源地址,专供受控动态调频;其它字段不得 通过源地址重新读取。 #### 4.1.4 任务快照 ```c typedef struct { uint16_t segment_count; uint16_t start_segment; PlsrPositionMode position_mode; PlsrOutputMode output_mode; uint8_t d_axis; PlsrS2Snapshot s2; PlsrResourceLease resources; PlsrSegmentSnapshot segments[PLSR_MAX_SEGMENTS]; } PlsrJobSnapshot; ``` 硬件计数租约作为输出资源租约的一部分: ```c typedef struct { PlsrCountMode mode; uint8_t owner_axis; uint8_t pulse_source; uint8_t trigger_select; bool valid; } PlsrCounterLease; ``` TIM9和TIM12各只能存在一个有效租约。软件计数模式不占用硬件计数租约。 #### 4.1.5 轴运行对象 ```c typedef struct { PlsrState state; PlsrJobSnapshot job; PlsrSegmentRuntime segment; PlsrProfile profile; PlsrPulseFastContext pulse_fast; int64_t logical_position; int64_t task_pulses; int64_t total_pulses; uint64_t physical_edges; bool position_valid; uint32_t event_flags; uint32_t event_sequence; uint32_t last_command_sequence; PlsrCommandResult last_command_result; PlsrError error; PlsrStatusPublish publish; } PlsrAxis; ``` #### 4.1.6 ISR快速上下文 ```c typedef struct { volatile uint32_t remaining_in_block; volatile uint32_t completed_in_block; volatile uint32_t hardware_wrap_count; volatile uint32_t pending_event; volatile uint8_t divider_pending; volatile uint8_t tail_stop_armed; PlsrCountMode count_mode; uint8_t pulse_source; uint16_t final_compare; uint64_t target_pulses; PlsrDivider active_divider; PlsrDivider pending_divider; } PlsrPulseFastContext; ``` 硬件计数模式下,`hardware_wrap_count`与TIM9/TIM12当前CNT组成完整累计;软件计数模式下使用 `remaining_in_block`逐周期递减。`count_mode`在段活动期间只读,只有输出完全停止后才允许改变。 快速上下文只保存ISR固定时间内需要的数据,不放置S0数组、Flash缓存和复杂状态对象。 #### 4.1.7 对外状态 ```c typedef struct { uint32_t version; PlsrState state; uint16_t current_segment; uint16_t total_segments; int8_t direction; uint8_t busy; uint8_t pulse_active; uint8_t done; uint32_t command_frequency_hz; uint32_t actual_frequency_hz; PlsrCountMode count_mode; uint32_t hardware_counter_value; int64_t segment_sent; int64_t segment_remaining; int64_t logical_position; int64_t task_pulses; int64_t total_pulses; PlsrError error; uint32_t stop_reason; uint32_t version_end; } PlsrStatus; ``` #### 4.1.8 固定软元件描述 ```c typedef struct { PlsrDeviceType type; uint16_t address; uint8_t width_words; uint8_t axis; uint8_t access; uint8_t persistence; int64_t minimum; int64_t maximum; } PlsrDeviceDescriptor; ``` 描述表必须覆盖HSD460~539、SFD900~1419、HSD0~15、固定SM、固定SD和I6000~6399, 并通过静态断言检查重复地址、位宽和轴归属。 ### 4.2 数据结构与程序的关系 #### 4.2.1 数据流关系 ![PLSR数据流关系图](./PLSR数据流关系图.svg) **图 4-1 PLSR数据流关系图** 图中蓝色表示配置和运动数据,橙色表示硬实时数据及中断事件,绿色表示持久化数据,紫色表示命令与 状态接口。为方便纯文本环境阅读,保留如下简化关系。 ```text S0/S1/S2/D逻辑软元件 | v PlsrParser_BuildSnapshot | v PlsrJobSnapshot ----------> PlsrPath / PlsrProfile | | v v PlsrAxis状态机 <---------- ISR事件和块计数 | +----> PlsrStatusPublish ----> HSD/SM/SD/I与Modbus读取 | +----> Flash / Backup SRAM检查点 ``` #### 4.2.2 数据所有权 | 数据 | 唯一写者 | 读取者 | 一致性方法 | | --- | --- | --- | --- | | ISR快速计数 | TIM9/TIM12块ISR或输出定时器兜底ISR | TIM6 ISR、PlsrTask | 计数模式锁存、32位原子交换 | | 速度规划状态 | TIM6 ISR | 脉冲ISR、PlsrTask | 待提交双缓冲 | | 状态机和路径游标 | PlsrTask | 状态发布 | 单写者 | | 输出资源位图 | 资源管理器 | PlsrTask、诊断 | 短临界区 | | 64位位置累计 | PlsrTask | 状态读取、保存 | 顺序锁/短临界区 | | 对外状态影子 | 状态发布器 | Modbus、内部API | 版本号前后校验 | | 固定配置镜像 | 参数模块 | 保存和设备访问 | 影子+COMMIT | 通信层禁止直接写 `PlsrAxis`。`volatile`只保证访问可见性,不代替原子性、临界区和内存屏障。 #### 4.2.3 中断事件数据 每轴使用32位事件字: ```text bit0 PULSE_BLOCK_DONE bit1 SEGMENT_OUTPUT_DONE bit2 LIMIT_POSITIVE bit3 LIMIT_NEGATIVE bit4 EXT_RISING bit5 STOP_IMMEDIATE_DONE bit6 TIMER_FAULT bit7 COUNTER_FAULT bit8 HW_COUNTER_WRAP bit9 HW_COUNTER_TARGET ``` 可合并事件采用原子置位;不能丢失的段事件另带单调递增序号。临界区内禁止遍历100段、除法、CRC、 Flash操作或通信发送,并使用DWT周期计数器测量最坏执行时间。 #### 4.2.4 固定运行状态发布 | 轴 | HSD累计 | SM标志 | SD实时状态 | 段事件 | | --- | --- | --- | --- | --- | | Y0 | HSD0~3 | SM1000、SM1001 | SD1000~1011 | I6000~6099 | | Y1 | HSD4~7 | SM1020、SM1021 | SD1020~1031 | I6100~6199 | | Y2 | HSD8~11 | SM1040、SM1041 | SD1040~1051 | I6200~6299 | | Y3 | HSD12~15 | SM1060、SM1061 | SD1060~1071 | I6300~6399 | 双字采用低地址低16位、下一地址高16位。第N段事件使用轴事件基址加 `N-1`,跳转目标不得改变原段 事件地址。 ## 5 错误处理设计 ### 5.1 错误处理设计描述 #### 5.1.1 错误分层 | 层级 | 示例 | 处理 | | --- | --- | --- | | 告警 | `SPEED_CLAMPED` | 记录并继续运行 | | 启动拒绝 | 参数越界、资源冲突、位置无效 | 不启动、不占资源、不破坏其它轴 | | 轴错误 | 计数异常、定时器异常、动态跳转越界 | 安全停止该轴、释放资源并锁存ERROR | | 全局严重错误 | HardFault、共享数据破坏 | 关闭全部高速输出并锁存全局故障 | 错误处理统一遵循:先禁止新脉冲,再锁存原因,再发布状态,最后在任务上下文执行资源释放和允许的 检查点保存。错误清除只回到IDLE,不自动恢复未完成任务。 #### 5.1.2 安全输出 以下时机调用统一 `PlsrHw_ForceSafe()`: - 上电及PLSR初始化前; - START硬件配置失败; - STOP_IMMEDIATE尾脉冲完成; - 定时器、计数或互斥严重错误; - HardFault、MemManage、BusFault、UsageFault; - 看门狗复位后的早期初始化。 安全关闭直接关闭TIM10/11/13/14通道和计数器,并把相关GPIO恢复为配置的安全无效电平。 故障处理函数不得写Flash。 #### 5.1.3 参数与运行错误 - 参数错误在START前尽量全部发现; - 运行中非法目标频率不破坏当前合法运动,保留最近合法目标并发布诊断; - 动态等待或跳转变量在运行时越界时进入ERROR; - 剩余量下溢、TIM9/TIM12硬件累计与输出诊断不一致、定时器意外停止或AB/CW/CCW互斥破坏时 立即关闭输出; - 兼容32位累计溢出时不得截断或回绕; - 限位触发按正负方向发布兼容码,并禁止继续向越界方向启动; - 多次STOP_IMMEDIATE按幂等命令处理。 #### 5.1.4 设计风险与关闭条件 | 编号 | 风险 | 处理及关闭条件 | | --- | --- | --- | | RISK-01 | 四轴100 kHz仍有两轴可能采用软件计数,最坏约200k周期事件/秒 | 分别验证两硬件+两软件计数组合,记录ISR最坏周期、CPU占用和通信压力结果 | | RISK-02 | TIM9/TIM12只能累计,不能反向自动关闭输出源 | 最终比较只武装尾边沿,逐数量边界验证无额外或窄脉冲 | | RISK-03 | AB配对定时器时钟分别为168/84 MHz | 全频段测量两组AB频率、相位及方向 | | RISK-04 | USB中断可能抢占运动实时路径 | 优先级已降为4;完成USB/Modbus/四轴长稳压力后关闭 | | RISK-05 | 输出电路极性和可靠带宽待实测 | 测量Q0~Q3带载波形后冻结参数 | | RISK-06 | 0.1 ms曲线计算量 | 定点化和预计算,DWT实测最坏执行时间小于周期预算 | | RISK-07 | 16位通信写入造成32位动态频率撕裂 | 使用影子+COMMIT版本和内核二次校验 | | RISK-08 | Backup SRAM不能保证掉电瞬间零误差 | 异常复位清position_valid,并记录恢复等级 | | RISK-09 | 现有历史写入破坏S0/S1数据 | 删除历史写入并完成全地址越界测试 | | RISK-10 | 信捷保留字段被扩展复用 | 固定描述表、静态断言和对标矩阵评审 | | RISK-11 | 将共用S2字段误当作PLSR的FOLLOW运算 | 已关闭:FOLLOW/FOLLOW_AB按信捷手册属于独立指令,不在PLSR V1.0执行范围 | | RISK-12 | TIM9/TIM12内部OC事件相位和跨时钟域同步延迟 | 测量Q0~Q3的计数对应边沿、首脉冲、末脉冲和动态调频后累计一致性 | 截至2026-08-10,P14端子实测Q0~Q3均为100kHz且各严格200000个上升沿;P16实测 `PlsrProcess`自身最大53748 cycles(319.929us)、响应最大85655 cycles,P14/P16已关闭。P15四轴 软限位矩阵亦已板测通过。双AB安全首沿/双计数器/00边界PAUSE/D1468完整快速窗口、0x47及 D1516~D1537 USB自动诊断、P18/K4长稳夹具和持久化分阶段掉电工具属于代码完成、Host/IAR已通过 但最终板测未关闭项;真实 X0~X3 GPIO 链已由 P19 回环板测关闭,HM保持介质仍待硬件定义。上述新批次落盘后必须重跑 P14/P15/P16回归,不能用修改前的通过记录替代发布回归。 ### 5.2 错误输出信息 #### 5.2.1 信捷兼容错误码 | 兼容码 | 含义 | 处理 | | ---: | --- | --- | | 1 | 脉冲数据段配置错误 | 拒绝启动,错误块号写SD的B+11 | | 2 | 每转脉冲数或每转移动量为0 | 拒绝启动 | | 3 | S2参数块号错误 | 拒绝启动 | | 4 | 脉冲参数块号或范围错误 | 拒绝启动 | | 5 | 正限位触发 | 减速停止并禁止继续正向启动 | | 6 | 负限位触发 | 减速停止并禁止继续反向启动 | | 15 | FOLLOW性能不在1~100 | 拒绝启动 | | 16 | FOLLOW前馈不在0~100 | 拒绝启动 | | 26 | 控制块或高速资源分配失败 | 拒绝启动或进入ERROR | #### 5.2.2 项目增强错误 | 错误 | 含义 | 级别 | | --- | --- | --- | | `DEFAULT_SPEED_INVALID` | 段频率0但S2默认速度非法 | 启动拒绝/轴错误 | | `SEGMENT_OVERFLOW` | 路径段数超过100 | 启动拒绝 | | `OUTPUT_MODE_INVALID` | 输出模式或D组合非法 | 启动拒绝 | | `RESOURCE_CONFLICT` | 脉冲点或DIR点冲突 | 启动拒绝 | | `PARAMETER_LOCKED` | 运行中修改锁定参数 | 写入拒绝 | | `DONE_STATE_ERROR` | DONE状态转换异常 | 轴错误 | | `SPEED_CLAMPED` | 速度被S2最高速度限幅 | 告警 | | `POSITION_INVALID` | 绝对定位前位置无效 | 启动拒绝 | | `COUNTER_OVERFLOW` | 内部或兼容累计溢出 | 轴错误 | | `ILLEGAL_TRANSITION` | 非法状态机转换 | 轴错误 | | `TIMER_FAULT` | 定时器初始化或运行异常 | 轴/全局错误 | | `PULSE_COUNT_MISMATCH` | 软件计数与诊断计数不一致 | 轴错误 | | `HW_COUNTER_FAULT` | TIM9/TIM12计数器意外停止、越权或累计不一致 | 轴错误 | | `HW_COUNTER_FALLBACK` | 硬件计数器不可用,当前段使用软件计数 | 诊断提示,不终止任务 | #### 5.2.3 错误信息结构 ```c typedef struct { PlsrError error; uint16_t compatible_code; uint8_t axis; uint16_t segment; uint16_t bad_block; uint32_t command_sequence; uint32_t stop_reason; uint32_t detail_a; uint32_t detail_b; uint64_t timestamp; } PlsrErrorDetail; ``` 错误信息通过增强状态接口发布;兼容码和错误块号同时写入固定SD字段。相同错误重复发生可增加计数, 但不得覆盖更高优先级停止原因。 #### 5.2.4 验证要求 | 验证阶段 | 内容 | 合格条件 | | --- | --- | --- | | V1 | Q0~Q3固定频率与安全电平 | 引脚、极性、频率、占空比正确 | | V2 | TIM9/TIM12单轴硬件计数及软件兜底计数 | 两种模式数量误差均为0,无窄脉冲和多余边沿 | | V3 | 四轴100 kHz并发,两硬件计数+两软件计数 | 计数误差0,轴间无串扰,CPU和ISR数据可接受 | | V4 | 两组AB及CW/CCW | 计数器分配、相序、周期、互斥和数量正确 | | V5 | 0.1/1 ms曲线与调频 | 响应、曲线和段边界正确 | | V6 | 多段、等待、跳转和事件 | 与S0语义一致 | | V7 | STOP、PAUSE、限位和错误 | 优先级、尾脉冲和终态正确 | | V8 | Modbus/USB压力及长稳 | 不影响脉冲和状态一致性 | | V9 | Flash、Backup SRAM和复位 | CRC有效、不自动续跑、位置有效性正确 | 测试记录应包含固件版本、参数快照、接线、测量设备、原始波形、实际边沿数、方向建立时间、AB相位、 ISR平均/最坏周期、CPU占用和结论。 ## 6 参考资料 1. [PLSR需求规格统计_V1.3.md](./PLSR需求规格统计_V1.3.md) 2. [PLSR地址映射.md](./PLSR地址映射.md) 3. [PLSR信捷对标追踪矩阵.md](./PLSR信捷对标追踪矩阵.md) 4. [实现PLSR指令.pdf](./实现PLSR指令.pdf) 5. [信捷XD/XL系列PLC定位控制手册](./信捷XD_XL系列PLC定位控制手册_PD02_20260510_V1.3.pdf) 6. [STM32F4xx参考手册 RM0090 Rev.22](./STM32F4xx参考手册_RM0090_Rev22.pdf) 7. 当前工程 `Core`、`Modbus`、`Middlewares`、`USB_DEVICE` 和 `EWARM` 目录