diff --git a/HostComputer/bin_to_time_freq.py b/HostComputer/bin_to_time_freq.py index fff40d5..b3424e2 100644 --- a/HostComputer/bin_to_time_freq.py +++ b/HostComputer/bin_to_time_freq.py @@ -28,7 +28,7 @@ Ctrl+滚轮 缩放 Y 轴(以鼠标 Y 位置为中心) 左键拖拽 双向平移(上下左右跟随鼠标) 双击 复位到全图 - 鼠标悬停 高亮最近的点并显示其时间与频率 + 鼠标悬停 高亮最近的点并显示其脉冲序号、时间与频率 依赖: pip install numpy matplotlib """ @@ -205,7 +205,8 @@ def plot_show(path, fs, thresh, ymax, save_path=None): if dist[k] <= 20.0: idx = int(np.flatnonzero(mask)[k]) hl_marker.set_data([tx_ms[idx]], [freq[idx]]) - hl_text.set_text("t = %.3f ms\nf = %.0f Hz" % (tx_ms[idx], freq[idx])) + hl_text.set_text("脉冲 #%d\nt = %.3f ms\nf = %.0f Hz" + % (idx + 1, tx_ms[idx], freq[idx])) hl_text.set_position((tx_ms[idx] + (x1 - x0) * 0.01, freq[idx] + (ax.get_ylim()[1] - ax.get_ylim()[0]) * 0.02)) hl_marker.set_visible(True) diff --git a/PLSR/Src/plsr.c b/PLSR/Src/plsr.c index 662ba4b..1a7cf00 100644 --- a/PLSR/Src/plsr.c +++ b/PLSR/Src/plsr.c @@ -52,6 +52,13 @@ #define PLSR_HANDOFF_WARMUP_ITEMS (8U) #define PLSR_REPLAN_WARMUP_ITEMS (8U) #define PLSR_RAMP_POLL_RESERVE_AREA_DIVISOR (20ULL) +/* 功能诊断(计数/频率/曲线检查)总开关。 + * 0 = 全部关闭:诊断采集、结算与锁定均不执行,Modbus 诊断寄存器保持全 0, + * 诊断控制字写入仍被接受(无操作)。运动核心先行跑通;曲线校准阶段再置 1。 */ +#define PLSR_DIAGNOSTIC_ENABLED (0U) +/* 计数错误停机检查:暂时关闭。counted 流计数同步与执行器重构对齐期间, + * 实际输出与预期的偏差只做数据钳制(delta=remaining),不再进 PLSR_ERROR_COUNT。 */ +#define PLSR_COUNT_ERROR_CHECK_ENABLED (0U) typedef struct { @@ -83,6 +90,8 @@ typedef struct { PLSR_PLATFORM_TIMER_SETTING setting; uint32_t requestedFrequencyHz; + uint32_t repeatCount; + uint8_t startsNextSegment; } PLSR_PROFILE_ENTRY; typedef struct @@ -93,6 +102,7 @@ typedef struct volatile uint32_t writeIndex; volatile uint32_t generation; uint32_t producerEpoch; + volatile uint32_t repeatRemaining; uint8_t producerSegment; uint8_t preparedHandoffBank; volatile uint8_t active; @@ -106,6 +116,8 @@ typedef struct uint32_t secondFrequencyHz; uint32_t firstRequestedFrequencyHz; uint32_t secondRequestedFrequencyHz; + uint32_t firstRepeatCount; + uint32_t secondRepeatCount; PLSR_PLATFORM_TIMER_SETTING firstSetting; PLSR_PLATFORM_TIMER_SETTING secondSetting; PLSR_PROFILE_ENTRY warmup[PLSR_HANDOFF_WARMUP_ITEMS]; @@ -206,6 +218,14 @@ static PLSR_RAMP PlsrRamp; static PLSR_SHORT_PROFILE PlsrShortProfile; static PLSR_PROFILE_QUEUE PlsrProfileQueue; static PLSR_HANDOFF_PLAN PlsrHandoffPlan; +static volatile uint64_t PlsrCountedObservedPublished; +static volatile uint8_t PlsrCountedHandoffStaged; +/* 段边界/流故障事件:IRQ 只置事件并快照(handoff 计划 + 边界累计计数), + 全部簿记由 1ms 任务消费事件时完成(IRQ 内不做状态转换与错误标志写入)。 */ +static volatile uint8_t PlsrCountedBoundaryEvent; +static volatile PLSR_HANDOFF_PLAN PlsrCountedBoundaryPlan; +static volatile uint64_t PlsrCountedBoundaryObserved; +static volatile uint8_t PlsrCountedFaultEvent; static PLSR_HANDOFF_PLAN PlsrPreparedHandoffPlans[2][PLSR_SEGMENT_COUNT_MAX]; static volatile uint8_t PlsrPreparedHandoffBank; @@ -289,7 +309,8 @@ static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile, uint32_t startFrequencyHz, uint32_t targetFrequencyHz, uint64_t pulseCount); -static uint32_t PlsrShortProfileTakeFrequency(PLSR_SHORT_PROFILE *profile); +static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile, + PLSR_PROFILE_ENTRY *entry); static uint8_t PlsrReplanPulseDir(uint32_t targetHz, uint32_t totalPulses); static void PlsrProfileQueueReset(void); @@ -300,6 +321,7 @@ static uint8_t PlsrProfileQueueBegin( uint8_t producerSegment, uint8_t preparedHandoffBank); static uint8_t PlsrProfileQueueFill(uint16_t targetCount); +static uint8_t PlsrStageCountedHandoff(void); static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext( uint8_t pulseOutput); static uint8_t PlsrPrepareFutureHandoffQueue(void); @@ -476,6 +498,7 @@ void PlsrFinalArmJobIrq(uint8_t pulseOutput) PlsrPlatformExitCritical(criticalState); } +#if PLSR_DIAGNOSTIC_ENABLED static uint32_t PlsrAbsDifferenceU32(uint32_t first, uint32_t second) { return (first >= second) ? (first - second) : (second - first); @@ -495,7 +518,9 @@ static int32_t PlsrDifferenceI32(uint32_t first, uint32_t second) } return (int32_t)difference; } +#endif +#if PLSR_DIAGNOSTIC_ENABLED static void PlsrDiagnosticLatch(uint16_t reason) { PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_FAULT_LATCHED; @@ -504,20 +529,27 @@ static void PlsrDiagnosticLatch(uint16_t reason) PlsrDiagnostic.reason = reason; } } +#endif static void PlsrDiagnosticReset(void) { +#if PLSR_DIAGNOSTIC_ENABLED (void)memset((void *)&PlsrDiagnostic, 0, sizeof(PlsrDiagnostic)); PlsrDiagnostic.firstMismatchSample = 0xFFFFFFFFUL; PlsrDiagnosticSegmentCounterBase = 0UL; PlsrDiagnosticQueuedExpectedHz = 0UL; PlsrDiagnosticFailedChecks = 0U; +#else + /* 关闭状态保持诊断区清零,Modbus 读诊断寄存器恒为 0。 */ + (void)memset((void *)&PlsrDiagnostic, 0, sizeof(PlsrDiagnostic)); +#endif } static void PlsrDiagnosticBeginSegment(uint8_t segmentNumber, uint64_t expectedCycles, uint8_t directionPositive) { +#if PLSR_DIAGNOSTIC_ENABLED if (expectedCycles > 0xFFFFFFFFUL) { PlsrDiagnostic.expectedCycles = 0xFFFFFFFFUL; @@ -538,10 +570,16 @@ static void PlsrDiagnosticBeginSegment(uint8_t segmentNumber, PlsrDiagnostic.countError = 0L; PlsrDiagnosticSegmentCounterBase = PlsrPlatformObservedPulses( (uint8_t)PlsrActiveConfig.pulseOutput); +#else + (void)segmentNumber; + (void)expectedCycles; + (void)directionPositive; +#endif } static void PlsrDiagnosticFinishSegment(uint8_t completedNormally) { +#if PLSR_DIAGNOSTIC_ENABLED uint64_t now; uint64_t observed; uint32_t observedCycles; @@ -594,12 +632,16 @@ static void PlsrDiagnosticFinishSegment(uint8_t completedNormally) { PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_COUNT_PASS; } +#else + (void)completedNormally; +#endif } static void PlsrDiagnosticRecordFrequency(uint32_t requestedHz, uint32_t expectedHz, uint32_t actualHz) { +#if PLSR_DIAGNOSTIC_ENABLED uint32_t error = PlsrAbsDifferenceU32(actualHz, expectedHz); PlsrDiagnostic.requestedHz = requestedHz; @@ -623,8 +665,14 @@ static void PlsrDiagnosticRecordFrequency(uint32_t requestedHz, { PlsrDiagnostic.curveMaxAbsErrorHz = error; } +#else + (void)requestedHz; + (void)expectedHz; + (void)actualHz; +#endif } +#if PLSR_DIAGNOSTIC_ENABLED static void PlsrDiagnosticRecordCurveSample(uint32_t expectedHz, uint32_t actualHz) { @@ -662,6 +710,7 @@ static void PlsrDiagnosticRecordCurveSample(uint32_t expectedHz, PlsrDiagnosticLatch(PLSR_DIAG_REASON_CURVE); } } +#endif static uint8_t PlsrDiagnosticStartPulse(uint8_t pulseOutput, uint32_t requestedFirstHz, @@ -685,12 +734,14 @@ static uint8_t PlsrDiagnosticStartPulse(uint8_t pulseOutput, PlsrDiagnosticFinishSegment(0U); return 0U; } +#if PLSR_DIAGNOSTIC_ENABLED PlsrDiagnosticRecordFrequency(requestedFirstHz, firstSetting.actualFrequencyHz, *actualFirstHz); PlsrDiagnosticRecordCurveSample(firstSetting.actualFrequencyHz, *actualFirstHz); PlsrDiagnosticQueuedExpectedHz = queuedSetting.actualFrequencyHz; +#endif return 1U; } @@ -699,8 +750,9 @@ static PLSR_PLATFORM_QUEUE_RESULT PlsrDiagnosticQueueFrequency( uint32_t requestedHz, uint32_t *actualHz) { - uint32_t expectedHz; PLSR_PLATFORM_QUEUE_RESULT result; +#if PLSR_DIAGNOSTIC_ENABLED + uint32_t expectedHz; if (PlsrPlatformExpectedFrequency( pulseOutput, (uint8_t)PlsrActiveConfig.outputMode, @@ -709,6 +761,7 @@ static PLSR_PLATFORM_QUEUE_RESULT PlsrDiagnosticQueueFrequency( PlsrDiagnosticFinishSegment(0U); return PLSR_PLATFORM_QUEUE_FAILED; } +#endif result = PlsrPlatformQueueFrequency(pulseOutput, requestedHz, actualHz); if (result == PLSR_PLATFORM_QUEUE_FAILED) { @@ -720,13 +773,16 @@ static PLSR_PLATFORM_QUEUE_RESULT PlsrDiagnosticQueueFrequency( return result; } +#if PLSR_DIAGNOSTIC_ENABLED PlsrDiagnosticRecordFrequency(requestedHz, expectedHz, *actualHz); PlsrDiagnosticQueuedExpectedHz = expectedHz; +#endif return PLSR_PLATFORM_QUEUE_APPLIED; } static void PlsrDiagnosticCheckActiveFrequency(uint32_t activeHz) { +#if PLSR_DIAGNOSTIC_ENABLED uint16_t platformFault = PlsrPlatformDiagnosticFault(); uint32_t observedHz = activeHz; @@ -773,6 +829,9 @@ static void PlsrDiagnosticCheckActiveFrequency(uint32_t activeHz) observedHz); } } +#else + (void)activeHz; +#endif } static void PlsrSetDefaults(PLSR_CONFIG *config) @@ -1648,20 +1707,19 @@ static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile, profile->entryPulses = profile->planner.entryPulses; profile->steadyPulses = profile->planner.steadyPulses; profile->exitPulses = profile->planner.exitPulses; - profile->active = ((profile->startHz != profile->peakHz) - || (profile->peakHz != profile->endHz)) - ? 1U : 0U; + profile->active = 1U; return 1U; } -static uint32_t PlsrShortProfileTakeFrequency(PLSR_SHORT_PROFILE *profile) +static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile, + PLSR_PROFILE_ENTRY *entry) { - uint32_t frequencyHz; + uint32_t repeatCount; - if ((profile->active == 0U) - || (profile->nextPeriod >= profile->pulseCount)) + if ((profile->nextPeriod >= profile->pulseCount) + || (entry == NULL)) { - return (profile->endHz == 0UL) ? 1UL : profile->endHz; + return 0U; } if (profile->pendingRepeats == 0UL) { @@ -1669,20 +1727,32 @@ static uint32_t PlsrShortProfileTakeFrequency(PLSR_SHORT_PROFILE *profile) &profile->pendingItem, 1U) == 0U) { profile->active = 0U; - return (profile->endHz == 0UL) ? 1UL : profile->endHz; + return 0U; } profile->pendingRepeats = profile->pendingItem.repeatCount; } - - frequencyHz = profile->pendingItem.setting.actualFrequencyHz; - profile->pendingRepeats--; - profile->nextPeriod++; - profile->lastRampFrequencyHz = frequencyHz; + repeatCount = profile->pendingRepeats; + if (repeatCount > profile->pulseCount - profile->nextPeriod) + { + repeatCount = profile->pulseCount - profile->nextPeriod; + } + if (repeatCount == 0UL) + { + profile->active = 0U; + return 0U; + } + entry->setting = profile->pendingItem.setting; + entry->requestedFrequencyHz = entry->setting.actualFrequencyHz; + entry->repeatCount = repeatCount; + entry->startsNextSegment = 0U; + profile->pendingRepeats -= repeatCount; + profile->nextPeriod += repeatCount; + profile->lastRampFrequencyHz = entry->setting.actualFrequencyHz; if (profile->nextPeriod >= profile->pulseCount) { profile->active = 0U; } - return frequencyHz; + return 1U; } /* Caller holds the platform critical section. The currently preloaded @@ -1759,6 +1829,7 @@ static void PlsrProfileQueueReset(void) PlsrProfileQueue.active = 0U; PlsrProfileQueue.generatorComplete = 0U; PlsrProfileQueue.producerEpoch = 0UL; + PlsrProfileQueue.repeatRemaining = 0UL; PlsrProfileQueue.producerSegment = 0U; PlsrProfileQueue.preparedHandoffBank = 0U; PlsrProfileQueue.producerProfile.active = 0U; @@ -1780,6 +1851,7 @@ static uint8_t PlsrProfileQueueBegin( PlsrProfileQueue.producerSegment = producerSegment; PlsrProfileQueue.preparedHandoffBank = preparedHandoffBank; PlsrProfileQueue.generatorComplete = 0U; + PlsrProfileQueue.repeatRemaining = 0UL; PlsrCopyShortProfile(&PlsrProfileQueue.producerProfile, producerProfile); PlsrProfileQueue.active = @@ -1803,6 +1875,7 @@ static void PlsrProfileQueueInvalidateGeneration(void) PlsrProfileQueue.generatorComplete = 0U; PlsrProfileQueue.readIndex = 0U; PlsrProfileQueue.writeIndex = 0U; + PlsrProfileQueue.repeatRemaining = 0UL; PlsrPlatformExitCritical(criticalState); } @@ -1870,12 +1943,7 @@ static uint8_t PlsrProfileQueueFill(uint16_t targetCount) && !defined(PLSR_HOST_TEST) startCycles = PlsrProfileTimingNow(); #endif - entry.requestedFrequencyHz = - PlsrShortProfileTakeFrequency(&candidate); - if (PlsrPlatformBuildTimerSetting( - (uint8_t)PlsrActiveConfig.pulseOutput, - (uint8_t)PlsrActiveConfig.outputMode, - entry.requestedFrequencyHz, &entry.setting) == 0U) + if (PlsrShortProfileTakeRun(&candidate, &entry) == 0U) { return 0U; } @@ -1916,6 +1984,12 @@ static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext( uint32_t actualFrequencyHz; PLSR_PLATFORM_QUEUE_RESULT result; + if (PlsrProfileQueue.repeatRemaining != 0UL) + { + PlsrProfileQueue.repeatRemaining--; + return PLSR_PLATFORM_QUEUE_APPLIED; + } + if (PlsrProfileQueue.active == 0U) { if (PlsrProfileQueue.generatorComplete != 0U) @@ -1945,6 +2019,7 @@ static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext( } nextReadIndex = readIndex + 1UL; PlsrProfileQueue.readIndex = nextReadIndex; + PlsrProfileQueue.repeatRemaining = entry->repeatCount - 1UL; PlsrDeferredFrequencyPending = 0U; PlsrQueuedFrequencyHz = actualFrequencyHz; PlsrDiagnosticRecordFrequency(entry->requestedFrequencyHz, @@ -1980,6 +2055,7 @@ static void PlsrInvalidateHandoffPlans(void) uint32_t criticalState = PlsrPlatformEnterCritical(); PlsrHandoffPlan.valid = 0U; + PlsrCountedHandoffStaged = 0U; for (bank = 0U; bank < 2U; bank++) { for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++) @@ -2116,9 +2192,11 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz) PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].frequencyHz; uint32_t firstFrequencyHz; uint32_t secondFrequencyHz; + uint32_t actualFrequencyHz; uint32_t profileEpoch; uint8_t profileSegment; uint8_t profileHandoffBank; + PLSR_PROFILE_ENTRY firstRun; PlsrSegmentClockStarted = 1U; PlsrSegmentElapsedMs = 0UL; @@ -2129,12 +2207,12 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz) { PlsrRamp.active = 0U; PlsrRefreshCurrentHandoffPlan(PlsrShortProfile.endHz); - firstFrequencyHz = - PlsrShortProfileTakeFrequency(&PlsrShortProfile); - secondFrequencyHz = - (PlsrShortProfile.nextPeriod < PlsrShortProfile.pulseCount) - ? PlsrShortProfileTakeFrequency(&PlsrShortProfile) - : firstFrequencyHz; + if (PlsrShortProfileTakeRun(&PlsrShortProfile, &firstRun) == 0U) + { + return 0U; + } + firstFrequencyHz = firstRun.setting.actualFrequencyHz; + secondFrequencyHz = firstFrequencyHz; profileEpoch = PlsrSegmentEpoch; profileSegment = PlsrCurrentSegment; profileHandoffBank = PlsrPreparedHandoffBank; @@ -2148,6 +2226,25 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz) PlsrShortProfile.active = 0U; return 0U; } + PlsrCountedHandoffStaged = 0U; + if ((PlsrStageCountedHandoff() == 0U) + || (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)) + { + PlsrProfileQueueReset(); + PlsrShortProfile.active = 0U; + return 0U; + } + { + uint32_t readIndex = PlsrProfileQueue.readIndex; + uint32_t writeIndex = PlsrProfileQueue.writeIndex; + + if (readIndex != writeIndex) + { + secondFrequencyHz = PlsrProfileQueue.entries[ + readIndex & PLSR_PROFILE_QUEUE_MASK] + .setting.actualFrequencyHz; + } + } if (secondFrequencyHz > firstFrequencyHz) { PlsrRunStatus = PLSR_STATUS_ACCELERATING; @@ -2160,16 +2257,31 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz) { PlsrRunStatus = PLSR_STATUS_RUNNING; } - if (PlsrApplyFrequencyPair(firstFrequencyHz, - secondFrequencyHz, - PlsrSegmentEpoch) == 0U) + PlsrCurrentFrequencyHz = firstFrequencyHz; + PlsrQueuedFrequencyHz = secondFrequencyHz; + PlsrDiagnosticQueuedExpectedHz = firstRun.setting.actualFrequencyHz; + PlsrCountedObservedPublished = PlsrPlatformObservedPulses( + (uint8_t)PlsrActiveConfig.pulseOutput); + PlsrPulseActive = 1U; + PlsrExecutor.generation++; + PlsrExecutor.mode = (PlsrProfileQueue.generatorComplete != 0U) + ? PLSR_EXEC_STEP_TABLE + : PLSR_EXEC_STREAM; + if (PlsrPlatformStartCountedStreamPrepared( + (uint8_t)PlsrActiveConfig.pulseOutput, + &firstRun.setting, firstRun.repeatCount, + &actualFrequencyHz) == 0U) { + PlsrPulseActive = 0U; + PlsrExecutor.mode = PLSR_EXEC_IDLE; PlsrProfileQueueReset(); PlsrShortProfile.active = 0U; return 0U; } - PlsrExecutor.generation++; - PlsrExecutor.mode = PLSR_EXEC_STREAM; + PlsrCurrentFrequencyHz = actualFrequencyHz; + PlsrDiagnosticRecordFrequency(firstRun.requestedFrequencyHz, + firstRun.setting.actualFrequencyHz, + actualFrequencyHz); return 1U; } @@ -2557,22 +2669,37 @@ static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment, { return 0U; } - plan->firstFrequencyHz = - PlsrShortProfileTakeFrequency(&plan->profile); - plan->secondFrequencyHz = - (plan->profile.nextPeriod < plan->profile.pulseCount) - ? PlsrShortProfileTakeFrequency(&plan->profile) - : plan->firstFrequencyHz; - plan->firstRequestedFrequencyHz = plan->firstFrequencyHz; - plan->secondRequestedFrequencyHz = plan->secondFrequencyHz; - if ((PlsrPlatformBuildTimerSetting( - (uint8_t)PlsrActiveConfig.pulseOutput, - (uint8_t)PlsrActiveConfig.outputMode, - plan->firstFrequencyHz, &plan->firstSetting) == 0U) - || (PlsrPlatformBuildTimerSetting( - (uint8_t)PlsrActiveConfig.pulseOutput, - (uint8_t)PlsrActiveConfig.outputMode, - plan->secondFrequencyHz, &plan->secondSetting) == 0U)) + { + PLSR_PROFILE_ENTRY firstEntry; + PLSR_PROFILE_ENTRY secondEntry; + + if (PlsrShortProfileTakeRun(&plan->profile, &firstEntry) == 0U) + { + return 0U; + } + plan->firstSetting = firstEntry.setting; + plan->firstFrequencyHz = firstEntry.setting.actualFrequencyHz; + plan->firstRequestedFrequencyHz = firstEntry.requestedFrequencyHz; + plan->firstRepeatCount = firstEntry.repeatCount; + if (PlsrShortProfileTakeRun(&plan->profile, &secondEntry) != 0U) + { + plan->secondSetting = secondEntry.setting; + plan->secondFrequencyHz = secondEntry.setting.actualFrequencyHz; + plan->secondRequestedFrequencyHz = + secondEntry.requestedFrequencyHz; + plan->secondRepeatCount = secondEntry.repeatCount; + } + else + { + plan->secondSetting = firstEntry.setting; + plan->secondFrequencyHz = firstEntry.setting.actualFrequencyHz; + plan->secondRequestedFrequencyHz = + firstEntry.requestedFrequencyHz; + plan->secondRepeatCount = 0UL; + } + } + if ((plan->firstRepeatCount == 0UL) + || (plan->firstFrequencyHz == 0UL)) { return 0U; } @@ -2584,12 +2711,7 @@ static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment, { PLSR_PROFILE_ENTRY *entry = &plan->warmup[warmupIndex]; - entry->requestedFrequencyHz = - PlsrShortProfileTakeFrequency(&plan->profile); - if (PlsrPlatformBuildTimerSetting( - (uint8_t)PlsrActiveConfig.pulseOutput, - (uint8_t)PlsrActiveConfig.outputMode, - entry->requestedFrequencyHz, &entry->setting) == 0U) + if (PlsrShortProfileTakeRun(&plan->profile, entry) == 0U) { return 0U; } @@ -2681,6 +2803,354 @@ static uint8_t PlsrSelectPreparedHandoffPlan(PLSR_HANDOFF_PLAN *plan) return 1U; } +static uint8_t PlsrStageCountedHandoff(void) +{ + const PLSR_HANDOFF_PLAN *prepared; + PLSR_HANDOFF_PLAN candidate; + PLSR_PROFILE_ENTRY entry; + uint32_t criticalState; + uint32_t writeIndex; + uint16_t required; + uint8_t currentSegment; + uint8_t index; + + if ((PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR) + || (PlsrCountedHandoffStaged != 0U) + || (PlsrStopRequested != 0U) + || (PlsrCutRequested != 0U) + || (PlsrProfileQueue.generatorComplete == 0U)) + { + return 1U; + } + currentSegment = PlsrCurrentSegment; + if ((currentSegment == 0U) + || (currentSegment > PlsrActiveConfig.segmentCount)) + { + return 1U; + } + prepared = &PlsrPreparedHandoffPlans[PlsrPreparedHandoffBank] + [currentSegment - 1U]; + if ((prepared->valid == 0U) + || (prepared->positive != PlsrCountPositive)) + { + return 1U; + } + candidate = *prepared; + required = (uint16_t)(1U + candidate.warmupCount + + ((candidate.secondRepeatCount != 0UL) + ? 1U : 0U)); + criticalState = PlsrPlatformEnterCritical(); + if ((PlsrCountedHandoffStaged != 0U) + || (PlsrProfileQueue.generatorComplete == 0U) + || ((uint16_t)(PLSR_PROFILE_QUEUE_CAPACITY + - PlsrProfileQueueCount()) < required)) + { + PlsrPlatformExitCritical(criticalState); + return 1U; + } + writeIndex = PlsrProfileQueue.writeIndex; + entry.setting = candidate.firstSetting; + entry.requestedFrequencyHz = candidate.firstRequestedFrequencyHz; + entry.repeatCount = candidate.firstRepeatCount; + entry.startsNextSegment = 1U; + PlsrProfileQueue.entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry; + writeIndex++; + if (candidate.secondRepeatCount != 0UL) + { + entry.setting = candidate.secondSetting; + entry.requestedFrequencyHz = + candidate.secondRequestedFrequencyHz; + entry.repeatCount = candidate.secondRepeatCount; + entry.startsNextSegment = 0U; + PlsrProfileQueue.entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry; + writeIndex++; + } + for (index = 0U; index < candidate.warmupCount; index++) + { + entry = candidate.warmup[index]; + entry.startsNextSegment = 0U; + PlsrProfileQueue.entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry; + writeIndex++; + } + PlsrProfileQueue.writeIndex = writeIndex; + PlsrCopyShortProfile(&PlsrProfileQueue.producerProfile, + &candidate.profile); + PlsrProfileQueue.producerEpoch = PlsrSegmentEpoch + 1UL; + PlsrProfileQueue.producerSegment = candidate.nextSegment; + PlsrProfileQueue.generatorComplete = + ((candidate.profile.active == 0U) + || (candidate.profile.nextPeriod >= candidate.profile.pulseCount)) + ? 1U : 0U; + PlsrProfileQueue.active = 1U; + PlsrHandoffPlan = candidate; + PlsrHandoffPlan.valid = 1U; + PlsrCountedHandoffStaged = 1U; + PlsrPlatformExitCritical(criticalState); + return 1U; +} + +static uint8_t PlsrSyncCountedProgress(void) +{ + uint64_t observed; + uint64_t delta; + uint64_t remaining; + int64_t nextPosition; + + observed = PlsrPlatformObservedPulses( + (uint8_t)PlsrActiveConfig.pulseOutput); + if (observed < PlsrCountedObservedPublished) + { + return 0U; + } + delta = observed - PlsrCountedObservedPublished; + if (delta == 0ULL) + { + return 1U; + } + remaining = PlsrRemainingPulses; + if (delta > remaining) + { + delta = remaining; +#if PLSR_COUNT_ERROR_CHECK_ENABLED + PlsrCountOverflowPending = 1U; +#endif + } + if (PlsrCountPositive != 0U) + { + nextPosition = (int64_t)PlsrPosition + (int64_t)delta; + } + else + { + nextPosition = (int64_t)PlsrPosition - (int64_t)delta; + } + if ((nextPosition > (int64_t)INT32_MAX) + || (nextPosition < (int64_t)INT32_MIN)) + { + PlsrPositionValid = 0U; +#if PLSR_COUNT_ERROR_CHECK_ENABLED + PlsrCountOverflowPending = 1U; +#endif + } + else + { + PlsrPosition = (int32_t)nextPosition; + } + PlsrRemainingPulses = remaining - delta; + PlsrCountedObservedPublished = observed; + PlsrPositionCheckpointDirty = 1U; + return 1U; +} + +uint8_t PlsrExecTakeCountedRunIrq( + uint8_t pulseOutput, + PLSR_PLATFORM_TIMER_SETTING *setting, + uint32_t *pulseCount, + uint8_t *startsNextSegment) +{ + const PLSR_PROFILE_ENTRY *entry; + uint32_t readIndex; + uint32_t nextReadIndex; + + if ((pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput) + || (setting == NULL) || (pulseCount == NULL) + || (startsNextSegment == NULL) + || (PlsrPulseActive == 0U)) + { + return PLSR_EXEC_RUN_FAILED; + } + readIndex = PlsrProfileQueue.readIndex; + if (readIndex == PlsrProfileQueue.writeIndex) + { + if (PlsrProfileQueue.generatorComplete != 0U) + { + return PLSR_EXEC_RUN_DONE; + } + return PLSR_EXEC_RUN_FAILED; + } + entry = &PlsrProfileQueue.entries[readIndex & PLSR_PROFILE_QUEUE_MASK]; + if (entry->repeatCount == 0UL) + { + return PLSR_EXEC_RUN_FAILED; + } + /* 先校验 handoff 前置条件,再推进读索引:失败时该项不被消费。 + 不在此处更新任何执行状态(Pending/active 等),全部由任务消费事件时做。 */ + if (entry->startsNextSegment != 0U) + { + if ((PlsrCountedHandoffStaged == 0U) + || (PlsrHandoffPlan.valid == 0U)) + { + return PLSR_EXEC_RUN_FAILED; + } + } + *setting = entry->setting; + *pulseCount = entry->repeatCount; + *startsNextSegment = entry->startsNextSegment; + nextReadIndex = readIndex + 1UL; + PlsrProfileQueue.readIndex = nextReadIndex; + /* 记录硬件即将生效的频率(事实镜像),不做任何状态转换。 */ + PlsrQueuedFrequencyHz = entry->setting.actualFrequencyHz; + return PLSR_EXEC_RUN_READY; +} + +void PlsrExecCountedSegmentBoundaryIrq(uint8_t pulseOutput, + uint32_t completedPulses) +{ + if (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput) + { + return; + } + if (PlsrHandoffPlan.valid == 0U) + { + PlsrCountedFaultEvent = 1U; + return; + } + /* 只置事件并快照:handoff 计划 + 边界累计计数(由平台层在 run 完成 + 累加后传入,IRQ 内不做带副作用的计数读取)。段切换簿记全部由任务 + 在 PlsrExecServiceCountedBoundaryEvent 完成。 */ + PlsrCountedBoundaryPlan = PlsrHandoffPlan; + PlsrCountedBoundaryObserved = completedPulses; + PlsrCountedBoundaryEvent = 1U; +} + +static void PlsrExecServiceCountedBoundaryEvent(void); + +/* 任务上下文:消费 counted 流的全部 IRQ 事件(流故障 + 段边界)。 + 段切换簿记与错误标志写入均在此完成,IRQ 内不再做状态转换。 */ +static void PlsrExecServiceCountedEvents(void) +{ + if (PlsrCountedFaultEvent != 0U) + { + PlsrCountedFaultEvent = 0U; + PlsrTimerErrorPending = 1U; + } + PlsrExecServiceCountedBoundaryEvent(); +} + +/* 任务上下文:消费段边界事件,完成全部段切换簿记。 + 硬件连续性不依赖本函数(下一段首 run 已由队列预装载),晚 1ms 消费无影响。 */ +static void PlsrExecServiceCountedBoundaryEvent(void) +{ + PLSR_HANDOFF_PLAN plan; + uint64_t observed; + uint64_t delta; + int64_t nextPosition; + uint32_t currentFrequencyHz; + uint32_t queuedFrequencyHz; + uint8_t nextSegment; + + if (PlsrCountedBoundaryEvent == 0U) + { + return; + } + PlsrCountedBoundaryEvent = 0U; + plan = PlsrCountedBoundaryPlan; + observed = PlsrCountedBoundaryObserved; + nextSegment = plan.nextSegment; + if ((nextSegment == 0U) + || (nextSegment > PlsrActiveConfig.segmentCount)) + { + PlsrTimerErrorPending = 1U; + return; + } + + /* 用 IRQ 边界时刻的计数快照结算旧段:任务消费时下一 run 可能已发出 + 若干脉冲,直接读当前硬件计数会把下一段脉冲算进旧段。 */ + if (observed < PlsrCountedObservedPublished) + { + PlsrTimerErrorPending = 1U; + return; + } + delta = observed - PlsrCountedObservedPublished; + if (delta > PlsrRemainingPulses) + { + delta = PlsrRemainingPulses; +#if PLSR_COUNT_ERROR_CHECK_ENABLED + PlsrCountOverflowPending = 1U; +#endif + } + if (PlsrCountPositive != 0U) + { + nextPosition = (int64_t)PlsrPosition + (int64_t)delta; + } + else + { + nextPosition = (int64_t)PlsrPosition - (int64_t)delta; + } + if ((nextPosition > (int64_t)INT32_MAX) + || (nextPosition < (int64_t)INT32_MIN)) + { + PlsrPositionValid = 0U; +#if PLSR_COUNT_ERROR_CHECK_ENABLED + PlsrCountOverflowPending = 1U; +#endif + } + else + { + PlsrPosition = (int32_t)nextPosition; + } + PlsrRemainingPulses -= delta; + PlsrCountedObservedPublished = observed; + PlsrPositionCheckpointDirty = 1U; + if (PlsrRemainingPulses != 0ULL) + { + PlsrTimerErrorPending = 1U; + return; + } + + PlsrDiagnosticFinishSegment(1U); + PlsrSegmentEpoch++; + PlsrCurrentSegment = nextSegment; + PlsrRemainingPulses = plan.magnitude; + PlsrCountPositive = plan.positive; + PlsrCurrentFrequencyHz = plan.firstFrequencyHz; + PlsrBoundaryFrequencyHz = plan.firstFrequencyHz; + PlsrSegmentClockStarted = 1U; + PlsrSegmentElapsedMs = 0UL; + PlsrWaitElapsedMs = 0UL; + PlsrBoundaryRampStarted = 0U; + PlsrBoundaryPending = 0U; + PlsrBoundaryWasCut = 0U; + PlsrCutRequested = 0U; + PlsrFrequencyUpdatePending = 0U; + PlsrDeferredFrequencyPending = 0U; + PlsrExtEdgePending = 0U; + PlsrExtPreviousLevel = + PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput); + PlsrCopyShortProfile(&PlsrShortProfile, + &PlsrProfileQueue.producerProfile); + PlsrDiagnosticBeginSegment(nextSegment, plan.magnitude, plan.positive); + PlsrSeamlessHandoffPending = 1U; + PlsrCountedHandoffStaged = 0U; + PlsrHandoffPlan.valid = 0U; + PlsrExecutor.generation++; + PlsrExecutor.mode = (PlsrProfileQueue.generatorComplete != 0U) + ? PLSR_EXEC_STEP_TABLE + : PLSR_EXEC_STREAM; + currentFrequencyHz = PlsrCurrentFrequencyHz; + queuedFrequencyHz = PlsrQueuedFrequencyHz; + if (queuedFrequencyHz > currentFrequencyHz) + { + PlsrRunStatus = PLSR_STATUS_ACCELERATING; + } + else if (queuedFrequencyHz < currentFrequencyHz) + { + PlsrRunStatus = PLSR_STATUS_DECELERATING; + } + else + { + PlsrRunStatus = PLSR_STATUS_RUNNING; + } +} + +void PlsrExecCountedStreamFaultIrq(uint8_t pulseOutput) +{ + if (pulseOutput == (uint8_t)PlsrActiveConfig.pulseOutput) + { + /* 只置事件:任务消费时统一置 PlsrTimerErrorPending。 */ + PlsrCountedFaultEvent = 1U; + } +} + static uint8_t PlsrPrepareFutureHandoffQueue(void) { const PLSR_HANDOFF_PLAN *prepared; @@ -2908,12 +3378,17 @@ static void PlsrHandleBoundary(uint8_t extEdge) PlsrEnterError(PLSR_ERROR_TIMER); return; } +#if PLSR_COUNT_ERROR_CHECK_ENABLED if (PlsrCountOverflowPending != 0U) { PlsrCountOverflowPending = 0U; PlsrEnterError(PLSR_ERROR_COUNT); return; } +#else + /* 计数错误检查暂时关闭:偏差已由同步路径钳制,标志直接清除。 */ + PlsrCountOverflowPending = 0U; +#endif if (PlsrStopRequested != 0U) { @@ -3152,6 +3627,12 @@ uint8_t PlsrInit(void) PlsrBoundaryPending = 0U; PlsrBoundaryWasCut = 0U; PlsrCountOverflowPending = 0U; + PlsrCountedObservedPublished = 0ULL; + PlsrCountedHandoffStaged = 0U; + PlsrCountedBoundaryEvent = 0U; + PlsrCountedBoundaryPlan.valid = 0U; + PlsrCountedBoundaryObserved = 0ULL; + PlsrCountedFaultEvent = 0U; PlsrPositionCheckpointDirty = 0U; PlsrFrequencyUpdatePending = 0U; PlsrDeferredFrequencyPending = 0U; @@ -3446,6 +3927,83 @@ static void PlsrEnterErrorIfEpoch(PLSR_ERROR error, uint32_t expectedEpoch) PlsrPlatformExitCritical(criticalState); } +static uint8_t PlsrServiceCountedExecutor(void) +{ + uint32_t completedPulses; + uint32_t completedFrequencyHz; + uint32_t activeFrequencyHz; + uint32_t queuedFrequencyHz; + uint8_t completedNormally; + + if ((PlsrPulseActive == 0U) + || ((PlsrExecutor.mode != PLSR_EXEC_STEP_TABLE) + && (PlsrExecutor.mode != PLSR_EXEC_STREAM) + && (PlsrExecutor.mode != PLSR_EXEC_STOPPING))) + { + return 0U; + } + if (PlsrSyncCountedProgress() == 0U) + { +#if PLSR_COUNT_ERROR_CHECK_ENABLED + PlsrEnterError(PLSR_ERROR_COUNT); + return 1U; +#else + /* 计数错误检查暂时关闭:observed 回退(平台计数器基准重置造成的 + 视图回退)时重新校准发布点,继续运行,不进错误。 */ + PlsrCountedObservedPublished = PlsrPlatformObservedPulses( + (uint8_t)PlsrActiveConfig.pulseOutput); + return 0U; +#endif + } + activeFrequencyHz = PlsrPlatformActiveFrequency( + (uint8_t)PlsrActiveConfig.pulseOutput); + if (activeFrequencyHz != 0UL) + { + PlsrCurrentFrequencyHz = activeFrequencyHz; + PlsrDiagnosticCheckActiveFrequency(activeFrequencyHz); + queuedFrequencyHz = PlsrQueuedFrequencyHz; + if (queuedFrequencyHz > activeFrequencyHz) + { + PlsrRunStatus = PLSR_STATUS_ACCELERATING; + } + else if (queuedFrequencyHz < activeFrequencyHz) + { + PlsrRunStatus = PLSR_STATUS_DECELERATING; + } + else + { + PlsrRunStatus = PLSR_STATUS_RUNNING; + } + } + if (PlsrPlatformTakeFiniteCompletion( + (uint8_t)PlsrActiveConfig.pulseOutput, + &completedPulses) == 0U) + { + return 0U; + } + (void)completedPulses; + (void)PlsrSyncCountedProgress(); + completedFrequencyHz = PlsrCurrentFrequencyHz; + completedNormally = ((PlsrRemainingPulses == 0ULL) + && (PlsrCutRequested == 0U) + && (PlsrCountOverflowPending == 0U) + && (PlsrTimerErrorPending == 0U)) ? 1U : 0U; + PlsrDiagnosticFinishSegment(completedNormally); + PlsrShortProfile.active = 0U; + PlsrProfileQueue.active = 0U; + PlsrHandoffPlan.valid = 0U; + PlsrCountedHandoffStaged = 0U; + PlsrBoundaryFrequencyHz = completedFrequencyHz; + PlsrBoundaryWasCut = (PlsrCutRequested != 0U) ? 1U : 0U; + PlsrCutRequested = 0U; + PlsrPulseActive = 0U; + PlsrCurrentFrequencyHz = 0UL; + PlsrQueuedFrequencyHz = 0UL; + PlsrBoundaryPending = 1U; + PlsrExecutor.mode = PLSR_EXEC_IDLE; + return 1U; +} + void PlsrPoll1ms(void) { uint8_t extLevel; @@ -3468,14 +4026,39 @@ void PlsrPoll1ms(void) return; } + /* 段边界事件必须在任何计数同步之前消费:快照是 IRQ 边界时刻的 + 硬件计数,晚消费会把下一 run 的脉冲算进旧段。 */ + PlsrExecServiceCountedEvents(); + PlsrPollPositionCheckpoint(); - if ((PlsrShortProfile.active != 0U) + if (PlsrServiceCountedExecutor() != 0U) + { + if (PlsrBoundaryPending != 0U) + { + PlsrHandleBoundary(0U); + } + PlsrPollPersistenceDelay(); + return; + } + + if (((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE) + || (PlsrExecutor.mode == PLSR_EXEC_STREAM)) + && (PlsrProfileQueue.active != 0U) + && (PlsrProfileQueue.generatorComplete == 0U) && (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)) { PlsrEnterError(PLSR_ERROR_TIMER); return; } + if (((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE) + || (PlsrExecutor.mode == PLSR_EXEC_STREAM)) + && ((PlsrStageCountedHandoff() == 0U) + || (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U))) + { + PlsrEnterError(PLSR_ERROR_TIMER); + return; + } criticalState = PlsrPlatformEnterCritical(); pollEpoch = PlsrSegmentEpoch; @@ -3692,6 +4275,12 @@ void PlsrPulseTimerIrq(uint8_t pulseOutput) { return; } + if ((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE) + || (PlsrExecutor.mode == PLSR_EXEC_STREAM) + || (PlsrExecutor.mode == PLSR_EXEC_STOPPING)) + { + return; + } completedFrequencyHz = PlsrCurrentFrequencyHz; PlsrDiagnosticCheckActiveFrequency(completedFrequencyHz); @@ -3715,7 +4304,9 @@ void PlsrPulseTimerIrq(uint8_t pulseOutput) if (positionBits == (uint32_t)INT32_MAX) { PlsrPositionValid = 0U; +#if PLSR_COUNT_ERROR_CHECK_ENABLED PlsrCountOverflowPending = 1U; +#endif } positionBits++; } @@ -3724,7 +4315,9 @@ void PlsrPulseTimerIrq(uint8_t pulseOutput) if (positionBits == (uint32_t)INT32_MIN) { PlsrPositionValid = 0U; +#if PLSR_COUNT_ERROR_CHECK_ENABLED PlsrCountOverflowPending = 1U; +#endif } positionBits--; } diff --git a/PLSR/Src/plsr_internal.h b/PLSR/Src/plsr_internal.h index b277314..a24f7ed 100644 --- a/PLSR/Src/plsr_internal.h +++ b/PLSR/Src/plsr_internal.h @@ -15,10 +15,17 @@ typedef enum { PLSR_EXEC_IDLE = 0, + PLSR_EXEC_STEP_TABLE, PLSR_EXEC_STREAM, - PLSR_EXEC_AB_LEGACY + PLSR_EXEC_AB_LEGACY, + PLSR_EXEC_REPLANNING, + PLSR_EXEC_STOPPING } PLSR_EXEC_MODE; +#define PLSR_EXEC_RUN_FAILED (0U) +#define PLSR_EXEC_RUN_READY (1U) +#define PLSR_EXEC_RUN_DONE (2U) + typedef struct { uint32_t frequencyHz; diff --git a/PLSR/Src/plsr_platform.h b/PLSR/Src/plsr_platform.h index 761e0dc..b2c40ef 100644 --- a/PLSR/Src/plsr_platform.h +++ b/PLSR/Src/plsr_platform.h @@ -73,6 +73,11 @@ uint8_t PlsrPlatformStartFinitePrepared( const PLSR_PLATFORM_TIMER_SETTING *setting, uint32_t pulseCount, uint32_t *actualFrequencyHz); +uint8_t PlsrPlatformStartCountedStreamPrepared( + uint8_t pulseOutput, + const PLSR_PLATFORM_TIMER_SETTING *setting, + uint32_t pulseCount, + uint32_t *actualFrequencyHz); uint8_t PlsrPlatformStartFiniteSequencePrepared( uint8_t pulseOutput, PLSR_PLATFORM_FINITE_STEP *steps, @@ -95,6 +100,19 @@ uint8_t PlsrPlatformTakeFiniteBoundary(uint8_t pulseOutput, uint32_t *completedPulses, uint8_t *sequenceContinues, uint32_t *activeFrequencyHz); + +/* Counted-stream callbacks are owned by the executor in plsr.c. The + platform invokes them only at a hardware counter run boundary. These + callbacks must only latch events/snapshots; all bookkeeping runs in the + 1 ms task. */ +uint8_t PlsrExecTakeCountedRunIrq( + uint8_t pulseOutput, + PLSR_PLATFORM_TIMER_SETTING *setting, + uint32_t *pulseCount, + uint8_t *startsNextSegment); +void PlsrExecCountedSegmentBoundaryIrq(uint8_t pulseOutput, + uint32_t completedPulses); +void PlsrExecCountedStreamFaultIrq(uint8_t pulseOutput); PLSR_PLATFORM_QUEUE_RESULT PlsrPlatformLoadPreparedFromIrq( uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *setting, diff --git a/PLSR/Src/plsr_platform_f407.c b/PLSR/Src/plsr_platform_f407.c index 6980dff..6447538 100644 --- a/PLSR/Src/plsr_platform_f407.c +++ b/PLSR/Src/plsr_platform_f407.c @@ -66,6 +66,7 @@ static uint8_t PlsrHostFiniteEnabled; static uint8_t PlsrHostFiniteActive[4]; static uint8_t PlsrHostFiniteComplete[4]; static uint8_t PlsrHostFiniteFrequencyPending[4]; +static uint8_t PlsrHostCountedStreamActive[4]; static uint32_t PlsrHostFiniteTarget[4]; static uint32_t PlsrHostFiniteEmitted[4]; static PLSR_PLATFORM_FINITE_STEP *PlsrHostFiniteSteps[4]; @@ -403,6 +404,7 @@ uint8_t PlsrPlatformStartFinitePrepared( PlsrHostFiniteActive[pulseOutput] = 1U; PlsrHostFiniteComplete[pulseOutput] = 0U; PlsrHostFiniteFrequencyPending[pulseOutput] = 0U; + PlsrHostCountedStreamActive[pulseOutput] = 0U; PlsrHostFiniteTarget[pulseOutput] = pulseCount; PlsrHostFiniteEmitted[pulseOutput] = 0UL; PlsrHostFiniteStepCount[pulseOutput] = 0U; @@ -418,6 +420,21 @@ uint8_t PlsrPlatformStartFinitePrepared( return 1U; } +uint8_t PlsrPlatformStartCountedStreamPrepared( + uint8_t pulseOutput, + const PLSR_PLATFORM_TIMER_SETTING *setting, + uint32_t pulseCount, + uint32_t *actualFrequencyHz) +{ + if (PlsrPlatformStartFinitePrepared(pulseOutput, setting, pulseCount, + actualFrequencyHz) == 0U) + { + return 0U; + } + PlsrHostCountedStreamActive[pulseOutput] = 1U; + return 1U; +} + uint8_t PlsrPlatformStartFiniteSequencePrepared( uint8_t pulseOutput, PLSR_PLATFORM_FINITE_STEP *steps, @@ -1488,6 +1505,13 @@ static uint32_t PlsrFiniteRetargetDrainPulses[4]; static uint32_t PlsrFiniteTargetPulses[4]; static uint32_t PlsrFiniteRemainingPulses[4]; static uint8_t PlsrFiniteCounterPreload[4]; +static volatile uint8_t PlsrFiniteStreamActive[4]; +static volatile uint8_t PlsrFiniteStreamNextValid[4]; +static volatile uint8_t PlsrFiniteStreamNextStartsSegment[4]; +static volatile uint8_t PlsrFiniteStreamSourceDone[4]; +static volatile uint8_t PlsrFiniteStreamSourceFault[4]; +static uint32_t PlsrFiniteStreamNextPulses[4]; +static PLSR_PLATFORM_TIMER_SETTING PlsrFiniteStreamNextSetting[4]; static PLSR_PLATFORM_FINITE_STEP *PlsrFiniteSteps[4]; static volatile uint16_t PlsrFiniteStepCount[4]; static volatile uint16_t PlsrFiniteStepIndex[4]; @@ -3179,6 +3203,10 @@ uint8_t PlsrPlatformStartFinitePrepared( PlsrFiniteRemainingPulses[pulseOutput] = pulseCount; PlsrFiniteCompletionPending[pulseOutput] = 0U; PlsrFiniteFrequencyPending[pulseOutput] = 0U; + PlsrFiniteStreamActive[pulseOutput] = 0U; + PlsrFiniteStreamNextValid[pulseOutput] = 0U; + PlsrFiniteStreamSourceDone[pulseOutput] = 0U; + PlsrFiniteStreamSourceFault[pulseOutput] = 0U; PlsrFiniteActive[pulseOutput] = 1U; PlsrFiniteStepCount[pulseOutput] = 0U; PlsrFiniteStepIndex[pulseOutput] = 0U; @@ -3198,6 +3226,32 @@ uint8_t PlsrPlatformStartFinitePrepared( return 1U; } +uint8_t PlsrPlatformStartCountedStreamPrepared( + uint8_t pulseOutput, + const PLSR_PLATFORM_TIMER_SETTING *setting, + uint32_t pulseCount, + uint32_t *actualFrequencyHz) +{ + TIM_TypeDef *counter; + uint32_t firstBlock; + + if (PlsrPlatformStartFinitePrepared(pulseOutput, setting, pulseCount, + actualFrequencyHz) == 0U) + { + return 0U; + } + PlsrFiniteStreamActive[pulseOutput] = 1U; + PlsrFiniteStreamNextValid[pulseOutput] = 0U; + PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; + PlsrFiniteStreamSourceDone[pulseOutput] = 0U; + PlsrFiniteStreamSourceFault[pulseOutput] = 0U; + firstBlock = (pulseCount > PLSR_COUNTER_BLOCK_PULSES) + ? PLSR_COUNTER_BLOCK_PULSES : pulseCount; + counter = PlsrCounters[PlsrCounterIndexByOutput[pulseOutput]]; + PlsrFiniteArmNextStepPrepare(pulseOutput, counter, firstBlock); + return 1U; +} + uint8_t PlsrPlatformStartFiniteSequencePrepared( uint8_t pulseOutput, PLSR_PLATFORM_FINITE_STEP *steps, @@ -3434,7 +3488,8 @@ uint8_t PlsrPlatformTakeFiniteCompletion(uint8_t pulseOutput, { *completedPulses = PlsrFiniteTargetPulses[pulseOutput]; } - if (PlsrFiniteStepCount[pulseOutput] == 0U) + if ((PlsrFiniteStepCount[pulseOutput] == 0U) + && (PlsrFiniteStreamActive[pulseOutput] == 0U)) { PlsrObservedPulseBase[pulseOutput] += *completedPulses; } @@ -3447,6 +3502,11 @@ uint8_t PlsrPlatformTakeFiniteCompletion(uint8_t pulseOutput, PlsrFiniteCounterPreload[pulseOutput] = 0U; PlsrFiniteStepCount[pulseOutput] = 0U; PlsrFiniteStepIndex[pulseOutput] = 0U; + PlsrFiniteStreamActive[pulseOutput] = 0U; + PlsrFiniteStreamNextValid[pulseOutput] = 0U; + PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; + PlsrFiniteStreamSourceDone[pulseOutput] = 0U; + PlsrFiniteStreamSourceFault[pulseOutput] = 0U; PlsrTimerActiveFrequencyHz[pulseOutput] = 0UL; PlsrTimerQueuedFrequencyHz[pulseOutput] = 0UL; PlsrTimerRunning[pulseOutput] = 0U; @@ -3944,6 +4004,11 @@ void PlsrPlatformStopPulse(uint8_t pulseOutput) PlsrFiniteRetargetDrainPulses[pulseOutput] = 0UL; PlsrFiniteTargetPulses[pulseOutput] = 0UL; PlsrFiniteRemainingPulses[pulseOutput] = 0UL; + PlsrFiniteStreamActive[pulseOutput] = 0U; + PlsrFiniteStreamNextValid[pulseOutput] = 0U; + PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; + PlsrFiniteStreamSourceDone[pulseOutput] = 0U; + PlsrFiniteStreamSourceFault[pulseOutput] = 0U; if (PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) { uint8_t pairOutput = (uint8_t)(pulseOutput + 1U); @@ -4747,8 +4812,12 @@ static void PlsrFiniteArmNextStepPrepare(uint8_t pulseOutput, counter->DIER &= ~TIM_DIER_CC1IE; counter->SR = ~TIM_SR_CC1IF; - if ((nextIndex >= PlsrFiniteStepCount[pulseOutput]) - || (PlsrFiniteRemainingPulses[pulseOutput] > blockPulses)) + if (PlsrFiniteRemainingPulses[pulseOutput] > blockPulses) + { + return; + } + if ((PlsrFiniteStreamActive[pulseOutput] == 0U) + && (nextIndex >= PlsrFiniteStepCount[pulseOutput])) { return; } @@ -4772,6 +4841,51 @@ static void PlsrFinitePrepareNextStepIrq(uint8_t pulseOutput, const PLSR_PLATFORM_TIMER_SETTING *next; counter->DIER &= ~TIM_DIER_CC1IE; + if (PlsrFiniteStreamActive[pulseOutput] != 0U) + { + PLSR_PLATFORM_TIMER_SETTING streamSetting; + uint32_t streamPulses = 0UL; + uint8_t startsNextSegment = 0U; + uint8_t takeResult; + + if ((PlsrFiniteStreamNextValid[pulseOutput] != 0U) + || (PlsrFiniteStreamSourceDone[pulseOutput] != 0U) + || (PlsrFiniteStreamSourceFault[pulseOutput] != 0U)) + { + return; + } + takeResult = PlsrExecTakeCountedRunIrq( + pulseOutput, &streamSetting, &streamPulses, + &startsNextSegment); + if (takeResult == PLSR_EXEC_RUN_DONE) + { + PlsrFiniteStreamSourceDone[pulseOutput] = 1U; + return; + } + if ((takeResult != PLSR_EXEC_RUN_READY) + || (streamPulses == 0UL) + || (PlsrPreparedSettingIsValid( + pulseOutput, PLSR_OUTPUT_PULSE_DIR, + &streamSetting) == 0U)) + { + PlsrFiniteStreamSourceFault[pulseOutput] = 1U; + PlsrExecCountedStreamFaultIrq(pulseOutput); + return; + } + timer = PlsrTimerMap[pulseOutput].timer; + timer->PSC = streamSetting.prescaler; + timer->ARR = streamSetting.period; + timer->CCR1 = streamSetting.compare; + PlsrTimerQueuedSetting[pulseOutput] = streamSetting; + PlsrTimerQueuedFrequencyHz[pulseOutput] = + streamSetting.actualFrequencyHz; + PlsrFiniteStreamNextSetting[pulseOutput] = streamSetting; + PlsrFiniteStreamNextPulses[pulseOutput] = streamPulses; + PlsrFiniteStreamNextStartsSegment[pulseOutput] = + startsNextSegment; + PlsrFiniteStreamNextValid[pulseOutput] = 1U; + return; + } if (nextIndex >= PlsrFiniteStepCount[pulseOutput]) { return; @@ -4813,7 +4927,47 @@ static void PlsrFiniteCounterIrq(uint8_t pulseOutput, return; } - if (PlsrFiniteStepCount[pulseOutput] != 0U) + if (PlsrFiniteStreamActive[pulseOutput] != 0U) + { + PlsrObservedPulseBase[pulseOutput] += + PlsrFiniteTargetPulses[pulseOutput]; + PlsrObservedPulsePublished[pulseOutput] = + PlsrObservedPulseBase[pulseOutput]; + if (PlsrFiniteStreamNextValid[pulseOutput] != 0U) + { + uint32_t nextPulses = + PlsrFiniteStreamNextPulses[pulseOutput]; + uint32_t firstBlock = + (nextPulses > PLSR_COUNTER_BLOCK_PULSES) + ? PLSR_COUNTER_BLOCK_PULSES : nextPulses; + + if (PlsrFiniteStreamNextStartsSegment[pulseOutput] != 0U) + { + /* 段边界回调只传"到当前 run 完成为止的累计计数"(IRQ 内 + 已累加完成的 base),执行器只置事件,不做簿记。 */ + PlsrExecCountedSegmentBoundaryIrq( + pulseOutput, PlsrObservedPulseBase[pulseOutput]); + } + PlsrFiniteTargetPulses[pulseOutput] = nextPulses; + PlsrFiniteRemainingPulses[pulseOutput] = nextPulses; + PlsrCounterOverflowPulses[ + PlsrCounterIndexByOutput[pulseOutput]] = 0UL; + counter->ARR = (firstBlock == 1UL) + ? 1UL : (firstBlock - 1UL); + PlsrFiniteCounterPreload[pulseOutput] = + (firstBlock == 1UL) ? 1U : 0U; + counter->CNT = PlsrFiniteCounterPreload[pulseOutput]; + PlsrTimerActiveSetting[pulseOutput] = + PlsrFiniteStreamNextSetting[pulseOutput]; + PlsrTimerActiveFrequencyHz[pulseOutput] = + PlsrFiniteStreamNextSetting[pulseOutput].actualFrequencyHz; + PlsrFiniteStreamNextValid[pulseOutput] = 0U; + PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; + PlsrFiniteArmNextStepPrepare(pulseOutput, counter, firstBlock); + return; + } + } + else if (PlsrFiniteStepCount[pulseOutput] != 0U) { uint16_t completedIndex = PlsrFiniteStepIndex[pulseOutput]; uint16_t nextIndex = (uint16_t)(completedIndex + 1U);