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;