#include "plsr_platform.h" #include "plsr.h" static uint8_t PlsrFlashNeedsStartupRecovery( uint8_t haveValidRecord, uint8_t sectorAHasProgrammedSlot, uint32_t sectorAFirstErasedAddress, uint8_t sectorBHasProgrammedSlot, uint32_t sectorBFirstErasedAddress) { return ((haveValidRecord == 0U) && (sectorAHasProgrammedSlot != 0U) && (sectorBHasProgrammedSlot != 0U) && (sectorAFirstErasedAddress == 0UL) && (sectorBFirstErasedAddress == 0UL)) ? 1U : 0U; } #ifdef PLSR_HOST_TEST #include static uint8_t PlsrHostPulseActive[4]; static uint32_t PlsrHostFrequency[4]; static uint32_t PlsrHostQueuedFrequency[4]; static PLSR_PLATFORM_TIMER_SETTING PlsrHostActiveSetting[4]; static PLSR_PLATFORM_TIMER_SETTING PlsrHostQueuedSetting[4]; static uint8_t PlsrHostUpdatePending[4]; static uint8_t PlsrHostOutputMode[4]; static uint8_t PlsrHostDirectionPositive[4]; static uint8_t PlsrHostAbQuarter[4]; static uint8_t PlsrHostAbPhase[4]; static uint32_t PlsrHostAbTransitions[4]; static uint8_t PlsrHostAbStopPending[4]; static uint8_t PlsrHostAbFastGated[4]; static uint32_t PlsrHostAbFastGateCount; static uint32_t PlsrHostAbCleanupCount; static uint64_t PlsrHostObservedPulses[4]; static uint8_t PlsrHostInputs[2]; static uint8_t PlsrHostSelectedPulse; static uint8_t PlsrHostDirectionLevel; static uint8_t PlsrHostDirectionPinLevel[4]; static uint32_t PlsrHostDirectionWriteCount[4]; static uint32_t PlsrHostDirectionTransitionCount[4]; static uint8_t PlsrHostEmitPulseOnCriticalEntry; static uint8_t PlsrHostEmitPulseOnCriticalExit; static uint8_t PlsrHostLatchPulseOnCriticalEntry; static uint8_t PlsrHostCriticalEntriesToSkip; static uint8_t PlsrHostLatchAbFinalQuarterOnStopArm; static uint8_t PlsrHostCompleteAbCycleOnQueueCommit; static uint32_t PlsrHostCriticalDepth; static uint8_t PlsrHostFailNextStart; static uint8_t PlsrHostStaleNextFrequencyAtUpdate; static uint8_t PlsrHostFailNextFrequencyAtUpdate; static uint8_t PlsrHostFailNextStopRequest; static uint8_t PlsrHostFinalArmJobPending; static uint8_t PlsrHostFinalArmJobOwner; static uint8_t PlsrHostDeferFinalArmJob; static int32_t PlsrHostCountOffset; static int32_t PlsrHostFrequencyOffsetHz; static uint8_t PlsrHostCurveMismatchPending; static uint16_t PlsrHostDiagnosticFault; static PLSR_PERSIST_PAYLOAD PlsrHostPersistentPayload; static uint8_t PlsrHostPersistentValid; static uint32_t PlsrHostSaveCount; static uint8_t PlsrHostFiniteEnabled; static uint8_t PlsrHostFiniteActive[4]; static uint8_t PlsrHostFiniteComplete[4]; static uint8_t PlsrHostFiniteFrequencyPending[4]; static uint8_t PlsrHostCountedStreamActive[4]; static uint32_t PlsrHostFiniteTarget[4]; static uint32_t PlsrHostFiniteEmitted[4]; static PLSR_PLATFORM_FINITE_STEP *PlsrHostFiniteSteps[4]; static uint16_t PlsrHostFiniteStepCount[4]; static uint16_t PlsrHostFiniteStepIndex[4]; static uint16_t PlsrHostFiniteBoundaryReadIndex[4]; static uint16_t PlsrHostFiniteCompletedStepCount[4]; static void PlsrHostServiceFinalArmJob(void); static uint32_t PlsrHostOffsetFrequency(uint32_t frequencyHz) { int64_t adjusted = (int64_t)frequencyHz + (int64_t)PlsrHostFrequencyOffsetHz; if (adjusted < 1) { adjusted = 1; } if (adjusted > (int64_t)PLSR_FREQUENCY_MAX_HZ) { adjusted = (int64_t)PLSR_FREQUENCY_MAX_HZ; } return (uint32_t)adjusted; } static void PlsrHostLatchPulse(uint8_t pulseOutput) { if ((pulseOutput <= 3U) && (PlsrHostPulseActive[pulseOutput] != 0U)) { if (PlsrHostCurveMismatchPending != 0U) { PlsrHostCurveMismatchPending = 0U; PlsrHostDiagnosticFault = 3U; } else if ((PlsrHostOutputMode[pulseOutput] != PLSR_OUTPUT_AB) || (PlsrHostAbStopPending[pulseOutput] == 0U)) { PlsrHostFrequency[pulseOutput] = PlsrHostQueuedFrequency[pulseOutput]; PlsrHostActiveSetting[pulseOutput] = PlsrHostQueuedSetting[pulseOutput]; } PlsrHostObservedPulses[pulseOutput]++; PlsrHostUpdatePending[pulseOutput] = 1U; } } static void PlsrHostServicePendingPulse(uint8_t pulseOutput) { if ((pulseOutput <= 3U) && (PlsrHostUpdatePending[pulseOutput] != 0U)) { PlsrHostUpdatePending[pulseOutput] = 0U; if ((PlsrHostOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (PlsrHostAbStopPending[pulseOutput] != 0U) && (PlsrHostAbFastGated[pulseOutput] == 0U)) { PlsrHostAbFastGated[pulseOutput] = 1U; PlsrHostPulseActive[pulseOutput] = 0U; PlsrHostAbFastGateCount++; } PlsrPulseTimerIrq(pulseOutput); } if (PlsrHostDeferFinalArmJob == 0U) { PlsrHostServiceFinalArmJob(); } } static void PlsrHostServiceFinalArmJob(void) { uint8_t owner; if (PlsrHostFinalArmJobPending == 0U) { return; } owner = PlsrHostFinalArmJobOwner; PlsrHostFinalArmJobPending = 0U; PlsrHostFinalArmJobOwner = 0xFFU; PlsrFinalArmJobIrq(owner); } static uint8_t PlsrHostAdvanceAbQuarter(uint8_t pulseOutput) { static const uint8_t positivePhase[4] = {0U, 2U, 3U, 1U}; static const uint8_t negativePhase[4] = {0U, 1U, 3U, 2U}; if ((pulseOutput > 3U) || (PlsrHostPulseActive[pulseOutput] == 0U) || (PlsrHostOutputMode[pulseOutput] != PLSR_OUTPUT_AB)) { return 0U; } PlsrHostAbQuarter[pulseOutput] = (uint8_t)((PlsrHostAbQuarter[pulseOutput] + 1U) & 3U); PlsrHostAbPhase[pulseOutput] = (PlsrHostDirectionPositive[pulseOutput] != 0U) ? positivePhase[PlsrHostAbQuarter[pulseOutput]] : negativePhase[PlsrHostAbQuarter[pulseOutput]]; PlsrHostAbTransitions[pulseOutput]++; if (PlsrHostAbQuarter[pulseOutput] != 0U) { return 0U; } PlsrHostLatchPulse(pulseOutput); return 1U; } uint8_t PlsrPlatformInit(void) { uint8_t index; (void)memset(PlsrHostPulseActive, 0, sizeof(PlsrHostPulseActive)); (void)memset(PlsrHostFrequency, 0, sizeof(PlsrHostFrequency)); (void)memset(PlsrHostQueuedFrequency, 0, sizeof(PlsrHostQueuedFrequency)); (void)memset(PlsrHostActiveSetting, 0, sizeof(PlsrHostActiveSetting)); (void)memset(PlsrHostQueuedSetting, 0, sizeof(PlsrHostQueuedSetting)); (void)memset(PlsrHostUpdatePending, 0, sizeof(PlsrHostUpdatePending)); (void)memset(PlsrHostOutputMode, 0, sizeof(PlsrHostOutputMode)); (void)memset(PlsrHostDirectionPositive, 0, sizeof(PlsrHostDirectionPositive)); (void)memset(PlsrHostAbQuarter, 0, sizeof(PlsrHostAbQuarter)); (void)memset(PlsrHostAbPhase, 0, sizeof(PlsrHostAbPhase)); (void)memset(PlsrHostAbTransitions, 0, sizeof(PlsrHostAbTransitions)); (void)memset(PlsrHostAbStopPending, 0, sizeof(PlsrHostAbStopPending)); (void)memset(PlsrHostAbFastGated, 0, sizeof(PlsrHostAbFastGated)); PlsrHostAbFastGateCount = 0UL; PlsrHostAbCleanupCount = 0UL; (void)memset(PlsrHostObservedPulses, 0, sizeof(PlsrHostObservedPulses)); PlsrHostSelectedPulse = 0U; PlsrHostDirectionLevel = 0U; for (index = 0U; index < 4U; index++) { PlsrHostDirectionPinLevel[index] = 1U; PlsrHostDirectionWriteCount[index] = 0UL; PlsrHostDirectionTransitionCount[index] = 0UL; } PlsrHostEmitPulseOnCriticalEntry = 0U; PlsrHostEmitPulseOnCriticalExit = 0U; PlsrHostLatchPulseOnCriticalEntry = 0U; PlsrHostCriticalEntriesToSkip = 0U; PlsrHostLatchAbFinalQuarterOnStopArm = 0U; PlsrHostCompleteAbCycleOnQueueCommit = 0U; PlsrHostCriticalDepth = 0UL; PlsrHostFailNextStart = 0U; PlsrHostStaleNextFrequencyAtUpdate = 0U; PlsrHostFailNextFrequencyAtUpdate = 0U; PlsrHostFailNextStopRequest = 0U; PlsrHostFinalArmJobPending = 0U; PlsrHostFinalArmJobOwner = 0xFFU; PlsrHostDeferFinalArmJob = 0U; PlsrHostCountOffset = 0L; PlsrHostFrequencyOffsetHz = 0L; PlsrHostCurveMismatchPending = 0U; PlsrHostDiagnosticFault = 0U; PlsrHostFiniteEnabled = 0U; (void)memset(PlsrHostFiniteActive, 0, sizeof(PlsrHostFiniteActive)); (void)memset(PlsrHostFiniteComplete, 0, sizeof(PlsrHostFiniteComplete)); (void)memset(PlsrHostFiniteFrequencyPending, 0, sizeof(PlsrHostFiniteFrequencyPending)); (void)memset(PlsrHostFiniteTarget, 0, sizeof(PlsrHostFiniteTarget)); (void)memset(PlsrHostFiniteEmitted, 0, sizeof(PlsrHostFiniteEmitted)); (void)memset(PlsrHostFiniteSteps, 0, sizeof(PlsrHostFiniteSteps)); (void)memset(PlsrHostFiniteStepCount, 0, sizeof(PlsrHostFiniteStepCount)); (void)memset(PlsrHostFiniteStepIndex, 0, sizeof(PlsrHostFiniteStepIndex)); (void)memset(PlsrHostFiniteBoundaryReadIndex, 0, sizeof(PlsrHostFiniteBoundaryReadIndex)); (void)memset(PlsrHostFiniteCompletedStepCount, 0, sizeof(PlsrHostFiniteCompletedStepCount)); return 1U; } uint8_t PlsrPlatformPrepare(uint8_t pulseOutput, uint8_t directionOutput, uint8_t directionLevel, uint8_t outputMode, uint8_t directionPositive) { uint8_t index; uint8_t pinLevel; if (PlsrHostFailNextStart != 0U) { PlsrHostFailNextStart = 0U; return 0U; } if ((pulseOutput > 3U) || (directionOutput > 3U) || (outputMode > PLSR_OUTPUT_AB) || ((outputMode == PLSR_OUTPUT_AB) && ((pulseOutput & 1U) != 0U)) || (PlsrHostAbStopPending[0] != 0U) || (PlsrHostAbStopPending[2] != 0U)) { return 0U; } for (index = 0U; index < 4U; index++) { PlsrHostPulseActive[index] = 0U; PlsrHostFrequency[index] = 0UL; PlsrHostQueuedFrequency[index] = 0UL; PlsrHostUpdatePending[index] = 0U; pinLevel = ((outputMode == PLSR_OUTPUT_PULSE_DIR) && (index == directionOutput) && (directionLevel != 0U)) ? 0U : 1U; PlsrHostDirectionWriteCount[index]++; if (PlsrHostDirectionPinLevel[index] != pinLevel) { PlsrHostDirectionTransitionCount[index]++; } PlsrHostDirectionPinLevel[index] = pinLevel; } PlsrHostSelectedPulse = pulseOutput; PlsrHostDirectionLevel = (directionLevel != 0U) ? 1U : 0U; PlsrHostOutputMode[pulseOutput] = outputMode; PlsrHostDirectionPositive[pulseOutput] = (directionPositive != 0U) ? 1U : 0U; PlsrHostAbQuarter[pulseOutput] = 0U; PlsrHostAbPhase[pulseOutput] = 0U; PlsrHostAbFastGated[pulseOutput] = 0U; return 1U; } uint8_t PlsrPlatformStartPulse(uint8_t pulseOutput, uint32_t firstFrequencyHz, uint32_t queuedFrequencyHz, uint32_t *actualFirstFrequencyHz, uint32_t *actualQueuedFrequencyHz) { PLSR_PLATFORM_TIMER_SETTING firstSetting; PLSR_PLATFORM_TIMER_SETTING queuedSetting; if ((pulseOutput > 3U) || (PlsrPlatformBuildTimerSetting( pulseOutput, PlsrHostOutputMode[pulseOutput], firstFrequencyHz, &firstSetting) == 0U) || (PlsrPlatformBuildTimerSetting( pulseOutput, PlsrHostOutputMode[pulseOutput], queuedFrequencyHz, &queuedSetting) == 0U)) { return 0U; } return PlsrPlatformStartPrepared(pulseOutput, &firstSetting, &queuedSetting, actualFirstFrequencyHz, actualQueuedFrequencyHz); } uint8_t PlsrPlatformBuildTimerSetting( uint8_t pulseOutput, uint8_t outputMode, uint32_t requestedFrequencyHz, PLSR_PLATFORM_TIMER_SETTING *setting) { if ((pulseOutput > 3U) || (outputMode > PLSR_OUTPUT_AB) || ((outputMode == PLSR_OUTPUT_AB) && ((pulseOutput & 1U) != 0U)) || (requestedFrequencyHz == 0UL) || (requestedFrequencyHz > PLSR_FREQUENCY_MAX_HZ) || (setting == NULL)) { return 0U; } setting->actualFrequencyHz = requestedFrequencyHz; setting->prescaler = (outputMode == PLSR_OUTPUT_AB) ? 1U : 0U; setting->pairPrescaler = 0U; setting->period = (outputMode == PLSR_OUTPUT_AB) ? 3U : 1U; setting->compare = (outputMode == PLSR_OUTPUT_AB) ? 2U : 1U; return 1U; } uint8_t PlsrPlatformStartPrepared( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *firstSetting, const PLSR_PLATFORM_TIMER_SETTING *queuedSetting, uint32_t *actualFirstFrequencyHz, uint32_t *actualQueuedFrequencyHz) { if ((pulseOutput > 3U) || (firstSetting == NULL) || (queuedSetting == NULL) || (actualFirstFrequencyHz == NULL) || (actualQueuedFrequencyHz == NULL) || (firstSetting->actualFrequencyHz == 0UL) || (firstSetting->actualFrequencyHz > PLSR_FREQUENCY_MAX_HZ) || (queuedSetting->actualFrequencyHz == 0UL) || (queuedSetting->actualFrequencyHz > PLSR_FREQUENCY_MAX_HZ) || (PlsrHostAbStopPending[pulseOutput] != 0U) || (PlsrHostAbFastGated[pulseOutput] != 0U)) { return 0U; } PlsrHostPulseActive[pulseOutput] = 1U; PlsrHostFrequency[pulseOutput] = firstSetting->actualFrequencyHz; PlsrHostQueuedFrequency[pulseOutput] = queuedSetting->actualFrequencyHz; PlsrHostActiveSetting[pulseOutput] = *firstSetting; PlsrHostQueuedSetting[pulseOutput] = *queuedSetting; PlsrHostUpdatePending[pulseOutput] = 0U; PlsrHostSelectedPulse = pulseOutput; *actualFirstFrequencyHz = firstSetting->actualFrequencyHz; *actualQueuedFrequencyHz = queuedSetting->actualFrequencyHz; return 1U; } uint8_t PlsrPlatformSupportsFinitePulseTrain(void) { return PlsrHostFiniteEnabled; } uint8_t PlsrPlatformStartFinitePrepared( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, uint32_t pulseCount, uint32_t *actualFrequencyHz) { if ((PlsrHostFiniteEnabled == 0U) || (pulseOutput > 3U) || (setting == NULL) || (pulseCount == 0UL) || (actualFrequencyHz == NULL) || (PlsrHostOutputMode[pulseOutput] != PLSR_OUTPUT_PULSE_DIR)) { return 0U; } PlsrHostPulseActive[pulseOutput] = 1U; PlsrHostFiniteActive[pulseOutput] = 1U; PlsrHostFiniteComplete[pulseOutput] = 0U; PlsrHostFiniteFrequencyPending[pulseOutput] = 0U; PlsrHostCountedStreamActive[pulseOutput] = 0U; PlsrHostFiniteTarget[pulseOutput] = pulseCount; PlsrHostFiniteEmitted[pulseOutput] = 0UL; PlsrHostFiniteStepCount[pulseOutput] = 0U; PlsrHostFiniteStepIndex[pulseOutput] = 0U; PlsrHostFiniteBoundaryReadIndex[pulseOutput] = 0U; PlsrHostFiniteCompletedStepCount[pulseOutput] = 0U; PlsrHostFrequency[pulseOutput] = setting->actualFrequencyHz; PlsrHostQueuedFrequency[pulseOutput] = setting->actualFrequencyHz; PlsrHostActiveSetting[pulseOutput] = *setting; PlsrHostQueuedSetting[pulseOutput] = *setting; PlsrHostSelectedPulse = pulseOutput; *actualFrequencyHz = setting->actualFrequencyHz; return 1U; } uint8_t PlsrPlatformStartCountedStreamPrepared( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, uint32_t pulseCount, uint32_t *actualFrequencyHz) { if (PlsrPlatformStartFinitePrepared(pulseOutput, setting, pulseCount, actualFrequencyHz) == 0U) { return 0U; } PlsrHostCountedStreamActive[pulseOutput] = 1U; return 1U; } uint8_t PlsrPlatformStartFiniteSequencePrepared( uint8_t pulseOutput, PLSR_PLATFORM_FINITE_STEP *steps, uint16_t stepCount, uint32_t *actualFrequencyHz) { if ((steps == NULL) || (stepCount == 0U) || (stepCount > PLSR_PLATFORM_FINITE_STEP_MAX) || (PlsrPlatformStartFinitePrepared( pulseOutput, &steps[0].setting, steps[0].pulseCount, actualFrequencyHz) == 0U)) { return 0U; } PlsrHostFiniteSteps[pulseOutput] = steps; PlsrHostFiniteStepCount[pulseOutput] = stepCount; PlsrHostFiniteStepIndex[pulseOutput] = 0U; PlsrHostFiniteBoundaryReadIndex[pulseOutput] = 0U; PlsrHostFiniteCompletedStepCount[pulseOutput] = 0U; return 1U; } PLSR_PLATFORM_QUEUE_RESULT PlsrPlatformUpdateFinitePrepared( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, uint32_t *actualFrequencyHz) { if (PlsrHostFailNextFrequencyAtUpdate != 0U) { PlsrHostFailNextFrequencyAtUpdate = 0U; return PLSR_PLATFORM_QUEUE_FAILED; } if ((pulseOutput > 3U) || (setting == NULL) || (actualFrequencyHz == NULL) || (PlsrHostFiniteActive[pulseOutput] == 0U)) { return PLSR_PLATFORM_QUEUE_STALE; } if (PlsrHostStaleNextFrequencyAtUpdate != 0U) { PlsrHostStaleNextFrequencyAtUpdate = 0U; return PLSR_PLATFORM_QUEUE_STALE; } if (PlsrHostFiniteFrequencyPending[pulseOutput] != 0U) { return PLSR_PLATFORM_QUEUE_STALE; } PlsrHostQueuedSetting[pulseOutput] = *setting; PlsrHostQueuedFrequency[pulseOutput] = setting->actualFrequencyHz; PlsrHostFiniteFrequencyPending[pulseOutput] = 1U; *actualFrequencyHz = setting->actualFrequencyHz; return PLSR_PLATFORM_QUEUE_APPLIED; } uint8_t PlsrPlatformRetargetFiniteStop(uint8_t pulseOutput, uint32_t drainPulses) { uint32_t completed; if ((pulseOutput > 3U) || (drainPulses == 0UL) || (PlsrHostFiniteActive[pulseOutput] == 0U)) { return 0U; } completed = PlsrHostFiniteEmitted[pulseOutput]; if (PlsrHostFiniteStepCount[pulseOutput] != 0U) { completed += PlsrHostFiniteSteps[pulseOutput][ PlsrHostFiniteStepIndex[pulseOutput]].segmentPulseOffset; } PlsrHostFiniteTarget[pulseOutput] = completed + drainPulses; PlsrHostFiniteEmitted[pulseOutput] = completed; PlsrHostFiniteStepCount[pulseOutput] = 0U; PlsrHostFiniteStepIndex[pulseOutput] = 0U; PlsrHostFiniteBoundaryReadIndex[pulseOutput] = 0U; PlsrHostFiniteCompletedStepCount[pulseOutput] = 0U; return 1U; } uint8_t PlsrPlatformRequestFiniteCut(uint8_t pulseOutput) { if ((pulseOutput > 3U) || (PlsrHostFiniteActive[pulseOutput] == 0U) || (PlsrHostCountedStreamActive[pulseOutput] == 0U)) { return 0U; } /* The host model has no half-pulse phase. Complete the cut at the current emitted boundary and publish the normal finite-completion event expected by the counted executor. */ PlsrHostFiniteTarget[pulseOutput] = PlsrHostFiniteEmitted[pulseOutput]; PlsrHostFiniteStepCount[pulseOutput] = 0U; PlsrHostFiniteStepIndex[pulseOutput] = 0U; PlsrHostFiniteBoundaryReadIndex[pulseOutput] = 0U; PlsrHostFiniteCompletedStepCount[pulseOutput] = 0U; PlsrHostFiniteActive[pulseOutput] = 0U; PlsrHostFiniteComplete[pulseOutput] = 1U; return 1U; } uint8_t PlsrPlatformFiniteRetargetReady(uint8_t pulseOutput, uint32_t *activeFrequencyHz) { if ((pulseOutput > 3U) || (activeFrequencyHz == NULL) || (PlsrHostFiniteActive[pulseOutput] == 0U)) { return 0U; } *activeFrequencyHz = PlsrHostFrequency[pulseOutput]; return (PlsrHostFiniteStepCount[pulseOutput] == 0U) ? 1U : 0U; } uint8_t PlsrPlatformFinitePipelineSnapshot(uint8_t pulseOutput, uint32_t *committedPulses, uint32_t *tailFrequencyHz, uint8_t *startsNextSegment) { uint32_t remaining; if ((pulseOutput > 3U) || (committedPulses == NULL) || (tailFrequencyHz == NULL) || (startsNextSegment == NULL) || (PlsrHostFiniteActive[pulseOutput] == 0U)) { return 0U; } remaining = PlsrHostFiniteTarget[pulseOutput] - PlsrHostFiniteEmitted[pulseOutput]; *committedPulses = remaining; *tailFrequencyHz = PlsrHostQueuedFrequency[pulseOutput]; *startsNextSegment = 0U; return 1U; } uint8_t PlsrPlatformFiniteProgress(uint8_t pulseOutput, uint32_t *completedPulses) { if ((pulseOutput > 3U) || (completedPulses == NULL) || ((PlsrHostFiniteActive[pulseOutput] == 0U) && (PlsrHostFiniteComplete[pulseOutput] == 0U))) { return 0U; } if (PlsrHostFiniteStepCount[pulseOutput] != 0U) { const PLSR_PLATFORM_FINITE_STEP *step = &PlsrHostFiniteSteps[pulseOutput][ PlsrHostFiniteStepIndex[pulseOutput]]; *completedPulses = step->segmentPulseOffset + PlsrHostFiniteEmitted[pulseOutput]; } else { *completedPulses = PlsrHostFiniteEmitted[pulseOutput]; } return 1U; } uint8_t PlsrPlatformTakeFiniteCompletion(uint8_t pulseOutput, uint32_t *completedPulses) { if ((pulseOutput > 3U) || (completedPulses == NULL) || (PlsrHostFiniteComplete[pulseOutput] == 0U)) { return 0U; } PlsrHostFiniteComplete[pulseOutput] = 0U; if (PlsrHostFiniteStepCount[pulseOutput] != 0U) { const PLSR_PLATFORM_FINITE_STEP *step = &PlsrHostFiniteSteps[pulseOutput][ PlsrHostFiniteStepCount[pulseOutput] - 1U]; *completedPulses = step->segmentPulseOffset + step->pulseCount; } else { *completedPulses = PlsrHostFiniteTarget[pulseOutput]; } return 1U; } uint8_t PlsrPlatformTakeFiniteBoundary(uint8_t pulseOutput, uint8_t *segmentNumber, uint32_t *completedPulses, uint8_t *sequenceContinues, uint32_t *activeFrequencyHz) { if ((pulseOutput > 3U) || (segmentNumber == NULL) || (completedPulses == NULL) || (sequenceContinues == NULL) || (activeFrequencyHz == NULL)) { return 0U; } while (PlsrHostFiniteBoundaryReadIndex[pulseOutput] < PlsrHostFiniteCompletedStepCount[pulseOutput]) { uint16_t index = PlsrHostFiniteBoundaryReadIndex[pulseOutput]++; const PLSR_PLATFORM_FINITE_STEP *step = &PlsrHostFiniteSteps[pulseOutput][index]; if (step->completesSegment != 0U) { *segmentNumber = step->segmentNumber; *completedPulses = step->segmentPulseOffset + step->pulseCount; *sequenceContinues = (index + 1U < PlsrHostFiniteStepCount[pulseOutput]) ? 1U : 0U; *activeFrequencyHz = (*sequenceContinues != 0U) ? PlsrHostFiniteSteps[pulseOutput][index + 1U] .setting.actualFrequencyHz : step->setting.actualFrequencyHz; return 1U; } } return 0U; } PLSR_PLATFORM_QUEUE_RESULT PlsrPlatformLoadPreparedFromIrq( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, uint32_t *actualFrequencyHz) { if (PlsrHostFailNextFrequencyAtUpdate != 0U) { PlsrHostFailNextFrequencyAtUpdate = 0U; return PLSR_PLATFORM_QUEUE_FAILED; } if ((pulseOutput > 3U) || (setting == NULL) || (actualFrequencyHz == NULL) || (setting->actualFrequencyHz == 0UL) || (setting->actualFrequencyHz > PLSR_FREQUENCY_MAX_HZ)) { return PLSR_PLATFORM_QUEUE_FAILED; } if (PlsrHostStaleNextFrequencyAtUpdate != 0U) { PlsrHostStaleNextFrequencyAtUpdate = 0U; return PLSR_PLATFORM_QUEUE_STALE; } if ((PlsrHostCompleteAbCycleOnQueueCommit != 0U) && (PlsrHostOutputMode[pulseOutput] == PLSR_OUTPUT_AB)) { PlsrHostCompleteAbCycleOnQueueCommit = 0U; PlsrTestEmitAbQuarters(4UL); } if ((PlsrHostPulseActive[pulseOutput] == 0U) || (PlsrHostAbStopPending[pulseOutput] != 0U) || (PlsrHostAbFastGated[pulseOutput] != 0U)) { return PLSR_PLATFORM_QUEUE_STALE; } PlsrHostQueuedSetting[pulseOutput] = *setting; PlsrHostQueuedFrequency[pulseOutput] = setting->actualFrequencyHz; *actualFrequencyHz = setting->actualFrequencyHz; return PLSR_PLATFORM_QUEUE_APPLIED; } void PlsrPlatformGateFromIrq(uint8_t pulseOutput) { if ((pulseOutput <= 3U) && (PlsrHostOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (PlsrHostAbFastGated[pulseOutput] != 0U)) { return; } PlsrPlatformStopPulse(pulseOutput); } PLSR_PLATFORM_QUEUE_RESULT PlsrPlatformQueueFrequency( uint8_t pulseOutput, uint32_t frequencyHz, uint32_t *actualFrequencyHz) { uint32_t criticalState; PLSR_PLATFORM_TIMER_SETTING setting; if (PlsrHostFailNextFrequencyAtUpdate != 0U) { PlsrHostFailNextFrequencyAtUpdate = 0U; return PLSR_PLATFORM_QUEUE_FAILED; } if ((pulseOutput > 3U) || (PlsrPlatformBuildTimerSetting( pulseOutput, PlsrHostOutputMode[pulseOutput], frequencyHz, &setting) == 0U) || (actualFrequencyHz == NULL) || (PlsrHostPulseActive[pulseOutput] == 0U) || (PlsrHostAbStopPending[pulseOutput] != 0U) || (PlsrHostAbFastGated[pulseOutput] != 0U)) { return PLSR_PLATFORM_QUEUE_FAILED; } if (PlsrHostStaleNextFrequencyAtUpdate != 0U) { PlsrHostStaleNextFrequencyAtUpdate = 0U; return PLSR_PLATFORM_QUEUE_STALE; } if ((PlsrHostCompleteAbCycleOnQueueCommit != 0U) && (PlsrHostOutputMode[pulseOutput] == PLSR_OUTPUT_AB)) { PlsrHostCompleteAbCycleOnQueueCommit = 0U; PlsrTestEmitAbQuarters(4UL); } criticalState = PlsrPlatformEnterCritical(); if ((PlsrHostPulseActive[pulseOutput] == 0U) || (PlsrHostAbStopPending[pulseOutput] != 0U) || (PlsrHostAbFastGated[pulseOutput] != 0U)) { PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_STALE; } PlsrHostQueuedFrequency[pulseOutput] = setting.actualFrequencyHz; PlsrHostQueuedSetting[pulseOutput] = setting; *actualFrequencyHz = setting.actualFrequencyHz; PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_APPLIED; } void PlsrPlatformDrainPendingPulse(uint8_t pulseOutput) { PlsrHostServicePendingPulse(pulseOutput); } uint32_t PlsrPlatformActiveFrequency(uint8_t pulseOutput) { if (pulseOutput > 3U) { return 0UL; } return (PlsrHostFrequencyOffsetHz != 0L) ? PlsrHostOffsetFrequency(PlsrHostFrequency[pulseOutput]) : PlsrHostFrequency[pulseOutput]; } uint8_t PlsrPlatformExpectedFrequency(uint8_t pulseOutput, uint8_t outputMode, uint32_t requestedFrequencyHz, uint32_t *actualFrequencyHz) { PLSR_PLATFORM_TIMER_SETTING setting; if (PlsrPlatformBuildTimerSetting(pulseOutput, outputMode, requestedFrequencyHz, &setting) == 0U) { return 0U; } *actualFrequencyHz = setting.actualFrequencyHz; return 1U; } uint64_t PlsrPlatformObservedPulses(uint8_t pulseOutput) { int64_t observed; if (pulseOutput > 3U) { return 0UL; } observed = (int64_t)PlsrHostObservedPulses[pulseOutput] + (int64_t)PlsrHostCountOffset; return (observed > 0) ? (uint64_t)observed : 0UL; } uint16_t PlsrPlatformDiagnosticFault(void) { uint16_t fault = PlsrHostDiagnosticFault; PlsrHostDiagnosticFault = 0U; return fault; } PLSR_PLATFORM_STOP_RESULT PlsrPlatformRequestStopLocked( uint8_t pulseOutput, uint8_t requireZeroBoundary) { if (pulseOutput > 3U) { return PLSR_PLATFORM_STOP_FORCED_FAULT; } if (PlsrHostFailNextStopRequest != 0U) { PlsrHostFailNextStopRequest = 0U; PlsrPlatformStopPulse(pulseOutput); return PLSR_PLATFORM_STOP_FORCED_FAULT; } if ((requireZeroBoundary != 0U) && (PlsrHostOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (PlsrHostPulseActive[pulseOutput] != 0U) && (PlsrHostAbFastGated[pulseOutput] == 0U)) { if (PlsrHostLatchAbFinalQuarterOnStopArm != 0U) { PlsrHostLatchAbFinalQuarterOnStopArm = 0U; (void)PlsrHostAdvanceAbQuarter(pulseOutput); } PlsrHostQueuedFrequency[pulseOutput] = PlsrHostFrequency[pulseOutput]; PlsrHostAbStopPending[pulseOutput] = 1U; return PLSR_PLATFORM_STOP_PENDING; } PlsrPlatformStopPulse(pulseOutput); return PLSR_PLATFORM_STOP_COMPLETE; } uint8_t PlsrPlatformQueueFinalArmFromIrq(uint8_t pulseOutput) { if ((pulseOutput > 2U) || ((pulseOutput & 1U) != 0U) || (PlsrHostOutputMode[pulseOutput] != PLSR_OUTPUT_AB) || (PlsrHostPulseActive[pulseOutput] == 0U) || (PlsrHostAbFastGated[pulseOutput] != 0U)) { return 0U; } PlsrHostFinalArmJobOwner = pulseOutput; PlsrHostFinalArmJobPending = 1U; return 1U; } void PlsrPlatformStopPulse(uint8_t pulseOutput) { if (pulseOutput <= 3U) { if ((PlsrHostOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && ((PlsrHostAbStopPending[pulseOutput] != 0U) || (PlsrHostAbFastGated[pulseOutput] != 0U))) { PlsrHostAbCleanupCount++; } PlsrHostPulseActive[pulseOutput] = 0U; PlsrHostFiniteActive[pulseOutput] = 0U; PlsrHostFiniteComplete[pulseOutput] = 0U; PlsrHostFrequency[pulseOutput] = 0UL; PlsrHostQueuedFrequency[pulseOutput] = 0UL; PlsrHostUpdatePending[pulseOutput] = 0U; PlsrHostAbQuarter[pulseOutput] = 0U; PlsrHostAbPhase[pulseOutput] = 0U; PlsrHostAbStopPending[pulseOutput] = 0U; PlsrHostAbFastGated[pulseOutput] = 0U; PlsrHostFrequencyOffsetHz = 0L; if (PlsrHostFinalArmJobOwner == pulseOutput) { PlsrHostFinalArmJobPending = 0U; PlsrHostFinalArmJobOwner = 0xFFU; } } } uint8_t PlsrPlatformReadInput(uint8_t inputSelection) { return (inputSelection <= 1U) ? PlsrHostInputs[inputSelection] : 0U; } uint8_t PlsrPlatformLoad(PLSR_PERSIST_PAYLOAD *payload) { if ((payload == NULL) || (PlsrHostPersistentValid == 0U)) { return 0U; } *payload = PlsrHostPersistentPayload; return 1U; } void PlsrPlatformForceSafeOutputsFromFault(void) { uint8_t index; for (index = 0U; index < 4U; index++) { PlsrPlatformStopPulse(index); } } PLSR_PLATFORM_SERVICE_RESULT PlsrPlatformServicePersistence(void) { return PLSR_PLATFORM_SERVICE_READY; } uint8_t PlsrPlatformSave(const PLSR_PERSIST_PAYLOAD *payload) { if (payload == NULL) { return 0U; } PlsrHostPersistentPayload = *payload; PlsrHostPersistentValid = 1U; PlsrHostSaveCount++; return 1U; } void PlsrPlatformCheckpointConfig(const PLSR_CONFIG *config) { if (config != NULL) { PlsrHostPersistentPayload.config = *config; PlsrHostPersistentValid = 1U; } } void PlsrPlatformCheckpointPosition(int32_t position, uint8_t positionValid, uint8_t wasBusy) { PlsrHostPersistentPayload.position = position; PlsrHostPersistentPayload.positionValid = positionValid; PlsrHostPersistentPayload.wasBusy = wasBusy; PlsrHostPersistentPayload.reserved = 0U; } uint32_t PlsrPlatformEnterCritical(void) { uint32_t previousDepth = PlsrHostCriticalDepth; if (PlsrHostEmitPulseOnCriticalEntry != 0U) { if (PlsrHostCriticalEntriesToSkip != 0U) { PlsrHostCriticalEntriesToSkip--; } else { PlsrHostEmitPulseOnCriticalEntry = 0U; PlsrHostLatchPulse(PlsrHostSelectedPulse); if (previousDepth == 0UL) { PlsrHostServicePendingPulse(PlsrHostSelectedPulse); } } } if (PlsrHostLatchPulseOnCriticalEntry != 0U) { PlsrHostLatchPulseOnCriticalEntry = 0U; PlsrHostLatchPulse(PlsrHostSelectedPulse); } PlsrHostCriticalDepth++; return previousDepth; } void PlsrPlatformExitCritical(uint32_t state) { (void)state; if (PlsrHostCriticalDepth != 0UL) { PlsrHostCriticalDepth--; } if (PlsrHostCriticalDepth != 0UL) { return; } if (PlsrHostEmitPulseOnCriticalExit != 0U) { PlsrHostEmitPulseOnCriticalExit = 0U; PlsrHostLatchPulse(PlsrHostSelectedPulse); } PlsrHostServicePendingPulse(PlsrHostSelectedPulse); } void PlsrTestSetInput(uint8_t inputSelection, uint8_t level) { if (inputSelection <= 1U) { PlsrHostInputs[inputSelection] = (level != 0U) ? 1U : 0U; } } void PlsrTestEmitPulses(uint32_t pulseCount) { if (PlsrHostFiniteActive[PlsrHostSelectedPulse] != 0U) { uint8_t pulseOutput = PlsrHostSelectedPulse; while ((pulseCount != 0UL) && (PlsrHostFiniteActive[pulseOutput] != 0U)) { uint32_t available = PlsrHostFiniteTarget[pulseOutput] - PlsrHostFiniteEmitted[pulseOutput]; uint32_t emitted = (pulseCount < available) ? pulseCount : available; if ((emitted != 0UL) && (PlsrHostFiniteFrequencyPending[pulseOutput] != 0U)) { PlsrHostActiveSetting[pulseOutput] = PlsrHostQueuedSetting[pulseOutput]; PlsrHostFrequency[pulseOutput] = PlsrHostQueuedFrequency[pulseOutput]; PlsrHostFiniteFrequencyPending[pulseOutput] = 0U; } PlsrHostFiniteEmitted[pulseOutput] += emitted; PlsrHostObservedPulses[pulseOutput] += emitted; pulseCount -= emitted; if (PlsrHostFiniteEmitted[pulseOutput] == PlsrHostFiniteTarget[pulseOutput]) { uint16_t index = PlsrHostFiniteStepIndex[pulseOutput]; uint8_t hasNext = (index + 1U < PlsrHostFiniteStepCount[pulseOutput]) ? 1U : 0U; if (PlsrHostFiniteStepCount[pulseOutput] != 0U) { PlsrHostFiniteCompletedStepCount[pulseOutput] = (uint16_t)(index + 1U); } if (hasNext != 0U) { const PLSR_PLATFORM_FINITE_STEP *next = &PlsrHostFiniteSteps[pulseOutput][index + 1U]; PlsrHostFiniteStepIndex[pulseOutput]++; PlsrHostFiniteTarget[pulseOutput] = next->pulseCount; PlsrHostFiniteEmitted[pulseOutput] = 0UL; PlsrHostFrequency[pulseOutput] = next->setting.actualFrequencyHz; PlsrHostQueuedFrequency[pulseOutput] = next->setting.actualFrequencyHz; PlsrHostActiveSetting[pulseOutput] = next->setting; PlsrHostQueuedSetting[pulseOutput] = next->setting; PlsrHostFiniteFrequencyPending[pulseOutput] = 0U; } else { PlsrHostFiniteActive[pulseOutput] = 0U; PlsrHostFiniteComplete[pulseOutput] = 1U; PlsrHostPulseActive[pulseOutput] = 0U; PlsrHostFiniteFrequencyPending[pulseOutput] = 0U; PlsrHostFrequency[pulseOutput] = 0UL; PlsrHostQueuedFrequency[pulseOutput] = 0UL; } } } return; } if (PlsrHostOutputMode[PlsrHostSelectedPulse] == PLSR_OUTPUT_AB) { while ((pulseCount != 0UL) && (PlsrHostPulseActive[PlsrHostSelectedPulse] != 0U)) { PlsrTestEmitAbQuarters(4UL); pulseCount--; } return; } while ((pulseCount != 0UL) && (PlsrHostPulseActive[PlsrHostSelectedPulse] != 0U)) { PlsrHostLatchPulse(PlsrHostSelectedPulse); PlsrHostServicePendingPulse(PlsrHostSelectedPulse); pulseCount--; } } void PlsrTestEnableFinitePulseTrain(uint8_t enable) { PlsrHostFiniteEnabled = (enable != 0U) ? 1U : 0U; } void PlsrTestCompleteFinitePulseTrain(void) { uint8_t pulseOutput = PlsrHostSelectedPulse; if ((PlsrHostFiniteActive[pulseOutput] != 0U) && (PlsrHostPulseActive[pulseOutput] != 0U)) { uint32_t remaining = PlsrHostFiniteTarget[pulseOutput] - PlsrHostFiniteEmitted[pulseOutput]; PlsrHostFiniteEmitted[pulseOutput] += remaining; PlsrHostObservedPulses[pulseOutput] += remaining; PlsrHostFiniteActive[pulseOutput] = 0U; PlsrHostFiniteComplete[pulseOutput] = 1U; PlsrHostPulseActive[pulseOutput] = 0U; PlsrHostFrequency[pulseOutput] = 0UL; PlsrHostQueuedFrequency[pulseOutput] = 0UL; } } uint8_t PlsrTestFinitePulseTrainActive(void) { return PlsrHostFiniteActive[PlsrHostSelectedPulse]; } void PlsrTestEmitPulseOnCriticalEntry(void) { PlsrHostCriticalEntriesToSkip = 0U; PlsrHostEmitPulseOnCriticalEntry = 1U; } void PlsrTestEmitPulseAfterCriticalEntries(uint8_t entriesToSkip) { PlsrHostCriticalEntriesToSkip = entriesToSkip; PlsrHostEmitPulseOnCriticalEntry = 1U; } void PlsrTestEmitPulseOnCriticalExit(void) { PlsrHostEmitPulseOnCriticalExit = 1U; } void PlsrTestLatchPulseOnCriticalEntry(void) { PlsrHostLatchPulseOnCriticalEntry = 1U; } void PlsrTestLatchAbFinalQuarterOnNextStopArm(void) { PlsrHostLatchAbFinalQuarterOnStopArm = 1U; } void PlsrTestCompleteAbCycleOnNextQueueCommit(void) { PlsrHostCompleteAbCycleOnQueueCommit = 1U; } void PlsrTestServicePendingPulse(void) { PlsrHostServicePendingPulse(PlsrHostSelectedPulse); } void PlsrTestFailNextStart(void) { PlsrHostFailNextStart = 1U; } void PlsrTestServiceFinalArmJob(void) { PlsrHostServiceFinalArmJob(); } void PlsrTestDeferFinalArmJob(uint8_t defer) { PlsrHostDeferFinalArmJob = (defer != 0U) ? 1U : 0U; if (PlsrHostDeferFinalArmJob == 0U) { PlsrHostServiceFinalArmJob(); } } void PlsrTestStaleNextFrequencyAtUpdate(void) { PlsrHostStaleNextFrequencyAtUpdate = 1U; } void PlsrTestFailNextFrequencyAtUpdate(void) { PlsrHostFailNextFrequencyAtUpdate = 1U; } void PlsrTestFailNextStopRequest(void) { PlsrHostFailNextStopRequest = 1U; } void PlsrTestEmitAbQuarters(uint32_t quarterCount) { uint8_t pulseOutput = PlsrHostSelectedPulse; while ((quarterCount != 0UL) && (PlsrHostPulseActive[pulseOutput] != 0U) && (PlsrHostOutputMode[pulseOutput] == PLSR_OUTPUT_AB)) { if (PlsrHostAdvanceAbQuarter(pulseOutput) != 0U) { PlsrHostServicePendingPulse(pulseOutput); } quarterCount--; } } uint8_t PlsrTestPulseIsActive(void) { return PlsrHostPulseActive[PlsrHostSelectedPulse]; } uint32_t PlsrTestOutputFrequency(void) { return PlsrHostFrequency[PlsrHostSelectedPulse]; } uint32_t PlsrTestQueuedFrequency(void) { return PlsrHostQueuedFrequency[PlsrHostSelectedPulse]; } uint8_t PlsrTestDirectionLevel(void) { return PlsrHostDirectionLevel; } uint8_t PlsrTestDirectionPinLevel(uint8_t directionOutput) { return (directionOutput < 4U) ? PlsrHostDirectionPinLevel[directionOutput] : 0U; } uint32_t PlsrTestDirectionWriteCount(uint8_t directionOutput) { return (directionOutput < 4U) ? PlsrHostDirectionWriteCount[directionOutput] : 0UL; } uint32_t PlsrTestDirectionTransitionCount(uint8_t directionOutput) { return (directionOutput < 4U) ? PlsrHostDirectionTransitionCount[directionOutput] : 0UL; } uint8_t PlsrTestAbPhase(void) { return PlsrHostAbPhase[PlsrHostSelectedPulse]; } uint32_t PlsrTestAbTransitionCount(void) { return PlsrHostAbTransitions[PlsrHostSelectedPulse]; } uint32_t PlsrTestAbFastGateCount(void) { return PlsrHostAbFastGateCount; } uint32_t PlsrTestAbCleanupCount(void) { return PlsrHostAbCleanupCount; } void PlsrTestInjectCountOffset(int32_t offset) { PlsrHostCountOffset = offset; } void PlsrTestInjectActiveFrequencyOffset(int32_t offsetHz) { PlsrHostFrequencyOffsetHz = offsetHz; PlsrHostDiagnosticFault = 2U; } void PlsrTestInjectCurveMismatch(void) { PlsrHostCurveMismatchPending = 1U; } void PlsrTestClearPersistentStorage(void) { (void)memset(&PlsrHostPersistentPayload, 0, sizeof(PlsrHostPersistentPayload)); (void)memset(PlsrHostInputs, 0, sizeof(PlsrHostInputs)); PlsrHostPersistentValid = 0U; PlsrHostSaveCount = 0UL; PlsrHostCountOffset = 0L; PlsrHostFrequencyOffsetHz = 0L; PlsrHostCurveMismatchPending = 0U; PlsrHostDiagnosticFault = 0U; } void PlsrTestResetSaveCount(void) { PlsrHostSaveCount = 0UL; } uint32_t PlsrTestSaveCount(void) { return PlsrHostSaveCount; } uint8_t PlsrTestFlashNeedsStartupRecovery( uint8_t haveValidRecord, uint8_t sectorAHasProgrammedSlot, uint32_t sectorAFirstErasedAddress, uint8_t sectorBHasProgrammedSlot, uint32_t sectorBFirstErasedAddress) { return PlsrFlashNeedsStartupRecovery( haveValidRecord, sectorAHasProgrammedSlot, sectorAFirstErasedAddress, sectorBHasProgrammedSlot, sectorBFirstErasedAddress); } #else #include "stm32f4xx_hal.h" #include #include #ifndef PLSR_DEBUG_TIMING #define PLSR_DEBUG_TIMING (0U) #endif #define PLSR_FLASH_SLOT_A_ADDRESS (0x080C0000UL) #define PLSR_FLASH_SLOT_B_ADDRESS (0x080E0000UL) #define PLSR_FLASH_SECTOR_SIZE (0x00020000UL) #define PLSR_FLASH_MAGIC (0x50534C52UL) #define PLSR_FLASH_VERSION_V2 (2U) #define PLSR_FLASH_VERSION (3U) #define PLSR_BACKUP_CONFIG_ADDRESS (BKPSRAM_BASE + 0x0100UL) #define PLSR_BACKUP_POSITION_ADDRESS (BKPSRAM_BASE + 0x0200UL) #define PLSR_BACKUP_CONFIG_MAGIC (0x50434647UL) #define PLSR_BACKUP_POSITION_MAGIC (0x50504F53UL) #define PLSR_CONFIG_V2_SIZE (offsetof(PLSR_CONFIG, outputMode)) #define PLSR_COUNTER_COUNT (2U) #define PLSR_COUNTER_NONE (0xFFU) #define PLSR_COUNTER_BLOCK_PULSES (65536UL) #define PLSR_PLATFORM_FAULT_FREQUENCY (2U) #define PLSR_PLATFORM_FAULT_CURVE (3U) #define PLSR_TIMER_OC1_MODE_MASK (7UL << TIM_CCMR1_OC1M_Pos) #define PLSR_TIMER_PWM1_MODE (6UL << TIM_CCMR1_OC1M_Pos) #define PLSR_STRUCTURE_VERIFY_INTERVAL (64U) #define PLSR_FREQUENCY_VERIFY_NONE (0U) #define PLSR_FREQUENCY_VERIFY_NOW (1U) #define PLSR_FREQUENCY_VERIFY_AB_AUX_IRQ (2U) #define PLSR_QUEUE_WRITE_GUARD_COUNTS (64UL) #define PLSR_FINITE_WRITE_GUARD_COUNTS (128UL) #define PLSR_FLASH_ERASE_NONE (0U) #define PLSR_FLASH_ERASE_SECTOR_A (1U) #define PLSR_FLASH_ERASE_SECTOR_B (2U) #define PLSR_FLASH_ERASE_FAILED (3U) typedef struct { TIM_TypeDef *timer; GPIO_TypeDef *port; uint16_t pin; uint8_t pinIndex; uint8_t alternate; IRQn_Type irq; uint32_t timerClockHz; } PLSR_TIMER_MAP; typedef struct { GPIO_TypeDef *port; uint16_t pin; } PLSR_GPIO_MAP; typedef struct { uint32_t prescaler; uint32_t period; uint32_t compare; uint32_t actualFrequencyHz; } PLSR_TIMER_SETTING; typedef struct { uint32_t basePrescaler; uint32_t pairPrescaler; uint32_t period; uint32_t compare; uint32_t actualFrequencyHz; } PLSR_AB_SETTING; typedef struct { uint32_t cr1; uint32_t ccmr1; uint32_t ccer; uint32_t psc; uint32_t arr; uint32_t ccr1; } PLSR_TIMER_SNAPSHOT; typedef struct { uint32_t magic; uint16_t version; uint16_t payloadSize; uint32_t generation; } PLSR_FLASH_HEADER; typedef struct { uint8_t config[PLSR_CONFIG_V2_SIZE]; int32_t position; uint8_t positionValid; uint8_t wasBusy; uint16_t reserved; } PLSR_PERSIST_PAYLOAD_V2; typedef struct { uint32_t magic; uint16_t version; uint16_t payloadSize; uint32_t generation; PLSR_PERSIST_PAYLOAD payload; uint32_t crc32; } PLSR_FLASH_RECORD; typedef struct { uint32_t magic; uint16_t version; uint16_t payloadSize; uint32_t generation; PLSR_PERSIST_PAYLOAD_V2 payload; uint32_t crc32; } PLSR_FLASH_RECORD_V2; #define PLSR_FLASH_RECORD_STRIDE \ ((uint32_t)sizeof(PLSR_FLASH_RECORD)) #define PLSR_FLASH_SLOT_COUNT \ (PLSR_FLASH_SECTOR_SIZE / PLSR_FLASH_RECORD_STRIDE) typedef char PLSR_FLASH_RECORD_SIZE_MUST_BE_228[ (sizeof(PLSR_FLASH_RECORD) == 228U) ? 1 : -1]; typedef struct { const PLSR_FLASH_HEADER *newest; uint32_t firstErasedAddress; uint8_t newestVersion; uint8_t hasProgrammedSlot; } PLSR_FLASH_SECTOR_SCAN; typedef struct { uint32_t magic; PLSR_CONFIG config; uint32_t crc32; } PLSR_BACKUP_CONFIG_RECORD; typedef struct { uint32_t magic; uint8_t config[PLSR_CONFIG_V2_SIZE]; uint32_t crc32; } PLSR_BACKUP_CONFIG_RECORD_V2; typedef struct { uint32_t magic; uint32_t generation; int32_t position; uint8_t positionValid; uint8_t wasBusy; uint16_t reserved; uint32_t crc32; } PLSR_BACKUP_POSITION_RECORD; static const PLSR_TIMER_MAP PlsrTimerMap[4] = { {TIM10, GPIOF, GPIO_PIN_6, 6U, GPIO_AF3_TIM10, TIM1_UP_TIM10_IRQn, 168000000UL}, {TIM13, GPIOF, GPIO_PIN_8, 8U, GPIO_AF9_TIM13, TIM8_UP_TIM13_IRQn, 84000000UL}, {TIM11, GPIOF, GPIO_PIN_7, 7U, GPIO_AF3_TIM11, TIM1_TRG_COM_TIM11_IRQn, 168000000UL}, {TIM14, GPIOF, GPIO_PIN_9, 9U, GPIO_AF9_TIM14, TIM8_TRG_COM_TIM14_IRQn, 84000000UL} }; static const PLSR_GPIO_MAP PlsrDirectionMap[4] = { {GPIOH, GPIO_PIN_9}, {GPIOH, GPIO_PIN_8}, {GPIOH, GPIO_PIN_7}, {GPIOH, GPIO_PIN_6} }; static PLSR_FLASH_RECORD PlsrFlashRecordBuffer; static uint32_t PlsrFlashNewestAddress; static uint32_t PlsrFlashNewestGeneration; static uint32_t PlsrFlashNextErasedAddress[2]; static uint8_t PlsrFlashJournalInitialized; static uint8_t PlsrFlashReserveEraseState; static uint32_t PlsrBackupPositionGeneration; static uint32_t PlsrTimerActiveFrequencyHz[4]; static uint32_t PlsrTimerQueuedFrequencyHz[4]; static PLSR_PLATFORM_TIMER_SETTING PlsrTimerActiveSetting[4]; static PLSR_PLATFORM_TIMER_SETTING PlsrTimerQueuedSetting[4]; static uint32_t PlsrTimerQueueGeneration[4]; static uint8_t PlsrTimerOutputMode[4]; static uint8_t PlsrTimerDirectionPositive[4]; static uint8_t PlsrTimerRunning[4]; static uint8_t PlsrFrequencyVerifyPending[4]; static uint8_t PlsrFrequencyVerifyPulseCount[4]; static volatile uint8_t PlsrDeferredPulsePending[4]; static volatile uint8_t PlsrAbVerifyOwner[4]; static volatile uint8_t PlsrAbFinalArmJobOwner[4]; static uint8_t PlsrTimerIrqActive[4]; static PLSR_AB_SETTING PlsrAbActiveSetting[4]; static PLSR_AB_SETTING PlsrAbPendingSetting[4]; static uint8_t PlsrAbFrequencyPending[4]; static uint8_t PlsrAbLagAxis[4]; static uint8_t PlsrAbStructureVerified[4]; static uint8_t PlsrAbCounterSourceAxis[4]; static uint32_t PlsrAbCounterBoundary[4]; static volatile uint8_t PlsrAbStopPending[4]; static volatile uint8_t PlsrAbFastGated[4]; static TIM_TypeDef * const PlsrCounters[PLSR_COUNTER_COUNT] = { TIM9, TIM12 }; static uint8_t PlsrCounterOwner[PLSR_COUNTER_COUNT]; static volatile uint64_t PlsrCounterOverflowPulses[PLSR_COUNTER_COUNT]; static uint8_t PlsrCounterIndexByOutput[4]; static uint64_t PlsrObservedPulseBase[4]; static uint64_t PlsrObservedPulsePublished[4]; static volatile uint8_t PlsrFiniteActive[4]; static volatile uint8_t PlsrFiniteCompletionPending[4]; static volatile uint8_t PlsrFiniteFrequencyPending[4]; static volatile uint8_t PlsrFiniteRetargetPending[4]; static volatile uint8_t PlsrFiniteTailStopPending[4]; static uint32_t PlsrFiniteRetargetDrainPulses[4]; static uint32_t PlsrFiniteTargetPulses[4]; static uint32_t PlsrFiniteRemainingPulses[4]; static uint8_t PlsrFiniteCounterPreload[4]; static volatile uint8_t PlsrFiniteStreamActive[4]; static volatile uint8_t PlsrFiniteStreamNextValid[4]; static volatile uint8_t PlsrFiniteStreamNextStartsSegment[4]; static volatile uint8_t PlsrFiniteStreamSourceDone[4]; static volatile uint8_t PlsrFiniteStreamSourceFault[4]; static uint32_t PlsrFiniteStreamNextPulses[4]; static PLSR_PLATFORM_TIMER_SETTING PlsrFiniteStreamNextSetting[4]; static PLSR_PLATFORM_FINITE_STEP *PlsrFiniteSteps[4]; static volatile uint16_t PlsrFiniteStepCount[4]; static volatile uint16_t PlsrFiniteStepIndex[4]; static volatile uint16_t PlsrFiniteBoundaryReadIndex[4]; static volatile uint16_t PlsrFiniteCompletedStepCount[4]; static volatile uint16_t PlsrPlatformFaultPending; static void PlsrHandleTimerIrq(uint8_t pulseOutput); static void PlsrCounterSuspend(uint8_t pulseOutput); static void PlsrAbFastGate(uint8_t pulseOutput); static void PlsrFiniteCounterIrq(uint8_t pulseOutput, TIM_TypeDef *counter); static void PlsrFinitePrepareNextStepIrq(uint8_t pulseOutput, TIM_TypeDef *counter); 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 uint8_t PlsrFinalArmJobOutput(uint8_t pulseOutput) { return (pulseOutput == 0U) ? 2U : 0U; } #if PLSR_DEBUG_TIMING volatile uint32_t PlsrIrqCount[4]; volatile uint32_t PlsrIrqLastCycles[4]; volatile uint32_t PlsrIrqMaxCycles[4]; volatile uint32_t PlsrFinalArmQueueCount[4]; volatile uint32_t PlsrFinalArmJobLastCycles[4]; volatile uint32_t PlsrFinalArmJobMaxCycles[4]; volatile uint32_t PlsrFinalArmQueueToStopLastCycles[4]; volatile uint32_t PlsrFinalArmQueueToStopMaxCycles[4]; volatile uint32_t PlsrFiniteBlockIrqCount[4]; volatile uint32_t PlsrFiniteBlockIrqMaxCycles[4]; volatile uint32_t PlsrFiniteFinalIrqLastCycles[4]; volatile uint32_t PlsrFiniteFinalIrqMaxCycles[4]; volatile uint32_t PlsrAbReloadCounterBefore[4]; volatile uint32_t PlsrAbReloadCounterArmed[4]; volatile uint32_t PlsrAbReloadCounterStarted[4]; volatile uint32_t PlsrAbReloadCount[4]; static volatile uint32_t PlsrFinalArmQueuedAt[4]; static volatile uint8_t PlsrFinalArmQueueTimingPending[4]; #endif static uint32_t PlsrCrc32(const void *data, uint32_t length) { const uint8_t *bytes = (const uint8_t *)data; uint32_t crc = 0xFFFFFFFFUL; uint32_t index; uint8_t bit; for (index = 0UL; index < length; index++) { crc ^= bytes[index]; for (bit = 0U; bit < 8U; bit++) { crc = ((crc & 1UL) != 0UL) ? ((crc >> 1U) ^ 0xEDB88320UL) : (crc >> 1U); } } return ~crc; } static uint8_t PlsrGenerationIsNewer(uint32_t first, uint32_t second) { return ((int32_t)(first - second) > 0) ? 1U : 0U; } static uint32_t PlsrFlashRecordCrc(const void *record, uint32_t payloadSize) { const PLSR_FLASH_HEADER *header = (const PLSR_FLASH_HEADER *)record; const uint8_t *start = (const uint8_t *)&header->version; uint32_t length = (uint32_t)(sizeof(header->version) + sizeof(header->payloadSize) + sizeof(header->generation)) + payloadSize; return PlsrCrc32(start, length); } static uint8_t PlsrFlashRecordVersion(const void *address) { const PLSR_FLASH_HEADER *header = (const PLSR_FLASH_HEADER *)address; if (header->magic != PLSR_FLASH_MAGIC) { return 0U; } if ((header->version == PLSR_FLASH_VERSION) && (header->payloadSize == sizeof(PLSR_PERSIST_PAYLOAD))) { const PLSR_FLASH_RECORD *record = (const PLSR_FLASH_RECORD *)address; return (record->crc32 == PlsrFlashRecordCrc(record, sizeof(record->payload))) ? PLSR_FLASH_VERSION : 0U; } if ((header->version == PLSR_FLASH_VERSION_V2) && (header->payloadSize == sizeof(PLSR_PERSIST_PAYLOAD_V2))) { const PLSR_FLASH_RECORD_V2 *record = (const PLSR_FLASH_RECORD_V2 *)address; return (record->crc32 == PlsrFlashRecordCrc(record, sizeof(record->payload))) ? PLSR_FLASH_VERSION_V2 : 0U; } return 0U; } static uint8_t PlsrFlashSlotIsErased(uint32_t address) { const uint32_t *words = (const uint32_t *)address; uint32_t index; for (index = 0UL; index < (PLSR_FLASH_RECORD_STRIDE / sizeof(uint32_t)); index++) { if (words[index] != 0xFFFFFFFFUL) { return 0U; } } return 1U; } static uint8_t PlsrFlashSectorIsErased(uint32_t address) { const uint32_t *words = (const uint32_t *)address; uint32_t index; for (index = 0UL; index < (PLSR_FLASH_SECTOR_SIZE / sizeof(uint32_t)); index++) { if (words[index] != 0xFFFFFFFFUL) { return 0U; } } return 1U; } static void PlsrFlashScanSector(uint32_t sectorAddress, PLSR_FLASH_SECTOR_SCAN *scan) { uint32_t index; (void)memset(scan, 0, sizeof(*scan)); for (index = 0UL; index < PLSR_FLASH_SLOT_COUNT; index++) { uint32_t slotAddress = sectorAddress + index * PLSR_FLASH_RECORD_STRIDE; const PLSR_FLASH_HEADER *header = (const PLSR_FLASH_HEADER *)slotAddress; uint8_t version = PlsrFlashRecordVersion(header); uint8_t erased = PlsrFlashSlotIsErased(slotAddress); if ((version != 0U) && ((scan->newest == NULL) || (PlsrGenerationIsNewer(header->generation, scan->newest->generation) != 0U))) { scan->newest = header; scan->newestVersion = version; } if ((scan->firstErasedAddress == 0UL) && (erased != 0U)) { scan->firstErasedAddress = slotAddress; } if (erased == 0U) { scan->hasProgrammedSlot = 1U; } } for (index = PLSR_FLASH_SLOT_COUNT * PLSR_FLASH_RECORD_STRIDE; index < PLSR_FLASH_SECTOR_SIZE; index += sizeof(uint32_t)) { if (*(const uint32_t *)(sectorAddress + index) != 0xFFFFFFFFUL) { scan->hasProgrammedSlot = 1U; } } } static const PLSR_FLASH_HEADER *PlsrFlashSelectNewest( const PLSR_FLASH_SECTOR_SCAN *scanA, const PLSR_FLASH_SECTOR_SCAN *scanB, uint8_t *version, uint32_t *sectorAddress) { const PLSR_FLASH_SECTOR_SCAN *selectedScan; if (scanA->newest == NULL) { selectedScan = (scanB->newest != NULL) ? scanB : NULL; } else if ((scanB->newest != NULL) && (PlsrGenerationIsNewer(scanB->newest->generation, scanA->newest->generation) != 0U)) { selectedScan = scanB; } else { selectedScan = scanA; } if (selectedScan == NULL) { *version = 0U; *sectorAddress = 0UL; return NULL; } *version = selectedScan->newestVersion; *sectorAddress = (selectedScan == scanA) ? PLSR_FLASH_SLOT_A_ADDRESS : PLSR_FLASH_SLOT_B_ADDRESS; return selectedScan->newest; } static const PLSR_FLASH_HEADER *PlsrFlashInitializeJournal( PLSR_FLASH_SECTOR_SCAN *scanA, PLSR_FLASH_SECTOR_SCAN *scanB, uint8_t *version, uint32_t *sectorAddress) { const PLSR_FLASH_HEADER *newest; PlsrFlashScanSector(PLSR_FLASH_SLOT_A_ADDRESS, scanA); PlsrFlashScanSector(PLSR_FLASH_SLOT_B_ADDRESS, scanB); newest = PlsrFlashSelectNewest(scanA, scanB, version, sectorAddress); PlsrFlashNextErasedAddress[0] = scanA->firstErasedAddress; PlsrFlashNextErasedAddress[1] = scanB->firstErasedAddress; PlsrFlashNewestAddress = (uint32_t)newest; PlsrFlashNewestGeneration = (newest != NULL) ? newest->generation : 0UL; PlsrFlashJournalInitialized = 1U; return newest; } static uint8_t PlsrFlashSectorIndex(uint32_t address) { return (address >= PLSR_FLASH_SLOT_B_ADDRESS) ? 1U : 0U; } static uint8_t PlsrFlashAddressIsJournalSlot(uint8_t sectorIndex, uint32_t address) { uint32_t sectorAddress = (sectorIndex == 0U) ? PLSR_FLASH_SLOT_A_ADDRESS : PLSR_FLASH_SLOT_B_ADDRESS; uint32_t offset; if ((address < sectorAddress) || (address >= sectorAddress + PLSR_FLASH_SECTOR_SIZE)) { return 0U; } offset = address - sectorAddress; return ((offset % PLSR_FLASH_RECORD_STRIDE) == 0UL) && ((offset / PLSR_FLASH_RECORD_STRIDE) < PLSR_FLASH_SLOT_COUNT) ? 1U : 0U; } static uint32_t PlsrFlashFindErasedAfter(uint8_t sectorIndex, uint32_t address) { uint32_t sectorAddress = (sectorIndex == 0U) ? PLSR_FLASH_SLOT_A_ADDRESS : PLSR_FLASH_SLOT_B_ADDRESS; uint32_t firstIndex = ((address - sectorAddress) / PLSR_FLASH_RECORD_STRIDE) + 1UL; uint32_t index; for (index = firstIndex; index < PLSR_FLASH_SLOT_COUNT; index++) { uint32_t slotAddress = sectorAddress + index * PLSR_FLASH_RECORD_STRIDE; if (PlsrFlashSlotIsErased(slotAddress) != 0U) { return slotAddress; } } return 0UL; } static uint8_t PlsrFlashEraseReserve(uint8_t sectorIndex) { FLASH_EraseInitTypeDef erase; uint32_t sectorError; HAL_StatusTypeDef status; if (HAL_FLASH_Unlock() != HAL_OK) { (void)HAL_FLASH_Lock(); return 0U; } __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); erase.TypeErase = FLASH_TYPEERASE_SECTORS; erase.VoltageRange = FLASH_VOLTAGE_RANGE_3; erase.Sector = (sectorIndex == 0U) ? FLASH_SECTOR_10 : FLASH_SECTOR_11; erase.NbSectors = 1U; status = HAL_FLASHEx_Erase(&erase, §orError); if ((status == HAL_OK) && (PlsrFlashSectorIsErased((sectorIndex == 0U) ? PLSR_FLASH_SLOT_A_ADDRESS : PLSR_FLASH_SLOT_B_ADDRESS) == 0U)) { status = HAL_ERROR; } if (HAL_FLASH_Lock() != HAL_OK) { (void)HAL_FLASH_Lock(); status = HAL_ERROR; } return (status == HAL_OK) ? 1U : 0U; } static uint8_t PlsrBackupConfigVersion(const void *address) { const PLSR_BACKUP_CONFIG_RECORD *record = (const PLSR_BACKUP_CONFIG_RECORD *)address; if (record->magic != PLSR_BACKUP_CONFIG_MAGIC) { return 0U; } if (record->crc32 == PlsrCrc32(&record->config, sizeof(record->config))) { return PLSR_FLASH_VERSION; } { const PLSR_BACKUP_CONFIG_RECORD_V2 *oldRecord = (const PLSR_BACKUP_CONFIG_RECORD_V2 *)address; return (oldRecord->crc32 == PlsrCrc32(oldRecord->config, sizeof(oldRecord->config))) ? PLSR_FLASH_VERSION_V2 : 0U; } } static void PlsrLoadV2Payload(PLSR_PERSIST_PAYLOAD *destination, const PLSR_PERSIST_PAYLOAD_V2 *source) { (void)memset(destination, 0, sizeof(*destination)); (void)memcpy(&destination->config, source->config, sizeof(source->config)); destination->config.outputMode = PLSR_OUTPUT_PULSE_DIR; destination->position = source->position; destination->positionValid = source->positionValid; destination->wasBusy = source->wasBusy; } static uint8_t PlsrBackupPositionIsValid( const PLSR_BACKUP_POSITION_RECORD *record) { uint32_t crc = PlsrCrc32(&record->generation, sizeof(record->generation) + sizeof(record->position) + sizeof(record->positionValid) + sizeof(record->wasBusy) + sizeof(record->reserved)); return ((record->magic == PLSR_BACKUP_POSITION_MAGIC) && (record->crc32 == crc)) ? 1U : 0U; } static const PLSR_BACKUP_POSITION_RECORD *PlsrNewestBackupPosition(void) { const PLSR_BACKUP_POSITION_RECORD *slots = (const PLSR_BACKUP_POSITION_RECORD *)PLSR_BACKUP_POSITION_ADDRESS; uint8_t validA = PlsrBackupPositionIsValid(&slots[0]); uint8_t validB = PlsrBackupPositionIsValid(&slots[1]); if ((validA == 0U) && (validB == 0U)) { return NULL; } if (validA == 0U) { return &slots[1]; } if (validB == 0U) { return &slots[0]; } return (PlsrGenerationIsNewer(slots[1].generation, slots[0].generation) != 0U) ? &slots[1] : &slots[0]; } static void PlsrTimerStop(TIM_TypeDef *timer) { timer->DIER &= ~(TIM_DIER_UIE | TIM_DIER_CC1IE); timer->CR1 &= ~TIM_CR1_CEN; timer->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); timer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); } static void PlsrTimerInitialize(TIM_TypeDef *timer) { timer->CR1 = TIM_CR1_ARPE | TIM_CR1_URS; timer->CR2 = 0UL; timer->SMCR = 0UL; timer->DIER = 0UL; timer->CCMR1 = TIM_CCMR1_OC1PE | (6UL << TIM_CCMR1_OC1M_Pos); timer->CCER = 0UL; timer->PSC = 0UL; timer->ARR = 999UL; timer->CCR1 = 500UL; timer->CNT = 0UL; timer->EGR = TIM_EGR_UG; timer->SR = 0UL; } static void PlsrPulsePinHoldIdle(uint8_t pulseOutput) { const PLSR_TIMER_MAP *map = &PlsrTimerMap[pulseOutput]; GPIO_InitTypeDef gpio; HAL_GPIO_WritePin(map->port, map->pin, GPIO_PIN_SET); gpio.Pin = map->pin; gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; gpio.Alternate = 0U; HAL_GPIO_Init(map->port, &gpio); } static void PlsrPulsePinCaptureIdle(uint8_t pulseOutput) { const PLSR_TIMER_MAP *map = &PlsrTimerMap[pulseOutput]; uint32_t shift = (uint32_t)map->pinIndex * 2UL; uint32_t mode = map->port->MODER; /* The update IRQ occurs while PWM is high; switch to GPIO high first. */ map->port->BSRR = map->pin; mode &= ~(3UL << shift); mode |= 1UL << shift; map->port->MODER = mode; __DSB(); } static void PlsrPulsePinRelease(uint8_t pulseOutput) { const PLSR_TIMER_MAP *map = &PlsrTimerMap[pulseOutput]; GPIO_InitTypeDef gpio; gpio.Pin = map->pin; gpio.Mode = GPIO_MODE_AF_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; gpio.Alternate = map->alternate; HAL_GPIO_Init(map->port, &gpio); __DSB(); } static uint8_t PlsrTimerCalculate(uint8_t pulseOutput, uint32_t frequencyHz, PLSR_TIMER_SETTING *setting) { const PLSR_TIMER_MAP *map; uint32_t prescalerDivider; uint32_t denominator; uint32_t periodCounts; if ((pulseOutput > 3U) || (frequencyHz == 0UL) || (frequencyHz > PLSR_FREQUENCY_MAX_HZ) || (setting == NULL)) { return 0U; } map = &PlsrTimerMap[pulseOutput]; prescalerDivider = (((map->timerClockHz - 1UL) / frequencyHz) >> 16U) + 1UL; if (prescalerDivider > 65536UL) { return 0U; } denominator = prescalerDivider * frequencyHz; periodCounts = (map->timerClockHz + denominator / 2UL) / denominator; if (periodCounts < 2UL) { periodCounts = 2UL; } if (periodCounts > 65536UL) { periodCounts = 65536UL; } setting->prescaler = prescalerDivider - 1UL; setting->period = periodCounts - 1UL; setting->compare = periodCounts / 2UL; denominator = prescalerDivider * periodCounts; setting->actualFrequencyHz = (map->timerClockHz + denominator / 2UL) / denominator; return 1U; } static void PlsrTimerWriteSetting(TIM_TypeDef *timer, const PLSR_TIMER_SETTING *setting) { timer->PSC = setting->prescaler; timer->ARR = setting->period; timer->CCR1 = setting->compare; } static void PlsrTimerSnapshot(TIM_TypeDef *timer, PLSR_TIMER_SNAPSHOT *snapshot) { snapshot->cr1 = timer->CR1; snapshot->ccmr1 = timer->CCMR1; snapshot->ccer = timer->CCER; snapshot->psc = timer->PSC; snapshot->arr = timer->ARR; snapshot->ccr1 = timer->CCR1; } static uint8_t PlsrAbCalculate(uint8_t pulseOutput, uint32_t frequencyHz, PLSR_AB_SETTING *setting) { const PLSR_TIMER_MAP *baseMap; const PLSR_TIMER_MAP *pairMap; uint64_t ratio; uint64_t pairDivider; uint64_t baseDivider; uint64_t periodCounts; if (((pulseOutput != 0U) && (pulseOutput != 2U)) || (frequencyHz == 0UL) || (frequencyHz > PLSR_FREQUENCY_MAX_HZ) || (setting == NULL)) { return 0U; } baseMap = &PlsrTimerMap[pulseOutput]; pairMap = &PlsrTimerMap[pulseOutput + 1U]; if ((pairMap->timerClockHz == 0UL) || ((baseMap->timerClockHz % pairMap->timerClockHz) != 0UL)) { return 0U; } ratio = baseMap->timerClockHz / pairMap->timerClockHz; pairDivider = ((uint64_t)pairMap->timerClockHz + (uint64_t)frequencyHz * 65536UL - 1UL) / ((uint64_t)frequencyHz * 65536UL); if (pairDivider == 0UL) { pairDivider = 1UL; } baseDivider = pairDivider * ratio; if ((pairDivider > 65536UL) || (baseDivider > 65536UL)) { return 0U; } periodCounts = ((uint64_t)pairMap->timerClockHz + ((uint64_t)frequencyHz * pairDivider) / 2UL) / ((uint64_t)frequencyHz * pairDivider); if ((periodCounts < 4UL) || (periodCounts > 65536UL)) { return 0U; } setting->basePrescaler = (uint32_t)(baseDivider - 1UL); setting->pairPrescaler = (uint32_t)(pairDivider - 1UL); setting->period = (uint32_t)(periodCounts - 1UL); setting->compare = (uint32_t)(periodCounts / 2UL); setting->actualFrequencyHz = (uint32_t)(((uint64_t)pairMap->timerClockHz + (pairDivider * periodCounts) / 2UL) / (pairDivider * periodCounts)); return 1U; } static void PlsrAbHoldPairIdle(uint8_t pulseOutput) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); GPIO_TypeDef *port = PlsrTimerMap[pulseOutput].port; uint32_t firstShift = (uint32_t)PlsrTimerMap[pulseOutput].pinIndex * 2UL; uint32_t secondShift = (uint32_t)PlsrTimerMap[pairOutput].pinIndex * 2UL; uint32_t mode = port->MODER; port->BSRR = (uint32_t)PlsrTimerMap[pulseOutput].pin | (uint32_t)PlsrTimerMap[pairOutput].pin; mode &= ~((3UL << firstShift) | (3UL << secondShift)); mode |= (1UL << firstShift) | (1UL << secondShift); port->MODER = mode; __DSB(); } static void PlsrAbReleasePair(uint8_t pulseOutput) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); GPIO_TypeDef *port = PlsrTimerMap[pulseOutput].port; uint32_t firstAfrIndex = (uint32_t)PlsrTimerMap[pulseOutput].pinIndex >> 3U; uint32_t secondAfrIndex = (uint32_t)PlsrTimerMap[pairOutput].pinIndex >> 3U; uint32_t firstAfrShift = ((uint32_t)PlsrTimerMap[pulseOutput].pinIndex & 7UL) * 4UL; uint32_t secondAfrShift = ((uint32_t)PlsrTimerMap[pairOutput].pinIndex & 7UL) * 4UL; uint32_t firstShift = (uint32_t)PlsrTimerMap[pulseOutput].pinIndex * 2UL; uint32_t secondShift = (uint32_t)PlsrTimerMap[pairOutput].pinIndex * 2UL; uint32_t alternate; uint32_t mode = port->MODER; alternate = port->AFR[firstAfrIndex]; alternate &= ~(0xFUL << firstAfrShift); alternate |= (uint32_t)PlsrTimerMap[pulseOutput].alternate << firstAfrShift; port->AFR[firstAfrIndex] = alternate; alternate = port->AFR[secondAfrIndex]; alternate &= ~(0xFUL << secondAfrShift); alternate |= (uint32_t)PlsrTimerMap[pairOutput].alternate << secondAfrShift; port->AFR[secondAfrIndex] = alternate; mode &= ~((3UL << firstShift) | (3UL << secondShift)); mode |= (2UL << firstShift) | (2UL << secondShift); port->MODER = mode; __DSB(); } static uint8_t PlsrAbStructureIsRunnable( uint8_t pulseOutput, const PLSR_TIMER_SNAPSHOT *base, const PLSR_TIMER_SNAPSHOT *pair) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); uint8_t lagOutput = PlsrAbLagAxis[pulseOutput]; return ((((base->cr1 & TIM_CR1_CEN) != 0UL) && ((pair->cr1 & TIM_CR1_CEN) != 0UL) && ((base->ccer & TIM_CCER_CC1E) != 0UL) && ((pair->ccer & TIM_CCER_CC1E) != 0UL) && ((base->ccer & TIM_CCER_CC1P) != 0UL) && ((pair->ccer & TIM_CCER_CC1P) != 0UL) && ((base->ccmr1 & PLSR_TIMER_OC1_MODE_MASK) == PLSR_TIMER_PWM1_MODE) && ((pair->ccmr1 & PLSR_TIMER_OC1_MODE_MASK) == PLSR_TIMER_PWM1_MODE) && (base->arr == pair->arr) && (base->ccr1 == pair->ccr1) && (base->ccr1 == ((base->arr + 1UL) / 2UL)) && ((base->psc + 1UL) == 2UL * (pair->psc + 1UL)) && ((lagOutput == pulseOutput) || (lagOutput == pairOutput))) ? 1U : 0U); } static uint8_t PlsrAbTimersAreRunnable(uint8_t pulseOutput, TIM_TypeDef *baseTimer, TIM_TypeDef *pairTimer) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); uint8_t lagOutput = PlsrAbLagAxis[pulseOutput]; uint32_t baseCr1 = baseTimer->CR1; uint32_t pairCr1 = pairTimer->CR1; uint32_t baseCcer = baseTimer->CCER; uint32_t pairCcer = pairTimer->CCER; uint32_t baseCcmr1 = baseTimer->CCMR1; uint32_t pairCcmr1 = pairTimer->CCMR1; uint32_t basePsc = baseTimer->PSC; uint32_t pairPsc = pairTimer->PSC; uint32_t baseCcr1 = baseTimer->CCR1; uint32_t pairCcr1 = pairTimer->CCR1; uint32_t baseArr = baseTimer->ARR; uint32_t pairArr = pairTimer->ARR; return (((((baseCr1 & TIM_CR1_CEN) != 0UL) && ((pairCr1 & TIM_CR1_CEN) != 0UL) && ((baseCcer & (TIM_CCER_CC1E | TIM_CCER_CC1P)) == (TIM_CCER_CC1E | TIM_CCER_CC1P)) && ((pairCcer & (TIM_CCER_CC1E | TIM_CCER_CC1P)) == (TIM_CCER_CC1E | TIM_CCER_CC1P)) && ((baseCcmr1 & PLSR_TIMER_OC1_MODE_MASK) == PLSR_TIMER_PWM1_MODE) && ((pairCcmr1 & PLSR_TIMER_OC1_MODE_MASK) == PLSR_TIMER_PWM1_MODE) && (baseArr == pairArr) && (baseCcr1 == pairCcr1) && (baseCcr1 == ((baseArr + 1UL) / 2UL)) && ((basePsc + 1UL) == 2UL * (pairPsc + 1UL)) && ((lagOutput == pulseOutput) || (lagOutput == pairOutput))) ? 1U : 0U)); } static uint8_t PlsrAbStopBoundaryIsReachable( uint8_t pulseOutput, TIM_TypeDef *baseTimer, TIM_TypeDef *pairTimer) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); uint8_t lagOutput = PlsrAbLagAxis[pulseOutput]; uint32_t baseCr1 = baseTimer->CR1; uint32_t pairCr1 = pairTimer->CR1; uint32_t baseCcer = baseTimer->CCER; uint32_t pairCcer = pairTimer->CCER; uint32_t baseCcr1 = baseTimer->CCR1; uint32_t pairCcr1 = pairTimer->CCR1; uint32_t baseArr = baseTimer->ARR; uint32_t pairArr = pairTimer->ARR; return (((((baseCr1 & TIM_CR1_CEN) != 0UL) && ((pairCr1 & TIM_CR1_CEN) != 0UL) && ((baseCcer & TIM_CCER_CC1E) != 0UL) && ((pairCcer & TIM_CCER_CC1E) != 0UL) && (baseCcr1 <= baseArr) && (pairCcr1 <= pairArr) && ((lagOutput == pulseOutput) || (lagOutput == pairOutput))) ? 1U : 0U)); } static void PlsrAbFastGate(uint8_t pulseOutput) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); TIM_TypeDef *baseTimer = PlsrTimerMap[pulseOutput].timer; TIM_TypeDef *pairTimer = PlsrTimerMap[pairOutput].timer; PlsrAbStructureVerified[pulseOutput] = 0U; baseTimer->CR1 &= ~TIM_CR1_CEN; pairTimer->CR1 &= ~TIM_CR1_CEN; PlsrCounterSuspend(pulseOutput); __DMB(); } #if defined(__ICCARM__) #pragma inline=never #endif static void PlsrAbEnableTimerPair(TIM_TypeDef *firstTimer, uint32_t firstCr1, TIM_TypeDef *secondTimer, uint32_t secondCr1) { firstTimer->CR1 = firstCr1; secondTimer->CR1 = secondCr1; } static uint8_t PlsrAbCanFastGateAtZero(uint8_t pulseOutput) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); TIM_TypeDef *baseTimer = PlsrTimerMap[pulseOutput].timer; TIM_TypeDef *pairTimer = PlsrTimerMap[pairOutput].timer; uint32_t baseCr1 = baseTimer->CR1; uint32_t pairCr1 = pairTimer->CR1; uint32_t baseCcer = baseTimer->CCER; uint32_t pairCcer = pairTimer->CCER; uint32_t baseCcr = baseTimer->CCR1; uint32_t pairCcr = pairTimer->CCR1; uint32_t baseCnt = baseTimer->CNT; uint32_t pairCnt = pairTimer->CNT; return ((((baseCr1 & TIM_CR1_CEN) != 0UL) && ((pairCr1 & TIM_CR1_CEN) != 0UL) && ((baseCcer & TIM_CCER_CC1E) != 0UL) && ((pairCcer & TIM_CCER_CC1E) != 0UL) && (baseCnt >= baseCcr) && (pairCnt >= pairCcr)) ? 1U : 0U); } static uint8_t PlsrCounterIndex(uint8_t pulseOutput, uint8_t outputMode) { return (outputMode == PLSR_OUTPUT_AB) ? (uint8_t)(pulseOutput >> 1U) : (uint8_t)(pulseOutput & 1U); } static uint64_t PlsrCounterCurrentRaw(uint8_t pulseOutput) { uint8_t index = PlsrCounterIndexByOutput[pulseOutput]; TIM_TypeDef *counter; uint64_t overflowBefore; uint64_t overflowAfter; uint32_t statusBefore; uint32_t statusAfter; uint32_t count; if (index >= PLSR_COUNTER_COUNT) { return 0UL; } counter = PlsrCounters[index]; for (;;) { overflowBefore = PlsrCounterOverflowPulses[index]; statusBefore = counter->SR & TIM_SR_UIF; count = (uint16_t)counter->CNT; statusAfter = counter->SR & TIM_SR_UIF; overflowAfter = PlsrCounterOverflowPulses[index]; if ((overflowBefore == overflowAfter) && (statusBefore == statusAfter)) { if (statusAfter != 0UL) { overflowAfter += PLSR_COUNTER_BLOCK_PULSES; } return overflowAfter + count; } } } static uint64_t PlsrCounterSnapshot(uint8_t pulseOutput) { uint64_t current = PlsrCounterCurrentRaw(pulseOutput); uint64_t observed; if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (current > 0UL)) { uint8_t sourceAxis = PlsrAbCounterSourceAxis[pulseOutput]; uint8_t attempt; for (attempt = 0U; attempt < 2U; attempt++) { uint64_t verified; current = PlsrCounterCurrentRaw(pulseOutput); if (sourceAxis <= 3U) { uint32_t sourceCount = PlsrTimerMap[sourceAxis].timer->CNT; verified = PlsrCounterCurrentRaw(pulseOutput); if (current == verified) { if ((sourceCount < PlsrAbCounterBoundary[pulseOutput]) && (current > 0UL)) { current--; } break; } current = verified; } } } observed = PlsrObservedPulseBase[pulseOutput] + current; if (observed < PlsrObservedPulsePublished[pulseOutput]) { observed = PlsrObservedPulsePublished[pulseOutput]; } else { PlsrObservedPulsePublished[pulseOutput] = observed; } return observed; } static uint64_t PlsrCounterSnapshotStopped(uint8_t pulseOutput) { uint8_t index = PlsrCounterIndexByOutput[pulseOutput]; TIM_TypeDef *counter = PlsrCounters[index]; uint64_t current = PlsrCounterOverflowPulses[index]; uint64_t observed; current += (uint16_t)counter->CNT; if ((counter->SR & TIM_SR_UIF) != 0UL) { current += PLSR_COUNTER_BLOCK_PULSES; } if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (current > 0UL)) { uint8_t sourceAxis = PlsrAbCounterSourceAxis[pulseOutput]; if ((sourceAxis <= 3U) && (PlsrTimerMap[sourceAxis].timer->CNT < PlsrAbCounterBoundary[pulseOutput])) { current--; } } observed = PlsrObservedPulseBase[pulseOutput] + current; if (observed < PlsrObservedPulsePublished[pulseOutput]) { observed = PlsrObservedPulsePublished[pulseOutput]; } else { PlsrObservedPulsePublished[pulseOutput] = observed; } return observed; } static void PlsrCounterStop(uint8_t pulseOutput) { uint8_t index = PlsrCounterIndexByOutput[pulseOutput]; if (index < PLSR_COUNTER_COUNT) { TIM_TypeDef *counter = PlsrCounters[index]; if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (PlsrAbFastGated[pulseOutput] != 0U)) { PlsrObservedPulseBase[pulseOutput] = PlsrCounterSnapshotStopped(pulseOutput); } else { PlsrCounterSuspend(pulseOutput); PlsrObservedPulseBase[pulseOutput] = PlsrCounterSnapshot(pulseOutput); } PlsrObservedPulsePublished[pulseOutput] = PlsrObservedPulseBase[pulseOutput]; counter->CR1 = 0UL; counter->DIER = 0UL; counter->SMCR = 0UL; counter->SR = 0UL; if (PlsrCounterOwner[index] == pulseOutput) { PlsrCounterOwner[index] = PLSR_COUNTER_NONE; } } PlsrCounterIndexByOutput[pulseOutput] = PLSR_COUNTER_NONE; } static uint8_t PlsrCounterConfigure(uint8_t pulseOutput, uint8_t outputMode) { uint8_t index = PlsrCounterIndex(pulseOutput, outputMode); TIM_TypeDef *counter = PlsrCounters[index]; uint32_t triggerSelection = ((pulseOutput & 2U) == 0U) ? TIM_SMCR_TS_1 : (TIM_SMCR_TS_1 | TIM_SMCR_TS_0); PlsrCounterStop(pulseOutput); if ((PlsrCounterOwner[index] != PLSR_COUNTER_NONE) && (PlsrCounterOwner[index] != pulseOutput)) { return 0U; } PlsrCounterOwner[index] = pulseOutput; PlsrCounterIndexByOutput[pulseOutput] = index; PlsrCounterOverflowPulses[index] = 0UL; counter->CR1 = 0UL; counter->DIER = 0UL; counter->SMCR = 0UL; counter->PSC = 0UL; counter->ARR = 0xFFFFUL; counter->CNT = 0UL; counter->EGR = TIM_EGR_UG; counter->SR = 0UL; /* RM0090 table 101 routes TIM10/11/13/14 OC directly to ITR2/3. */ counter->SMCR = triggerSelection; counter->DIER = TIM_DIER_UIE; return 1U; } static void PlsrCounterBegin(uint8_t pulseOutput) { uint8_t index = PlsrCounterIndexByOutput[pulseOutput]; if (index < PLSR_COUNTER_COUNT) { TIM_TypeDef *counter = PlsrCounters[index]; counter->SMCR |= TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0; counter->CR1 |= TIM_CR1_CEN; } } static void PlsrCounterSuspend(uint8_t pulseOutput) { uint8_t index = PlsrCounterIndexByOutput[pulseOutput]; if (index < PLSR_COUNTER_COUNT) { PlsrCounters[index]->CR1 &= ~TIM_CR1_CEN; PlsrCounters[index]->SMCR &= ~(TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0); } } static void PlsrAbLoadAndStart(uint8_t pulseOutput, const PLSR_AB_SETTING *setting) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); uint8_t leadOutput = (PlsrTimerDirectionPositive[pulseOutput] != 0U) ? pulseOutput : pairOutput; uint8_t lagOutput = (leadOutput == pulseOutput) ? pairOutput : pulseOutput; TIM_TypeDef *baseTimer = PlsrTimerMap[pulseOutput].timer; TIM_TypeDef *pairTimer = PlsrTimerMap[pairOutput].timer; TIM_TypeDef *counterSourceTimer; TIM_TypeDef *otherTimer; uint32_t periodCounts = setting->period + 1UL; uint32_t leadStart = (periodCounts * 3UL) / 4UL + 1UL; uint32_t lagStart = periodCounts / 2UL + 1UL; uint32_t counterSourceCr1; uint32_t otherCr1; #if PLSR_DEBUG_TIMING uint8_t debugCounterIndex = PlsrCounterIndexByOutput[pulseOutput]; uint8_t debugReload = PlsrTimerRunning[pulseOutput]; if ((debugReload != 0U) && (debugCounterIndex < PLSR_COUNTER_COUNT)) { PlsrAbReloadCounterBefore[pulseOutput] = (uint16_t)PlsrCounters[debugCounterIndex]->CNT; PlsrAbReloadCount[pulseOutput]++; } #endif if (leadStart >= periodCounts) { leadStart = periodCounts - 1UL; } if (lagStart >= periodCounts) { lagStart = periodCounts - 1UL; } PlsrAbStructureVerified[pulseOutput] = 0U; PlsrAbLagAxis[pulseOutput] = lagOutput; PlsrAbCounterSourceAxis[pulseOutput] = (pulseOutput == 0U) ? pulseOutput : pairOutput; PlsrAbCounterBoundary[pulseOutput] = (PlsrAbCounterSourceAxis[pulseOutput] == leadOutput) ? (leadStart - 1UL) : (periodCounts / 2UL); PlsrCounterSuspend(pulseOutput); baseTimer->CR1 &= ~TIM_CR1_CEN; pairTimer->CR1 &= ~TIM_CR1_CEN; PlsrAbHoldPairIdle(pulseOutput); baseTimer->CCER &= ~TIM_CCER_CC1E; pairTimer->CCER &= ~TIM_CCER_CC1E; baseTimer->DIER = 0UL; pairTimer->DIER = 0UL; baseTimer->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1PE; pairTimer->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1PE; baseTimer->PSC = setting->basePrescaler; pairTimer->PSC = setting->pairPrescaler; baseTimer->ARR = setting->period; pairTimer->ARR = setting->period; baseTimer->CCR1 = setting->compare; pairTimer->CCR1 = setting->compare; baseTimer->CR1 = TIM_CR1_ARPE | TIM_CR1_URS; pairTimer->CR1 = TIM_CR1_ARPE | TIM_CR1_URS; baseTimer->EGR = TIM_EGR_UG; pairTimer->EGR = TIM_EGR_UG; baseTimer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); pairTimer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); PlsrTimerMap[leadOutput].timer->CNT = leadStart; PlsrTimerMap[lagOutput].timer->CNT = lagStart; baseTimer->CCER = (baseTimer->CCER & ~(TIM_CCER_CC1P | TIM_CCER_CC1E)) | TIM_CCER_CC1P | TIM_CCER_CC1E; pairTimer->CCER = (pairTimer->CCER & ~(TIM_CCER_CC1P | TIM_CCER_CC1E)) | TIM_CCER_CC1P | TIM_CCER_CC1E; PlsrAbReleasePair(pulseOutput); baseTimer->CCMR1 = TIM_CCMR1_OC1PE | (6UL << TIM_CCMR1_OC1M_Pos); pairTimer->CCMR1 = TIM_CCMR1_OC1PE | (6UL << TIM_CCMR1_OC1M_Pos); PlsrCounterBegin(pulseOutput); #if PLSR_DEBUG_TIMING if ((debugReload != 0U) && (debugCounterIndex < PLSR_COUNTER_COUNT)) { PlsrAbReloadCounterArmed[pulseOutput] = (uint16_t)PlsrCounters[debugCounterIndex]->CNT; } #endif counterSourceTimer = PlsrTimerMap[PlsrAbCounterSourceAxis[pulseOutput]].timer; otherTimer = PlsrTimerMap[(PlsrAbCounterSourceAxis[pulseOutput] == pulseOutput) ? pairOutput : pulseOutput].timer; counterSourceCr1 = counterSourceTimer->CR1 | TIM_CR1_CEN; otherCr1 = otherTimer->CR1 | TIM_CR1_CEN; PlsrAbEnableTimerPair(counterSourceTimer, counterSourceCr1, otherTimer, otherCr1); #if PLSR_DEBUG_TIMING if ((debugReload != 0U) && (debugCounterIndex < PLSR_COUNTER_COUNT)) { __DSB(); PlsrAbReloadCounterStarted[pulseOutput] = (uint16_t)PlsrCounters[debugCounterIndex]->CNT; } #endif baseTimer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); pairTimer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); PlsrTimerMap[lagOutput].timer->DIER |= TIM_DIER_CC1IE; __DMB(); } static void PlsrAbScheduleFrequencyVerify(uint8_t pulseOutput) { uint8_t verifyOutput = (PlsrAbLagAxis[pulseOutput] == pulseOutput) ? (uint8_t)(pulseOutput + 1U) : pulseOutput; TIM_TypeDef *verifyTimer = PlsrTimerMap[verifyOutput].timer; PlsrFrequencyVerifyPending[pulseOutput] = PLSR_FREQUENCY_VERIFY_AB_AUX_IRQ; PlsrAbVerifyOwner[verifyOutput] = pulseOutput; verifyTimer->SR = ~TIM_SR_UIF; verifyTimer->DIER |= TIM_DIER_UIE; if (PlsrDeferredPulsePending[pulseOutput] != 0U) { verifyTimer->SR = ~TIM_SR_CC1IF; verifyTimer->DIER |= TIM_DIER_CC1IE; } __DMB(); } static uint32_t PlsrFrequencyFromSnapshot( uint8_t pulseOutput, const PLSR_TIMER_SNAPSHOT *snapshot) { uint64_t divider = ((uint64_t)snapshot->psc + 1UL) * ((uint64_t)snapshot->arr + 1UL); if (divider == 0UL) { return 0UL; } return (uint32_t)(((uint64_t)PlsrTimerMap[pulseOutput].timerClockHz + divider / 2UL) / divider); } static uint32_t PlsrVerifyActiveFrequency(uint8_t pulseOutput) { TIM_TypeDef *baseTimer = PlsrTimerMap[pulseOutput].timer; PLSR_TIMER_SNAPSHOT baseSnapshot; uint32_t activeFrequency = PlsrTimerActiveFrequencyHz[pulseOutput]; PlsrTimerSnapshot(baseTimer, &baseSnapshot); if (PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); TIM_TypeDef *pairTimer = PlsrTimerMap[pairOutput].timer; PLSR_TIMER_SNAPSHOT pairSnapshot; uint8_t structureValid; PlsrTimerSnapshot(pairTimer, &pairSnapshot); structureValid = PlsrAbStructureIsRunnable( pulseOutput, &baseSnapshot, &pairSnapshot); PlsrAbStructureVerified[pulseOutput] = structureValid; if (structureValid == 0U) { PlsrPlatformFaultPending = PLSR_PLATFORM_FAULT_CURVE; } if ((baseSnapshot.psc != PlsrAbActiveSetting[pulseOutput].basePrescaler) || (pairSnapshot.psc != PlsrAbActiveSetting[pulseOutput].pairPrescaler) || (baseSnapshot.arr != PlsrAbActiveSetting[pulseOutput].period) || (pairSnapshot.arr != PlsrAbActiveSetting[pulseOutput].period) || (baseSnapshot.ccr1 != PlsrAbActiveSetting[pulseOutput].compare) || (pairSnapshot.ccr1 != PlsrAbActiveSetting[pulseOutput].compare)) { activeFrequency = PlsrFrequencyFromSnapshot(pairOutput, &pairSnapshot); if (PlsrPlatformFaultPending != PLSR_PLATFORM_FAULT_CURVE) { PlsrPlatformFaultPending = PLSR_PLATFORM_FAULT_FREQUENCY; } } } else { uint8_t structureValid = ((((baseSnapshot.cr1 & TIM_CR1_CEN) != 0UL) && ((baseSnapshot.ccer & TIM_CCER_CC1E) != 0UL) && ((baseSnapshot.ccer & TIM_CCER_CC1P) == 0UL) && ((baseSnapshot.ccmr1 & PLSR_TIMER_OC1_MODE_MASK) == PLSR_TIMER_PWM1_MODE) && (baseSnapshot.ccr1 == ((baseSnapshot.arr + 1UL) / 2UL))) ? 1U : 0U); if (structureValid == 0U) { PlsrPlatformFaultPending = PLSR_PLATFORM_FAULT_CURVE; } if ((baseSnapshot.psc != PlsrTimerQueuedSetting[pulseOutput].prescaler) || (baseSnapshot.arr != PlsrTimerQueuedSetting[pulseOutput].period) || (baseSnapshot.ccr1 != PlsrTimerQueuedSetting[pulseOutput].compare)) { activeFrequency = PlsrFrequencyFromSnapshot(pulseOutput, &baseSnapshot); if (PlsrPlatformFaultPending != PLSR_PLATFORM_FAULT_CURVE) { PlsrPlatformFaultPending = PLSR_PLATFORM_FAULT_FREQUENCY; } } } if (activeFrequency == 0UL) { PlsrPlatformFaultPending = PLSR_PLATFORM_FAULT_FREQUENCY; } return activeFrequency; } uint8_t PlsrPlatformInit(void) { GPIO_InitTypeDef gpio; uint8_t index; const PLSR_BACKUP_POSITION_RECORD *positionRecord; PlsrFlashReserveEraseState = PLSR_FLASH_ERASE_NONE; __HAL_RCC_GPIOB_CLK_ENABLE(); __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(); __HAL_RCC_TIM14_CLK_ENABLE(); __HAL_RCC_TIM9_CLK_ENABLE(); __HAL_RCC_TIM12_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWR_EnableBkUpAccess(); __HAL_RCC_BKPSRAM_CLK_ENABLE(); if (HAL_PWREx_EnableBkUpReg() != HAL_OK) { return 0U; } #if PLSR_DEBUG_TIMING CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0UL; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; (void)memset((void *)PlsrIrqCount, 0, sizeof(PlsrIrqCount)); (void)memset((void *)PlsrIrqLastCycles, 0, sizeof(PlsrIrqLastCycles)); (void)memset((void *)PlsrIrqMaxCycles, 0, sizeof(PlsrIrqMaxCycles)); (void)memset((void *)PlsrFinalArmQueueCount, 0, sizeof(PlsrFinalArmQueueCount)); (void)memset((void *)PlsrFinalArmJobLastCycles, 0, sizeof(PlsrFinalArmJobLastCycles)); (void)memset((void *)PlsrFinalArmJobMaxCycles, 0, sizeof(PlsrFinalArmJobMaxCycles)); (void)memset((void *)PlsrFinalArmQueueToStopLastCycles, 0, sizeof(PlsrFinalArmQueueToStopLastCycles)); (void)memset((void *)PlsrFinalArmQueueToStopMaxCycles, 0, sizeof(PlsrFinalArmQueueToStopMaxCycles)); (void)memset((void *)PlsrFinalArmQueuedAt, 0, sizeof(PlsrFinalArmQueuedAt)); (void)memset((void *)PlsrFinalArmQueueTimingPending, 0, sizeof(PlsrFinalArmQueueTimingPending)); #endif HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9, GPIO_PIN_SET); gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9; gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_HIGH; gpio.Alternate = 0U; HAL_GPIO_Init(GPIOH, &gpio); gpio.Mode = GPIO_MODE_IT_RISING; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_LOW; gpio.Alternate = 0U; gpio.Pin = GPIO_PIN_5; 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++) { PlsrTimerActiveFrequencyHz[index] = 0UL; PlsrTimerQueuedFrequencyHz[index] = 0UL; (void)memset(&PlsrTimerActiveSetting[index], 0, sizeof(PlsrTimerActiveSetting[index])); (void)memset(&PlsrTimerQueuedSetting[index], 0, sizeof(PlsrTimerQueuedSetting[index])); PlsrTimerQueueGeneration[index] = 0UL; PlsrTimerOutputMode[index] = PLSR_OUTPUT_PULSE_DIR; PlsrTimerDirectionPositive[index] = 1U; PlsrTimerRunning[index] = 0U; PlsrFrequencyVerifyPending[index] = 0U; PlsrFrequencyVerifyPulseCount[index] = 0U; PlsrDeferredPulsePending[index] = 0U; PlsrAbVerifyOwner[index] = PLSR_COUNTER_NONE; PlsrAbFinalArmJobOwner[index] = PLSR_COUNTER_NONE; PlsrTimerIrqActive[index] = 0U; PlsrAbFrequencyPending[index] = 0U; PlsrAbLagAxis[index] = PLSR_COUNTER_NONE; PlsrAbStructureVerified[index] = 0U; PlsrAbCounterSourceAxis[index] = PLSR_COUNTER_NONE; PlsrAbCounterBoundary[index] = 0UL; PlsrAbStopPending[index] = 0U; PlsrAbFastGated[index] = 0U; PlsrCounterIndexByOutput[index] = PLSR_COUNTER_NONE; PlsrObservedPulseBase[index] = 0UL; PlsrObservedPulsePublished[index] = 0UL; PlsrFiniteActive[index] = 0U; PlsrFiniteCompletionPending[index] = 0U; PlsrFiniteFrequencyPending[index] = 0U; PlsrFiniteRetargetPending[index] = 0U; PlsrFiniteTailStopPending[index] = 0U; PlsrFiniteRetargetDrainPulses[index] = 0UL; PlsrFiniteTargetPulses[index] = 0UL; PlsrFiniteRemainingPulses[index] = 0UL; PlsrFiniteCounterPreload[index] = 0U; PlsrFiniteStepCount[index] = 0U; PlsrFiniteStepIndex[index] = 0U; PlsrFiniteBoundaryReadIndex[index] = 0U; PlsrFiniteCompletedStepCount[index] = 0U; PlsrTimerInitialize(PlsrTimerMap[index].timer); PlsrPulsePinHoldIdle(index); HAL_NVIC_SetPriority(PlsrTimerMap[index].irq, 0U, 0U); HAL_NVIC_EnableIRQ(PlsrTimerMap[index].irq); } for (index = 0U; index < PLSR_COUNTER_COUNT; index++) { PlsrCounterOwner[index] = PLSR_COUNTER_NONE; PlsrCounterOverflowPulses[index] = 0UL; PlsrCounters[index]->CR1 = 0UL; PlsrCounters[index]->DIER = 0UL; PlsrCounters[index]->SMCR = 0UL; PlsrCounters[index]->SR = 0UL; } PlsrPlatformFaultPending = 0U; HAL_NVIC_SetPriority(TIM1_BRK_TIM9_IRQn, 0U, 0U); HAL_NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn); HAL_NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 0U, 0U); HAL_NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn); positionRecord = PlsrNewestBackupPosition(); PlsrBackupPositionGeneration = (positionRecord == NULL) ? 0UL : positionRecord->generation; return 1U; } uint8_t PlsrPlatformPrepare(uint8_t pulseOutput, uint8_t directionOutput, uint8_t directionLevel, uint8_t outputMode, uint8_t directionPositive) { uint8_t index; if ((pulseOutput > 3U) || (directionOutput > 3U) || (outputMode > PLSR_OUTPUT_AB) || ((outputMode == PLSR_OUTPUT_AB) && (pulseOutput != 0U) && (pulseOutput != 2U))) { return 0U; } if ((PlsrAbStopPending[0] != 0U) || (PlsrAbStopPending[2] != 0U)) { return 0U; } for (index = 0U; index < 4U; index++) { PlsrAbFinalArmJobOwner[index] = PLSR_COUNTER_NONE; NVIC_ClearPendingIRQ(PlsrTimerMap[index].irq); PlsrCounterStop(index); PlsrPulsePinHoldIdle(index); PlsrTimerStop(PlsrTimerMap[index].timer); HAL_GPIO_WritePin(PlsrDirectionMap[index].port, PlsrDirectionMap[index].pin, ((outputMode == PLSR_OUTPUT_PULSE_DIR) && (index == directionOutput) && (directionLevel != 0U)) ? GPIO_PIN_RESET : GPIO_PIN_SET); PlsrTimerRunning[index] = 0U; PlsrFrequencyVerifyPending[index] = 0U; PlsrFrequencyVerifyPulseCount[index] = 0U; PlsrDeferredPulsePending[index] = 0U; PlsrAbVerifyOwner[index] = PLSR_COUNTER_NONE; PlsrAbFrequencyPending[index] = 0U; PlsrAbStructureVerified[index] = 0U; PlsrAbFastGated[index] = 0U; } PlsrTimerOutputMode[pulseOutput] = outputMode; PlsrTimerDirectionPositive[pulseOutput] = (directionPositive != 0U) ? 1U : 0U; PlsrPlatformFaultPending = 0U; return 1U; } uint8_t PlsrPlatformStartPulse(uint8_t pulseOutput, uint32_t firstFrequencyHz, uint32_t queuedFrequencyHz, uint32_t *actualFirstFrequencyHz, uint32_t *actualQueuedFrequencyHz) { PLSR_PLATFORM_TIMER_SETTING firstSetting; PLSR_PLATFORM_TIMER_SETTING queuedSetting; if ((pulseOutput > 3U) || (PlsrPlatformBuildTimerSetting( pulseOutput, PlsrTimerOutputMode[pulseOutput], firstFrequencyHz, &firstSetting) == 0U) || (PlsrPlatformBuildTimerSetting( pulseOutput, PlsrTimerOutputMode[pulseOutput], queuedFrequencyHz, &queuedSetting) == 0U)) { return 0U; } return PlsrPlatformStartPrepared(pulseOutput, &firstSetting, &queuedSetting, actualFirstFrequencyHz, actualQueuedFrequencyHz); } static uint8_t PlsrPreparedSettingIsValid( uint8_t pulseOutput, uint8_t outputMode, const PLSR_PLATFORM_TIMER_SETTING *setting) { uint32_t periodCounts; if ((pulseOutput > 3U) || (setting == NULL) || (setting->actualFrequencyHz == 0UL) || (setting->actualFrequencyHz > PLSR_FREQUENCY_MAX_HZ)) { return 0U; } periodCounts = (uint32_t)setting->period + 1UL; if (setting->compare != (uint16_t)(periodCounts / 2UL)) { return 0U; } if (outputMode == PLSR_OUTPUT_PULSE_DIR) { return ((periodCounts >= 2UL) && (setting->pairPrescaler == 0U)) ? 1U : 0U; } if ((outputMode != PLSR_OUTPUT_AB) || ((pulseOutput & 1U) != 0U) || (periodCounts < 4UL)) { return 0U; } return ((((uint32_t)setting->prescaler + 1UL) == 2UL * ((uint32_t)setting->pairPrescaler + 1UL)) ? 1U : 0U); } static void PlsrPlatformToTimerSetting( const PLSR_PLATFORM_TIMER_SETTING *source, PLSR_TIMER_SETTING *destination) { destination->prescaler = source->prescaler; destination->period = source->period; destination->compare = source->compare; destination->actualFrequencyHz = source->actualFrequencyHz; } static void PlsrPlatformToAbSetting( const PLSR_PLATFORM_TIMER_SETTING *source, PLSR_AB_SETTING *destination) { destination->basePrescaler = source->prescaler; destination->pairPrescaler = source->pairPrescaler; destination->period = source->period; destination->compare = source->compare; destination->actualFrequencyHz = source->actualFrequencyHz; } static uint8_t PlsrPlatformSettingsDiffer( const PLSR_PLATFORM_TIMER_SETTING *first, const PLSR_PLATFORM_TIMER_SETTING *second) { return (((first->actualFrequencyHz != second->actualFrequencyHz) || (first->prescaler != second->prescaler) || (first->pairPrescaler != second->pairPrescaler) || (first->period != second->period) || (first->compare != second->compare)) ? 1U : 0U); } uint8_t PlsrPlatformBuildTimerSetting( uint8_t pulseOutput, uint8_t outputMode, uint32_t requestedFrequencyHz, PLSR_PLATFORM_TIMER_SETTING *setting) { PLSR_TIMER_SETTING timerSetting; PLSR_AB_SETTING abSetting; if (setting == NULL) { return 0U; } if (outputMode == PLSR_OUTPUT_AB) { if (PlsrAbCalculate(pulseOutput, requestedFrequencyHz, &abSetting) == 0U) { return 0U; } setting->actualFrequencyHz = abSetting.actualFrequencyHz; setting->prescaler = (uint16_t)abSetting.basePrescaler; setting->pairPrescaler = (uint16_t)abSetting.pairPrescaler; setting->period = (uint16_t)abSetting.period; setting->compare = (uint16_t)abSetting.compare; return 1U; } if ((outputMode != PLSR_OUTPUT_PULSE_DIR) || (PlsrTimerCalculate(pulseOutput, requestedFrequencyHz, &timerSetting) == 0U)) { return 0U; } setting->actualFrequencyHz = timerSetting.actualFrequencyHz; setting->prescaler = (uint16_t)timerSetting.prescaler; setting->pairPrescaler = 0U; setting->period = (uint16_t)timerSetting.period; setting->compare = (uint16_t)timerSetting.compare; return 1U; } uint8_t PlsrPlatformStartPrepared( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *firstSetting, const PLSR_PLATFORM_TIMER_SETTING *queuedSetting, uint32_t *actualFirstFrequencyHz, uint32_t *actualQueuedFrequencyHz) { uint8_t outputMode; if ((pulseOutput > 3U) || (actualFirstFrequencyHz == NULL) || (actualQueuedFrequencyHz == NULL)) { return 0U; } outputMode = PlsrTimerOutputMode[pulseOutput]; if ((PlsrPreparedSettingIsValid(pulseOutput, outputMode, firstSetting) == 0U) || (PlsrPreparedSettingIsValid(pulseOutput, outputMode, queuedSetting) == 0U)) { return 0U; } if (outputMode == PLSR_OUTPUT_AB) { PLSR_AB_SETTING firstAbSetting; PLSR_AB_SETTING queuedAbSetting; if ((PlsrAbStopPending[pulseOutput] != 0U) || (PlsrAbFastGated[pulseOutput] != 0U) || (PlsrCounterConfigure(pulseOutput, PLSR_OUTPUT_AB) == 0U)) { return 0U; } PlsrPlatformToAbSetting(firstSetting, &firstAbSetting); PlsrPlatformToAbSetting(queuedSetting, &queuedAbSetting); PlsrAbLoadAndStart(pulseOutput, &firstAbSetting); PlsrAbActiveSetting[pulseOutput] = firstAbSetting; PlsrAbPendingSetting[pulseOutput] = queuedAbSetting; PlsrAbFrequencyPending[pulseOutput] = ((firstSetting->prescaler != queuedSetting->prescaler) || (firstSetting->pairPrescaler != queuedSetting->pairPrescaler) || (firstSetting->period != queuedSetting->period)) ? 1U : 0U; } else { TIM_TypeDef *timer = PlsrTimerMap[pulseOutput].timer; PLSR_TIMER_SETTING firstTimerSetting; PLSR_TIMER_SETTING queuedTimerSetting; if (PlsrCounterConfigure(pulseOutput, PLSR_OUTPUT_PULSE_DIR) == 0U) { return 0U; } PlsrPlatformToTimerSetting(firstSetting, &firstTimerSetting); PlsrPlatformToTimerSetting(queuedSetting, &queuedTimerSetting); timer->DIER &= ~TIM_DIER_UIE; timer->CR1 &= ~TIM_CR1_CEN; timer->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); timer->CNT = 0UL; PlsrTimerWriteSetting(timer, &firstTimerSetting); timer->EGR = TIM_EGR_UG; PlsrTimerWriteSetting(timer, &queuedTimerSetting); timer->CNT = firstTimerSetting.compare; timer->SR = 0UL; timer->CCER = (timer->CCER & ~(TIM_CCER_CC1E | TIM_CCER_CC1P)) | TIM_CCER_CC1E; __DSB(); timer->DIER |= TIM_DIER_UIE; PlsrPulsePinRelease(pulseOutput); PlsrCounterBegin(pulseOutput); timer->CR1 |= TIM_CR1_CEN; } PlsrTimerActiveSetting[pulseOutput] = *firstSetting; PlsrTimerQueuedSetting[pulseOutput] = *queuedSetting; PlsrTimerActiveFrequencyHz[pulseOutput] = firstSetting->actualFrequencyHz; PlsrTimerQueuedFrequencyHz[pulseOutput] = queuedSetting->actualFrequencyHz; PlsrTimerQueueGeneration[pulseOutput]++; PlsrTimerRunning[pulseOutput] = 1U; if (outputMode == PLSR_OUTPUT_AB) { PlsrAbScheduleFrequencyVerify(pulseOutput); } else { PlsrFrequencyVerifyPending[pulseOutput] = PLSR_FREQUENCY_VERIFY_NOW; } PlsrFrequencyVerifyPulseCount[pulseOutput] = 0U; *actualFirstFrequencyHz = firstSetting->actualFrequencyHz; *actualQueuedFrequencyHz = queuedSetting->actualFrequencyHz; return 1U; } uint8_t PlsrPlatformSupportsFinitePulseTrain(void) { return 1U; } uint8_t PlsrPlatformStartFinitePrepared( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, uint32_t pulseCount, uint32_t *actualFrequencyHz) { TIM_TypeDef *timer; TIM_TypeDef *counter; PLSR_TIMER_SETTING timerSetting; uint32_t firstBlock; uint8_t counterIndex; if ((pulseOutput > 3U) || (setting == NULL) || (pulseCount == 0UL) || (actualFrequencyHz == NULL) || (PlsrTimerOutputMode[pulseOutput] != PLSR_OUTPUT_PULSE_DIR) || (PlsrPreparedSettingIsValid(pulseOutput, PLSR_OUTPUT_PULSE_DIR, setting) == 0U) || (PlsrCounterConfigure(pulseOutput, PLSR_OUTPUT_PULSE_DIR) == 0U)) { return 0U; } timer = PlsrTimerMap[pulseOutput].timer; counterIndex = PlsrCounterIndexByOutput[pulseOutput]; counter = PlsrCounters[counterIndex]; firstBlock = (pulseCount > PLSR_COUNTER_BLOCK_PULSES) ? PLSR_COUNTER_BLOCK_PULSES : pulseCount; PlsrPlatformToTimerSetting(setting, &timerSetting); counter->CR1 &= ~TIM_CR1_CEN; counter->SMCR &= ~(TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0); counter->ARR = (firstBlock == 1UL) ? 1UL : (firstBlock - 1UL); counter->CNT = 0UL; counter->EGR = TIM_EGR_UG; PlsrFiniteCounterPreload[pulseOutput] = (firstBlock == 1UL) ? 1U : 0U; counter->CNT = PlsrFiniteCounterPreload[pulseOutput]; counter->SR = 0UL; counter->DIER = TIM_DIER_UIE; timer->DIER = 0UL; timer->CR1 &= ~TIM_CR1_CEN; timer->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); timer->CNT = 0UL; PlsrTimerWriteSetting(timer, &timerSetting); timer->EGR = TIM_EGR_UG; /* * The board's high-speed output stage is active low. Keep OC1 high * while the pin changes from GPIO idle to the timer alternate function, * then let the first terminal pulse start at CCR1. Starting at CCR1 * would expose an uncounted terminal pulse before the first OC rising * edge reaches TIM9/TIM12. */ timer->CNT = 0UL; timer->SR = 0UL; timer->CCER = (timer->CCER & ~(TIM_CCER_CC1E | TIM_CCER_CC1P)) | TIM_CCER_CC1E; PlsrFiniteTargetPulses[pulseOutput] = pulseCount; PlsrFiniteRemainingPulses[pulseOutput] = pulseCount; PlsrFiniteCompletionPending[pulseOutput] = 0U; PlsrFiniteFrequencyPending[pulseOutput] = 0U; PlsrFiniteStreamActive[pulseOutput] = 0U; PlsrFiniteStreamNextValid[pulseOutput] = 0U; PlsrFiniteStreamSourceDone[pulseOutput] = 0U; PlsrFiniteStreamSourceFault[pulseOutput] = 0U; PlsrFiniteActive[pulseOutput] = 1U; PlsrFiniteStepCount[pulseOutput] = 0U; PlsrFiniteStepIndex[pulseOutput] = 0U; PlsrFiniteBoundaryReadIndex[pulseOutput] = 0U; PlsrFiniteCompletedStepCount[pulseOutput] = 0U; PlsrTimerActiveSetting[pulseOutput] = *setting; PlsrTimerQueuedSetting[pulseOutput] = *setting; PlsrTimerActiveFrequencyHz[pulseOutput] = setting->actualFrequencyHz; PlsrTimerQueuedFrequencyHz[pulseOutput] = setting->actualFrequencyHz; PlsrTimerRunning[pulseOutput] = 1U; *actualFrequencyHz = setting->actualFrequencyHz; __DSB(); PlsrPulsePinRelease(pulseOutput); PlsrCounterBegin(pulseOutput); timer->CR1 |= TIM_CR1_CEN; return 1U; } uint8_t PlsrPlatformStartCountedStreamPrepared( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, uint32_t pulseCount, uint32_t *actualFrequencyHz) { TIM_TypeDef *counter; uint32_t firstBlock; if (PlsrPlatformStartFinitePrepared(pulseOutput, setting, pulseCount, actualFrequencyHz) == 0U) { return 0U; } PlsrFiniteStreamActive[pulseOutput] = 1U; PlsrFiniteStreamNextValid[pulseOutput] = 0U; PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; PlsrFiniteStreamSourceDone[pulseOutput] = 0U; PlsrFiniteStreamSourceFault[pulseOutput] = 0U; firstBlock = (pulseCount > PLSR_COUNTER_BLOCK_PULSES) ? PLSR_COUNTER_BLOCK_PULSES : pulseCount; counter = PlsrCounters[PlsrCounterIndexByOutput[pulseOutput]]; PlsrFiniteArmNextStepPrepare(pulseOutput, counter, firstBlock); return 1U; } uint8_t PlsrPlatformStartFiniteSequencePrepared( uint8_t pulseOutput, PLSR_PLATFORM_FINITE_STEP *steps, uint16_t stepCount, uint32_t *actualFrequencyHz) { TIM_TypeDef *counter; uint16_t index; if ((steps == NULL) || (stepCount == 0U) || (stepCount > PLSR_PLATFORM_FINITE_STEP_MAX)) { return 0U; } for (index = 0U; index < stepCount; index++) { if ((steps[index].pulseCount == 0UL) || (steps[index].segmentNumber == 0U) || (PlsrPreparedSettingIsValid( pulseOutput, PLSR_OUTPUT_PULSE_DIR, &steps[index].setting) == 0U)) { return 0U; } } if (PlsrPlatformStartFinitePrepared( pulseOutput, &steps[0].setting, steps[0].pulseCount, actualFrequencyHz) == 0U) { return 0U; } PlsrFiniteSteps[pulseOutput] = steps; PlsrFiniteStepCount[pulseOutput] = stepCount; PlsrFiniteStepIndex[pulseOutput] = 0U; PlsrFiniteBoundaryReadIndex[pulseOutput] = 0U; PlsrFiniteCompletedStepCount[pulseOutput] = 0U; if (stepCount > 1U) { counter = PlsrCounters[PlsrCounterIndexByOutput[pulseOutput]]; PlsrFiniteArmNextStepPrepare( pulseOutput, counter, (steps[0].pulseCount > PLSR_COUNTER_BLOCK_PULSES) ? PLSR_COUNTER_BLOCK_PULSES : steps[0].pulseCount); } return 1U; } PLSR_PLATFORM_QUEUE_RESULT PlsrPlatformUpdateFinitePrepared( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, uint32_t *actualFrequencyHz) { TIM_TypeDef *timer; uint32_t activePeriod; uint32_t counter; uint32_t criticalState; if ((pulseOutput > 3U) || (setting == NULL) || (actualFrequencyHz == NULL) || (PlsrFiniteActive[pulseOutput] == 0U) || (PlsrPreparedSettingIsValid(pulseOutput, PLSR_OUTPUT_PULSE_DIR, setting) == 0U)) { return PLSR_PLATFORM_QUEUE_STALE; } timer = PlsrTimerMap[pulseOutput].timer; criticalState = PlsrPlatformEnterCritical(); if ((PlsrFiniteActive[pulseOutput] == 0U) || ((timer->CR1 & TIM_CR1_CEN) == 0UL)) { PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_STALE; } if (PlsrFiniteFrequencyPending[pulseOutput] != 0U) { if ((timer->SR & TIM_SR_UIF) == 0UL) { PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_STALE; } /* The update IRQ normally commits this preload. Also consume a latched update here so a delayed/shared IRQ cannot stall a ramp. */ timer->SR = ~TIM_SR_UIF; timer->DIER &= ~TIM_DIER_UIE; PlsrTimerActiveFrequencyHz[pulseOutput] = PlsrTimerQueuedFrequencyHz[pulseOutput]; PlsrTimerActiveSetting[pulseOutput] = PlsrTimerQueuedSetting[pulseOutput]; PlsrFiniteFrequencyPending[pulseOutput] = 0U; } activePeriod = PlsrTimerActiveSetting[pulseOutput].period; counter = timer->CNT; if ((counter > activePeriod) || ((activePeriod - counter) < PLSR_FINITE_WRITE_GUARD_COUNTS)) { PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_STALE; } timer->PSC = setting->prescaler; timer->ARR = setting->period; timer->CCR1 = setting->compare; __DMB(); PlsrTimerQueuedSetting[pulseOutput] = *setting; PlsrTimerQueuedFrequencyHz[pulseOutput] = setting->actualFrequencyHz; PlsrTimerQueueGeneration[pulseOutput]++; PlsrFiniteFrequencyPending[pulseOutput] = 1U; timer->SR = ~TIM_SR_UIF; timer->DIER |= TIM_DIER_UIE; *actualFrequencyHz = setting->actualFrequencyHz; PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_APPLIED; } uint8_t PlsrPlatformRetargetFiniteStop(uint8_t pulseOutput, uint32_t drainPulses) { TIM_TypeDef *timer; if ((pulseOutput > 3U) || (drainPulses == 0UL) || (PlsrFiniteActive[pulseOutput] == 0U) || (PlsrCounterIndexByOutput[pulseOutput] >= PLSR_COUNTER_COUNT) || (PlsrFiniteRetargetPending[pulseOutput] != 0U) || (PlsrFiniteTailStopPending[pulseOutput] != 0U)) { return 0U; } timer = PlsrTimerMap[pulseOutput].timer; PlsrFiniteRetargetDrainPulses[pulseOutput] = drainPulses; PlsrFiniteRetargetPending[pulseOutput] = 1U; timer->SR = ~TIM_SR_CC1IF; timer->DIER |= TIM_DIER_CC1IE; __DMB(); return 1U; } uint8_t PlsrPlatformRequestFiniteCut(uint8_t pulseOutput) { TIM_TypeDef *timer; uint32_t criticalState; if (pulseOutput > 3U) { return 0U; } criticalState = PlsrPlatformEnterCritical(); if ((PlsrFiniteActive[pulseOutput] == 0U) || (PlsrFiniteStreamActive[pulseOutput] == 0U) || (PlsrCounterIndexByOutput[pulseOutput] >= PLSR_COUNTER_COUNT) || (PlsrFiniteRetargetPending[pulseOutput] != 0U)) { PlsrPlatformExitCritical(criticalState); return 0U; } if (PlsrFiniteTailStopPending[pulseOutput] != 0U) { PlsrPlatformExitCritical(criticalState); 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. */ PlsrFiniteStreamNextValid[pulseOutput] = 0U; PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; PlsrFiniteStreamSourceDone[pulseOutput] = 1U; PlsrFiniteStreamSourceFault[pulseOutput] = 0U; PlsrFiniteTailStopPending[pulseOutput] = 1U; timer = PlsrTimerMap[pulseOutput].timer; timer->SR = ~TIM_SR_CC1IF; timer->DIER |= TIM_DIER_CC1IE; __DMB(); PlsrPlatformExitCritical(criticalState); return 1U; } uint8_t PlsrPlatformFiniteRetargetReady(uint8_t pulseOutput, uint32_t *activeFrequencyHz) { uint32_t criticalState; uint8_t ready; if ((pulseOutput > 3U) || (activeFrequencyHz == NULL)) { return 0U; } criticalState = PlsrPlatformEnterCritical(); ready = ((PlsrFiniteActive[pulseOutput] != 0U) && (PlsrFiniteRetargetPending[pulseOutput] == 0U) && (PlsrFiniteStepCount[pulseOutput] == 0U)) ? 1U : 0U; *activeFrequencyHz = PlsrTimerActiveFrequencyHz[pulseOutput]; PlsrPlatformExitCritical(criticalState); return ready; } uint8_t PlsrPlatformFinitePipelineSnapshot(uint8_t pulseOutput, uint32_t *committedPulses, uint32_t *tailFrequencyHz, uint8_t *startsNextSegment) { TIM_TypeDef *counter; uint32_t criticalState; uint32_t blockCount; uint32_t remaining; if ((pulseOutput > 3U) || (committedPulses == NULL) || (tailFrequencyHz == NULL) || (startsNextSegment == NULL)) { return 0U; } criticalState = PlsrPlatformEnterCritical(); if ((PlsrFiniteActive[pulseOutput] == 0U) || (PlsrFiniteStreamActive[pulseOutput] == 0U) || (PlsrCounterIndexByOutput[pulseOutput] >= PLSR_COUNTER_COUNT)) { PlsrPlatformExitCritical(criticalState); return 0U; } counter = PlsrCounters[PlsrCounterIndexByOutput[pulseOutput]]; blockCount = (uint16_t)counter->CNT; if (blockCount >= PlsrFiniteCounterPreload[pulseOutput]) { blockCount -= PlsrFiniteCounterPreload[pulseOutput]; } else { blockCount = 0UL; } remaining = PlsrFiniteRemainingPulses[pulseOutput]; if (blockCount > remaining) { blockCount = remaining; } remaining -= blockCount; *tailFrequencyHz = PlsrTimerActiveFrequencyHz[pulseOutput]; *startsNextSegment = 0U; if (PlsrFiniteStreamNextValid[pulseOutput] != 0U) { uint32_t nextPulses = PlsrFiniteStreamNextPulses[pulseOutput]; remaining = (nextPulses > (0xFFFFFFFFUL - remaining)) ? 0xFFFFFFFFUL : remaining + nextPulses; *tailFrequencyHz = PlsrFiniteStreamNextSetting[pulseOutput].actualFrequencyHz; *startsNextSegment = PlsrFiniteStreamNextStartsSegment[pulseOutput]; } *committedPulses = remaining; PlsrPlatformExitCritical(criticalState); return 1U; } uint8_t PlsrPlatformFiniteProgress(uint8_t pulseOutput, uint32_t *completedPulses) { uint8_t counterIndex; TIM_TypeDef *counter; uint32_t criticalState; uint32_t completed; if ((pulseOutput > 3U) || (completedPulses == NULL) || ((PlsrFiniteActive[pulseOutput] == 0U) && (PlsrFiniteCompletionPending[pulseOutput] == 0U))) { return 0U; } criticalState = PlsrPlatformEnterCritical(); counterIndex = PlsrCounterIndexByOutput[pulseOutput]; if (PlsrFiniteCompletionPending[pulseOutput] != 0U) { completed = PlsrFiniteTargetPulses[pulseOutput]; } else if (counterIndex < PLSR_COUNTER_COUNT) { counter = PlsrCounters[counterIndex]; uint32_t blockCount = (uint16_t)counter->CNT; if (blockCount >= PlsrFiniteCounterPreload[pulseOutput]) { blockCount -= PlsrFiniteCounterPreload[pulseOutput]; } completed = PlsrFiniteTargetPulses[pulseOutput] - PlsrFiniteRemainingPulses[pulseOutput] + blockCount; if (completed > PlsrFiniteTargetPulses[pulseOutput]) { completed = PlsrFiniteTargetPulses[pulseOutput]; } } else { PlsrPlatformExitCritical(criticalState); return 0U; } if (PlsrFiniteStepCount[pulseOutput] != 0U) { completed += PlsrFiniteSteps[pulseOutput][ PlsrFiniteStepIndex[pulseOutput]].segmentPulseOffset; } *completedPulses = completed; PlsrPlatformExitCritical(criticalState); return 1U; } uint8_t PlsrPlatformTakeFiniteCompletion(uint8_t pulseOutput, uint32_t *completedPulses) { uint8_t counterIndex; TIM_TypeDef *counter; if ((pulseOutput > 3U) || (completedPulses == NULL) || (PlsrFiniteCompletionPending[pulseOutput] == 0U)) { return 0U; } counterIndex = PlsrCounterIndexByOutput[pulseOutput]; if (PlsrFiniteStepCount[pulseOutput] != 0U) { const PLSR_PLATFORM_FINITE_STEP *step = &PlsrFiniteSteps[pulseOutput][ PlsrFiniteStepCount[pulseOutput] - 1U]; *completedPulses = step->segmentPulseOffset + step->pulseCount; } else { *completedPulses = PlsrFiniteTargetPulses[pulseOutput]; } if ((PlsrFiniteStepCount[pulseOutput] == 0U) && (PlsrFiniteStreamActive[pulseOutput] == 0U)) { PlsrObservedPulseBase[pulseOutput] += *completedPulses; } PlsrObservedPulsePublished[pulseOutput] = PlsrObservedPulseBase[pulseOutput]; PlsrFiniteCompletionPending[pulseOutput] = 0U; PlsrFiniteFrequencyPending[pulseOutput] = 0U; PlsrFiniteTargetPulses[pulseOutput] = 0UL; PlsrFiniteRemainingPulses[pulseOutput] = 0UL; PlsrFiniteCounterPreload[pulseOutput] = 0U; PlsrFiniteStepCount[pulseOutput] = 0U; PlsrFiniteStepIndex[pulseOutput] = 0U; PlsrFiniteStreamActive[pulseOutput] = 0U; PlsrFiniteStreamNextValid[pulseOutput] = 0U; PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; PlsrFiniteStreamSourceDone[pulseOutput] = 0U; PlsrFiniteStreamSourceFault[pulseOutput] = 0U; PlsrTimerActiveFrequencyHz[pulseOutput] = 0UL; PlsrTimerQueuedFrequencyHz[pulseOutput] = 0UL; PlsrTimerRunning[pulseOutput] = 0U; if (counterIndex < PLSR_COUNTER_COUNT) { counter = PlsrCounters[counterIndex]; counter->CR1 = 0UL; counter->DIER = 0UL; counter->SMCR = 0UL; counter->SR = 0UL; PlsrCounterOverflowPulses[counterIndex] = 0UL; PlsrCounterOwner[counterIndex] = PLSR_COUNTER_NONE; } PlsrCounterIndexByOutput[pulseOutput] = PLSR_COUNTER_NONE; return 1U; } uint8_t PlsrPlatformTakeFiniteBoundary(uint8_t pulseOutput, uint8_t *segmentNumber, uint32_t *completedPulses, uint8_t *sequenceContinues, uint32_t *activeFrequencyHz) { uint32_t criticalState; uint16_t readIndex; uint16_t completedCount; if ((pulseOutput > 3U) || (segmentNumber == NULL) || (completedPulses == NULL) || (sequenceContinues == NULL) || (activeFrequencyHz == NULL)) { return 0U; } criticalState = PlsrPlatformEnterCritical(); readIndex = PlsrFiniteBoundaryReadIndex[pulseOutput]; completedCount = PlsrFiniteCompletedStepCount[pulseOutput]; while (readIndex < completedCount) { uint16_t index = readIndex++; const PLSR_PLATFORM_FINITE_STEP *step = &PlsrFiniteSteps[pulseOutput][index]; PlsrFiniteBoundaryReadIndex[pulseOutput] = readIndex; if (step->completesSegment != 0U) { *segmentNumber = step->segmentNumber; *completedPulses = step->segmentPulseOffset + step->pulseCount; *sequenceContinues = (index + 1U < PlsrFiniteStepCount[pulseOutput]) ? 1U : 0U; *activeFrequencyHz = (*sequenceContinues != 0U) ? PlsrFiniteSteps[pulseOutput][index + 1U] .setting.actualFrequencyHz : step->setting.actualFrequencyHz; PlsrPlatformExitCritical(criticalState); return 1U; } } PlsrPlatformExitCritical(criticalState); return 0U; } PLSR_PLATFORM_QUEUE_RESULT PlsrPlatformLoadPreparedFromIrq( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, uint32_t *actualFrequencyHz) { uint8_t outputMode; if ((pulseOutput > 3U) || (actualFrequencyHz == NULL)) { return PLSR_PLATFORM_QUEUE_FAILED; } outputMode = PlsrTimerOutputMode[pulseOutput]; if (PlsrPreparedSettingIsValid(pulseOutput, outputMode, setting) == 0U) { return PLSR_PLATFORM_QUEUE_FAILED; } if ((PlsrTimerRunning[pulseOutput] == 0U) || (PlsrAbStopPending[pulseOutput] != 0U) || (PlsrAbFastGated[pulseOutput] != 0U)) { return PLSR_PLATFORM_QUEUE_STALE; } if (outputMode == PLSR_OUTPUT_AB) { PLSR_AB_SETTING pending; PlsrPlatformToAbSetting(setting, &pending); PlsrAbPendingSetting[pulseOutput] = pending; PlsrAbFrequencyPending[pulseOutput] = ((setting->prescaler != PlsrAbActiveSetting[pulseOutput].basePrescaler) || (setting->pairPrescaler != PlsrAbActiveSetting[pulseOutput].pairPrescaler) || (setting->period != PlsrAbActiveSetting[pulseOutput].period)) ? 1U : 0U; } else { TIM_TypeDef *timer = PlsrTimerMap[pulseOutput].timer; if ((timer->CR1 & TIM_CR1_CEN) == 0UL) { return PLSR_PLATFORM_QUEUE_STALE; } timer->PSC = setting->prescaler; timer->ARR = setting->period; timer->CCR1 = setting->compare; __DMB(); } PlsrTimerQueuedSetting[pulseOutput] = *setting; PlsrTimerQueuedFrequencyHz[pulseOutput] = setting->actualFrequencyHz; PlsrTimerQueueGeneration[pulseOutput]++; *actualFrequencyHz = setting->actualFrequencyHz; return PLSR_PLATFORM_QUEUE_APPLIED; } void PlsrPlatformGateFromIrq(uint8_t pulseOutput) { if ((pulseOutput <= 3U) && (PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (PlsrAbFastGated[pulseOutput] != 0U)) { return; } PlsrPlatformStopPulse(pulseOutput); } PLSR_PLATFORM_QUEUE_RESULT PlsrPlatformQueueFrequency( uint8_t pulseOutput, uint32_t frequencyHz, uint32_t *actualFrequencyHz) { TIM_TypeDef *timer; PLSR_PLATFORM_TIMER_SETTING setting; uint32_t activePeriod; uint32_t counter; uint32_t criticalState; uint32_t ownGeneration; uint8_t updatePending; if ((pulseOutput > 3U) || (actualFrequencyHz == NULL) || (PlsrPlatformBuildTimerSetting( pulseOutput, PlsrTimerOutputMode[pulseOutput], frequencyHz, &setting) == 0U)) { return PLSR_PLATFORM_QUEUE_FAILED; } if (PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) { PLSR_AB_SETTING pending; uint32_t criticalState; if ((PlsrTimerRunning[pulseOutput] == 0U) || (PlsrAbStopPending[pulseOutput] != 0U) || (PlsrAbFastGated[pulseOutput] != 0U)) { return PLSR_PLATFORM_QUEUE_STALE; } criticalState = PlsrPlatformEnterCritical(); if ((PlsrTimerRunning[pulseOutput] == 0U) || (PlsrAbStopPending[pulseOutput] != 0U) || (PlsrAbFastGated[pulseOutput] != 0U)) { PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_STALE; } PlsrPlatformToAbSetting(&setting, &pending); PlsrAbPendingSetting[pulseOutput] = pending; PlsrAbFrequencyPending[pulseOutput] = ((pending.basePrescaler != PlsrAbActiveSetting[pulseOutput].basePrescaler) || (pending.pairPrescaler != PlsrAbActiveSetting[pulseOutput].pairPrescaler) || (pending.period != PlsrAbActiveSetting[pulseOutput].period)) ? 1U : 0U; PlsrTimerQueuedSetting[pulseOutput] = setting; PlsrTimerQueuedFrequencyHz[pulseOutput] = setting.actualFrequencyHz; PlsrTimerQueueGeneration[pulseOutput]++; *actualFrequencyHz = setting.actualFrequencyHz; PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_APPLIED; } timer = PlsrTimerMap[pulseOutput].timer; if ((timer->CR1 & TIM_CR1_CEN) == 0UL) { return PLSR_PLATFORM_QUEUE_STALE; } criticalState = PlsrPlatformEnterCritical(); if ((timer->SR & TIM_SR_UIF) != 0UL) { *actualFrequencyHz = PlsrTimerQueuedFrequencyHz[pulseOutput]; PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_STALE; } activePeriod = PlsrTimerActiveSetting[pulseOutput].period; counter = timer->CNT; if ((counter > activePeriod) || ((activePeriod - counter) < PLSR_QUEUE_WRITE_GUARD_COUNTS)) { *actualFrequencyHz = PlsrTimerQueuedFrequencyHz[pulseOutput]; PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_STALE; } /* Preserve real update events and their TRGO pulse while replacing the three preload registers. The near-wrap guard bounds the write window. */ timer->PSC = setting.prescaler; timer->ARR = setting.period; timer->CCR1 = setting.compare; __DMB(); updatePending = ((timer->SR & TIM_SR_UIF) != 0UL) ? 1U : 0U; PlsrTimerQueuedFrequencyHz[pulseOutput] = setting.actualFrequencyHz; PlsrTimerQueuedSetting[pulseOutput] = setting; PlsrTimerQueueGeneration[pulseOutput]++; ownGeneration = PlsrTimerQueueGeneration[pulseOutput]; if (updatePending != 0U) { *actualFrequencyHz = PlsrTimerQueuedFrequencyHz[pulseOutput]; PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_STALE; } *actualFrequencyHz = (PlsrTimerQueueGeneration[pulseOutput] == ownGeneration) ? setting.actualFrequencyHz : PlsrTimerQueuedFrequencyHz[pulseOutput]; if (PlsrTimerQueueGeneration[pulseOutput] != ownGeneration) { PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_STALE; } PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_QUEUE_APPLIED; } void PlsrPlatformDrainPendingPulse(uint8_t pulseOutput) { if (pulseOutput <= 3U) { if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (PlsrDeferredPulsePending[pulseOutput] != 0U)) { uint8_t verifyOutput = (PlsrAbLagAxis[pulseOutput] == pulseOutput) ? (uint8_t)(pulseOutput + 1U) : pulseOutput; TIM_TypeDef *verifyTimer = PlsrTimerMap[verifyOutput].timer; verifyTimer->DIER &= ~(TIM_DIER_UIE | TIM_DIER_CC1IE); verifyTimer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); PlsrAbVerifyOwner[verifyOutput] = PLSR_COUNTER_NONE; if (PlsrFrequencyVerifyPending[pulseOutput] == PLSR_FREQUENCY_VERIFY_AB_AUX_IRQ) { PlsrFrequencyVerifyPending[pulseOutput] = PLSR_FREQUENCY_VERIFY_NONE; PlsrFrequencyVerifyPulseCount[pulseOutput] = 0U; (void)PlsrVerifyActiveFrequency(pulseOutput); } PlsrDeferredPulsePending[pulseOutput] = 0U; PlsrPulseTimerIrq(pulseOutput); return; } PlsrHandleTimerIrq(pulseOutput); } } uint32_t PlsrPlatformActiveFrequency(uint8_t pulseOutput) { if (pulseOutput > 3U) { return 0UL; } if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (PlsrAbFastGated[pulseOutput] != 0U)) { PlsrFrequencyVerifyPending[pulseOutput] = PLSR_FREQUENCY_VERIFY_NONE; PlsrFrequencyVerifyPulseCount[pulseOutput] = 0U; return PlsrTimerActiveFrequencyHz[pulseOutput]; } if (PlsrFrequencyVerifyPending[pulseOutput] == PLSR_FREQUENCY_VERIFY_AB_AUX_IRQ) { return PlsrTimerActiveFrequencyHz[pulseOutput]; } if (PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) { PlsrFrequencyVerifyPulseCount[pulseOutput]++; if (PlsrFrequencyVerifyPulseCount[pulseOutput] >= PLSR_STRUCTURE_VERIFY_INTERVAL) { PlsrFrequencyVerifyPulseCount[pulseOutput] = 0U; PlsrAbScheduleFrequencyVerify(pulseOutput); } return PlsrTimerActiveFrequencyHz[pulseOutput]; } if (PlsrFrequencyVerifyPending[pulseOutput] == PLSR_FREQUENCY_VERIFY_NOW) { PlsrFrequencyVerifyPending[pulseOutput] = PLSR_FREQUENCY_VERIFY_NONE; PlsrFrequencyVerifyPulseCount[pulseOutput] = 0U; return PlsrVerifyActiveFrequency(pulseOutput); } PlsrFrequencyVerifyPulseCount[pulseOutput]++; if (PlsrFrequencyVerifyPulseCount[pulseOutput] >= PLSR_STRUCTURE_VERIFY_INTERVAL) { PlsrFrequencyVerifyPulseCount[pulseOutput] = 0U; return PlsrVerifyActiveFrequency(pulseOutput); } return PlsrTimerActiveFrequencyHz[pulseOutput]; } uint8_t PlsrPlatformExpectedFrequency(uint8_t pulseOutput, uint8_t outputMode, uint32_t requestedFrequencyHz, uint32_t *actualFrequencyHz) { PLSR_PLATFORM_TIMER_SETTING setting; if (actualFrequencyHz == NULL) { return 0U; } if (PlsrPlatformBuildTimerSetting(pulseOutput, outputMode, requestedFrequencyHz, &setting) == 0U) { return 0U; } *actualFrequencyHz = setting.actualFrequencyHz; return 1U; } uint64_t PlsrPlatformObservedPulses(uint8_t pulseOutput) { uint32_t criticalState; uint64_t observed; if (pulseOutput > 3U) { return 0UL; } criticalState = PlsrPlatformEnterCritical(); if (PlsrCounterIndexByOutput[pulseOutput] < PLSR_COUNTER_COUNT) { observed = ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (PlsrAbFastGated[pulseOutput] != 0U)) ? PlsrCounterSnapshotStopped(pulseOutput) : PlsrCounterSnapshot(pulseOutput); } else { observed = PlsrObservedPulseBase[pulseOutput]; } PlsrPlatformExitCritical(criticalState); return observed; } uint16_t PlsrPlatformDiagnosticFault(void) { uint16_t fault = PlsrPlatformFaultPending; PlsrPlatformFaultPending = 0U; return fault; } PLSR_PLATFORM_STOP_RESULT PlsrPlatformRequestStopLocked( uint8_t pulseOutput, uint8_t requireZeroBoundary) { if (pulseOutput > 3U) { return PLSR_PLATFORM_STOP_FORCED_FAULT; } if ((requireZeroBoundary != 0U) && (PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) && (PlsrTimerRunning[pulseOutput] != 0U) && (PlsrAbFastGated[pulseOutput] == 0U)) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); uint8_t lagOutput = PlsrAbLagAxis[pulseOutput]; uint32_t activeFrequencyHz; TIM_TypeDef *baseTimer = PlsrTimerMap[pulseOutput].timer; TIM_TypeDef *pairTimer = PlsrTimerMap[pairOutput].timer; uint8_t structureRunnable = ((PlsrAbStructureVerified[pulseOutput] != 0U) && (PlsrFrequencyVerifyPending[pulseOutput] == PLSR_FREQUENCY_VERIFY_NONE)) ? PlsrAbStopBoundaryIsReachable(pulseOutput, baseTimer, pairTimer) : PlsrAbTimersAreRunnable(pulseOutput, baseTimer, pairTimer); if (structureRunnable == 0U) { PlsrCounterSuspend(pulseOutput); PlsrAbHoldPairIdle(pulseOutput); baseTimer->CR1 &= ~TIM_CR1_CEN; pairTimer->CR1 &= ~TIM_CR1_CEN; __DMB(); PlsrPlatformStopPulse(pulseOutput); return PLSR_PLATFORM_STOP_FORCED_FAULT; } if (PlsrAbStopPending[pulseOutput] != 0U) { return PLSR_PLATFORM_STOP_PENDING; } PlsrAbFrequencyPending[pulseOutput] = 0U; baseTimer->DIER &= ~TIM_DIER_UIE; pairTimer->DIER &= ~TIM_DIER_UIE; PlsrFrequencyVerifyPending[pulseOutput] = PLSR_FREQUENCY_VERIFY_NONE; PlsrFrequencyVerifyPulseCount[pulseOutput] = 0U; PlsrAbVerifyOwner[pulseOutput] = PLSR_COUNTER_NONE; PlsrAbVerifyOwner[pairOutput] = PLSR_COUNTER_NONE; activeFrequencyHz = PlsrTimerActiveFrequencyHz[pulseOutput]; PlsrTimerQueuedFrequencyHz[pulseOutput] = activeFrequencyHz; PlsrTimerQueueGeneration[pulseOutput]++; PlsrAbStopPending[pulseOutput] = 1U; #if PLSR_DEBUG_TIMING if (PlsrFinalArmQueueTimingPending[pulseOutput] != 0U) { uint32_t queuedAt = PlsrFinalArmQueuedAt[pulseOutput]; uint32_t stoppedAt = DWT->CYCCNT; uint32_t latency = stoppedAt - queuedAt; PlsrFinalArmQueueTimingPending[pulseOutput] = 0U; PlsrFinalArmQueueToStopLastCycles[pulseOutput] = latency; if (latency > PlsrFinalArmQueueToStopMaxCycles[pulseOutput]) { PlsrFinalArmQueueToStopMaxCycles[pulseOutput] = latency; } } #endif if (lagOutput == pulseOutput) { pairTimer->SR = ~TIM_SR_CC1IF; } else { baseTimer->SR = ~TIM_SR_CC1IF; } baseTimer->DIER |= TIM_DIER_CC1IE; pairTimer->DIER |= TIM_DIER_CC1IE; __DMB(); return PLSR_PLATFORM_STOP_PENDING; } PlsrPlatformStopPulse(pulseOutput); return PLSR_PLATFORM_STOP_COMPLETE; } uint8_t PlsrPlatformQueueFinalArmFromIrq(uint8_t pulseOutput) { uint8_t jobOutput; if ((pulseOutput > 2U) || ((pulseOutput & 1U) != 0U) || (PlsrTimerOutputMode[pulseOutput] != PLSR_OUTPUT_AB) || (PlsrTimerRunning[pulseOutput] == 0U) || (PlsrAbFastGated[pulseOutput] != 0U)) { return 0U; } jobOutput = PlsrFinalArmJobOutput(pulseOutput); if (PlsrAbFinalArmJobOwner[jobOutput] != PLSR_COUNTER_NONE) { return 0U; } PlsrAbFinalArmJobOwner[jobOutput] = pulseOutput; #if PLSR_DEBUG_TIMING PlsrFinalArmQueuedAt[pulseOutput] = DWT->CYCCNT; PlsrFinalArmQueueTimingPending[pulseOutput] = 1U; PlsrFinalArmQueueCount[pulseOutput]++; #endif __DMB(); NVIC_SetPendingIRQ(PlsrTimerMap[jobOutput].irq); return 1U; } void PlsrPlatformStopPulse(uint8_t pulseOutput) { if (pulseOutput <= 3U) { PlsrFiniteActive[pulseOutput] = 0U; PlsrFiniteCompletionPending[pulseOutput] = 0U; PlsrFiniteFrequencyPending[pulseOutput] = 0U; PlsrFiniteRetargetPending[pulseOutput] = 0U; PlsrFiniteTailStopPending[pulseOutput] = 0U; PlsrFiniteRetargetDrainPulses[pulseOutput] = 0UL; PlsrFiniteTargetPulses[pulseOutput] = 0UL; PlsrFiniteRemainingPulses[pulseOutput] = 0UL; PlsrFiniteStreamActive[pulseOutput] = 0U; PlsrFiniteStreamNextValid[pulseOutput] = 0U; PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; PlsrFiniteStreamSourceDone[pulseOutput] = 0U; PlsrFiniteStreamSourceFault[pulseOutput] = 0U; if (PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); uint8_t jobOutput = PlsrFinalArmJobOutput(pulseOutput); TIM_TypeDef *baseTimer = PlsrTimerMap[pulseOutput].timer; TIM_TypeDef *pairTimer = PlsrTimerMap[pairOutput].timer; PlsrAbStructureVerified[pulseOutput] = 0U; PlsrAbFinalArmJobOwner[jobOutput] = PLSR_COUNTER_NONE; #if PLSR_DEBUG_TIMING PlsrFinalArmQueueTimingPending[pulseOutput] = 0U; #endif NVIC_ClearPendingIRQ(PlsrTimerMap[jobOutput].irq); if (PlsrAbFastGated[pulseOutput] != 0U) { PlsrAbHoldPairIdle(pulseOutput); baseTimer->DIER = 0UL; pairTimer->DIER = 0UL; baseTimer->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); pairTimer->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); baseTimer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); pairTimer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); } else { PlsrCounterSuspend(pulseOutput); PlsrAbHoldPairIdle(pulseOutput); PlsrTimerStop(baseTimer); PlsrTimerStop(pairTimer); } } else { PlsrPulsePinCaptureIdle(pulseOutput); PlsrTimerStop(PlsrTimerMap[pulseOutput].timer); } PlsrCounterStop(pulseOutput); PlsrTimerActiveFrequencyHz[pulseOutput] = 0UL; PlsrTimerQueuedFrequencyHz[pulseOutput] = 0UL; PlsrTimerQueueGeneration[pulseOutput]++; PlsrTimerRunning[pulseOutput] = 0U; PlsrFrequencyVerifyPending[pulseOutput] = 0U; PlsrDeferredPulsePending[pulseOutput] = 0U; PlsrAbVerifyOwner[pulseOutput] = PLSR_COUNTER_NONE; if (PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) { PlsrAbVerifyOwner[pulseOutput + 1U] = PLSR_COUNTER_NONE; } PlsrAbFrequencyPending[pulseOutput] = 0U; PlsrAbStopPending[pulseOutput] = 0U; PlsrAbFastGated[pulseOutput] = 0U; } } void PlsrPlatformForceSafeOutputsFromFault(void) { uint32_t mode; const uint32_t outputPins = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9; const uint32_t outputModeMask = (3UL << (6U * 2U)) | (3UL << (7U * 2U)) | (3UL << (8U * 2U)) | (3UL << (9U * 2U)); __disable_irq(); TIM10->DIER = 0UL; TIM10->CR1 &= ~TIM_CR1_CEN; TIM10->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); TIM10->SR = 0UL; TIM11->DIER = 0UL; TIM11->CR1 &= ~TIM_CR1_CEN; TIM11->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); TIM11->SR = 0UL; TIM13->DIER = 0UL; TIM13->CR1 &= ~TIM_CR1_CEN; TIM13->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); TIM13->SR = 0UL; TIM14->DIER = 0UL; TIM14->CR1 &= ~TIM_CR1_CEN; TIM14->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); TIM14->SR = 0UL; TIM9->DIER = 0UL; TIM9->CR1 &= ~TIM_CR1_CEN; TIM9->SMCR = 0UL; TIM9->SR = 0UL; TIM12->DIER = 0UL; TIM12->CR1 &= ~TIM_CR1_CEN; TIM12->SMCR = 0UL; TIM12->SR = 0UL; RCC->AHB1ENR |= RCC_AHB1ENR_GPIOFEN | RCC_AHB1ENR_GPIOHEN; __DSB(); GPIOF->BSRR = outputPins; GPIOH->BSRR = outputPins; GPIOF->OTYPER &= ~outputPins; GPIOH->OTYPER &= ~outputPins; GPIOF->PUPDR &= ~outputModeMask; GPIOH->PUPDR &= ~outputModeMask; mode = GPIOF->MODER; mode &= ~outputModeMask; mode |= (1UL << (6U * 2U)) | (1UL << (7U * 2U)) | (1UL << (8U * 2U)) | (1UL << (9U * 2U)); GPIOF->MODER = mode; mode = GPIOH->MODER; mode &= ~outputModeMask; mode |= (1UL << (6U * 2U)) | (1UL << (7U * 2U)) | (1UL << (8U * 2U)) | (1UL << (9U * 2U)); GPIOH->MODER = mode; __DSB(); } uint8_t PlsrPlatformReadInput(uint8_t inputSelection) { if (inputSelection == 0U) { return (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_SET) ? 1U : 0U; } if (inputSelection == 1U) { return (HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_12) == GPIO_PIN_SET) ? 1U : 0U; } return 0U; } uint8_t PlsrPlatformLoad(PLSR_PERSIST_PAYLOAD *payload) { PLSR_FLASH_SECTOR_SCAN scanA; PLSR_FLASH_SECTOR_SCAN scanB; const PLSR_FLASH_HEADER *selected = NULL; const void *backupConfig = (const void *)PLSR_BACKUP_CONFIG_ADDRESS; const PLSR_BACKUP_POSITION_RECORD *backupPosition; uint8_t selectedVersion = 0U; uint8_t backupVersion; uint8_t haveConfig = 0U; uint32_t selectedSectorAddress; if (payload == NULL) { return 0U; } selected = PlsrFlashInitializeJournal(&scanA, &scanB, &selectedVersion, &selectedSectorAddress); if (selected != NULL) { if (selectedVersion == PLSR_FLASH_VERSION) { *payload = ((const PLSR_FLASH_RECORD *)selected)->payload; } else { PlsrLoadV2Payload( payload, &((const PLSR_FLASH_RECORD_V2 *)selected)->payload); } haveConfig = 1U; } else { (void)memset(payload, 0, sizeof(*payload)); } backupVersion = PlsrBackupConfigVersion(backupConfig); if (backupVersion == PLSR_FLASH_VERSION) { payload->config = ((const PLSR_BACKUP_CONFIG_RECORD *)backupConfig)->config; haveConfig = 1U; } else if (backupVersion == PLSR_FLASH_VERSION_V2) { const PLSR_BACKUP_CONFIG_RECORD_V2 *oldConfig = (const PLSR_BACKUP_CONFIG_RECORD_V2 *)backupConfig; (void)memcpy(&payload->config, oldConfig->config, sizeof(oldConfig->config)); payload->config.outputMode = PLSR_OUTPUT_PULSE_DIR; haveConfig = 1U; } backupPosition = PlsrNewestBackupPosition(); if (backupPosition != NULL) { payload->position = backupPosition->position; payload->positionValid = backupPosition->positionValid; payload->wasBusy = backupPosition->wasBusy; } if (selected != NULL) { uint8_t reserveIndex = (selectedSectorAddress == PLSR_FLASH_SLOT_A_ADDRESS) ? 1U : 0U; const PLSR_FLASH_SECTOR_SCAN *reserveScan = (reserveIndex == 0U) ? &scanA : &scanB; if (reserveScan->hasProgrammedSlot != 0U) { PlsrFlashReserveEraseState = (uint8_t)(reserveIndex + 1U); } } else if (PlsrFlashNeedsStartupRecovery( 0U, scanA.hasProgrammedSlot, scanA.firstErasedAddress, scanB.hasProgrammedSlot, scanB.firstErasedAddress) != 0U) { PlsrFlashReserveEraseState = PLSR_FLASH_ERASE_SECTOR_A; } return haveConfig; } PLSR_PLATFORM_SERVICE_RESULT PlsrPlatformServicePersistence(void) { uint32_t criticalState; uint8_t eraseState; uint8_t sectorIndex; uint8_t index; criticalState = PlsrPlatformEnterCritical(); eraseState = PlsrFlashReserveEraseState; if (eraseState == PLSR_FLASH_ERASE_FAILED) { PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_SERVICE_FAILED; } if (eraseState == PLSR_FLASH_ERASE_NONE) { PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_SERVICE_READY; } if ((eraseState < PLSR_FLASH_ERASE_SECTOR_A) || (eraseState > PLSR_FLASH_ERASE_SECTOR_B)) { PlsrFlashReserveEraseState = PLSR_FLASH_ERASE_FAILED; PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_SERVICE_FAILED; } for (index = 0U; index < 4U; index++) { if ((PlsrTimerRunning[index] != 0U) || (PlsrTimerIrqActive[index] != 0U)) { PlsrPlatformExitCritical(criticalState); return PLSR_PLATFORM_SERVICE_DEFERRED; } } sectorIndex = (uint8_t)(eraseState - PLSR_FLASH_ERASE_SECTOR_A); PlsrPlatformExitCritical(criticalState); if (PlsrFlashEraseReserve(sectorIndex) == 0U) { PlsrFlashReserveEraseState = PLSR_FLASH_ERASE_FAILED; return PLSR_PLATFORM_SERVICE_FAILED; } PlsrFlashNextErasedAddress[sectorIndex] = (sectorIndex == 0U) ? PLSR_FLASH_SLOT_A_ADDRESS : PLSR_FLASH_SLOT_B_ADDRESS; PlsrFlashReserveEraseState = PLSR_FLASH_ERASE_NONE; return PLSR_PLATFORM_SERVICE_READY; } uint8_t PlsrPlatformSave(const PLSR_PERSIST_PAYLOAD *payload) { PLSR_FLASH_SECTOR_SCAN scanA; PLSR_FLASH_SECTOR_SCAN scanB; uint8_t newestVersion; uint32_t newestSectorAddress; uint8_t targetIndex; uint32_t targetAddress; uint32_t index; uint32_t wordCount; const uint32_t *words; HAL_StatusTypeDef status = HAL_OK; if (payload == NULL) { return 0U; } if (PlsrFlashJournalInitialized == 0U) { (void)PlsrFlashInitializeJournal(&scanA, &scanB, &newestVersion, &newestSectorAddress); (void)newestVersion; (void)newestSectorAddress; } if (PlsrFlashNewestAddress != 0UL) { targetIndex = PlsrFlashSectorIndex(PlsrFlashNewestAddress); if (PlsrFlashNextErasedAddress[targetIndex] == 0UL) { targetIndex ^= 1U; } } else if (PlsrFlashNextErasedAddress[0] != 0UL) { targetIndex = 0U; } else { targetIndex = 1U; } targetAddress = PlsrFlashNextErasedAddress[targetIndex]; if ((targetAddress != 0UL) && ((PlsrFlashAddressIsJournalSlot(targetIndex, targetAddress) == 0U) || (PlsrFlashSlotIsErased(targetAddress) == 0U))) { targetAddress = 0UL; PlsrFlashNextErasedAddress[targetIndex] = 0UL; } if (targetAddress == 0UL) { uint8_t newestIndex = (PlsrFlashNewestAddress != 0UL) ? PlsrFlashSectorIndex( PlsrFlashNewestAddress) : 0xFFU; uint8_t alternateIndex = targetIndex ^ 1U; if ((targetIndex == newestIndex) || (PlsrFlashNextErasedAddress[alternateIndex] != 0UL)) { targetIndex = alternateIndex; targetAddress = PlsrFlashNextErasedAddress[targetIndex]; if ((targetAddress != 0UL) && ((PlsrFlashAddressIsJournalSlot(targetIndex, targetAddress) == 0U) || (PlsrFlashSlotIsErased(targetAddress) == 0U))) { targetAddress = 0UL; PlsrFlashNextErasedAddress[targetIndex] = 0UL; } } if (targetAddress == 0UL) { return 0U; } } PlsrFlashNextErasedAddress[targetIndex] = PlsrFlashFindErasedAfter(targetIndex, targetAddress); (void)memset(&PlsrFlashRecordBuffer, 0, sizeof(PlsrFlashRecordBuffer)); PlsrFlashRecordBuffer.magic = PLSR_FLASH_MAGIC; PlsrFlashRecordBuffer.version = PLSR_FLASH_VERSION; PlsrFlashRecordBuffer.payloadSize = sizeof(PLSR_PERSIST_PAYLOAD); PlsrFlashRecordBuffer.generation = PlsrFlashNewestGeneration + 1UL; PlsrFlashRecordBuffer.payload = *payload; PlsrFlashRecordBuffer.crc32 = PlsrFlashRecordCrc(&PlsrFlashRecordBuffer, sizeof(PlsrFlashRecordBuffer.payload)); if (HAL_FLASH_Unlock() != HAL_OK) { (void)HAL_FLASH_Lock(); return 0U; } __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); words = (const uint32_t *)&PlsrFlashRecordBuffer; wordCount = sizeof(PlsrFlashRecordBuffer) / sizeof(uint32_t); if (status == HAL_OK) { for (index = 1UL; index < wordCount; index++) { if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, targetAddress + index * 4UL, words[index]) != HAL_OK) { status = HAL_ERROR; break; } } } if ((status == HAL_OK) && (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, targetAddress, PLSR_FLASH_MAGIC) != HAL_OK)) { status = HAL_ERROR; } if (HAL_FLASH_Lock() != HAL_OK) { (void)HAL_FLASH_Lock(); status = HAL_ERROR; } if (PlsrFlashRecordVersion((const void *)targetAddress) == PLSR_FLASH_VERSION) { PlsrFlashNewestAddress = targetAddress; PlsrFlashNewestGeneration = PlsrFlashRecordBuffer.generation; return (status == HAL_OK) ? 1U : 0U; } return 0U; } void PlsrPlatformCheckpointConfig(const PLSR_CONFIG *config) { PLSR_BACKUP_CONFIG_RECORD *record = (PLSR_BACKUP_CONFIG_RECORD *)PLSR_BACKUP_CONFIG_ADDRESS; if (config == NULL) { return; } record->magic = 0UL; record->config = *config; record->crc32 = PlsrCrc32(&record->config, sizeof(record->config)); __DMB(); record->magic = PLSR_BACKUP_CONFIG_MAGIC; __DMB(); } void PlsrPlatformCheckpointPosition(int32_t position, uint8_t positionValid, uint8_t wasBusy) { PLSR_BACKUP_POSITION_RECORD *slots = (PLSR_BACKUP_POSITION_RECORD *)PLSR_BACKUP_POSITION_ADDRESS; PLSR_BACKUP_POSITION_RECORD *record; PlsrBackupPositionGeneration++; record = &slots[PlsrBackupPositionGeneration & 1UL]; record->magic = 0UL; record->generation = PlsrBackupPositionGeneration; record->position = position; record->positionValid = (positionValid != 0U) ? 1U : 0U; record->wasBusy = (wasBusy != 0U) ? 1U : 0U; record->reserved = 0U; record->crc32 = PlsrCrc32(&record->generation, sizeof(record->generation) + sizeof(record->position) + sizeof(record->positionValid) + sizeof(record->wasBusy) + sizeof(record->reserved)); __DMB(); record->magic = PLSR_BACKUP_POSITION_MAGIC; __DMB(); } uint32_t PlsrPlatformEnterCritical(void) { uint32_t state = __get_PRIMASK(); __disable_irq(); __DMB(); return state; } void PlsrPlatformExitCritical(uint32_t state) { __DMB(); if (state == 0UL) { __enable_irq(); } } static void PlsrHandleTimerIrq(uint8_t pulseOutput) { TIM_TypeDef *timer; #if PLSR_DEBUG_TIMING uint32_t startedAt; uint32_t elapsedCycles; uint8_t timingOutput = pulseOutput; startedAt = DWT->CYCCNT; #endif timer = PlsrTimerMap[pulseOutput].timer; if (PlsrTimerIrqActive[pulseOutput] != 0U) { #if PLSR_DEBUG_TIMING goto irq_record; #else return; #endif } PlsrTimerIrqActive[pulseOutput] = 1U; if (((timer->SR & TIM_SR_CC1IF) != 0UL) && ((timer->DIER & TIM_DIER_CC1IE) != 0UL)) { uint8_t owner = ((pulseOutput & 2U) == 0U) ? 0U : 2U; if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_PULSE_DIR) && (PlsrFiniteRetargetPending[pulseOutput] != 0U)) { timer->SR = ~TIM_SR_CC1IF; PlsrFiniteRetargetAtFallingEdge(pulseOutput); goto irq_done; } if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_PULSE_DIR) && (PlsrFiniteTailStopPending[pulseOutput] != 0U)) { timer->SR = ~TIM_SR_CC1IF; PlsrFiniteCutAtFallingEdge(pulseOutput); goto irq_done; } #if PLSR_DEBUG_TIMING timingOutput = owner; #endif timer->SR = ~TIM_SR_CC1IF; if ((owner <= 2U) && (PlsrTimerRunning[owner] != 0U) && (PlsrTimerOutputMode[owner] == PLSR_OUTPUT_AB)) { uint8_t pairOutput = (uint8_t)(owner + 1U); TIM_TypeDef *baseTimer = PlsrTimerMap[owner].timer; TIM_TypeDef *pairTimer = PlsrTimerMap[pairOutput].timer; PLSR_AB_SETTING pending; if (PlsrAbStopPending[owner] != 0U) { if (PlsrAbCanFastGateAtZero(owner) == 0U) { goto irq_done; } baseTimer->DIER &= ~(TIM_DIER_CC1IE | TIM_DIER_UIE); pairTimer->DIER &= ~(TIM_DIER_CC1IE | TIM_DIER_UIE); baseTimer->SR = ~TIM_SR_CC1IF; pairTimer->SR = ~TIM_SR_CC1IF; PlsrFrequencyVerifyPending[owner] = PLSR_FREQUENCY_VERIFY_NONE; PlsrAbVerifyOwner[owner] = PLSR_COUNTER_NONE; PlsrAbVerifyOwner[pairOutput] = PLSR_COUNTER_NONE; PlsrAbFastGate(owner); PlsrAbFastGated[owner] = 1U; PlsrDeferredPulsePending[owner] = 0U; PlsrPulseTimerIrq(owner); goto irq_done; } if (pulseOutput != PlsrAbLagAxis[owner]) { if (PlsrDeferredPulsePending[owner] != 0U) { PlsrDeferredPulsePending[owner] = 0U; timer->DIER &= ~TIM_DIER_CC1IE; PlsrPulseTimerIrq(owner); } goto irq_done; } if (PlsrDeferredPulsePending[owner] != 0U) { goto irq_done; } if (PlsrAbFrequencyPending[owner] != 0U) { pending = PlsrAbPendingSetting[owner]; PlsrAbFrequencyPending[owner] = 0U; PlsrAbLoadAndStart(owner, &pending); PlsrAbActiveSetting[owner] = pending; PlsrTimerActiveSetting[owner] = PlsrTimerQueuedSetting[owner]; PlsrTimerActiveFrequencyHz[owner] = pending.actualFrequencyHz; PlsrDeferredPulsePending[owner] = 1U; PlsrAbScheduleFrequencyVerify(owner); goto irq_done; } PlsrPulseTimerIrq(owner); } goto irq_done; } if (((timer->SR & TIM_SR_UIF) != 0UL) && ((timer->DIER & TIM_DIER_UIE) != 0UL)) { timer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); if ((PlsrFiniteActive[pulseOutput] != 0U) && (PlsrFiniteFrequencyPending[pulseOutput] != 0U)) { PlsrTimerActiveFrequencyHz[pulseOutput] = PlsrTimerQueuedFrequencyHz[pulseOutput]; PlsrTimerActiveSetting[pulseOutput] = PlsrTimerQueuedSetting[pulseOutput]; PlsrFiniteFrequencyPending[pulseOutput] = 0U; timer->DIER &= ~TIM_DIER_UIE; goto irq_done; } if (PlsrPlatformSettingsDiffer( &PlsrTimerActiveSetting[pulseOutput], &PlsrTimerQueuedSetting[pulseOutput]) != 0U) { PlsrFrequencyVerifyPending[pulseOutput] = 1U; PlsrTimerActiveFrequencyHz[pulseOutput] = PlsrTimerQueuedFrequencyHz[pulseOutput]; PlsrTimerActiveSetting[pulseOutput] = PlsrTimerQueuedSetting[pulseOutput]; } PlsrPulseTimerIrq(pulseOutput); } irq_done: PlsrTimerIrqActive[pulseOutput] = 0U; #if PLSR_DEBUG_TIMING irq_record: elapsedCycles = DWT->CYCCNT - startedAt; PlsrIrqCount[timingOutput]++; PlsrIrqLastCycles[timingOutput] = elapsedCycles; if (elapsedCycles > PlsrIrqMaxCycles[timingOutput]) { PlsrIrqMaxCycles[timingOutput] = elapsedCycles; } #endif } static uint8_t PlsrHandleScheduledAbVerify(uint8_t pulseOutput) { uint8_t verifyOwner = PlsrAbVerifyOwner[pulseOutput]; TIM_TypeDef *timer; #if PLSR_DEBUG_TIMING uint32_t startedAt; uint32_t elapsedCycles; #endif if (verifyOwner > 2U) { return 0U; } timer = PlsrTimerMap[pulseOutput].timer; if (((timer->SR & TIM_SR_UIF) == 0UL) || ((timer->DIER & TIM_DIER_UIE) == 0UL)) { return 0U; } #if PLSR_DEBUG_TIMING startedAt = DWT->CYCCNT; #endif timer->SR = ~TIM_SR_UIF; timer->DIER &= ~TIM_DIER_UIE; PlsrAbVerifyOwner[pulseOutput] = PLSR_COUNTER_NONE; if (PlsrFrequencyVerifyPending[verifyOwner] == PLSR_FREQUENCY_VERIFY_AB_AUX_IRQ) { PlsrFrequencyVerifyPending[verifyOwner] = PLSR_FREQUENCY_VERIFY_NONE; PlsrFrequencyVerifyPulseCount[verifyOwner] = 0U; (void)PlsrVerifyActiveFrequency(verifyOwner); } #if PLSR_DEBUG_TIMING elapsedCycles = DWT->CYCCNT - startedAt; PlsrIrqCount[verifyOwner]++; PlsrIrqLastCycles[verifyOwner] = elapsedCycles; if (elapsedCycles > PlsrIrqMaxCycles[verifyOwner]) { PlsrIrqMaxCycles[verifyOwner] = elapsedCycles; } #endif return 1U; } static uint8_t PlsrFinalStopIrqIsPending(uint8_t pulseOutput) { uint8_t owner = ((pulseOutput & 2U) == 0U) ? 0U : 2U; TIM_TypeDef *timer = PlsrTimerMap[pulseOutput].timer; return ((PlsrAbStopPending[owner] != 0U) && ((timer->SR & TIM_SR_CC1IF) != 0UL) && ((timer->DIER & TIM_DIER_CC1IE) != 0UL)) ? 1U : 0U; } static uint8_t PlsrHandleFinalArmJob(uint8_t pulseOutput) { uint8_t owner = PlsrAbFinalArmJobOwner[pulseOutput]; #if PLSR_DEBUG_TIMING uint32_t startedAt; uint32_t elapsedCycles; #endif if (owner > 2U) { return 0U; } PlsrAbFinalArmJobOwner[pulseOutput] = PLSR_COUNTER_NONE; #if PLSR_DEBUG_TIMING startedAt = DWT->CYCCNT; #endif PlsrFinalArmJobIrq(owner); #if PLSR_DEBUG_TIMING elapsedCycles = DWT->CYCCNT - startedAt; PlsrFinalArmJobLastCycles[owner] = elapsedCycles; if (elapsedCycles > PlsrFinalArmJobMaxCycles[owner]) { PlsrFinalArmJobMaxCycles[owner] = elapsedCycles; } #endif return 1U; } static void PlsrDispatchTimerIrq(uint8_t pulseOutput) { if (PlsrFinalStopIrqIsPending(pulseOutput) != 0U) { PlsrHandleTimerIrq(pulseOutput); return; } if (PlsrHandleFinalArmJob(pulseOutput) != 0U) { return; } if (PlsrHandleScheduledAbVerify(pulseOutput) == 0U) { PlsrHandleTimerIrq(pulseOutput); } } void TIM1_UP_TIM10_IRQHandler(void) { PlsrDispatchTimerIrq(0U); } void TIM8_UP_TIM13_IRQHandler(void) { PlsrDispatchTimerIrq(1U); } void TIM1_TRG_COM_TIM11_IRQHandler(void) { PlsrDispatchTimerIrq(2U); } 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; #if PLSR_DEBUG_TIMING uint32_t startedAt = DWT->CYCCNT; #endif if (counterIndex >= PLSR_COUNTER_COUNT) { return; } counter = PlsrCounters[counterIndex]; if (((counter->SR & TIM_SR_CC1IF) != 0UL) && ((counter->DIER & TIM_DIER_CC1IE) != 0UL)) { uint8_t owner = PlsrCounterOwner[counterIndex]; counter->SR = ~TIM_SR_CC1IF; if ((owner <= 3U) && (PlsrFiniteActive[owner] != 0U)) { PlsrFinitePrepareNextStepIrq(owner, counter); } } if (((counter->SR & TIM_SR_UIF) != 0UL) && ((counter->DIER & TIM_DIER_UIE) != 0UL)) { uint8_t owner = PlsrCounterOwner[counterIndex]; counter->SR = ~TIM_SR_UIF; if ((owner <= 3U) && (PlsrFiniteActive[owner] != 0U)) { PlsrFiniteCounterIrq(owner, counter); #if PLSR_DEBUG_TIMING { uint32_t elapsedCycles = DWT->CYCCNT - startedAt; if (PlsrFiniteCompletionPending[owner] != 0U) { PlsrFiniteFinalIrqLastCycles[owner] = elapsedCycles; if (elapsedCycles > PlsrFiniteFinalIrqMaxCycles[owner]) { PlsrFiniteFinalIrqMaxCycles[owner] = elapsedCycles; } } else { PlsrFiniteBlockIrqCount[owner]++; if (elapsedCycles > PlsrFiniteBlockIrqMaxCycles[owner]) { PlsrFiniteBlockIrqMaxCycles[owner] = elapsedCycles; } } } #endif } else { PlsrCounterOverflowPulses[counterIndex] += PLSR_COUNTER_BLOCK_PULSES; } } } static void PlsrFiniteArmNextStepPrepare(uint8_t pulseOutput, TIM_TypeDef *counter, uint32_t blockPulses) { uint16_t nextIndex = (uint16_t)(PlsrFiniteStepIndex[pulseOutput] + 1U); counter->DIER &= ~TIM_DIER_CC1IE; counter->SR = ~TIM_SR_CC1IF; if (PlsrFiniteRemainingPulses[pulseOutput] > blockPulses) { return; } if ((PlsrFiniteStreamActive[pulseOutput] == 0U) && (nextIndex >= PlsrFiniteStepCount[pulseOutput])) { return; } if (blockPulses > 1UL) { counter->CCR1 = blockPulses - 1UL; counter->DIER |= TIM_DIER_CC1IE; } else { PlsrFinitePrepareNextStepIrq(pulseOutput, counter); } } static void PlsrFinitePrepareNextStepIrq(uint8_t pulseOutput, TIM_TypeDef *counter) { uint16_t nextIndex = (uint16_t)(PlsrFiniteStepIndex[pulseOutput] + 1U); TIM_TypeDef *timer; const PLSR_PLATFORM_TIMER_SETTING *next; counter->DIER &= ~TIM_DIER_CC1IE; if (PlsrFiniteStreamActive[pulseOutput] != 0U) { PLSR_PLATFORM_TIMER_SETTING streamSetting; uint32_t streamPulses = 0UL; uint8_t startsNextSegment = 0U; uint8_t takeResult; if ((PlsrFiniteStreamNextValid[pulseOutput] != 0U) || (PlsrFiniteStreamSourceDone[pulseOutput] != 0U) || (PlsrFiniteStreamSourceFault[pulseOutput] != 0U)) { return; } takeResult = PlsrExecTakeCountedRunIrq( pulseOutput, &streamSetting, &streamPulses, &startsNextSegment); if (takeResult == PLSR_EXEC_RUN_DONE) { PlsrFiniteStreamSourceDone[pulseOutput] = 1U; return; } if ((takeResult != PLSR_EXEC_RUN_READY) || (streamPulses == 0UL) || (PlsrPreparedSettingIsValid( pulseOutput, PLSR_OUTPUT_PULSE_DIR, &streamSetting) == 0U)) { PlsrFiniteStreamSourceFault[pulseOutput] = 1U; PlsrExecCountedStreamFaultIrq(pulseOutput); return; } timer = PlsrTimerMap[pulseOutput].timer; timer->PSC = streamSetting.prescaler; timer->ARR = streamSetting.period; timer->CCR1 = streamSetting.compare; PlsrTimerQueuedSetting[pulseOutput] = streamSetting; PlsrTimerQueuedFrequencyHz[pulseOutput] = streamSetting.actualFrequencyHz; PlsrFiniteStreamNextSetting[pulseOutput] = streamSetting; PlsrFiniteStreamNextPulses[pulseOutput] = streamPulses; PlsrFiniteStreamNextStartsSegment[pulseOutput] = startsNextSegment; PlsrFiniteStreamNextValid[pulseOutput] = 1U; return; } if (nextIndex >= PlsrFiniteStepCount[pulseOutput]) { return; } timer = PlsrTimerMap[pulseOutput].timer; next = &PlsrFiniteSteps[pulseOutput][nextIndex].setting; timer->PSC = next->prescaler; timer->ARR = next->period; timer->CCR1 = next->compare; PlsrTimerQueuedSetting[pulseOutput] = *next; PlsrTimerQueuedFrequencyHz[pulseOutput] = next->actualFrequencyHz; } static void PlsrFiniteCounterIrq(uint8_t pulseOutput, TIM_TypeDef *counter) { uint32_t completedBlock = (PlsrFiniteRemainingPulses[pulseOutput] > PLSR_COUNTER_BLOCK_PULSES) ? PLSR_COUNTER_BLOCK_PULSES : PlsrFiniteRemainingPulses[pulseOutput]; PlsrFiniteRemainingPulses[pulseOutput] -= completedBlock; if (PlsrFiniteRemainingPulses[pulseOutput] != 0UL) { uint32_t nextBlock = (PlsrFiniteRemainingPulses[pulseOutput] > PLSR_COUNTER_BLOCK_PULSES) ? PLSR_COUNTER_BLOCK_PULSES : PlsrFiniteRemainingPulses[pulseOutput]; PlsrCounterOverflowPulses[PlsrCounterIndexByOutput[pulseOutput]] += completedBlock; counter->ARR = (nextBlock == 1UL) ? 1UL : (nextBlock - 1UL); PlsrFiniteCounterPreload[pulseOutput] = (nextBlock == 1UL) ? 1U : 0U; counter->CNT = PlsrFiniteCounterPreload[pulseOutput]; PlsrFiniteArmNextStepPrepare(pulseOutput, counter, nextBlock); return; } if (PlsrFiniteStreamActive[pulseOutput] != 0U) { PlsrObservedPulseBase[pulseOutput] += PlsrFiniteTargetPulses[pulseOutput]; PlsrObservedPulsePublished[pulseOutput] = PlsrObservedPulseBase[pulseOutput]; if (PlsrFiniteStreamNextValid[pulseOutput] != 0U) { uint32_t nextPulses = PlsrFiniteStreamNextPulses[pulseOutput]; uint32_t firstBlock = (nextPulses > PLSR_COUNTER_BLOCK_PULSES) ? PLSR_COUNTER_BLOCK_PULSES : nextPulses; if (PlsrFiniteStreamNextStartsSegment[pulseOutput] != 0U) { /* 段边界回调只传"到当前 run 完成为止的累计计数"(IRQ 内 已累加完成的 base),执行器只置事件,不做簿记。 */ PlsrExecCountedSegmentBoundaryIrq( pulseOutput, PlsrObservedPulseBase[pulseOutput]); } PlsrFiniteTargetPulses[pulseOutput] = nextPulses; PlsrFiniteRemainingPulses[pulseOutput] = nextPulses; PlsrCounterOverflowPulses[ PlsrCounterIndexByOutput[pulseOutput]] = 0UL; counter->ARR = (firstBlock == 1UL) ? 1UL : (firstBlock - 1UL); PlsrFiniteCounterPreload[pulseOutput] = (firstBlock == 1UL) ? 1U : 0U; counter->CNT = PlsrFiniteCounterPreload[pulseOutput]; PlsrTimerActiveSetting[pulseOutput] = PlsrFiniteStreamNextSetting[pulseOutput]; PlsrTimerActiveFrequencyHz[pulseOutput] = PlsrFiniteStreamNextSetting[pulseOutput].actualFrequencyHz; PlsrFiniteStreamNextValid[pulseOutput] = 0U; PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; PlsrFiniteArmNextStepPrepare(pulseOutput, counter, firstBlock); return; } } else if (PlsrFiniteStepCount[pulseOutput] != 0U) { uint16_t completedIndex = PlsrFiniteStepIndex[pulseOutput]; uint16_t nextIndex = (uint16_t)(completedIndex + 1U); uint8_t hasNext = (nextIndex < PlsrFiniteStepCount[pulseOutput]) ? 1U : 0U; PlsrObservedPulseBase[pulseOutput] += PlsrFiniteTargetPulses[pulseOutput]; PlsrObservedPulsePublished[pulseOutput] = PlsrObservedPulseBase[pulseOutput]; PlsrFiniteCompletedStepCount[pulseOutput] = (uint16_t)(completedIndex + 1U); if (hasNext != 0U) { const PLSR_PLATFORM_FINITE_STEP *next = &PlsrFiniteSteps[pulseOutput][nextIndex]; uint32_t firstBlock = (next->pulseCount > PLSR_COUNTER_BLOCK_PULSES) ? PLSR_COUNTER_BLOCK_PULSES : next->pulseCount; PlsrFiniteStepIndex[pulseOutput] = nextIndex; PlsrFiniteTargetPulses[pulseOutput] = next->pulseCount; PlsrFiniteRemainingPulses[pulseOutput] = next->pulseCount; PlsrCounterOverflowPulses[ PlsrCounterIndexByOutput[pulseOutput]] = 0UL; counter->ARR = (firstBlock == 1UL) ? 1UL : (firstBlock - 1UL); PlsrFiniteCounterPreload[pulseOutput] = (firstBlock == 1UL) ? 1U : 0U; counter->CNT = PlsrFiniteCounterPreload[pulseOutput]; PlsrTimerActiveSetting[pulseOutput] = next->setting; PlsrTimerActiveFrequencyHz[pulseOutput] = next->setting.actualFrequencyHz; PlsrTimerQueuedSetting[pulseOutput] = next->setting; PlsrTimerQueuedFrequencyHz[pulseOutput] = next->setting.actualFrequencyHz; PlsrFiniteArmNextStepPrepare(pulseOutput, counter, firstBlock); return; } } counter->DIER = 0UL; 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); } static void PlsrFiniteRetargetAtFallingEdge(uint8_t pulseOutput) { uint8_t counterIndex = PlsrCounterIndexByOutput[pulseOutput]; TIM_TypeDef *counter = PlsrCounters[counterIndex]; TIM_TypeDef *timer = PlsrTimerMap[pulseOutput].timer; uint32_t drainPulses = PlsrFiniteRetargetDrainPulses[pulseOutput]; uint32_t blockCount; uint32_t completed; PlsrFiniteRetargetPending[pulseOutput] = 0U; PlsrFiniteRetargetDrainPulses[pulseOutput] = 0UL; timer->DIER &= ~TIM_DIER_CC1IE; PlsrCounterSuspend(pulseOutput); blockCount = (uint16_t)counter->CNT; if (blockCount >= PlsrFiniteCounterPreload[pulseOutput]) { blockCount -= PlsrFiniteCounterPreload[pulseOutput]; } completed = PlsrFiniteTargetPulses[pulseOutput] - PlsrFiniteRemainingPulses[pulseOutput] + blockCount; if (PlsrFiniteStepCount[pulseOutput] != 0U) { completed += PlsrFiniteSteps[pulseOutput][ PlsrFiniteStepIndex[pulseOutput]].segmentPulseOffset; } if (completed > PlsrFiniteTargetPulses[pulseOutput]) { completed = PlsrFiniteTargetPulses[pulseOutput]; } PlsrFiniteTargetPulses[pulseOutput] = completed + drainPulses; PlsrFiniteRemainingPulses[pulseOutput] = drainPulses; PlsrFiniteStepCount[pulseOutput] = 0U; PlsrFiniteStepIndex[pulseOutput] = 0U; PlsrFiniteBoundaryReadIndex[pulseOutput] = 0U; PlsrFiniteCompletedStepCount[pulseOutput] = 0U; counter->ARR = (drainPulses == 1UL) ? 1UL : (drainPulses - 1UL); PlsrFiniteCounterPreload[pulseOutput] = (drainPulses == 1UL) ? 1U : 0U; counter->CNT = 0UL; counter->EGR = TIM_EGR_UG; counter->CNT = PlsrFiniteCounterPreload[pulseOutput]; counter->SR = 0UL; counter->DIER = TIM_DIER_UIE; PlsrCounterBegin(pulseOutput); } static void PlsrFiniteCutAtFallingEdge(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(). */ 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]; } PlsrObservedPulseBase[pulseOutput] += completed; PlsrObservedPulsePublished[pulseOutput] = PlsrObservedPulseBase[pulseOutput]; PlsrFiniteTargetPulses[pulseOutput] = completed; PlsrFiniteRemainingPulses[pulseOutput] = 0UL; PlsrFiniteStepCount[pulseOutput] = 0U; PlsrFiniteStepIndex[pulseOutput] = 0U; PlsrFiniteBoundaryReadIndex[pulseOutput] = 0U; PlsrFiniteCompletedStepCount[pulseOutput] = 0U; PlsrFiniteStreamNextValid[pulseOutput] = 0U; PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; PlsrCounterOverflowPulses[counterIndex] = 0UL; counter->CNT = 0UL; counter->SR = 0UL; PlsrFiniteStopAtFallingEdge(pulseOutput); } static void PlsrFiniteStopAtFallingEdge(uint8_t pulseOutput) { TIM_TypeDef *timer = PlsrTimerMap[pulseOutput].timer; /* OC1 and GPIO idle are both high here; hand off without a pin glitch. */ PlsrPulsePinCaptureIdle(pulseOutput); timer->DIER = 0UL; timer->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1P); timer->CR1 &= ~TIM_CR1_CEN; timer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); PlsrFiniteTailStopPending[pulseOutput] = 0U; PlsrFiniteActive[pulseOutput] = 0U; PlsrFiniteCompletionPending[pulseOutput] = 1U; PlsrFiniteFrequencyPending[pulseOutput] = 0U; PlsrFiniteCounterPreload[pulseOutput] = 0U; __DSB(); } void TIM1_BRK_TIM9_IRQHandler(void) { PlsrHandleCounterIrq(0U); } void TIM8_BRK_TIM12_IRQHandler(void) { PlsrHandleCounterIrq(1U); } #endif /* PLSR_HOST_TEST */