Parcourir la source

加入EXT信号

codex/plsr-2026-minimal
ywh il y a 1 mois
Parent
révision
a81228b629
2 fichiers modifiés avec 165 ajouts et 60 suppressions
  1. +45
    -21
      PLSR/Src/plsr.c
  2. +120
    -39
      PLSR/Src/plsr_platform_f407.c

+ 45
- 21
PLSR/Src/plsr.c Voir le fichier

@@ -152,6 +152,7 @@ typedef struct
{
PLSR_PROFILE_ENTRY firstRun;
uint64_t magnitude;
int64_t resolvedDisplacement;
uint32_t sourceEpoch;
uint32_t queueGeneration;
uint16_t generatedItems;
@@ -396,6 +397,7 @@ static uint32_t PlsrEffectiveStopFrequency(uint32_t segmentFrequencyHz);
static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz);
static void PlsrHandleBoundary(uint8_t extEdge);
static void PlsrTransitionToNext(uint8_t allowCarry);
static void PlsrRequestCut(uint32_t expectedEpoch);
static void PlsrFinishCompleted(void);
static void PlsrFinishStopped(void);
static void PlsrEnterError(PLSR_ERROR error);
@@ -437,7 +439,8 @@ static void PlsrProfileQueueResetBankLocked(uint8_t bank);
static void PlsrInvalidateTimedStartLocked(void);
static void PlsrServiceTimedStartPreparation(void);
static PLSR_PLATFORM_SERVICE_RESULT PlsrTryStartPreparedTimedSegment(
uint8_t segmentNumber);
uint8_t segmentNumber,
int64_t resolvedDisplacement);
static uint8_t PlsrStartPreparedTimedOutput(void);
static void PlsrProfileQueueInvalidateGeneration(void);
static uint8_t PlsrProfileQueueBegin(
@@ -2363,6 +2366,7 @@ static void PlsrInvalidateTimedStartLocked(void)
PlsrTimedStart.valid = 0U;
PlsrTimedStart.pendingActivation = 0U;
PlsrTimedStart.nextActTimedCut = 0U;
PlsrTimedStart.resolvedDisplacement = 0;
}

static void PlsrProfileQueueResetBankLocked(uint8_t bank)
@@ -2678,6 +2682,7 @@ static void PlsrServiceTimedStartPreparation(void)

PlsrTimedStart.firstRun = entry;
PlsrTimedStart.magnitude = magnitude;
PlsrTimedStart.resolvedDisplacement = displacement;
PlsrTimedStart.sourceEpoch = sourceEpoch;
PlsrTimedStart.queueGeneration = queue->generation;
PlsrTimedStart.generatedItems = 0U;
@@ -2910,6 +2915,9 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrPrepareDelayedCurrentOutput(
}
PlsrTimedStart.firstRun = firstRun;
PlsrTimedStart.magnitude = profile.pulseCount;
PlsrTimedStart.resolvedDisplacement = (countPositive != 0U)
? (int64_t)remainingPulses
: -(int64_t)remainingPulses;
PlsrTimedStart.sourceEpoch = PlsrSegmentEpoch - 1UL;
PlsrTimedStart.queueGeneration = queueGeneration;
PlsrTimedStart.generatedItems = generatedItems;
@@ -3407,7 +3415,8 @@ static uint8_t PlsrStartPreparedTimedOutput(void)
}

static PLSR_PLATFORM_SERVICE_RESULT PlsrTryStartPreparedTimedSegment(
uint8_t segmentNumber)
uint8_t segmentNumber,
int64_t resolvedDisplacement)
{
PLSR_PROFILE_QUEUE *queue;
uint32_t criticalState;
@@ -3422,13 +3431,23 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrTryStartPreparedTimedSegment(
|| (PlsrTimedStart.pendingActivation != 0U)
|| (PlsrTimedStart.sourceEpoch != PlsrSegmentEpoch)
|| (PlsrTimedStart.sourceSegment != PlsrCurrentSegment)
|| (PlsrTimedStart.nextSegment != segmentNumber)
|| (PlsrTimedStart.queueBank == PlsrProfileQueueBank)
|| (queue->generation != PlsrTimedStart.queueGeneration))
{
PlsrPlatformExitCritical(criticalState);
return PLSR_PLATFORM_SERVICE_DEFERRED;
}
if ((PlsrTimedStart.nextSegment != segmentNumber)
|| (PlsrTimedStart.resolvedDisplacement != resolvedDisplacement))
{
/* An unpredictable boundary (notably an early EXT cut) can change the
next segment's resolved relative move. Never publish a profile
built for the old endpoint. */
PlsrProfileQueueResetBankLocked(PlsrTimedStart.queueBank);
PlsrInvalidateTimedStartLocked();
PlsrPlatformExitCritical(criticalState);
return PLSR_PLATFORM_SERVICE_DEFERRED;
}
magnitude = PlsrTimedStart.magnitude;
positive = PlsrTimedStart.positive;
directionLevel = PlsrTimedStart.directionLevel;
@@ -4016,7 +4035,8 @@ static void PlsrTransitionToNext(uint8_t allowCarry)
if ((allowCarry == 0U)
|| (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR))
{
preparedResult = PlsrTryStartPreparedTimedSegment(nextSegment);
preparedResult = PlsrTryStartPreparedTimedSegment(
nextSegment, displacement);
if (preparedResult == PLSR_PLATFORM_SERVICE_READY)
{
return;
@@ -4429,6 +4449,7 @@ uint8_t PlsrExecTakeCountedRunIrq(
uint32_t availablePulses;
uint32_t holdPulses;
uint32_t holdFrequencyHz;
uint32_t producerRemaining;

if (queue->generatorComplete != 0U)
{
@@ -4440,19 +4461,23 @@ uint8_t PlsrExecTakeCountedRunIrq(
pulses and hold the last applied timer setting. The task repays
this debt by advancing (without enqueueing) the same number of
planner pulses, so segment pulse count remains exact. */
availablePulses =
producerRemaining =
(queue->producerProfile.pulseCount
> queue->producerProfile.nextPeriod)
? queue->producerProfile.pulseCount
- queue->producerProfile.nextPeriod
: 0UL;
if (availablePulses > queue->underrunDebtPulses)
if (producerRemaining > queue->underrunDebtPulses)
{
availablePulses -= queue->underrunDebtPulses;
availablePulses =
producerRemaining - queue->underrunDebtPulses;
}
else
{
availablePulses = 0UL;
/* Every remaining planner pulse is already represented by a
borrowed run. The current committed run is the terminal tail;
stopping after it is completion, not a stream underrun. */
return PLSR_EXEC_RUN_DONE;
}
holdFrequencyHz = queue->lastSetting.actualFrequencyHz;
holdPulses = (uint32_t)(
@@ -4964,10 +4989,9 @@ static PLSR_PLATFORM_QUEUE_RESULT PlsrTryContinuousHandoff(void)
return PLSR_PLATFORM_QUEUE_APPLIED;
}

/* EXTI only records an input edge. Motion state transitions and timer
operations remain in the task context. WAIT uses an armed mask; EXT binds
the edge to the active segment epoch so a stale edge cannot cut a later
segment. */
/* EXTI records an input edge. WAIT remains latch-only; active EXT also arms
the bounded finite-cut path so pulse output stops at the next complete
falling edge. Planning and segment transitions remain in task context. */
void PlsrWaitInputExtiIrq(uint8_t inputSelection)
{
uint8_t bit;
@@ -5002,6 +5026,10 @@ void PlsrWaitInputExtiIrq(uint8_t inputSelection)
PlsrExtEdgePendingSegment = captureSegment;
PlsrExtEdgePendingEpoch = captureEpoch;
PlsrExtEdgePending = 1U;
if (PlsrPulseActive != 0U)
{
PlsrRequestCut(captureEpoch);
}
}
}

@@ -5743,16 +5771,8 @@ static uint8_t PlsrServiceCountedExecutor(void)
}
if (PlsrSyncCountedProgress() == 0U)
{
#if PLSR_COUNT_ERROR_CHECK_ENABLED
PlsrEnterError(PLSR_ERROR_COUNT);
return 1U;
#else
/* 计数错误检查暂时关闭:observed 回退(平台计数器基准重置造成的
视图回退)时重新校准发布点,继续运行,不进错误。 */
PlsrCountedObservedPublished = PlsrPlatformObservedPulses(
(uint8_t)PlsrActiveConfig.pulseOutput);
return 0U;
#endif
}
activeFrequencyHz = PlsrPlatformActiveFrequency(
(uint8_t)PlsrActiveConfig.pulseOutput);
@@ -5781,7 +5801,11 @@ static uint8_t PlsrServiceCountedExecutor(void)
return 0U;
}
(void)completedPulses;
(void)PlsrSyncCountedProgress();
if (PlsrSyncCountedProgress() == 0U)
{
PlsrEnterError(PLSR_ERROR_COUNT);
return 1U;
}
completedFrequencyHz = PlsrCurrentFrequencyHz;
completedNormally = ((PlsrRemainingPulses == 0ULL)
&& (PlsrCutRequested == 0U)


+ 120
- 39
PLSR/Src/plsr_platform_f407.c Voir le fichier

@@ -1580,8 +1580,8 @@ static void PlsrFiniteArmNextStepPrepare(uint8_t pulseOutput,
TIM_TypeDef *counter,
uint32_t blockPulses);
static void PlsrFiniteRetargetAtFallingEdge(uint8_t pulseOutput);
static void PlsrFiniteCutAtFallingEdge(uint8_t pulseOutput);
static void PlsrFiniteStopAtFallingEdge(uint8_t pulseOutput);
static void PlsrFiniteCutAtIdleBoundary(uint8_t pulseOutput);
static void PlsrFiniteStopAtIdleBoundary(uint8_t pulseOutput);

static uint8_t PlsrFinalArmJobOutput(uint8_t pulseOutput)
{
@@ -2370,11 +2370,86 @@ static uint64_t PlsrCounterCurrentRaw(uint8_t pulseOutput)
}
}

/* Return completed pulses in the active PUL/DIR run. The one-pulse block
preload is an implementation detail, and a pending counter update means
the current block has completed even if its IRQ has not run yet. */
static uint32_t PlsrFiniteCompletedPulsesSnapshot(uint8_t pulseOutput)
{
uint8_t index = PlsrCounterIndexByOutput[pulseOutput];
TIM_TypeDef *counter;
uint32_t target;
uint32_t remainingBefore;
uint32_t remainingAfter;
uint32_t statusBefore;
uint32_t statusAfter;
uint32_t count;
uint32_t blockCount;
uint32_t completed;

if (index >= PLSR_COUNTER_COUNT)
{
return 0UL;
}
counter = PlsrCounters[index];
for (;;)
{
remainingBefore = PlsrFiniteRemainingPulses[pulseOutput];
statusBefore = counter->SR & TIM_SR_UIF;
count = (uint16_t)counter->CNT;
statusAfter = counter->SR & TIM_SR_UIF;
remainingAfter = PlsrFiniteRemainingPulses[pulseOutput];
if ((remainingBefore == remainingAfter)
&& (statusBefore == statusAfter))
{
break;
}
}

target = PlsrFiniteTargetPulses[pulseOutput];
if (remainingAfter > target)
{
return 0UL;
}
completed = target - remainingAfter;
if (statusAfter != 0UL)
{
blockCount = (remainingAfter > PLSR_COUNTER_BLOCK_PULSES)
? PLSR_COUNTER_BLOCK_PULSES : remainingAfter;
if (count > (remainingAfter - blockCount))
{
count = remainingAfter - blockCount;
}
blockCount += count;
}
else if (count >= PlsrFiniteCounterPreload[pulseOutput])
{
blockCount = count - PlsrFiniteCounterPreload[pulseOutput];
}
else
{
blockCount = 0UL;
}
if (blockCount > remainingAfter)
{
blockCount = remainingAfter;
}
return completed + blockCount;
}

static uint64_t PlsrCounterSnapshot(uint8_t pulseOutput)
{
uint64_t current = PlsrCounterCurrentRaw(pulseOutput);
uint64_t current;
uint64_t observed;

if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_PULSE_DIR)
&& (PlsrFiniteActive[pulseOutput] != 0U))
{
current = PlsrFiniteCompletedPulsesSnapshot(pulseOutput);
}
else
{
current = PlsrCounterCurrentRaw(pulseOutput);
}
if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB)
&& (current > 0UL))
{
@@ -3451,6 +3526,8 @@ uint8_t PlsrPlatformRetargetFiniteStop(uint8_t pulseOutput,
uint8_t PlsrPlatformRequestFiniteCut(uint8_t pulseOutput)
{
TIM_TypeDef *timer;
uint32_t timerCompare;
uint32_t timerCount;
uint32_t criticalState;

if (pulseOutput > 3U)
@@ -3461,8 +3538,7 @@ uint8_t PlsrPlatformRequestFiniteCut(uint8_t pulseOutput)
criticalState = PlsrPlatformEnterCritical();
if ((PlsrFiniteActive[pulseOutput] == 0U)
|| (PlsrFiniteStreamActive[pulseOutput] == 0U)
|| (PlsrCounterIndexByOutput[pulseOutput] >= PLSR_COUNTER_COUNT)
|| (PlsrFiniteRetargetPending[pulseOutput] != 0U))
|| (PlsrCounterIndexByOutput[pulseOutput] >= PLSR_COUNTER_COUNT))
{
PlsrPlatformExitCritical(criticalState);
return 0U;
@@ -3473,17 +3549,35 @@ uint8_t PlsrPlatformRequestFiniteCut(uint8_t pulseOutput)
return 1U;
}

/* Do not allow a run already staged by the producer to cross the cut.
CC1 reaches the physical pulse's falling edge, where the output is
idle and can be stopped without shortening the high or low width. */
/* EXT supersedes an unpublished retarget and any producer-staged run. */
PlsrFiniteRetargetPending[pulseOutput] = 0U;
PlsrFiniteRetargetDrainPulses[pulseOutput] = 0UL;
PlsrFiniteStreamNextValid[pulseOutput] = 0U;
PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U;
PlsrFiniteStreamSourceDone[pulseOutput] = 1U;
PlsrFiniteStreamSourceFault[pulseOutput] = 0U;
PlsrFiniteTailStopPending[pulseOutput] = 1U;
timer = PlsrTimerMap[pulseOutput].timer;
timer->DIER &= ~TIM_DIER_CC1IE;
timer->SR = ~TIM_SR_CC1IF;
timer->DIER |= TIM_DIER_CC1IE;

/* PWM1 is idle high before CCR1 and active low after CCR1. Freeze the
source briefly so the phase decision cannot turn a full pulse into a
short glitch. A low pulse is resumed and allowed to finish at update. */
timer->CR1 &= ~TIM_CR1_CEN;
__DSB();
timerCount = timer->CNT;
timerCompare = PlsrTimerActiveSetting[pulseOutput].compare;
if (timerCount < timerCompare)
{
PlsrFiniteCutAtIdleBoundary(pulseOutput);
}
else
{
timer->SR = ~TIM_SR_UIF;
timer->DIER |= TIM_DIER_UIE;
timer->CR1 |= TIM_CR1_CEN;
}
__DMB();
PlsrPlatformExitCritical(criticalState);
return 1U;
@@ -4689,7 +4783,8 @@ static void PlsrHandleTimerIrq(uint8_t pulseOutput)
&& (PlsrFiniteTailStopPending[pulseOutput] != 0U))
{
timer->SR = ~TIM_SR_CC1IF;
PlsrFiniteCutAtFallingEdge(pulseOutput);
timer->DIER &= ~TIM_DIER_CC1IE;
timer->DIER |= TIM_DIER_UIE;
goto irq_done;
}
#if PLSR_DEBUG_TIMING
@@ -4762,6 +4857,12 @@ static void PlsrHandleTimerIrq(uint8_t pulseOutput)
&& ((timer->DIER & TIM_DIER_UIE) != 0UL))
{
timer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF);
if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_PULSE_DIR)
&& (PlsrFiniteTailStopPending[pulseOutput] != 0U))
{
PlsrFiniteCutAtIdleBoundary(pulseOutput);
goto irq_done;
}
if ((PlsrFiniteActive[pulseOutput] != 0U)
&& (PlsrFiniteFrequencyPending[pulseOutput] != 0U))
{
@@ -5210,13 +5311,9 @@ static void PlsrFiniteCounterIrq(uint8_t pulseOutput,
counter->CR1 &= ~TIM_CR1_CEN;
counter->SMCR &= ~(TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0);

/*
* An OC rising edge is the terminal pulse's falling edge because the
* output stage is active low. The target-count update IRQ therefore is
* already the safe idle boundary: stop here before CCR1 can start an
* extra terminal pulse.
*/
PlsrFiniteStopAtFallingEdge(pulseOutput);
/* The counter update is sourced by the PWM edge that returns the MCU pin
high. The terminal pulse is complete and the output is safely idle. */
PlsrFiniteStopAtIdleBoundary(pulseOutput);
}

static void PlsrFiniteRetargetAtFallingEdge(uint8_t pulseOutput)
@@ -5265,32 +5362,16 @@ static void PlsrFiniteRetargetAtFallingEdge(uint8_t pulseOutput)
PlsrCounterBegin(pulseOutput);
}

static void PlsrFiniteCutAtFallingEdge(uint8_t pulseOutput)
static void PlsrFiniteCutAtIdleBoundary(uint8_t pulseOutput)
{
uint8_t counterIndex = PlsrCounterIndexByOutput[pulseOutput];
TIM_TypeDef *counter = PlsrCounters[counterIndex];
uint32_t blockCount;
uint32_t completed;

/* Freeze the external counter at the same falling edge that makes the
pulse output idle, then convert the partial current run into the
terminal run consumed by PlsrPlatformTakeFiniteCompletion(). */
/* The source output is high here. Freeze the slave counter and publish
exactly the completed full pulses from the partial current run. */
PlsrCounterSuspend(pulseOutput);
blockCount = (uint16_t)counter->CNT;
if (blockCount >= PlsrFiniteCounterPreload[pulseOutput])
{
blockCount -= PlsrFiniteCounterPreload[pulseOutput];
}
else
{
blockCount = 0UL;
}
completed = PlsrFiniteTargetPulses[pulseOutput]
- PlsrFiniteRemainingPulses[pulseOutput] + blockCount;
if (completed > PlsrFiniteTargetPulses[pulseOutput])
{
completed = PlsrFiniteTargetPulses[pulseOutput];
}
completed = PlsrFiniteCompletedPulsesSnapshot(pulseOutput);

PlsrObservedPulseBase[pulseOutput] += completed;
PlsrObservedPulsePublished[pulseOutput] =
@@ -5306,10 +5387,10 @@ static void PlsrFiniteCutAtFallingEdge(uint8_t pulseOutput)
PlsrCounterOverflowPulses[counterIndex] = 0UL;
counter->CNT = 0UL;
counter->SR = 0UL;
PlsrFiniteStopAtFallingEdge(pulseOutput);
PlsrFiniteStopAtIdleBoundary(pulseOutput);
}

static void PlsrFiniteStopAtFallingEdge(uint8_t pulseOutput)
static void PlsrFiniteStopAtIdleBoundary(uint8_t pulseOutput)
{
TIM_TypeDef *timer = PlsrTimerMap[pulseOutput].timer;



Chargement…
Annuler
Enregistrer