From 7750e43045fb3dcf01a641039b80be22648ee954 Mon Sep 17 00:00:00 2001 From: ywh <2227158009@qq.com> Date: Sun, 9 Aug 2026 16:37:49 +0800 Subject: [PATCH] =?UTF-8?q?P6=20=E5=9B=9B=E8=BD=B4=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E8=87=AA=E6=B5=8B=E8=90=BD=E5=9C=B0=EF=BC=9AQ0~Q3=20=E5=9B=9B?= =?UTF-8?q?=E8=B7=AF=E7=8B=AC=E7=AB=8B=20PULSE/DIR=20=E7=9C=9F=E6=9C=BA?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=20+=20=E9=9B=B6=E5=8A=A0=E9=80=9F=E6=AE=B5?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9C=BA=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本批完成内容: 四轴并发自测(P6): - 新增 PlsrFourAxisSelfTestQueue:Q0~Q3 四路独立 PULSE/DIR 任务(1000Hz/1000、2000Hz/2000、3000Hz/3000、4000Hz/4000 脉冲),每轴独立 S0/S1 基址与 SFD 配置(Q4~Q7 方向点)。 - main.c 上电自测入口切换为四轴并发测试(验证后可删除)。 状态机修复: - start==target 或零加速时直接进入 CRUISE 的段,补发 ACCEL_COMPLETE 事件,避免轴状态卡在 ACCEL 整段。 host 测试扩展: - 四轴并发启动/计数相关断言(HAL 测试 +90 项)。 上板验证(逻辑分析仪实测): - Q0/Q1/Q2/Q3 = 1000/2000/3000/4000Hz,上升沿 1000/2000/3000/4000 全部精确,占空比 50%,时长约 1s, 四路独立无干扰。 - 同时验证 84MHz 定时器时钟修正有效:Q1(TIM13)、Q3 (TIM14)频率精确无减半。 --- Core/Src/main.c | 5 +- PLSR/Inc/plsr_self_test.h | 3 ++ PLSR/Src/plsr_core.c | 6 +++ PLSR/Src/plsr_self_test.c | 109 +++++++++++++++++++++++++++++++++++++- PLSR/Test/test_plsr_hal.c | 90 +++++++++++++++++++++++++++++++ 5 files changed, 209 insertions(+), 4 deletions(-) diff --git a/Core/Src/main.c b/Core/Src/main.c index f73af31..c299f0c 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -202,9 +202,8 @@ int main(void) /* 上电自测:延时 1s 后由 Q0/Q1 输出三段 AB 正交周期(验证后关闭)。 */ HAL_Delay(1000U); - /* P5 board test: Q0=PULSE, Q4=DIR, controlled stop at +500. */ - //(void)PlsrProtectionSelfTestQueue(); - (void)PlsrProtectionSelfTestQueue(); + /* P6 board test: Q0..Q3 run four independent PULSE/DIR jobs. */ + (void)PlsrFourAxisSelfTestQueue(); OSStart(); /* USER CODE END 2 */ diff --git a/PLSR/Inc/plsr_self_test.h b/PLSR/Inc/plsr_self_test.h index 3b8df58..ec7492c 100644 --- a/PLSR/Inc/plsr_self_test.h +++ b/PLSR/Inc/plsr_self_test.h @@ -19,6 +19,9 @@ PLSR_RESULT PlsrEquivalentSelfTestQueue(void); * distance is deliberately longer than the +500-pulse soft limit. */ PLSR_RESULT PlsrProtectionSelfTestQueue(void); +/* P6 board test: start four independent PULSE/DIR axes together. */ +PLSR_RESULT PlsrFourAxisSelfTestQueue(void); + #ifdef __cplusplus } #endif diff --git a/PLSR/Src/plsr_core.c b/PLSR/Src/plsr_core.c index 945e11f..1ed30a4 100644 --- a/PLSR/Src/plsr_core.c +++ b/PLSR/Src/plsr_core.c @@ -1782,6 +1782,12 @@ static PLSR_RESULT PlsrStartSegmentHardware(uint8_t axis, axisObject->profileWasAccel = (axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL) ? 1U : 0U; PlsrPublishAxis(axis); + if (axisObject->profileWasAccel == 0U) + { + /* start==target or zero acceleration enters CRUISE directly. The + * axis state must not remain stuck in ACCEL for the whole segment. */ + (void)PlsrPostEvent(axis, PLSR_EVENT_ACCEL_COMPLETE); + } return PLSR_RESULT_OK; } diff --git a/PLSR/Src/plsr_self_test.c b/PLSR/Src/plsr_self_test.c index 53f112c..0e24eaf 100644 --- a/PLSR/Src/plsr_self_test.c +++ b/PLSR/Src/plsr_self_test.c @@ -12,10 +12,12 @@ * 段3:1000Hz / -500 周期(B 超前 A,验证反向) * 数据源为静态数组,仅自测使用(正式 D 设备适配器见 Modbus 阶段)。 */ -#define SELF_TEST_WORD_CAPACITY (64U) +#define SELF_TEST_WORD_CAPACITY (192U) #define SELF_TEST_S0_BASE (10U) #define SELF_TEST_S1_BASE (60U) #define SELF_TEST_DIR_POINT (4U) +#define SELF_TEST_SFD_AXIS_STRIDE (130U) +#define SELF_TEST_SFD_SET_OFFSET (50U) static uint16_t SelfTestWords[3][SELF_TEST_WORD_CAPACITY]; @@ -234,3 +236,108 @@ PLSR_RESULT PlsrProtectionSelfTestQueue(void) call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR; return PlsrPostCall(&call); } + +PLSR_RESULT PlsrFourAxisSelfTestQueue(void) +{ + static const uint16_t s0Base[PLSR_AXIS_COUNT] = + { + 10U, 40U, 70U, 100U + }; + static const uint16_t s1Base[PLSR_AXIS_COUNT] = + { + 160U, 164U, 168U, 172U + }; + static const uint32_t frequencyHz[PLSR_AXIS_COUNT] = + { + 1000UL, 2000UL, 3000UL, 4000UL + }; + static const int32_t pulseCount[PLSR_AXIS_COUNT] = + { + 1000, 2000, 3000, 4000 + }; + PLSR_CALL call; + PLSR_COMMAND command; + PLSR_RESULT result; + uint16_t commonBase; + uint16_t setBase; + uint8_t axis; + + (void)memset(SelfTestWords, 0, sizeof(SelfTestWords)); + + for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) + { + commonBase = (uint16_t)(900U + + (uint16_t)axis + * SELF_TEST_SFD_AXIS_STRIDE); + setBase = (uint16_t)(commonBase + SELF_TEST_SFD_SET_OFFSET); + + /* Pulse unit, PULSE/DIR, no limit input, Q4..Q7 as DIR. */ + (void)PlcDeviceWriteSfd(commonBase, 0U); + SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL); + SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL); + (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U), + (uint16_t)(SELF_TEST_DIR_POINT + axis)); + (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 10U); + (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U); + (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU); + + /* K1 has no ramp so all four channels keep an exact fixed rate. */ + SelfTestWriteSfdDword(setBase, frequencyHz[axis]); + (void)PlcDeviceWriteSfd((uint16_t)(setBase + 2U), 0U); + (void)PlcDeviceWriteSfd((uint16_t)(setBase + 3U), 0U); + (void)PlcDeviceWriteSfd((uint16_t)(setBase + 4U), 0U); + (void)PlcDeviceWriteSfd((uint16_t)(setBase + 5U), 0U); + SelfTestWriteSfdDword((uint16_t)(setBase + 6U), 100000UL); + SelfTestWriteSfdDword((uint16_t)(setBase + 8U), + frequencyHz[axis]); + SelfTestWriteSfdDword((uint16_t)(setBase + 10U), 0UL); + (void)PlcDeviceWriteSfd((uint16_t)(setBase + 12U), 50U); + (void)PlcDeviceWriteSfd((uint16_t)(setBase + 13U), 0U); + (void)PlcDeviceWriteSfd((uint16_t)(setBase + 14U), 0U); + SelfTestWriteSfdDword((uint16_t)(setBase + 16U), 2000UL); + SelfTestWriteSfdDword((uint16_t)(setBase + 18U), 200UL); + + SelfTestWriteDword(PLSR_DEVICE_D, s0Base[axis], 1U); + SelfTestWriteDword(PLSR_DEVICE_D, + (uint32_t)s0Base[axis] + 10UL, + frequencyHz[axis]); + SelfTestWriteDword(PLSR_DEVICE_D, + (uint32_t)s0Base[axis] + 12UL, + (uint32_t)pulseCount[axis]); + SelfTestWriteDword(PLSR_DEVICE_D, s1Base[axis], 0U); + + /* Make the board-test result independent of a previously restored + * Backup SRAM position. */ + (void)memset(&command, 0, sizeof(command)); + command.sequence = 0xA500UL + axis; + command.axis = axis; + command.opcode = PLSR_CMD_SET_POSITION; + command.argument = 0; + result = PlsrPostCommand(&command); + if (result != PLSR_RESULT_QUEUED) + { + return result; + } + + (void)memset(&call, 0, sizeof(call)); + call.sequence = 0xA600UL + axis; + call.source.context = NULL; + call.source.validateWords = SelfTestValidateWords; + call.source.readWord = SelfTestReadWord; + call.source.readBit = SelfTestReadBit; + call.s0.device = PLSR_DEVICE_D; + call.s0.address = s0Base[axis]; + call.s1.device = PLSR_DEVICE_D; + call.s1.address = s1Base[axis]; + call.s2.type = PLSR_OPERAND_CONSTANT; + call.s2.constant = 1; + call.dAxis = axis; + call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR; + result = PlsrPostCall(&call); + if (result != PLSR_RESULT_QUEUED) + { + return result; + } + } + return PLSR_RESULT_QUEUED; +} diff --git a/PLSR/Test/test_plsr_hal.c b/PLSR/Test/test_plsr_hal.c index 1acd23b..7cf7575 100644 --- a/PLSR/Test/test_plsr_hal.c +++ b/PLSR/Test/test_plsr_hal.c @@ -3,6 +3,7 @@ #include "plsr_hal_f407.h" #include "plsr_job.h" #include "plsr_persistence.h" +#include "plsr_resource.h" #include "plsr_self_test.h" #include #include @@ -1243,6 +1244,94 @@ static void TestProtectionSelfTest(void) CHECK(eventRecord.lastReason == PLSR_STOP_REASON_LIMIT_POSITIVE); } +static void TestFourAxisSelfTest(void) +{ + static const uint32_t expectedFrequency[PLSR_AXIS_COUNT] = + { + 1000UL, 2000UL, 3000UL, 4000UL + }; + static const int32_t expectedPulses[PLSR_AXIS_COUNT] = + { + 1000, 2000, 3000, 4000 + }; + PLC_DEVICE_EVENT_RECORD eventRecord; + PLSR_RESOURCE_STATUS resources; + PLSR_STATUS status; + int32_t hsdPulses; + int subTick; + int ticks; + uint8_t axis; + + TestResetEnvironment(); + CHECK(PlsrFourAxisSelfTestQueue() == PLSR_RESULT_QUEUED); + PlsrProcess(); + + for (ticks = 0; ticks < 10; ticks++) + { + PlsrProcess(); + } + for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) + { + CHECK(PlsrGetStatus(axis, &status) == PLSR_RESULT_OK); + CHECK(status.state == PLSR_STATE_RUN); + CHECK(status.outputMode == PLSR_OUTPUT_PULSE_DIR); + CHECK(status.directionPoint == (uint8_t)(4U + axis)); + CHECK(status.directionPositive != 0U); + CHECK(PlsrHwGetState(axis) == PLSR_HW_STATE_RUNNING); + CHECK(PlsrHwGetCurrentFrequencyHz(axis) + == expectedFrequency[axis]); + } + + /* A 0.25ms base slot produces 1/2/3/4kHz update ratios while all four + * hardware channels are active concurrently for one simulated second. */ + for (subTick = 0; subTick < 4000; subTick++) + { + if ((subTick & 3) == 0) + { + PlsrHwTestTriggerUpdate(0U); + } + if ((subTick & 1) == 0) + { + PlsrHwTestTriggerUpdate(1U); + } + if ((subTick & 3) != 3) + { + PlsrHwTestTriggerUpdate(2U); + } + PlsrHwTestTriggerUpdate(3U); + + if ((subTick & 3) == 3) + { + PlsrProcess(); + } + } + + for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) + { + CHECK(PlsrGetStatus(axis, &status) == PLSR_RESULT_OK); + CHECK(status.state == PLSR_STATE_COMPLETED); + CHECK(status.stopReason == PLSR_STOP_REASON_NORMAL_COMPLETE); + CHECK(status.done != 0U); + CHECK(status.logicalPosition == expectedPulses[axis]); + CHECK(status.taskPulses == expectedPulses[axis]); + CHECK(status.totalPulses == expectedPulses[axis]); + CHECK(PlsrHwGetState(axis) == PLSR_HW_STATE_IDLE); + CHECK(PlcDeviceReadHsdDword((uint16_t)(axis * 4U), + &hsdPulses) == PLC_DEVICE_OK); + CHECK(hsdPulses == expectedPulses[axis]); + CHECK(PlcDeviceReadEvent((uint16_t)(6000U + + (uint16_t)axis * 100U), + &eventRecord) == PLC_DEVICE_OK); + CHECK(eventRecord.count == 1UL); + CHECK(eventRecord.pending != 0U); + CHECK(eventRecord.lastReason == PLSR_STOP_REASON_NORMAL_COMPLETE); + } + PlsrResourceGetStatus(&resources); + CHECK(resources.outputMask == 0UL); + CHECK(resources.highMask == 0U); + CHECK(PlsrResourceCheckInvariant() != 0U); +} + static void TestStopStopsHardware(void) { TEST_MEMORY memory; @@ -1304,6 +1393,7 @@ int main(void) TestProductionSelfTestStartsAb(); TestEquivalentSelfTest(); TestProtectionSelfTest(); + TestFourAxisSelfTest(); TestStopStopsHardware(); if (TestFailures != 0)