diff --git a/Core/Inc/stm32f4xx_it.h b/Core/Inc/stm32f4xx_it.h index 885d93d..29e1984 100644 --- a/Core/Inc/stm32f4xx_it.h +++ b/Core/Inc/stm32f4xx_it.h @@ -66,6 +66,8 @@ void TIM1_TRG_COM_TIM11_IRQHandler(void); void TIM8_TRG_COM_TIM14_IRQHandler(void); void TIM1_BRK_TIM9_IRQHandler(void); void TIM8_BRK_TIM12_IRQHandler(void); +void EXTI9_5_IRQHandler(void); +void EXTI15_10_IRQHandler(void); /* USER CODE END EFP */ #ifdef __cplusplus diff --git a/Document/信捷XD_XL系列PLC用户手册_硬件篇_PD01_20260410_V1.6.pdf b/Document/信捷XD_XL系列PLC用户手册_硬件篇_PD01_20260410_V1.6.pdf new file mode 100644 index 0000000..eebc233 Binary files /dev/null and b/Document/信捷XD_XL系列PLC用户手册_硬件篇_PD01_20260410_V1.6.pdf differ diff --git a/PLSR/Src/plsr.c b/PLSR/Src/plsr.c index df9456e..9db6c3c 100644 --- a/PLSR/Src/plsr.c +++ b/PLSR/Src/plsr.c @@ -143,10 +143,10 @@ typedef struct volatile uint8_t generatorComplete; } PLSR_PROFILE_QUEUE; -/* A WAIT_TIME boundary is a cold start, but its planner work is predictable - while the source segment is still running. Build that next stream in the - inactive queue bank and publish it only after the startup horizon is ready. - The boundary path then contains no planner loop. */ +/* WAIT_TIME and WAIT_SIGNAL boundaries are cold starts, but their planner + work is predictable while the source segment is still running or waiting. + Build that next stream in the inactive queue bank and publish it only after + the startup horizon is ready. The release path then has no planner loop. */ typedef struct { PLSR_PROFILE_ENTRY firstRun; @@ -313,6 +313,8 @@ static volatile uint32_t PlsrSegmentElapsedMs; static volatile uint32_t PlsrWaitElapsedMs; static volatile uint8_t PlsrExtPreviousLevel; static volatile uint8_t PlsrExtEdgePending; +static volatile uint8_t PlsrWaitSignalArmedMask; +static volatile uint8_t PlsrWaitSignalPendingMask; static volatile uint8_t PlsrStopRequested; static volatile uint8_t PlsrStopPulsesRemaining; static volatile uint8_t PlsrAbStopArmed; @@ -379,6 +381,9 @@ static void PlsrEnterErrorIfEpoch(PLSR_ERROR error, static void PlsrMarkPersistenceDirty(uint16_t delayMs); static void PlsrCheckpointPosition(uint8_t wasBusy); static void PlsrPollPositionCheckpoint(void); +static void PlsrArmWaitSignal(uint8_t inputSelection); +static void PlsrDisarmWaitSignal(void); +static uint8_t PlsrWaitSignalDetected(uint8_t inputSelection); static PLSR_PLATFORM_QUEUE_RESULT PlsrTryContinuousHandoff(void); static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile, uint8_t segmentNumber, @@ -2360,8 +2365,10 @@ static void PlsrServiceTimedStartPreparation(void) sourceSegment = PlsrCurrentSegment; if ((sourceSegment == 0U) || (sourceSegment > PlsrActiveConfig.segmentCount) - || (PlsrActiveConfig.segments[sourceSegment - 1U].waitType - != PLSR_WAIT_TIME)) + || ((PlsrActiveConfig.segments[sourceSegment - 1U].waitType + != PLSR_WAIT_TIME) + && (PlsrActiveConfig.segments[sourceSegment - 1U].waitType + != PLSR_WAIT_SIGNAL))) { PlsrInvalidateTimedStartLocked(); PlsrPlatformExitCritical(criticalState); @@ -3293,6 +3300,7 @@ static uint8_t PlsrStartSegment(uint8_t segmentNumber, { return 0U; } + PlsrDisarmWaitSignal(); criticalState = PlsrPlatformEnterCritical(); position = PlsrPosition; @@ -3445,6 +3453,7 @@ static void PlsrPollPositionCheckpoint(void) static void PlsrFinishCompleted(void) { + PlsrDisarmWaitSignal(); PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput); PlsrRemainingPulses = 0UL; PlsrPulseActive = 0U; @@ -3482,6 +3491,7 @@ static void PlsrFinishCompleted(void) static void PlsrFinishStopped(void) { + PlsrDisarmWaitSignal(); PlsrDiagnosticFinishSegment(0U); PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput); PlsrRemainingPulses = 0UL; @@ -3520,6 +3530,7 @@ static void PlsrFinishStopped(void) static void PlsrEnterError(PLSR_ERROR error) { + PlsrDisarmWaitSignal(); PlsrDiagnosticFinishSegment(0U); PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput); PlsrRemainingPulses = 0UL; @@ -4461,6 +4472,82 @@ 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. */ +void PlsrWaitInputExtiIrq(uint8_t inputSelection) +{ + uint8_t bit; + + if (inputSelection > 1U) + { + return; + } + bit = (uint8_t)(1U << inputSelection); + if ((PlsrWaitSignalArmedMask & bit) != 0U) + { + PlsrWaitSignalPendingMask |= bit; + } +} + +static void PlsrArmWaitSignal(uint8_t inputSelection) +{ + uint32_t criticalState; + uint8_t bit; + + if (inputSelection > 1U) + { + return; + } + bit = (uint8_t)(1U << inputSelection); + criticalState = PlsrPlatformEnterCritical(); + PlsrWaitSignalPendingMask = 0U; + PlsrWaitSignalArmedMask = bit; + PlsrPlatformExitCritical(criticalState); +} + +static void PlsrDisarmWaitSignal(void) +{ + uint32_t criticalState = PlsrPlatformEnterCritical(); + + PlsrWaitSignalArmedMask = 0U; + PlsrWaitSignalPendingMask = 0U; + PlsrPlatformExitCritical(criticalState); +} + +static uint8_t PlsrWaitSignalDetected(uint8_t inputSelection) +{ + uint32_t criticalState; + uint8_t bit; + + if (inputSelection > 1U) + { + return 0U; + } + bit = (uint8_t)(1U << inputSelection); + criticalState = PlsrPlatformEnterCritical(); + if ((PlsrWaitSignalPendingMask & bit) != 0U) + { + PlsrWaitSignalPendingMask &= (uint8_t)~bit; + PlsrWaitSignalArmedMask &= (uint8_t)~bit; + PlsrPlatformExitCritical(criticalState); + return 1U; + } + PlsrPlatformExitCritical(criticalState); + + /* Preserve the original level semantics: a signal already high when the + segment enters WAIT must release it even though no new EXTI edge occurs. */ + if (PlsrPlatformReadInput(inputSelection) != 0U) + { + criticalState = PlsrPlatformEnterCritical(); + PlsrWaitSignalPendingMask &= (uint8_t)~bit; + PlsrWaitSignalArmedMask &= (uint8_t)~bit; + PlsrPlatformExitCritical(criticalState); + return 1U; + } + return 0U; +} + static void PlsrHandleBoundary(uint8_t extEdge) { const PLSR_SEGMENT_CONFIG *segment; @@ -4550,14 +4637,13 @@ static void PlsrHandleBoundary(uint8_t extEdge) break; case PLSR_WAIT_SIGNAL: - if (PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.waitInput) != 0U) + PlsrRunStatus = PLSR_STATUS_WAITING; + PlsrArmWaitSignal((uint8_t)PlsrActiveConfig.waitInput); + if (PlsrWaitSignalDetected( + (uint8_t)PlsrActiveConfig.waitInput) != 0U) { PlsrTransitionToNext(0U); } - else - { - PlsrRunStatus = PLSR_STATUS_WAITING; - } break; case PLSR_ACT_TIME: @@ -4634,7 +4720,8 @@ static void PlsrPollWaiting(uint8_t extEdge) } break; case PLSR_WAIT_SIGNAL: - if (PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.waitInput) != 0U) + if (PlsrWaitSignalDetected( + (uint8_t)PlsrActiveConfig.waitInput) != 0U) { PlsrTransitionToNext(0U); } @@ -4786,6 +4873,8 @@ uint8_t PlsrInit(void) PlsrSegmentClockStarted = 0U; PlsrExtPreviousLevel = 0U; PlsrExtEdgePending = 0U; + PlsrWaitSignalArmedMask = 0U; + PlsrWaitSignalPendingMask = 0U; PlsrStopRequested = 0U; PlsrStopPulsesRemaining = 0U; PlsrAbStopArmed = 0U; @@ -4995,6 +5084,7 @@ static void PlsrExecuteClear(void) { uint32_t criticalState; + PlsrDisarmWaitSignal(); criticalState = PlsrPlatformEnterCritical(); PlsrPosition = 0L; PlsrPositionValid = 1U; diff --git a/PLSR/Src/plsr_platform.h b/PLSR/Src/plsr_platform.h index 2b11fab..c6b148e 100644 --- a/PLSR/Src/plsr_platform.h +++ b/PLSR/Src/plsr_platform.h @@ -117,6 +117,8 @@ 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. */ +void PlsrWaitInputExtiIrq(uint8_t inputSelection); PLSR_PLATFORM_QUEUE_RESULT PlsrPlatformLoadPreparedFromIrq( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, diff --git a/PLSR/Src/plsr_platform_f407.c b/PLSR/Src/plsr_platform_f407.c index c937ac3..2dabd05 100644 --- a/PLSR/Src/plsr_platform_f407.c +++ b/PLSR/Src/plsr_platform_f407.c @@ -2756,6 +2756,7 @@ uint8_t PlsrPlatformInit(void) __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_RCC_TIM10_CLK_ENABLE(); __HAL_RCC_TIM11_CLK_ENABLE(); __HAL_RCC_TIM13_CLK_ENABLE(); @@ -2802,7 +2803,7 @@ uint8_t PlsrPlatformInit(void) gpio.Alternate = 0U; HAL_GPIO_Init(GPIOH, &gpio); - gpio.Mode = GPIO_MODE_INPUT; + gpio.Mode = GPIO_MODE_IT_RISING; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_LOW; gpio.Alternate = 0U; @@ -2810,6 +2811,11 @@ uint8_t PlsrPlatformInit(void) HAL_GPIO_Init(GPIOB, &gpio); gpio.Pin = GPIO_PIN_12; HAL_GPIO_Init(GPIOG, &gpio); + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5 | GPIO_PIN_12); + HAL_NVIC_SetPriority(EXTI9_5_IRQn, 2U, 0U); + HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); + HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2U, 0U); + HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); for (index = 0U; index < 4U; index++) { @@ -4818,6 +4824,24 @@ void TIM8_TRG_COM_TIM14_IRQHandler(void) PlsrDispatchTimerIrq(3U); } +void EXTI9_5_IRQHandler(void) +{ + if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_5) != RESET) + { + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5); + PlsrWaitInputExtiIrq(0U); + } +} + +void EXTI15_10_IRQHandler(void) +{ + if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_12) != RESET) + { + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_12); + PlsrWaitInputExtiIrq(1U); + } +} + static void PlsrHandleCounterIrq(uint8_t counterIndex) { TIM_TypeDef *counter;