Explorar el Código

本批完成内容:

HAL 启动参数增加 outputMode,core 会明确传递 PULSE/DIR、AB 或 CW/CCW 模式。
实现 AB 正向相序:00→10→11→01→00。
实现 AB 反向相序:00→01→11→10→00。
四次相位跳变、一个完整周期只累计一个指令脉冲。
AB 仅允许 D=Y0 或 Y2,对应 Q0/Q1、Q2/Q3。
AB 模式忽略 DIR 点和 SFD907 方向延时。
调频同时更新 A、B 两路,且不重置当前相位。
正常完成只在完整 00 周期边界停止。
紧急停止会将主机模型恢复至安全 00。
支持两组 AB 轴独立运行,停止一轴不会影响另一轴。
CW/CCW 目前明确返回 PLSR_RESULT_NOT_SUPPORTED。
目标板 AB 硬件尚未实现时也明确拒绝启动,防止误输出为单路 PWM。
同时修复两个旧边界问题:
零脉冲跳转链耗尽本轮预算时,不再误启动一个 0 脉冲硬件段。
极短段可能在 ACCEL 或 DECEL 阶段结束;现在 ACCEL/RUN/DECEL 均可正确处理段完成事件。
deepseek
ywh hace 1 mes
padre
commit
f1babb383a
Se han modificado 4 ficheros con 457 adiciones y 30 borrados
  1. +5
    -0
      PLSR/Inc/plsr_hal_f407.h
  2. +55
    -15
      PLSR/Src/plsr_core.c
  3. +204
    -15
      PLSR/Src/plsr_hal_f407.c
  4. +193
    -0
      PLSR/Test/test_plsr_hal.c

+ 5
- 0
PLSR/Inc/plsr_hal_f407.h Ver fichero

@@ -24,6 +24,7 @@ typedef struct
{
uint32_t frequencyHz; /* 初始频率(起始速度,可为 0) */
int64_t targetPulses; /* 本段目标脉冲数 */
PLSR_OUTPUT_MODE outputMode; /* PULSE/DIR、AB 或 CW/CCW */
uint8_t directionPoint; /* DIR 输出点(Y 点号,0xFF=无) */
uint8_t directionPositive;
uint16_t directionDelayMs;
@@ -57,7 +58,11 @@ uint32_t PlsrHwTestGetCr1(uint8_t axis);
uint32_t PlsrHwTestGetPsc(uint8_t axis);
uint8_t PlsrHwTestGetPwmEnabled(uint8_t axis);
uint8_t PlsrHwTestGetDirLevel(uint8_t axis);
uint8_t PlsrHwTestGetAbPhaseA(uint8_t axis);
uint8_t PlsrHwTestGetAbPhaseB(uint8_t axis);
uint8_t PlsrHwTestGetAbQuarter(uint8_t axis);
void PlsrHwTestTriggerUpdate(uint8_t axis);
void PlsrHwTestAdvanceAbQuarter(uint8_t axis);
#endif

#ifdef __cplusplus


+ 55
- 15
PLSR/Src/plsr_core.c Ver fichero

@@ -59,7 +59,8 @@ static uint8_t PlsrInitialized;
static PLSR_JOB_SNAPSHOT PlsrJobScratch;

static void PlsrStopSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject);
static void PlsrStartSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject);
static PLSR_RESULT PlsrStartSegmentHardware(uint8_t axis,
PLSR_AXIS *axisObject);

static uint32_t PlsrCoreEnterCritical(void)
{
@@ -636,7 +637,22 @@ static PLSR_RESULT PlsrStartCall(PLSR_AXIS *axisObject,
else
{
/* 启动当前段硬件输出与速度曲线。 */
PlsrStartSegmentHardware(call->dAxis, axisObject);
/* 零脉冲跳转链耗尽本轮预算时没有实际运动段,等待下一次
* PlsrPathTick 找到非零段后再启动硬件。 */
if (axisObject->path.jumpChainPending == 0U)
{
result = PlsrStartSegmentHardware(call->dAxis, axisObject);
}
if (result != PLSR_RESULT_OK)
{
axisObject->error = PLSR_ERROR_TIMER_FAULT;
PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
axisObject->done = 0U;
(void)PlsrStateTransition(call->dAxis,
PLSR_STATE_ERROR,
PLSR_TRANSITION_FAULT);
return result;
}
/* 运动开始:掉电恢复时据此判定"断电时在运动中"。 */
(void)PlcDeviceSetHsdCheckpointMeta(axisObject->positionValid, 1U);
(void)PlcDeviceCheckpointHsd();
@@ -1008,13 +1024,15 @@ static void PlsrProcessCriticalEvents(uint8_t axis, uint32_t events)

/* 启动当前段的硬件输出与速度曲线(P3a:单轴 PULSE/DIR)。
* 由段进入 ACCEL 时调用(任务启动 + 段间推进)。 */
static void PlsrStartSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject)
static PLSR_RESULT PlsrStartSegmentHardware(uint8_t axis,
PLSR_AXIS *axisObject)
{
const PLSR_JOB_SNAPSHOT *job = &axisObject->job;
const PLSR_SEGMENT_SNAPSHOT *segment =
&job->segments[axisObject->path.currentSegment - 1U];
PLSR_PROFILE_REQUEST profileRequest;
PLSR_HW_START_PARAMS params;
PLSR_RESULT result;
int64_t pulses;
uint8_t positive;

@@ -1050,24 +1068,32 @@ static void PlsrStartSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject)
: 0UL;
profileRequest.curveMode = job->s2.curveMode;

if (PlsrProfileStart(&axisObject->profile,
&profileRequest,
pulses,
1000U) == PLSR_RESULT_OK)
result = PlsrProfileStart(&axisObject->profile,
&profileRequest,
pulses,
1000U);
if (result != PLSR_RESULT_OK)
{
axisObject->profileActive = 1U;
axisObject->profileWasAccel =
(axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL)
? 1U
: 0U;
return result;
}

params.frequencyHz = job->s2.startSpeed;
params.targetPulses = pulses;
params.outputMode = (PLSR_OUTPUT_MODE)job->outputMode;
params.directionPoint = job->directionPoint;
params.directionPositive = positive;
params.directionDelayMs = job->s2.directionDelayMs;
(void)PlsrHwStartPulse(axis, &params);
result = PlsrHwStartPulse(axis, &params);
if (result != PLSR_RESULT_OK)
{
axisObject->profileActive = 0U;
axisObject->profileWasAccel = 0U;
return result;
}
axisObject->profileActive = 1U;
axisObject->profileWasAccel =
(axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL) ? 1U : 0U;
return PLSR_RESULT_OK;
}

/* 停止当前段的硬件输出与速度曲线。 */
@@ -1086,6 +1112,9 @@ static void PlsrApplyPathAction(uint8_t axis, PLSR_PATH_ACTION action)
switch (action)
{
case PLSR_PATH_ACTION_NEXT_SEGMENT:
/* SEGMENT_COMPLETE 表示上一段输出边界已经结束。统一收口旧段
* profile/HAL 后再启动新段;真实 IRQ 与测试注入事件均一致。 */
PlsrStopSegmentHardware(axis, axisObject);
if (axisObject->state == PLSR_STATE_WAIT)
{
(void)PlsrStateTransition(axis,
@@ -1103,7 +1132,16 @@ static void PlsrApplyPathAction(uint8_t axis, PLSR_PATH_ACTION action)
/* 进入新段:重新启动硬件输出与速度曲线。 */
if (axisObject->state == PLSR_STATE_ACCEL)
{
PlsrStartSegmentHardware(axis, axisObject);
if (PlsrStartSegmentHardware(axis, axisObject)
!= PLSR_RESULT_OK)
{
axisObject->error = PLSR_ERROR_TIMER_FAULT;
PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
axisObject->done = 0U;
(void)PlsrStateTransition(axis,
PLSR_STATE_ERROR,
PLSR_TRANSITION_FAULT);
}
}
break;

@@ -1208,7 +1246,9 @@ static void PlsrProcessNormalEvents(uint8_t axis, uint32_t events)
}

if (((events & PLSR_EVENT_SEGMENT_COMPLETE) != 0UL)
&& (axisObject->state == PLSR_STATE_RUN)
&& ((axisObject->state == PLSR_STATE_ACCEL)
|| (axisObject->state == PLSR_STATE_RUN)
|| (axisObject->state == PLSR_STATE_DECEL))
&& (axisObject->pendingTerminal == PLSR_STATE_UNINITIALIZED)
&& (axisObject->immediateStopPending == 0U))
{


+ 204
- 15
PLSR/Src/plsr_hal_f407.c Ver fichero

@@ -13,6 +13,7 @@
#define PLSR_HW_TIMER_UPDATE_BIT (0x0001U)
#define PLSR_HW_OUTPUT_POINT_COUNT (21U)
#define PLSR_HW_DBG_SNAPSHOT_COUNT (160U)
#define PLSR_HW_AB_QUARTER_COUNT (4U)

typedef struct
{
@@ -101,12 +102,14 @@ static PLSR_HW_TIMER_REGS PlsrHwTimers[PLSR_HW_AXIS_COUNT];
typedef struct
{
PLSR_HW_STATE state;
PLSR_OUTPUT_MODE outputMode;
uint32_t currentFrequencyHz;
int64_t targetPulses;
int64_t emittedPulses;
uint16_t directionDelayRemainingMs;
uint8_t directionPoint;
uint8_t directionPositive;
uint8_t abQuarter;
} PLSR_HW_AXIS_STATE;

static PLSR_HW_AXIS_STATE PlsrHwAxes[PLSR_HW_AXIS_COUNT];
@@ -375,6 +378,63 @@ static void PlsrHwStopPwmTimer(uint8_t axis)
PlsrHwTimerSetCen(axis, 0UL);
}

static uint8_t PlsrHwIsAbBaseAxis(uint8_t axis)
{
return ((axis == 0U) || (axis == 2U)) ? 1U : 0U;
}

#ifdef PLSR_HOST_TEST
static uint8_t PlsrHwGetPairedAxis(uint8_t axis)
{
return (uint8_t)(axis + 1U);
}
#endif

/* P3b-1:AB 正交相序先在 host 模型中闭环。真实 STM32 双定时器的
* 同步启动、相位偏置和安全停止将在 P3b-2 接入。 */
static void PlsrHwConfigureActiveOutput(uint8_t axis,
PLSR_OUTPUT_MODE outputMode,
uint32_t frequencyHz)
{
PlsrHwConfigurePwm(axis, frequencyHz);
#ifdef PLSR_HOST_TEST
if (outputMode == PLSR_OUTPUT_AB)
{
PlsrHwConfigurePwm(PlsrHwGetPairedAxis(axis), frequencyHz);
}
#else
(void)outputMode;
#endif
}

static void PlsrHwBeginActiveOutput(uint8_t axis,
PLSR_OUTPUT_MODE outputMode)
{
PlsrHwPwmBegin(axis);
#ifdef PLSR_HOST_TEST
if (outputMode == PLSR_OUTPUT_AB)
{
PlsrHwPwmBegin(PlsrHwGetPairedAxis(axis));
}
#else
(void)outputMode;
#endif
}

static void PlsrHwStopActiveOutput(uint8_t axis,
PLSR_OUTPUT_MODE outputMode)
{
PlsrHwStopPwmTimer(axis);
#ifdef PLSR_HOST_TEST
if ((outputMode == PLSR_OUTPUT_AB) && (PlsrHwIsAbBaseAxis(axis) != 0U))
{
PlsrHwStopPwmTimer(PlsrHwGetPairedAxis(axis));
}
#else
(void)outputMode;
#endif
}

uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber)
{
/* 与资源层一致的合法输出点掩码(Q0~Q7、Q10~Q17、Q20)。 */
@@ -465,7 +525,7 @@ PLSR_RESULT PlsrHwInit(void)
PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params)
{
PLSR_HW_AXIS_STATE *state;
uint8_t directionChanged;
uint8_t directionChanged = 0U;

if ((axis >= PLSR_HW_AXIS_COUNT) || (params == NULL))
{
@@ -475,6 +535,27 @@ PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params)
{
return PLSR_RESULT_INVALID_ARGUMENT;
}
if ((uint32_t)params->outputMode > (uint32_t)PLSR_OUTPUT_CW_CCW)
{
return PLSR_RESULT_INVALID_ARGUMENT;
}
if ((params->outputMode == PLSR_OUTPUT_AB)
&& (PlsrHwIsAbBaseAxis(axis) == 0U))
{
return PLSR_RESULT_INVALID_AXIS;
}
if (params->outputMode == PLSR_OUTPUT_CW_CCW)
{
return PLSR_RESULT_NOT_SUPPORTED;
}
#ifndef PLSR_HOST_TEST
if (params->outputMode == PLSR_OUTPUT_AB)
{
/* P3b-1 只交付可验证的 host 相序模型;禁止目标板误输出成
* 单路 PULSE/DIR。P3b-2 接入双定时器后移除此保护。 */
return PLSR_RESULT_NOT_SUPPORTED;
}
#endif
state = &PlsrHwAxes[axis];
if (state->state == PLSR_HW_STATE_RUNNING)
{
@@ -483,17 +564,37 @@ PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params)

/* 方向延时只在方向发生变化时生效(首次启动/换向/换方向点):
* 段间同向衔接不再等待 10ms,直接进入 PWM 待启动。 */
directionChanged = (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
|| (state->directionPoint != params->directionPoint)
|| (state->directionPositive != params->directionPositive);
if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
{
directionChanged =
(state->directionPoint == PLSR_HW_DIR_POINT_NONE)
|| (state->directionPoint != params->directionPoint)
|| (state->directionPositive != params->directionPositive);
}

state->outputMode = params->outputMode;
state->targetPulses = params->targetPulses;
state->emittedPulses = 0;
state->currentFrequencyHz = params->frequencyHz;
state->directionPoint = params->directionPoint;
state->directionPoint =
(params->outputMode == PLSR_OUTPUT_PULSE_DIR)
? params->directionPoint
: PLSR_HW_DIR_POINT_NONE;
state->directionDelayRemainingMs =
(directionChanged != 0U) ? params->directionDelayMs : 0U;
PlsrHwSetDirLevel(axis, params->directionPositive);
((params->outputMode == PLSR_OUTPUT_PULSE_DIR)
&& (directionChanged != 0U))
? params->directionDelayMs
: 0U;
state->abQuarter = 0U;
if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
{
PlsrHwSetDirLevel(axis, params->directionPositive);
}
else
{
state->directionPositive =
(params->directionPositive != 0U) ? 1U : 0U;
}
state->state = (state->directionDelayRemainingMs > 0U)
? PLSR_HW_STATE_DIR_SETTLING
: PLSR_HW_STATE_PWM_PENDING;
@@ -515,18 +616,18 @@ PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz)
if (frequencyHz > 0UL)
{
/* 运行中调频:预装载写入,更新事件时生效,不触碰使能位。 */
PlsrHwConfigurePwm(axis, frequencyHz);
PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz);
}
else
{
PlsrHwStopPwmTimer(axis);
PlsrHwStopActiveOutput(axis, state->outputMode);
}
}
else if ((state->state == PLSR_HW_STATE_PWM_PENDING)
&& (frequencyHz > 0UL))
{
PlsrHwConfigurePwm(axis, frequencyHz);
PlsrHwPwmBegin(axis);
PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz);
PlsrHwBeginActiveOutput(axis, state->outputMode);
state->state = PLSR_HW_STATE_RUNNING;
}
return PLSR_RESULT_OK;
@@ -543,7 +644,8 @@ PLSR_RESULT PlsrHwStopPulse(uint8_t axis)
state = &PlsrHwAxes[axis];
if (state->state != PLSR_HW_STATE_IDLE)
{
PlsrHwStopPwmTimer(axis);
PlsrHwStopActiveOutput(axis, state->outputMode);
state->abQuarter = 0U;
state->state = PLSR_HW_STATE_IDLE;
}
return PLSR_RESULT_OK;
@@ -631,8 +733,10 @@ void PlsrHwTick(uint8_t axis)
case PLSR_HW_STATE_PWM_PENDING:
if (state->currentFrequencyHz > 0UL)
{
PlsrHwConfigurePwm(axis, state->currentFrequencyHz);
PlsrHwPwmBegin(axis);
PlsrHwConfigureActiveOutput(axis,
state->outputMode,
state->currentFrequencyHz);
PlsrHwBeginActiveOutput(axis, state->outputMode);
state->state = PLSR_HW_STATE_RUNNING;
}
break;
@@ -661,12 +765,18 @@ void PlsrHwOnTimerUpdate(uint8_t axis)
{
return;
}
if (state->outputMode != PLSR_OUTPUT_PULSE_DIR)
{
/* AB host 模型按四分之一周期推进,不能把任一物理定时器的
* update 直接当成完整 AB 指令脉冲。 */
return;
}

state->emittedPulses++;
if (state->emittedPulses >= state->targetPulses)
{
/* 更新时刻 = 周期结束:关通道即完整下降沿后停止,无额外脉冲。 */
PlsrHwStopPwmTimer(axis);
PlsrHwStopActiveOutput(axis, state->outputMode);
state->state = PLSR_HW_STATE_DONE;
(void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
}
@@ -710,6 +820,85 @@ uint8_t PlsrHwTestGetDirLevel(uint8_t axis)
return PlsrHwTimers[axis].dirLevel;
}

uint8_t PlsrHwTestGetAbPhaseA(uint8_t axis)
{
const PLSR_HW_AXIS_STATE *state;

if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
{
return 0U;
}
state = &PlsrHwAxes[axis];
if (state->directionPositive != 0U)
{
return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
? 1U
: 0U;
}
return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
? 1U
: 0U;
}

uint8_t PlsrHwTestGetAbPhaseB(uint8_t axis)
{
const PLSR_HW_AXIS_STATE *state;

if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
{
return 0U;
}
state = &PlsrHwAxes[axis];
if (state->directionPositive != 0U)
{
return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
? 1U
: 0U;
}
return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
? 1U
: 0U;
}

uint8_t PlsrHwTestGetAbQuarter(uint8_t axis)
{
if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
{
return 0U;
}
return PlsrHwAxes[axis].abQuarter;
}

void PlsrHwTestAdvanceAbQuarter(uint8_t axis)
{
PLSR_HW_AXIS_STATE *state;

if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
{
return;
}
state = &PlsrHwAxes[axis];
if ((state->state != PLSR_HW_STATE_RUNNING)
|| (state->outputMode != PLSR_OUTPUT_AB))
{
return;
}

state->abQuarter = (uint8_t)((state->abQuarter + 1U)
% PLSR_HW_AB_QUARTER_COUNT);
if (state->abQuarter == 0U)
{
state->emittedPulses++;
if (state->emittedPulses >= state->targetPulses)
{
/* 仅在完整 00 边界停机,禁止留下半个正交周期。 */
PlsrHwStopActiveOutput(axis, state->outputMode);
state->state = PLSR_HW_STATE_DONE;
(void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
}
}
}

void PlsrHwTestTriggerUpdate(uint8_t axis)
{
if (axis < PLSR_HW_AXIS_COUNT)


+ 193
- 0
PLSR/Test/test_plsr_hal.c Ver fichero

@@ -274,6 +274,147 @@ static void TestPulseCounting(void)
CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE);
}

static void TestAbPhaseAndCounting(void)
{
PLSR_HW_START_PARAMS params;
uint16_t psc;
uint16_t arr;
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};
int quarter;

(void)PlsrHwInit();
(void)memset(&params, 0, sizeof(params));
params.frequencyHz = 1000UL;
params.targetPulses = 2;
params.outputMode = PLSR_OUTPUT_AB;
params.directionPoint = 4U; /* AB 模式必须忽略独立 DIR 点。 */
params.directionPositive = 1U;
params.directionDelayMs = 10U; /* AB 模式不得执行方向延时。 */

CHECK(PlsrHwStartPulse(1U, &params) == PLSR_RESULT_INVALID_AXIS);
CHECK(PlsrHwStartPulse(0U, &params) == 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(PlsrCalculateTimerDivider(168000000UL, 1000UL, &psc, &arr)
== PLSR_RESULT_OK);
CHECK(PlsrHwTestGetPsc(0U) == psc);
CHECK(PlsrHwTestGetArr(0U) == arr);
CHECK(PlsrCalculateTimerDivider(84000000UL, 1000UL, &psc, &arr)
== PLSR_RESULT_OK);
CHECK(PlsrHwTestGetPsc(1U) == psc);
CHECK(PlsrHwTestGetArr(1U) == arr);

/* 任一物理 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);

/* 调频同时更新 A/B 两路,且不得重置正交相位。 */
CHECK(PlsrHwSetFrequency(0U, 2000UL) == PLSR_RESULT_OK);
CHECK(PlsrHwTestGetAbQuarter(0U) == 0U);
CHECK(PlsrCalculateTimerDivider(168000000UL, 2000UL, &psc, &arr)
== PLSR_RESULT_OK);
CHECK(PlsrHwTestGetArr(0U) == arr);
CHECK(PlsrCalculateTimerDivider(84000000UL, 2000UL, &psc, &arr)
== PLSR_RESULT_OK);
CHECK(PlsrHwTestGetArr(1U) == arr);

for (quarter = 0; quarter < 4; quarter++)
{
PlsrHwTestAdvanceAbQuarter(0U);
}
CHECK(PlsrHwGetEmittedPulses(0U) == 2);
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, &params) == 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, &params) == 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(&params, 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, &params) == PLSR_RESULT_OK);
CHECK(PlsrHwStartPulse(2U, &params) == 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 TestStopAndInvalidArgs(void)
{
(void)PlsrHwInit();
@@ -298,6 +439,11 @@ static void TestStopAndInvalidArgs(void)
CHECK(PlsrHwStartPulse(0U, NULL) == PLSR_RESULT_INVALID_ARGUMENT);
params.targetPulses = 0;
CHECK(PlsrHwStartPulse(0U, &params) == PLSR_RESULT_INVALID_ARGUMENT);
params.targetPulses = 1;
params.outputMode = PLSR_OUTPUT_CW_CCW;
CHECK(PlsrHwStartPulse(0U, &params) == PLSR_RESULT_NOT_SUPPORTED);
params.outputMode = (PLSR_OUTPUT_MODE)99;
CHECK(PlsrHwStartPulse(0U, &params) == PLSR_RESULT_INVALID_ARGUMENT);
CHECK(PlsrHwSetFrequency(4U, 1000UL) == PLSR_RESULT_INVALID_ARGUMENT);
CHECK(PlsrHwStopPulse(4U) == PLSR_RESULT_INVALID_ARGUMENT);
}
@@ -392,6 +538,50 @@ static void TestEndToEndTwoSegments(void)
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 TestStopStopsHardware(void)
{
TEST_MEMORY memory;
@@ -438,8 +628,11 @@ int main(void)
TestDirDelaySequence();
TestZeroFrequencyWaits();
TestPulseCounting();
TestAbPhaseAndCounting();
TestTwoAbAxesIndependent();
TestStopAndInvalidArgs();
TestEndToEndTwoSegments();
TestEndToEndAbSegment();
TestStopStopsHardware();

if (TestFailures != 0)


Cargando…
Cancelar
Guardar