From ec2aa94775f166e3f1a0539062c91998d5dd1f50 Mon Sep 17 00:00:00 2001 From: ywh <2227158009@qq.com> Date: Mon, 17 Aug 2026 14:00:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DEXT=20=E7=A1=AC=E4=BB=B6=20pe?= =?UTF-8?q?nding=20=E7=AB=9E=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PLSR/Src/plsr.c | 127 ++++++++++++++++++++++++++++++---- PLSR/Src/plsr_platform.h | 5 +- PLSR/Src/plsr_platform_f407.c | 30 ++++++++ 3 files changed, 146 insertions(+), 16 deletions(-) diff --git a/PLSR/Src/plsr.c b/PLSR/Src/plsr.c index cbb2812..eabbcab 100644 --- a/PLSR/Src/plsr.c +++ b/PLSR/Src/plsr.c @@ -327,6 +327,10 @@ static volatile uint32_t PlsrSegmentElapsedMs; static volatile uint32_t PlsrWaitElapsedMs; static volatile uint8_t PlsrExtPreviousLevel; static volatile uint8_t PlsrExtEdgePending; +static volatile uint8_t PlsrExtEdgePendingSegment; +static volatile uint32_t PlsrExtEdgePendingEpoch; +static volatile uint8_t PlsrExtCaptureSegment; +static volatile uint32_t PlsrExtCaptureEpoch; static volatile uint8_t PlsrWaitSignalArmedMask; static volatile uint8_t PlsrWaitSignalPendingMask; static volatile uint8_t PlsrStopRequested; @@ -2608,7 +2612,8 @@ static void PlsrServiceTimedStartPreparation(void) || (PlsrLastDirectionLevel != directionLevel)) ? 1U : 0U; coldStartBoundary = ((sourceWaitType == PLSR_WAIT_TIME) || (sourceWaitType == PLSR_WAIT_SIGNAL) - || ((sourceWaitType == PLSR_ACT_TIME) + || (((sourceWaitType == PLSR_ACT_TIME) + || (sourceWaitType == PLSR_EXT_SIGNAL)) && (sourceWaiting != 0U))) ? 1U : 0U; if ((coldStartBoundary == 0U) && (directionChanged == 0U)) { @@ -3431,6 +3436,8 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrTryStartPreparedTimedSegment( PlsrSegmentEpoch++; PlsrCurrentSegment = segmentNumber; + PlsrExtCaptureSegment = segmentNumber; + PlsrExtCaptureEpoch = PlsrSegmentEpoch; PlsrSegmentClockStarted = 0U; PlsrSegmentElapsedMs = 0UL; PlsrWaitElapsedMs = 0UL; @@ -3449,7 +3456,6 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrTryStartPreparedTimedSegment( PlsrShortProfile.nextPeriod = 0U; PlsrDirectionDelayActive = 0U; PlsrDirectionDelayRemainingMs = 0U; - PlsrExtEdgePending = 0U; PlsrRemainingPulses = magnitude; PlsrCountPositive = positive; PlsrActTimedCutPlanned = PlsrTimedStart.nextActTimedCut; @@ -3697,8 +3703,12 @@ static uint8_t PlsrStartSegment(uint8_t segmentNumber, magnitude = (displacement < 0) ? (uint64_t)(-displacement) : (uint64_t)displacement; + criticalState = PlsrPlatformEnterCritical(); PlsrSegmentEpoch++; PlsrCurrentSegment = segmentNumber; + PlsrExtCaptureSegment = segmentNumber; + PlsrExtCaptureEpoch = PlsrSegmentEpoch; + PlsrPlatformExitCritical(criticalState); PlsrSegmentClockStarted = 0U; PlsrSegmentElapsedMs = 0UL; PlsrWaitElapsedMs = 0UL; @@ -3725,7 +3735,6 @@ static uint8_t PlsrStartSegment(uint8_t segmentNumber, } PlsrDirectionDelayActive = 0U; PlsrDirectionDelayRemainingMs = 0U; - PlsrExtEdgePending = 0U; PlsrExtPreviousLevel = PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput); @@ -3873,6 +3882,7 @@ static void PlsrFinishCompleted(void) PlsrSegmentClockStarted = 0U; PlsrDirectionDelayActive = 0U; PlsrDirectionDelayRemainingMs = 0U; + PlsrExtCaptureSegment = 0U; PlsrExtEdgePending = 0U; PlsrStopRequested = 0U; PlsrStopPulsesRemaining = 0U; @@ -3913,6 +3923,7 @@ static void PlsrFinishStopped(void) PlsrSegmentClockStarted = 0U; PlsrDirectionDelayActive = 0U; PlsrDirectionDelayRemainingMs = 0U; + PlsrExtCaptureSegment = 0U; PlsrExtEdgePending = 0U; PlsrStopRequested = 0U; PlsrStopPulsesRemaining = 0U; @@ -3953,6 +3964,7 @@ static void PlsrEnterError(PLSR_ERROR error) PlsrSegmentClockStarted = 0U; PlsrDirectionDelayActive = 0U; PlsrDirectionDelayRemainingMs = 0U; + PlsrExtCaptureSegment = 0U; PlsrExtEdgePending = 0U; PlsrStopRequested = 0U; PlsrStopPulsesRemaining = 0U; @@ -4508,6 +4520,9 @@ void PlsrExecCountedSegmentBoundaryIrq(uint8_t pulseOutput, { PLSR_COUNTED_BOUNDARY_EVENT *event; uint8_t writeIndex; + uint8_t previousExtSegment; + uint8_t hardwareExtPending; + uint32_t previousExtEpoch; if (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput) { @@ -4534,6 +4549,27 @@ void PlsrExecCountedSegmentBoundaryIrq(uint8_t pulseOutput, event->nextSegment = PlsrHandoffPlan.nextSegment; event->positive = PlsrHandoffPlan.positive; event->nextActTimedCut = PlsrHandoffPlan.nextActTimedCut; + previousExtSegment = PlsrExtCaptureSegment; + previousExtEpoch = PlsrExtCaptureEpoch; + hardwareExtPending = PlsrPlatformTakeInputExtiPending( + (uint8_t)PlsrActiveConfig.extInput); + if (hardwareExtPending != 0U) + { + /* The lower-priority EXTI ISR has not run yet. The natural boundary + consumes this source-segment edge, so discard any matching software + latch as well and do not let either reach the next segment. */ + PlsrExtEdgePending = 0U; + } + else if ((PlsrExtEdgePending != 0U) + && (PlsrExtEdgePendingSegment == previousExtSegment) + && (PlsrExtEdgePendingEpoch == previousExtEpoch)) + { + /* The EXTI ISR already captured the source-segment edge. Natural + completion satisfies EXT_OR_COMPLETE, preventing a double step. */ + PlsrExtEdgePending = 0U; + } + PlsrExtCaptureSegment = event->nextSegment; + PlsrExtCaptureEpoch = previousExtEpoch + 1UL; #if defined(__ICCARM__) __DMB(); #endif @@ -4661,7 +4697,6 @@ static void PlsrExecServiceCountedBoundaryEvent(void) PlsrActiveConfig.segments[nextSegment - 1U].frequencyHz; } PlsrDeferredFrequencyPending = 0U; - PlsrExtEdgePending = 0U; PlsrExtPreviousLevel = PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput); PlsrCopyShortProfile(&PlsrShortProfile, @@ -4929,12 +4964,16 @@ static PLSR_PLATFORM_QUEUE_RESULT PlsrTryContinuousHandoff(void) return PLSR_PLATFORM_QUEUE_APPLIED; } -/* EXTI only records a WAIT edge. Motion state transitions and timer startup - remain in the task context. The armed mask prevents an edge from an idle - or unrelated input from releasing a later segment. */ +/* 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. */ void PlsrWaitInputExtiIrq(uint8_t inputSelection) { uint8_t bit; + uint8_t captureSegment; + uint32_t captureEpoch; + uint16_t waitType; if (inputSelection > 1U) { @@ -4945,6 +4984,25 @@ void PlsrWaitInputExtiIrq(uint8_t inputSelection) { PlsrWaitSignalPendingMask |= bit; } + captureEpoch = PlsrExtCaptureEpoch; + captureSegment = PlsrExtCaptureSegment; + if ((PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR) + || (inputSelection != (uint8_t)PlsrActiveConfig.extInput) + || (captureSegment == 0U) + || (captureSegment > PlsrActiveConfig.segmentCount)) + { + return; + } + waitType = PlsrActiveConfig.segments[captureSegment - 1U].waitType; + if (((waitType == PLSR_EXT_SIGNAL) + || (waitType == PLSR_EXT_OR_COMPLETE)) + && (captureEpoch == PlsrExtCaptureEpoch) + && (captureSegment == PlsrExtCaptureSegment)) + { + PlsrExtEdgePendingSegment = captureSegment; + PlsrExtEdgePendingEpoch = captureEpoch; + PlsrExtEdgePending = 1U; + } } static void PlsrArmWaitSignal(uint8_t inputSelection) @@ -5009,8 +5067,10 @@ static void PlsrHandleBoundary(uint8_t extEdge) { const PLSR_SEGMENT_CONFIG *segment; uint32_t criticalState; + uint32_t currentEpoch; uint8_t wasCut = PlsrBoundaryWasCut; uint8_t preserveTimedStart; + uint8_t currentSegment; PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput); PlsrBoundaryPending = 0U; @@ -5074,10 +5134,18 @@ static void PlsrHandleBoundary(uint8_t extEdge) segment = &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U]; if (wasCut != 0U) { - PlsrTransitionToNext( + uint8_t allowCarry = ((segment->waitType == PLSR_ACT_TIME) || (PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT)) - ? 1U : 0U); + ? 1U : 0U; + + if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR) + && ((segment->waitType == PLSR_EXT_SIGNAL) + || (segment->waitType == PLSR_EXT_OR_COMPLETE))) + { + allowCarry = 1U; + } + PlsrTransitionToNext(allowCarry); return; } @@ -5117,6 +5185,17 @@ static void PlsrHandleBoundary(uint8_t extEdge) break; case PLSR_EXT_SIGNAL: + criticalState = PlsrPlatformEnterCritical(); + currentEpoch = PlsrSegmentEpoch; + currentSegment = PlsrCurrentSegment; + if ((PlsrExtEdgePending != 0U) + && (PlsrExtEdgePendingEpoch == currentEpoch) + && (PlsrExtEdgePendingSegment == currentSegment)) + { + extEdge = 1U; + PlsrExtEdgePending = 0U; + } + PlsrPlatformExitCritical(criticalState); if (extEdge != 0U) { PlsrTransitionToNext(0U); @@ -5353,6 +5432,10 @@ uint8_t PlsrInit(void) PlsrSegmentClockStarted = 0U; PlsrExtPreviousLevel = 0U; PlsrExtEdgePending = 0U; + PlsrExtEdgePendingSegment = 0U; + PlsrExtEdgePendingEpoch = 0UL; + PlsrExtCaptureSegment = 0U; + PlsrExtCaptureEpoch = 0UL; PlsrWaitSignalArmedMask = 0U; PlsrWaitSignalPendingMask = 0U; PlsrStopRequested = 0U; @@ -5586,6 +5669,7 @@ static void PlsrExecuteClear(void) PlsrBoundaryWasCut = 0U; PlsrDirectionDelayActive = 0U; PlsrDirectionDelayRemainingMs = 0U; + PlsrExtCaptureSegment = 0U; PlsrExtEdgePending = 0U; PlsrShortProfile.active = 0U; PlsrProfileQueueReset(); @@ -5801,18 +5885,23 @@ void PlsrPoll1ms(void) criticalState = PlsrPlatformEnterCritical(); pollEpoch = PlsrSegmentEpoch; + activeSegmentNumber = PlsrCurrentSegment; extLevel = PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput); extEdge = ((extLevel != 0U) && (PlsrExtPreviousLevel == 0U)) ? 1U : 0U; PlsrExtPreviousLevel = extLevel; if (PlsrExtEdgePending != 0U) { - extEdge = 1U; + if ((PlsrExtEdgePendingEpoch == pollEpoch) + && (PlsrExtEdgePendingSegment == activeSegmentNumber)) + { + extEdge = 1U; + } + PlsrExtEdgePending = 0U; } PlsrPlatformExitCritical(criticalState); if (PlsrBoundaryPending != 0U) { - PlsrExtEdgePending = 0U; PlsrHandleBoundary(extEdge); PlsrPollPersistenceDelay(); return; @@ -5832,9 +5921,18 @@ void PlsrPoll1ms(void) if (PlsrDirectionDelayActive != 0U) { - if (extEdge != 0U) - { - PlsrExtEdgePending = 1U; + activeSegmentNumber = PlsrCurrentSegment; + if ((extEdge != 0U) + && (activeSegmentNumber != 0U) + && (activeSegmentNumber <= PlsrActiveConfig.segmentCount) + && ((PlsrActiveConfig.segments[activeSegmentNumber - 1U].waitType + == PLSR_EXT_SIGNAL) + || (PlsrActiveConfig.segments[ + activeSegmentNumber - 1U].waitType + == PLSR_EXT_OR_COMPLETE))) + { + PlsrRequestCut(pollEpoch); + return; } if (PlsrDirectionDelayRemainingMs != 0U) { @@ -5868,7 +5966,6 @@ void PlsrPoll1ms(void) PlsrPlatformExitCritical(criticalState); return; } - PlsrExtEdgePending = 0U; if (PlsrSegmentClockStarted != 0U) { PlsrSegmentElapsedMs++; diff --git a/PLSR/Src/plsr_platform.h b/PLSR/Src/plsr_platform.h index 85771ab..8a93a8f 100644 --- a/PLSR/Src/plsr_platform.h +++ b/PLSR/Src/plsr_platform.h @@ -118,7 +118,7 @@ uint8_t PlsrExecTakeCountedRunIrq( void PlsrExecCountedSegmentBoundaryIrq(uint8_t pulseOutput, uint32_t completedPulses); void PlsrExecCountedStreamFaultIrq(uint8_t pulseOutput); -/* EXTI callback: records only an armed WAIT input edge. */ +/* EXTI callback: records an armed WAIT or active EXT input edge. */ void PlsrWaitInputExtiIrq(uint8_t inputSelection); PLSR_PLATFORM_QUEUE_RESULT PlsrPlatformLoadPreparedFromIrq( uint8_t pulseOutput, @@ -145,6 +145,9 @@ PLSR_PLATFORM_STOP_RESULT PlsrPlatformRequestStopLocked( uint8_t PlsrPlatformQueueFinalArmFromIrq(uint8_t pulseOutput); void PlsrPlatformStopPulse(uint8_t pulseOutput); uint8_t PlsrPlatformReadInput(uint8_t inputSelection); +/* Called from the counted-boundary IRQ before the EXT capture context moves + to the next segment. Returns and clears a rising edge pending in EXTI. */ +uint8_t PlsrPlatformTakeInputExtiPending(uint8_t inputSelection); uint8_t PlsrPlatformLoad(PLSR_PERSIST_PAYLOAD *payload); PLSR_PLATFORM_SERVICE_RESULT PlsrPlatformServicePersistence(void); diff --git a/PLSR/Src/plsr_platform_f407.c b/PLSR/Src/plsr_platform_f407.c index ce90896..be8ae2b 100644 --- a/PLSR/Src/plsr_platform_f407.c +++ b/PLSR/Src/plsr_platform_f407.c @@ -893,6 +893,12 @@ uint8_t PlsrPlatformReadInput(uint8_t inputSelection) return (inputSelection <= 1U) ? PlsrHostInputs[inputSelection] : 0U; } +uint8_t PlsrPlatformTakeInputExtiPending(uint8_t inputSelection) +{ + (void)inputSelection; + return 0U; +} + uint8_t PlsrPlatformLoad(PLSR_PERSIST_PAYLOAD *payload) { if ((payload == NULL) || (PlsrHostPersistentValid == 0U)) @@ -4284,6 +4290,30 @@ uint8_t PlsrPlatformReadInput(uint8_t inputSelection) return 0U; } +uint8_t PlsrPlatformTakeInputExtiPending(uint8_t inputSelection) +{ + uint16_t pin; + + if (inputSelection == 0U) + { + pin = GPIO_PIN_5; + } + else if (inputSelection == 1U) + { + pin = GPIO_PIN_12; + } + else + { + return 0U; + } + if (__HAL_GPIO_EXTI_GET_IT(pin) == RESET) + { + return 0U; + } + __HAL_GPIO_EXTI_CLEAR_IT(pin); + return 1U; +} + uint8_t PlsrPlatformLoad(PLSR_PERSIST_PAYLOAD *payload) { PLSR_FLASH_SECTOR_SCAN scanA;