From 295a2592151c03c40c8caafa22f747c367b4350a Mon Sep 17 00:00:00 2001 From: ywh <2227158009@qq.com> Date: Sat, 15 Aug 2026 03:29:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=85=E9=9A=9C=E5=AE=89=E5=85=A8=EF=BC=9ANM?= =?UTF-8?q?I=5FHandler()=20=E5=92=8C=20Error=5FHandler()=20=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8=E9=83=BD=E4=BC=9A=E5=85=88=E5=BC=BA=E5=88=B6=E5=85=B3?= =?UTF-8?q?=E9=97=AD=20PLSR=20=E5=AE=9A=E6=97=B6=E5=99=A8=E3=80=81?= =?UTF-8?q?=E8=AE=A1=E6=95=B0=E5=99=A8=E5=B9=B6=E5=B0=86=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E7=BD=AE=E4=B8=BA=E5=AE=89=E5=85=A8=E7=94=B5=E5=B9=B3=E3=80=82?= =?UTF-8?q?[stm32f4xx=5Fit.c=20(line=2073)](F:/Xinje=5FModbus=5FIAR/TrainC?= =?UTF-8?q?amp=5Fyuwenhao=5Fmodbus/Core/Src/stm32f4xx=5Fit.c:73)=20[main.c?= =?UTF-8?q?=20(line=20310)](F:/Xinje=5FModbus=5FIAR/TrainCamp=5Fyuwenhao?= =?UTF-8?q?=5Fmodbus/Core/Src/main.c:310)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增量规划:不再单次填满 1024 项队列。启动预填 400 项,运行期补到 800 项,每轮最多生成 200 项;按 100 kHz 极限分别提供约 4 ms、8 ms 缓冲,并限制单轮计算量。[plsr.c (line 50)](F:/Xinje_Modbus_IAR/TrainCamp_yuwenhao_modbus/PLSR/Src/plsr.c:50) [plsr.c (line 1918)](F:/Xinje_Modbus_IAR/TrainCamp_yuwenhao_modbus/PLSR/Src/plsr.c:1918) USB CDC:移除了主程序中的 USB 头文件和 MX_USB_DEVICE_Init(),未使用的 USB 不再启动,也不会启用 OTG 最高优先级中断。[main.c (line 118)](F:/Xinje_Modbus_IAR/TrainCamp_yuwenhao_modbus/Core/Src/main.c:118) --- Core/Src/main.c | 4 ++-- Core/Src/stm32f4xx_it.c | 3 ++- PLSR/Src/plsr.c | 43 ++++++++++++++++++++++++++++++++--------- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Core/Src/main.c b/Core/Src/main.c index 346df0c..8ab29c1 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -18,7 +18,6 @@ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" -#include "usb_device.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ @@ -58,6 +57,7 @@ static void MX_DMA_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */ static void AppTaskStart(void *pArg); +extern void PlsrPlatformForceSafeOutputsFromFault(void); /* USER CODE END PFP */ @@ -118,7 +118,6 @@ int main(void) /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); - MX_USB_DEVICE_Init(); MX_USART1_UART_Init(); if (PlsrInit() == 0U) { @@ -313,6 +312,7 @@ void Error_Handler(void) /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ + PlsrPlatformForceSafeOutputsFromFault(); __disable_irq(); while (1) { diff --git a/Core/Src/stm32f4xx_it.c b/Core/Src/stm32f4xx_it.c index 5da38a8..c685db2 100644 --- a/Core/Src/stm32f4xx_it.c +++ b/Core/Src/stm32f4xx_it.c @@ -73,7 +73,8 @@ extern UART_HandleTypeDef huart1; void NMI_Handler(void) { /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ - + /* CSS clock failures can leave autonomous pulse timers running. */ + PlsrPlatformForceSafeOutputsFromFault(); /* USER CODE END NonMaskableInt_IRQn 0 */ HAL_RCC_NMI_IRQHandler(); /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ diff --git a/PLSR/Src/plsr.c b/PLSR/Src/plsr.c index 1a7cf00..8dfb72d 100644 --- a/PLSR/Src/plsr.c +++ b/PLSR/Src/plsr.c @@ -49,6 +49,13 @@ #define PLSR_POSITION_CHECKPOINT_MS (10U) #define PLSR_PROFILE_QUEUE_CAPACITY (1024U) #define PLSR_PROFILE_QUEUE_MASK (PLSR_PROFILE_QUEUE_CAPACITY - 1U) +/* A profile item can represent only one pulse. At the 100 kHz limit these + thresholds provide 4 ms of startup data, refill toward 8 ms, and cap each + 1 ms producer pass at 2 ms worth of newly planned items. */ +#define PLSR_PROFILE_STARTUP_TARGET (400U) +#define PLSR_PROFILE_STARTUP_BUDGET (400U) +#define PLSR_PROFILE_REFILL_TARGET (800U) +#define PLSR_PROFILE_REFILL_BUDGET (200U) #define PLSR_HANDOFF_WARMUP_ITEMS (8U) #define PLSR_REPLAN_WARMUP_ITEMS (8U) #define PLSR_RAMP_POLL_RESERVE_AREA_DIVISOR (20ULL) @@ -320,7 +327,8 @@ static uint8_t PlsrProfileQueueBegin( uint32_t producerEpoch, uint8_t producerSegment, uint8_t preparedHandoffBank); -static uint8_t PlsrProfileQueueFill(uint16_t targetCount); +static uint8_t PlsrProfileQueueFill(uint16_t targetCount, + uint16_t *itemBudget); static uint8_t PlsrStageCountedHandoff(void); static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext( uint8_t pulseOutput); @@ -1764,6 +1772,7 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz, uint32_t epoch; uint8_t segmentNumber; uint8_t handoffBank; + uint16_t fillBudget = PLSR_REPLAN_WARMUP_ITEMS; PlsrRamp.active = 0U; PlsrShortProfile.active = 0U; @@ -1794,7 +1803,8 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz, handoffBank = PlsrPreparedHandoffBank; (void)PlsrProfileQueueBegin(&PlsrShortProfile, epoch, segmentNumber, handoffBank); - if (PlsrProfileQueueFill(PLSR_REPLAN_WARMUP_ITEMS) == 0U) + if (PlsrProfileQueueFill(PLSR_REPLAN_WARMUP_ITEMS, + &fillBudget) == 0U) { PlsrProfileQueueReset(); PlsrShortProfile.active = 0U; @@ -1905,7 +1915,8 @@ static void PlsrProfileRecordProducerCycles(uint32_t startCycles) } #endif -static uint8_t PlsrProfileQueueFill(uint16_t targetCount) +static uint8_t PlsrProfileQueueFill(uint16_t targetCount, + uint16_t *itemBudget) { PLSR_SHORT_PROFILE candidate; PLSR_PROFILE_ENTRY entry; @@ -1918,6 +1929,10 @@ static uint8_t PlsrProfileQueueFill(uint16_t targetCount) uint32_t startCycles; #endif + if (itemBudget == NULL) + { + return 0U; + } if ((targetCount == 0U) || (targetCount > PLSR_PROFILE_QUEUE_CAPACITY)) { @@ -1928,11 +1943,13 @@ static uint8_t PlsrProfileQueueFill(uint16_t targetCount) criticalState = PlsrPlatformEnterCritical(); if ((PlsrProfileQueue.active == 0U) || (PlsrProfileQueue.generatorComplete != 0U) - || (PlsrProfileQueueCount() >= targetCount)) + || (PlsrProfileQueueCount() >= targetCount) + || (*itemBudget == 0U)) { PlsrPlatformExitCritical(criticalState); return 1U; } + (*itemBudget)--; generation = PlsrProfileQueue.generation; producerEpoch = PlsrProfileQueue.producerEpoch; PlsrCopyShortProfile(&candidate, @@ -2196,6 +2213,7 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz) uint32_t profileEpoch; uint8_t profileSegment; uint8_t profileHandoffBank; + uint16_t fillBudget = PLSR_PROFILE_STARTUP_BUDGET; PLSR_PROFILE_ENTRY firstRun; PlsrSegmentClockStarted = 1U; @@ -2220,7 +2238,8 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz) profileEpoch, profileSegment, profileHandoffBank); - if (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U) + if (PlsrProfileQueueFill(PLSR_PROFILE_STARTUP_TARGET, + &fillBudget) == 0U) { PlsrProfileQueueReset(); PlsrShortProfile.active = 0U; @@ -2228,7 +2247,8 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz) } PlsrCountedHandoffStaged = 0U; if ((PlsrStageCountedHandoff() == 0U) - || (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)) + || (PlsrProfileQueueFill(PLSR_PROFILE_STARTUP_TARGET, + &fillBudget) == 0U)) { PlsrProfileQueueReset(); PlsrShortProfile.active = 0U; @@ -3156,6 +3176,7 @@ static uint8_t PlsrPrepareFutureHandoffQueue(void) const PLSR_HANDOFF_PLAN *prepared; uint8_t currentSegment = PlsrCurrentSegment; uint8_t preparedBank = PlsrPreparedHandoffBank; + uint16_t fillBudget = PLSR_PROFILE_STARTUP_BUDGET; PlsrProfileQueueReset(); if ((currentSegment == 0U) @@ -3173,7 +3194,8 @@ static uint8_t PlsrPrepareFutureHandoffQueue(void) PlsrSegmentEpoch + 1UL, prepared->nextSegment, preparedBank); - if (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U) + if (PlsrProfileQueueFill(PLSR_PROFILE_STARTUP_TARGET, + &fillBudget) == 0U) { PlsrProfileQueueReset(); return 0U; @@ -4015,6 +4037,7 @@ void PlsrPoll1ms(void) uint32_t criticalState; uint32_t newTargetHz; uint32_t pollEpoch; + uint16_t fillBudget = PLSR_PROFILE_REFILL_BUDGET; if (PlsrInitialized == 0U) { @@ -4046,7 +4069,8 @@ void PlsrPoll1ms(void) || (PlsrExecutor.mode == PLSR_EXEC_STREAM)) && (PlsrProfileQueue.active != 0U) && (PlsrProfileQueue.generatorComplete == 0U) - && (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)) + && (PlsrProfileQueueFill(PLSR_PROFILE_REFILL_TARGET, + &fillBudget) == 0U)) { PlsrEnterError(PLSR_ERROR_TIMER); return; @@ -4054,7 +4078,8 @@ void PlsrPoll1ms(void) if (((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE) || (PlsrExecutor.mode == PLSR_EXEC_STREAM)) && ((PlsrStageCountedHandoff() == 0U) - || (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U))) + || (PlsrProfileQueueFill(PLSR_PROFILE_REFILL_TARGET, + &fillBudget) == 0U))) { PlsrEnterError(PLSR_ERROR_TIMER); return;