#include "plc_device.h" #include "plsr_core.h" #include "plsr_hal_f407.h" #include "plsr_job.h" #include "plsr_persistence.h" #include "plsr_self_test.h" #include #include #define TEST_WORD_CAPACITY (3000U) #define TEST_S0_BASE (100U) #define TEST_S1_BASE (200U) typedef struct { uint16_t words[3][TEST_WORD_CAPACITY]; } TEST_MEMORY; static int TestFailures; static int TestChecks; #define CHECK(condition) \ do \ { \ TestChecks++; \ if (!(condition)) \ { \ TestFailures++; \ (void)printf("FAIL line %d: %s\n", __LINE__, #condition); \ } \ } while (0) static uint8_t TestValidateWords(void *context, PLSR_DEVICE_TYPE device, uint32_t firstAddress, uint32_t wordCount) { (void)context; (void)device; return (((uint64_t)firstAddress + wordCount) <= TEST_WORD_CAPACITY) ? 1U : 0U; } static uint8_t TestReadWord(void *context, PLSR_DEVICE_TYPE device, uint32_t address, uint16_t *value) { TEST_MEMORY *memory = (TEST_MEMORY *)context; if ((memory == NULL) || (value == NULL) || (device > PLSR_DEVICE_FD) || (address >= TEST_WORD_CAPACITY)) { return 0U; } *value = memory->words[device][address]; return 1U; } static uint8_t TestReadBit(void *context, PLSR_DEVICE_TYPE device, uint32_t address, uint8_t *value) { (void)context; (void)device; (void)address; *value = 0U; return 1U; } static void TestWriteDword(TEST_MEMORY *memory, PLSR_DEVICE_TYPE device, uint32_t address, int32_t value) { uint32_t raw = (uint32_t)value; memory->words[device][address] = (uint16_t)(raw & 0xFFFFUL); memory->words[device][address + 1UL] = (uint16_t)(raw >> 16U); } static void TestSetSegment(TEST_MEMORY *memory, uint16_t number, uint32_t frequency, int32_t pulses) { uint32_t base = TEST_S0_BASE + (uint32_t)number * 10UL; TestWriteDword(memory, PLSR_DEVICE_D, base, (int32_t)frequency); TestWriteDword(memory, PLSR_DEVICE_D, base + 2UL, pulses); memory->words[PLSR_DEVICE_D][base + 4UL] = 0U; TestWriteDword(memory, PLSR_DEVICE_D, base + 5UL, 0); memory->words[PLSR_DEVICE_D][base + 7UL] = 0U; TestWriteDword(memory, PLSR_DEVICE_D, base + 8UL, 0); } static void TestResetEnvironment(void) { PlsrPersistenceTestResetStorage(); CHECK(PlcDeviceInit() == PLC_DEVICE_OK); CHECK(PlcDeviceWriteSfd(906U, 4) == PLC_DEVICE_OK); CHECK(PlsrInit() == PLSR_RESULT_OK); } static PLSR_CALL TestMakeCall(TEST_MEMORY *memory) { PLSR_CALL call; (void)memset(&call, 0, sizeof(call)); call.sequence = 10UL; call.source.context = memory; call.source.validateWords = TestValidateWords; call.source.readWord = TestReadWord; call.source.readBit = TestReadBit; call.s0.device = PLSR_DEVICE_D; call.s0.address = TEST_S0_BASE; call.s1.device = PLSR_DEVICE_D; call.s1.address = TEST_S1_BASE; call.s2.type = PLSR_OPERAND_CONSTANT; call.s2.constant = 1; call.dAxis = 0U; call.outputModeOverride = PLSR_OUTPUT_MODE_FROM_SFD; return call; } static PLSR_STATUS TestGetStatus(void) { PLSR_STATUS status; (void)memset(&status, 0, sizeof(status)); CHECK(PlsrGetStatus(0U, &status) == PLSR_RESULT_OK); return status; } /* ---- HAL 单测 ---- */ static void TestMapping(void) { (void)PlsrHwInit(); CHECK(PlsrHwGetTimerClockHz(0U) == 168000000UL); CHECK(PlsrHwGetTimerClockHz(1U) == 84000000UL); CHECK(PlsrHwGetTimerClockHz(2U) == 168000000UL); CHECK(PlsrHwGetTimerClockHz(3U) == 84000000UL); CHECK(PlsrHwGetTimerClockHz(4U) == 0UL); CHECK(PlsrHwResolveDirectionPoint(4U) != 0U); CHECK(PlsrHwResolveDirectionPoint(8U) == 0U); CHECK(PlsrHwResolveDirectionPoint(20U) != 0U); CHECK(PlsrHwResolveDirectionPoint(21U) == 0U); } static void TestDirDelaySequence(void) { (void)PlsrHwInit(); PLSR_HW_START_PARAMS params; uint16_t psc; uint16_t arr; int ticks; (void)memset(¶ms, 0, sizeof(params)); params.frequencyHz = 1000UL; params.targetPulses = 100; params.directionPoint = 4U; params.directionPositive = 1U; params.directionDelayMs = 10U; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DIR_SETTLING); CHECK(PlsrHwTestGetDirLevel(0U) == 1U); CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U); CHECK(PlsrHwIsPulseActive(0U) == 0U); for (ticks = 0; ticks < 9; ticks++) { PlsrHwTick(0U); } CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DIR_SETTLING); PlsrHwTick(0U); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING); /* 首个非零频率启动 PWM,ARR/CCR 与分频计算一致。 */ CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); CHECK(PlsrHwTestGetPwmEnabled(0U) == 1U); CHECK(PlsrHwIsPulseActive(0U) == 1U); CHECK(PlsrCalculateTimerDivider(168000000UL, 1000UL, &psc, &arr) == PLSR_RESULT_OK); CHECK(PlsrHwTestGetArr(0U) == arr); CHECK(PlsrHwTestGetPsc(0U) == psc); CHECK(PlsrHwTestGetCcr(0U) == arr / 2UL); /* PWM 模式 1(OC1M=110):复位后 CCMR1=0 冻结,无此配置输出恒定电平。 */ CHECK((PlsrHwTestGetCcmr1(0U) & 0x70UL) == 0x60UL); /* ARR/CCR 预装载(ARPE=CR1 bit7,OC1PE=CCMR1 bit3): * 运行中调频不产生提前回绕,否则加速段多出 ~ln(f1/f0) 个假脉冲。 */ CHECK((PlsrHwTestGetCr1(0U) & 0x80UL) == 0x80UL); CHECK((PlsrHwTestGetCcmr1(0U) & 0x08UL) == 0x08UL); /* 段间同向衔接:方向不变时跳过方向延时,直接进入 PWM 待启动。 */ CHECK(PlsrHwStopPulse(0U) == PLSR_RESULT_OK); params.targetPulses = 50; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING); CHECK(PlsrHwTestGetDirLevel(0U) == 1U); /* 反向时方向延时仍生效。 */ params.directionPositive = 0U; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DIR_SETTLING); CHECK(PlsrHwTestGetDirLevel(0U) == 0U); } static void TestZeroFrequencyWaits(void) { (void)PlsrHwInit(); PLSR_HW_START_PARAMS params; (void)memset(¶ms, 0, sizeof(params)); params.frequencyHz = 0UL; params.targetPulses = 50; params.directionPoint = PLSR_HW_DIR_POINT_NONE; params.directionPositive = 1U; params.directionDelayMs = 0U; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING); PlsrHwTick(0U); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING); CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U); /* 起始速度为 0:profile 升频后首个非零频率才启动 PWM。 */ CHECK(PlsrHwSetFrequency(0U, 10UL) == PLSR_RESULT_OK); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); CHECK(PlsrHwTestGetPwmEnabled(0U) == 1U); } static void TestPulseCounting(void) { (void)PlsrHwInit(); PLSR_HW_START_PARAMS params; int pulse; (void)memset(¶ms, 0, sizeof(params)); params.frequencyHz = 1000UL; params.targetPulses = 5; params.directionPoint = PLSR_HW_DIR_POINT_NONE; params.directionPositive = 1U; params.directionDelayMs = 0U; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); CHECK(PlsrHwGetEmittedPulses(0U) == 0); /* EGR.UG 只加载预装载寄存器,不能被当作物理脉冲。 * 共享 IRQ 入口在对应定时器没有 UIF 时也必须无动作。 */ PlsrHwOnTimerUpdate(0U); CHECK(PlsrHwGetEmittedPulses(0U) == 0); for (pulse = 0; pulse < 4; pulse++) { PlsrHwTestTriggerUpdate(0U); CHECK(PlsrHwGetEmittedPulses(0U) == pulse + 1); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); } /* 第 5 个脉冲:到目标,停止 + 段完成事件。 */ PlsrHwTestTriggerUpdate(0U); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE); CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U); CHECK(PlsrHwIsPulseActive(0U) == 0U); /* 停止后再触发更新中断无动作。 */ PlsrHwTestTriggerUpdate(0U); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE); } static void TestAbPhaseAndCounting(void) { PLSR_HW_START_PARAMS params; static const uint8_t positiveA[4] = {1U, 1U, 0U, 0U}; static const uint8_t positiveB[4] = {0U, 1U, 1U, 0U}; static const uint8_t negativeA[4] = {0U, 1U, 1U, 0U}; static const uint8_t negativeB[4] = {1U, 1U, 0U, 0U}; uint32_t oldArr; uint32_t oldBasePsc; uint32_t oldPairPsc; uint32_t newPeriod; int quarter; (void)PlsrHwInit(); (void)memset(¶ms, 0, sizeof(params)); params.frequencyHz = 1000UL; params.targetPulses = 4; params.outputMode = PLSR_OUTPUT_AB; params.directionPoint = 4U; /* AB 模式必须忽略独立 DIR 点。 */ params.directionPositive = 1U; params.directionDelayMs = 10U; /* AB 模式不得执行方向延时。 */ CHECK(PlsrHwStartPulse(1U, ¶ms) == PLSR_RESULT_INVALID_AXIS); CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING); CHECK(PlsrHwTestGetAbPhaseA(0U) == 0U); CHECK(PlsrHwTestGetAbPhaseB(0U) == 0U); CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); CHECK(PlsrHwTestGetPwmEnabled(0U) != 0U); CHECK(PlsrHwTestGetPwmEnabled(1U) != 0U); CHECK((PlsrHwTestGetPsc(0U) + 1UL) == 2UL * (PlsrHwTestGetPsc(1U) + 1UL)); CHECK(PlsrHwTestGetArr(0U) == PlsrHwTestGetArr(1U)); CHECK(PlsrHwTestGetCcr(0U) == PlsrHwTestGetCcr(1U)); CHECK(PlsrHwTestGetCcr(0U) == (PlsrHwTestGetArr(0U) + 1UL) / 2UL); /* 两相从精确 00 边界起步;CC1IF 会在开中断前再次清除。 */ CHECK(PlsrHwTestGetCnt(0U) == ((PlsrHwTestGetArr(0U) + 1UL) * 3UL) / 4UL); CHECK(PlsrHwTestGetCnt(1U) == PlsrHwTestGetCcr(1U)); /* 任一物理 timer update 不能直接计作完整 AB 周期。 */ PlsrHwTestTriggerUpdate(0U); CHECK(PlsrHwGetEmittedPulses(0U) == 0); /* 正向:00→10→11→01→00;四次相位跳变只计一个脉冲。 */ for (quarter = 0; quarter < 4; quarter++) { PlsrHwTestAdvanceAbQuarter(0U); CHECK(PlsrHwTestGetAbPhaseA(0U) == positiveA[quarter]); CHECK(PlsrHwTestGetAbPhaseB(0U) == positiveB[quarter]); } CHECK(PlsrHwGetEmittedPulses(0U) == 1); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); /* 运行中调频先排队,不能让相差 1/4 周期的两路各自加载 ARR。 */ oldArr = PlsrHwTestGetArr(0U); oldBasePsc = PlsrHwTestGetPsc(0U); oldPairPsc = PlsrHwTestGetPsc(1U); CHECK(PlsrHwSetFrequency(0U, 2000UL) == PLSR_RESULT_OK); CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK); for (quarter = 0; quarter < 4; quarter++) { PlsrHwTestAdvanceAbQuarter(0U); } CHECK(PlsrHwGetEmittedPulses(0U) == 2); CHECK(PlsrHwTestGetArr(0U) == oldArr); CHECK(PlsrHwTestGetPsc(0U) == oldBasePsc); CHECK(PlsrHwTestGetPsc(1U) == oldPairPsc); CHECK(PlsrHwSetFrequency(0U, 2000UL) == PLSR_RESULT_OK); CHECK(PlsrHwTestGetAbQuarter(0U) == 0U); CHECK(PlsrHwTestGetArr(0U) == oldArr); CHECK(PlsrHwTestGetArr(1U) == oldArr); CHECK(PlsrHwTestGetPsc(0U) == oldBasePsc); CHECK(PlsrHwTestGetPsc(1U) == oldPairPsc); for (quarter = 0; quarter < 3; quarter++) { PlsrHwTestAdvanceAbQuarter(0U); CHECK(PlsrHwTestGetArr(0U) == oldArr); CHECK(PlsrHwTestGetArr(1U) == oldArr); CHECK(PlsrHwTestGetPsc(0U) == oldBasePsc); CHECK(PlsrHwTestGetPsc(1U) == oldPairPsc); } /* 回到 00 后,两路同时装载新频率并从精确 90° 位置重启。 */ PlsrHwTestAdvanceAbQuarter(0U); CHECK(PlsrHwGetEmittedPulses(0U) == 3); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); CHECK((PlsrHwTestGetArr(0U) != oldArr) || (PlsrHwTestGetPsc(0U) != oldBasePsc)); CHECK((PlsrHwTestGetPsc(0U) + 1UL) == 2UL * (PlsrHwTestGetPsc(1U) + 1UL)); CHECK(PlsrHwTestGetArr(0U) == PlsrHwTestGetArr(1U)); newPeriod = PlsrHwTestGetArr(0U) + 1UL; CHECK(PlsrHwTestGetCnt(0U) == (newPeriod * 3UL) / 4UL); CHECK(PlsrHwTestGetCnt(1U) == newPeriod / 2UL); for (quarter = 0; quarter < 4; quarter++) { PlsrHwTestAdvanceAbQuarter(0U); } CHECK(PlsrHwGetEmittedPulses(0U) == 4); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE); CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U); CHECK(PlsrHwTestGetPwmEnabled(1U) == 0U); CHECK(PlsrHwTestGetAbPhaseA(0U) == 0U); CHECK(PlsrHwTestGetAbPhaseB(0U) == 0U); /* 反向:00→01→11→10→00。 */ params.targetPulses = 1; params.directionPositive = 0U; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK); for (quarter = 0; quarter < 4; quarter++) { PlsrHwTestAdvanceAbQuarter(0U); CHECK(PlsrHwTestGetAbPhaseA(0U) == negativeA[quarter]); CHECK(PlsrHwTestGetAbPhaseB(0U) == negativeB[quarter]); } CHECK(PlsrHwGetEmittedPulses(0U) == 1); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE); /* 紧急停止即使发生在周期中间,也必须回到安全 00。 */ params.targetPulses = 10; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK); PlsrHwTestAdvanceAbQuarter(0U); CHECK(PlsrHwTestGetAbQuarter(0U) == 1U); CHECK(PlsrHwStopPulse(0U) == PLSR_RESULT_OK); CHECK(PlsrHwTestGetAbQuarter(0U) == 0U); CHECK(PlsrHwTestGetAbPhaseA(0U) == 0U); CHECK(PlsrHwTestGetAbPhaseB(0U) == 0U); } static void TestTwoAbAxesIndependent(void) { PLSR_HW_START_PARAMS params; int quarter; (void)PlsrHwInit(); (void)memset(¶ms, 0, sizeof(params)); params.frequencyHz = 1000UL; params.targetPulses = 1; params.outputMode = PLSR_OUTPUT_AB; params.directionPoint = PLSR_HW_DIR_POINT_NONE; params.directionPositive = 1U; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwStartPulse(2U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK); CHECK(PlsrHwSetFrequency(2U, 2000UL) == PLSR_RESULT_OK); CHECK(PlsrHwTestGetPwmEnabled(0U) != 0U); CHECK(PlsrHwTestGetPwmEnabled(1U) != 0U); CHECK(PlsrHwTestGetPwmEnabled(2U) != 0U); CHECK(PlsrHwTestGetPwmEnabled(3U) != 0U); for (quarter = 0; quarter < 4; quarter++) { PlsrHwTestAdvanceAbQuarter(0U); } CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE); CHECK(PlsrHwGetState(2U) == PLSR_HW_STATE_RUNNING); CHECK(PlsrHwGetEmittedPulses(2U) == 0); CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U); CHECK(PlsrHwTestGetPwmEnabled(1U) == 0U); CHECK(PlsrHwTestGetPwmEnabled(2U) != 0U); CHECK(PlsrHwTestGetPwmEnabled(3U) != 0U); for (quarter = 0; quarter < 4; quarter++) { PlsrHwTestAdvanceAbQuarter(2U); } CHECK(PlsrHwGetState(2U) == PLSR_HW_STATE_DONE); CHECK(PlsrHwGetEmittedPulses(2U) == 1); } static void TestAbFrequencyLimits(void) { PLSR_HW_START_PARAMS params; int quarter; (void)PlsrHwInit(); (void)memset(¶ms, 0, sizeof(params)); params.frequencyHz = 1UL; params.targetPulses = 100; params.outputMode = PLSR_OUTPUT_AB; params.directionPoint = PLSR_HW_DIR_POINT_NONE; params.directionPositive = 1U; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwSetFrequency(0U, 1UL) == PLSR_RESULT_OK); CHECK(PlsrHwTestGetArr(0U) == PlsrHwTestGetArr(1U)); CHECK((PlsrHwTestGetPsc(0U) + 1UL) == 2UL * (PlsrHwTestGetPsc(1U) + 1UL)); CHECK(PlsrHwTestGetArr(0U) <= 65535UL); CHECK(PlsrHwSetFrequency(0U, 100000UL) == PLSR_RESULT_OK); for (quarter = 0; quarter < 4; quarter++) { PlsrHwTestAdvanceAbQuarter(0U); } CHECK(PlsrHwTestGetArr(0U) == PlsrHwTestGetArr(1U)); CHECK((PlsrHwTestGetPsc(0U) + 1UL) == 2UL * (PlsrHwTestGetPsc(1U) + 1UL)); CHECK(PlsrHwTestGetArr(0U) >= 3UL); CHECK(PlsrHwStopPulse(0U) == PLSR_RESULT_OK); } static void TestStopAndInvalidArgs(void) { (void)PlsrHwInit(); PLSR_HW_START_PARAMS params; (void)memset(¶ms, 0, sizeof(params)); params.frequencyHz = 1000UL; params.targetPulses = 100; params.directionPoint = PLSR_HW_DIR_POINT_NONE; params.directionPositive = 1U; params.directionDelayMs = 0U; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK); CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK); CHECK(PlsrHwIsPulseActive(0U) == 1U); CHECK(PlsrHwStopPulse(0U) == PLSR_RESULT_OK); CHECK(PlsrHwIsPulseActive(0U) == 0U); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_IDLE); CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U); CHECK(PlsrHwStartPulse(4U, ¶ms) == PLSR_RESULT_INVALID_ARGUMENT); CHECK(PlsrHwStartPulse(0U, NULL) == PLSR_RESULT_INVALID_ARGUMENT); params.targetPulses = 0; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_INVALID_ARGUMENT); params.targetPulses = 1; params.outputMode = PLSR_OUTPUT_CW_CCW; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_NOT_SUPPORTED); params.outputMode = (PLSR_OUTPUT_MODE)99; CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_INVALID_ARGUMENT); CHECK(PlsrHwSetFrequency(4U, 1000UL) == PLSR_RESULT_INVALID_ARGUMENT); CHECK(PlsrHwStopPulse(4U) == PLSR_RESULT_INVALID_ARGUMENT); } /* ---- 端到端集成:START → 硬件 → 计数 → 事件 → 段间 → 完成 ---- */ static void TestEndToEndTwoSegments(void) { TEST_MEMORY memory; PLSR_CALL call; PLSR_STATUS status; uint16_t initialPsc; uint16_t initialArr; int ticks; int pulse; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2); TestSetSegment(&memory, 1U, 1000U, 100); TestSetSegment(&memory, 2U, 2000U, 200); call = TestMakeCall(&memory); CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); PlsrProcess(); status = TestGetStatus(); CHECK(status.state == PLSR_STATE_ACCEL); CHECK(status.currentSegment == 1U); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DIR_SETTLING); /* DIR 延时 10ms → PWM 启动(段1 起始速度 0,profile 升频后启动)。 */ for (ticks = 0; ticks < 9; ticks++) { PlsrProcess(); } CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); CHECK(PlsrHwTestGetPwmEnabled(0U) == 1U); CHECK(PlsrCalculateTimerDivider(168000000UL, 75UL, &initialPsc, &initialArr) == PLSR_RESULT_OK); CHECK(PlsrHwTestGetPsc(0U) == initialPsc); CHECK(PlsrHwTestGetArr(0U) == initialArr); /* 加速完成 → 状态机进入 RUN。 */ for (ticks = 0; ticks < 500; ticks++) { PlsrProcess(); if (TestGetStatus().state == PLSR_STATE_RUN) { break; } } status = TestGetStatus(); CHECK(status.state == PLSR_STATE_RUN); CHECK(status.currentSegment == 1U); /* 段1 脉冲完成:100 次更新中断 → SEGMENT_COMPLETE → 段2 启动。 */ for (pulse = 0; pulse < 100; pulse++) { PlsrHwTestTriggerUpdate(0U); } CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE); PlsrProcess(); status = TestGetStatus(); CHECK(status.state == PLSR_STATE_ACCEL); CHECK(status.currentSegment == 2U); /* 段2:DIR 延时 → PWM → 加速 → RUN。 */ for (ticks = 0; ticks < 600; ticks++) { PlsrProcess(); if (TestGetStatus().state == PLSR_STATE_RUN) { break; } } status = TestGetStatus(); CHECK(status.state == PLSR_STATE_RUN); CHECK(status.currentSegment == 2U); /* 段2 脉冲完成 → 任务结束。 */ for (pulse = 0; pulse < 200; pulse++) { PlsrHwTestTriggerUpdate(0U); } PlsrProcess(); status = TestGetStatus(); CHECK(status.state == PLSR_STATE_COMPLETED); CHECK(status.done != 0U); /* 终态转换后 HAL 回 IDLE(允许重新启动),脉冲已停止。 */ CHECK(PlsrHwIsPulseActive(0U) == 0U); CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U); } static void TestEndToEndAbSegment(void) { TEST_MEMORY memory; PLSR_CALL call; PLSR_STATUS status; int quarter; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 1); TestSetSegment(&memory, 1U, 1000U, -2); call = TestMakeCall(&memory); call.sequence = 15UL; call.outputModeOverride = PLSR_OUTPUT_AB; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); PlsrProcess(); status = TestGetStatus(); CHECK(status.state == PLSR_STATE_ACCEL); CHECK(status.outputMode == PLSR_OUTPUT_AB); CHECK(status.directionPoint == PLSR_DIRECTION_POINT_NONE); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); CHECK(PlsrHwTestGetPwmEnabled(0U) != 0U); CHECK(PlsrHwTestGetPwmEnabled(1U) != 0U); /* 负脉冲选择反向相序,完整两个周期后由同一事件链结束任务。 */ PlsrHwTestAdvanceAbQuarter(0U); CHECK(PlsrHwTestGetAbPhaseA(0U) == 0U); CHECK(PlsrHwTestGetAbPhaseB(0U) == 1U); for (quarter = 1; quarter < 8; quarter++) { PlsrHwTestAdvanceAbQuarter(0U); } CHECK(PlsrHwGetEmittedPulses(0U) == 2); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE); PlsrProcess(); status = TestGetStatus(); CHECK(status.state == PLSR_STATE_COMPLETED); CHECK(status.done != 0U); CHECK(status.highResourceMask == 0U); CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U); CHECK(PlsrHwTestGetPwmEnabled(1U) == 0U); } static void TestProductionSelfTestStartsAb(void) { PLSR_STATUS status; TestResetEnvironment(); CHECK(PlsrSelfTestQueue() == PLSR_RESULT_QUEUED); PlsrProcess(); status = TestGetStatus(); CHECK(status.lastCommandResult == PLSR_RESULT_OK); CHECK(status.outputMode == PLSR_OUTPUT_AB); CHECK(status.currentSegment == 1U); CHECK(status.state == PLSR_STATE_ACCEL); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING); CHECK(PlsrHwTestGetPwmEnabled(0U) != 0U); CHECK(PlsrHwTestGetPwmEnabled(1U) != 0U); CHECK(PlsrHwStopPulse(0U) == PLSR_RESULT_OK); } static void TestStopStopsHardware(void) { TEST_MEMORY memory; PLSR_CALL call; PLSR_COMMAND command; PLSR_STATUS status; int ticks; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 1); TestSetSegment(&memory, 1U, 1000U, 10000); call = TestMakeCall(&memory); call.sequence = 20UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); PlsrProcess(); for (ticks = 0; ticks < 10; ticks++) { PlsrProcess(); } CHECK(PlsrHwIsPulseActive(0U) == 1U); /* STOP_IMMEDIATE:硬件立即停止。 */ command.sequence = 21UL; command.axis = 0U; command.opcode = PLSR_CMD_STOP_IMMEDIATE; command.argument = 0; CHECK(PlsrPostCommand(&command) == PLSR_RESULT_QUEUED); PlsrProcess(); CHECK(PlsrHwIsPulseActive(0U) == 0U); CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_IDLE); CHECK(PlsrPostEvent(0U, PLSR_EVENT_STOP_IMMEDIATE_DONE) == PLSR_RESULT_OK); PlsrProcess(); status = TestGetStatus(); CHECK(status.state == PLSR_STATE_STOPPED); } int main(void) { TestMapping(); TestDirDelaySequence(); TestZeroFrequencyWaits(); TestPulseCounting(); TestAbPhaseAndCounting(); TestTwoAbAxesIndependent(); TestAbFrequencyLimits(); TestStopAndInvalidArgs(); TestEndToEndTwoSegments(); TestEndToEndAbSegment(); TestProductionSelfTestStartsAb(); TestStopStopsHardware(); if (TestFailures != 0) { (void)printf("FAIL: %d of %d PLSR HAL checks failed\n", TestFailures, TestChecks); return 1; } (void)printf("PASS: %d PLSR HAL checks\n", TestChecks); return 0; }