#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 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; 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 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 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 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 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 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_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_INPUT; 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); 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; 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 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 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 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) { 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; 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; 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; PlsrFiniteStopAtFallingEdge(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); } 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 ((nextIndex >= PlsrFiniteStepCount[pulseOutput]) || (PlsrFiniteRemainingPulses[pulseOutput] > blockPulses)) { 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 (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 (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 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 */