Przeglądaj źródła

修复了定时器异常的bug

codex/plsr-2026-minimal
ywh 1 miesiąc temu
rodzic
commit
90dc112828
1 zmienionych plików z 351 dodań i 67 usunięć
  1. +351
    -67
      PLSR/Src/plsr.c

+ 351
- 67
PLSR/Src/plsr.c Wyświetl plik

@@ -64,6 +64,8 @@
#define PLSR_PROFILE_REFILL_BUDGET (200U)
#define PLSR_PROFILE_LOW_WATER (100U)
#define PLSR_PROFILE_LOW_WATER_CLEAR (200U)
#define PLSR_UNDERRUN_HOLD_TIME_US (2000UL)
#define PLSR_UNDERRUN_HOLD_MAX_PULSES (200UL)
#define PLSR_HANDOFF_WARMUP_ITEMS (8U)
#define PLSR_REPLAN_PREFIX_ITEMS (512U)
#define PLSR_REPLAN_PREFIX_TIME_US (5000ULL)
@@ -130,8 +132,11 @@ typedef struct
volatile uint32_t generation;
uint32_t producerEpoch;
volatile uint32_t repeatRemaining;
volatile uint32_t underrunDebtPulses;
PLSR_PLATFORM_TIMER_SETTING lastSetting;
uint8_t producerSegment;
uint8_t preparedHandoffBank;
volatile uint8_t haveLastSetting;
volatile uint8_t active;
volatile uint8_t generatorComplete;
} PLSR_PROFILE_QUEUE;
@@ -357,10 +362,15 @@ static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
uint64_t pulseCount);
static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile,
PLSR_PROFILE_ENTRY *entry);
static uint8_t PlsrShortProfileTakeRunLimited(
PLSR_SHORT_PROFILE *profile,
PLSR_PROFILE_ENTRY *entry,
uint32_t maximumRepeats);
static void PlsrProfileRecordPlannerStatus(
const PLSR_SHORT_PROFILE *profile);
static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
uint32_t totalPulses);
static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
uint32_t targetHz,
uint32_t totalPulses);
static void PlsrProfileQueueReset(void);
static void PlsrProfileQueueInvalidateGeneration(void);
static uint8_t PlsrProfileQueueBegin(
@@ -370,6 +380,12 @@ static uint8_t PlsrProfileQueueBegin(
uint8_t preparedHandoffBank);
static uint8_t PlsrProfileQueueFill(uint16_t targetCount,
uint16_t *itemBudget);
static uint8_t PlsrTimerSettingsEqual(
const PLSR_PLATFORM_TIMER_SETTING *first,
const PLSR_PLATFORM_TIMER_SETTING *second);
static uint8_t PlsrProfileQueueAppendLocked(
PLSR_PROFILE_QUEUE *queue,
const PLSR_PROFILE_ENTRY *entry);
static uint8_t PlsrStageCountedHandoff(void);
static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext(
uint8_t pulseOutput);
@@ -1770,11 +1786,19 @@ static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,

static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile,
PLSR_PROFILE_ENTRY *entry)
{
return PlsrShortProfileTakeRunLimited(profile, entry, 0xFFFFFFFFUL);
}

static uint8_t PlsrShortProfileTakeRunLimited(
PLSR_SHORT_PROFILE *profile,
PLSR_PROFILE_ENTRY *entry,
uint32_t maximumRepeats)
{
uint32_t repeatCount;

if ((profile->nextPeriod >= profile->pulseCount)
|| (entry == NULL))
|| (entry == NULL) || (maximumRepeats == 0UL))
{
return 0U;
}
@@ -1793,6 +1817,10 @@ static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile,
{
repeatCount = profile->pulseCount - profile->nextPeriod;
}
if (repeatCount > maximumRepeats)
{
repeatCount = maximumRepeats;
}
if (repeatCount == 0UL)
{
profile->active = 0U;
@@ -1816,8 +1844,9 @@ static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile,
/* Build the replacement stream in the inactive queue bank while the IRQ keeps
consuming the published bank. A bounded prefix from the old queue bridges
the construction interval; the final bank flip is the only critical part. */
static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
uint32_t totalPulses)
static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
uint32_t targetHz,
uint32_t totalPulses)
{
PLSR_PROFILE_QUEUE *source;
PLSR_PROFILE_QUEUE *destination;
@@ -1835,6 +1864,7 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
uint32_t availablePlanPulses;
uint32_t replacementPulses;
uint32_t prefixCount = 0UL;
uint32_t replacementStartIndex;
uint32_t consumedPrefix;
uint32_t sourceIndex;
uint32_t criticalState;
@@ -1844,7 +1874,7 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
uint8_t sourceBank;
uint8_t destinationBank;
uint8_t boundaryWriteIndex;
uint8_t pipelineStartsNextSegment;
uint8_t pipelineStartsNextSegment = 0U;
uint8_t tailWasClipped = 0U;
uint16_t fillBudget = PLSR_REPLAN_BUILD_ITEMS;

@@ -1862,16 +1892,28 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
boundaryWriteIndex = PlsrCountedBoundaryWriteIndex;
if ((PlsrPulseActive == 0U) || (segmentNumber == 0U)
|| (segmentNumber > PlsrActiveConfig.segmentCount)
|| (boundaryWriteIndex != PlsrCountedBoundaryReadIndex)
|| (PlsrCountedFaultEvent != 0U)
|| (PlsrPlatformFinitePipelineSnapshot(
(uint8_t)PlsrActiveConfig.pulseOutput,
&committedPulses, &tailFrequencyHz,
&pipelineStartsNextSegment) == 0U)
|| (pipelineStartsNextSegment != 0U))
|| (PlsrCountedFaultEvent != 0U))
{
PlsrPlatformExitCritical(criticalState);
return 0U;
return PLSR_PLATFORM_SERVICE_FAILED;
}
if (boundaryWriteIndex != PlsrCountedBoundaryReadIndex)
{
PlsrPlatformExitCritical(criticalState);
return PLSR_PLATFORM_SERVICE_DEFERRED;
}
if (PlsrPlatformFinitePipelineSnapshot(
(uint8_t)PlsrActiveConfig.pulseOutput,
&committedPulses, &tailFrequencyHz,
&pipelineStartsNextSegment) == 0U)
{
PlsrPlatformExitCritical(criticalState);
return PLSR_PLATFORM_SERVICE_FAILED;
}
if (pipelineStartsNextSegment != 0U)
{
PlsrPlatformExitCritical(criticalState);
return PLSR_PLATFORM_SERVICE_DEFERRED;
}
PlsrPlatformExitCritical(criticalState);

@@ -1884,6 +1926,8 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
destination->readIndex = 0UL;
destination->writeIndex = 0UL;
destination->repeatRemaining = 0UL;
destination->underrunDebtPulses = 0UL;
destination->haveLastSetting = 0U;
destination->producerEpoch = epoch;
destination->producerSegment = segmentNumber;
destination->preparedHandoffBank = handoffBank;
@@ -1912,7 +1956,7 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
frequencyHz = entry.setting.actualFrequencyHz;
if (frequencyHz == 0UL)
{
return 0U;
return PLSR_PLATFORM_SERVICE_FAILED;
}
remainingPrefixTimeUs =
PLSR_REPLAN_PREFIX_TIME_US - prefixTimeUs;
@@ -1943,6 +1987,7 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
}

replacementPulses = availablePlanPulses - (uint32_t)prefixPulses;
replacementStartIndex = prefixCount;
if (replacementPulses != 0UL)
{
if ((tailFrequencyHz == 0UL)
@@ -1950,7 +1995,7 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
tailFrequencyHz, targetHz,
replacementPulses) == 0U))
{
return 0U;
return PLSR_PLATFORM_SERVICE_FAILED;
}
PlsrCopyShortProfile(&destination->producerProfile, &replacement);
destination->active = 1U;
@@ -1962,9 +2007,24 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
fillBudget--;
if (PlsrShortProfileTakeRun(&candidate, &entry) == 0U)
{
return 0U;
return PLSR_PLATFORM_SERVICE_FAILED;
}
if ((prefixCount > replacementStartIndex)
&& (destination->entries[prefixCount - 1UL]
.startsNextSegment == 0U)
&& (PlsrTimerSettingsEqual(
&destination->entries[prefixCount - 1UL].setting,
&entry.setting) != 0U)
&& (destination->entries[prefixCount - 1UL].repeatCount
<= (0xFFFFFFFFUL - entry.repeatCount)))
{
destination->entries[prefixCount - 1UL].repeatCount +=
entry.repeatCount;
}
else
{
destination->entries[prefixCount++] = entry;
}
destination->entries[prefixCount++] = entry;
}
PlsrCopyShortProfile(&destination->producerProfile, &candidate);
destination->generatorComplete =
@@ -1996,7 +2056,7 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
&& ((currentReadIndex - snapshotReadIndex) >= prefixCount)))
{
PlsrPlatformExitCritical(criticalState);
return 0U;
return PLSR_PLATFORM_SERVICE_DEFERRED;
}
consumedPrefix = currentReadIndex - snapshotReadIndex;
destination->readIndex = consumedPrefix;
@@ -2018,7 +2078,7 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,

PlsrProfileRecordPlannerStatus(&replacement);
PlsrRefreshCurrentHandoffPlan(replacement.endHz);
return 1U;
return PLSR_PLATFORM_SERVICE_READY;
}

static void PlsrCopyShortProfile(PLSR_SHORT_PROFILE *destination,
@@ -2099,8 +2159,10 @@ static void PlsrProfileQueueReset(void)
PlsrProfileQueues[bank].generatorComplete = 0U;
PlsrProfileQueues[bank].producerEpoch = 0UL;
PlsrProfileQueues[bank].repeatRemaining = 0UL;
PlsrProfileQueues[bank].underrunDebtPulses = 0UL;
PlsrProfileQueues[bank].producerSegment = 0U;
PlsrProfileQueues[bank].preparedHandoffBank = 0U;
PlsrProfileQueues[bank].haveLastSetting = 0U;
PlsrProfileQueues[bank].producerProfile.active = 0U;
}
PlsrProfileQueueBank = 0U;
@@ -2126,6 +2188,8 @@ static uint8_t PlsrProfileQueueBegin(
queue->preparedHandoffBank = preparedHandoffBank;
queue->generatorComplete = 0U;
queue->repeatRemaining = 0UL;
queue->underrunDebtPulses = 0UL;
queue->haveLastSetting = 0U;
PlsrProfileQueueMinimumDepth = PLSR_PROFILE_QUEUE_CAPACITY;
PlsrProfileQueueLowWaterLatched = 0U;
PlsrCopyShortProfile(&queue->producerProfile, producerProfile);
@@ -2154,9 +2218,61 @@ static void PlsrProfileQueueInvalidateGeneration(void)
queue->readIndex = 0U;
queue->writeIndex = 0U;
queue->repeatRemaining = 0UL;
queue->underrunDebtPulses = 0UL;
queue->haveLastSetting = 0U;
PlsrPlatformExitCritical(criticalState);
}

/* Called with pulse IRQs masked. Quantized-equal adjacent settings form one
hardware run even if their requested ramp frequencies differ. Segment
markers remain separate because their completion owns the boundary event. */
static uint8_t PlsrTimerSettingsEqual(
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;
}

static uint8_t PlsrProfileQueueAppendLocked(
PLSR_PROFILE_QUEUE *queue,
const PLSR_PROFILE_ENTRY *entry)
{
PLSR_PROFILE_ENTRY *previous;
uint32_t writeIndex;

if ((queue == NULL) || (entry == NULL) || (entry->repeatCount == 0UL))
{
return 0U;
}
writeIndex = queue->writeIndex;
if (writeIndex != queue->readIndex)
{
previous = &queue->entries[
(writeIndex - 1UL) & PLSR_PROFILE_QUEUE_MASK];
if ((previous->startsNextSegment == 0U)
&& (entry->startsNextSegment == 0U)
&& (PlsrTimerSettingsEqual(
&previous->setting, &entry->setting) != 0U)
&& (previous->repeatCount
<= (0xFFFFFFFFUL - entry->repeatCount)))
{
previous->repeatCount += entry->repeatCount;
return 1U;
}
}
if ((writeIndex - queue->readIndex) >= PLSR_PROFILE_QUEUE_CAPACITY)
{
return 0U;
}
queue->entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = *entry;
queue->writeIndex = writeIndex + 1UL;
return 1U;
}

#if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
&& !defined(PLSR_HOST_TEST)
static uint32_t PlsrProfileTimingNow(void)
@@ -2191,7 +2307,18 @@ static uint8_t PlsrProfileQueueFill(uint16_t targetCount,
uint32_t generation;
uint32_t producerEpoch;
uint32_t criticalState;
uint32_t writeIndex;
uint32_t underrunDebt;
uint32_t queueReadIndex;
uint32_t queueWriteIndex;
uint32_t queueCount;
uint32_t currentGeneration;
uint32_t currentProducerEpoch;
PLSR_PROFILE_QUEUE *queue;
uint8_t queueBank;
uint8_t currentBank;
uint8_t queueActive;
uint8_t generatorComplete;
uint8_t payingUnderrunDebt;
#if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
&& !defined(PLSR_HOST_TEST)
uint32_t startCycles;
@@ -2209,51 +2336,88 @@ static uint8_t PlsrProfileQueueFill(uint16_t targetCount,
while (1)
{
criticalState = PlsrPlatformEnterCritical();
if ((PlsrProfileQueue.active == 0U)
|| (PlsrProfileQueue.generatorComplete != 0U)
|| (PlsrProfileQueueCount() >= targetCount)
queueBank = PlsrProfileQueueBank;
queue = &PlsrProfileQueues[queueBank];
queueActive = queue->active;
generatorComplete = queue->generatorComplete;
queueWriteIndex = queue->writeIndex;
queueReadIndex = queue->readIndex;
queueCount = queueWriteIndex - queueReadIndex;
if ((queueActive == 0U)
|| (generatorComplete != 0U)
|| (queueCount >= targetCount)
|| (*itemBudget == 0U))
{
PlsrPlatformExitCritical(criticalState);
return 1U;
}
(*itemBudget)--;
generation = PlsrProfileQueue.generation;
producerEpoch = PlsrProfileQueue.producerEpoch;
PlsrCopyShortProfile(&candidate,
&PlsrProfileQueue.producerProfile);
generation = queue->generation;
producerEpoch = queue->producerEpoch;
underrunDebt = queue->underrunDebtPulses;
payingUnderrunDebt = (underrunDebt != 0UL) ? 1U : 0U;
PlsrCopyShortProfile(&candidate, &queue->producerProfile);
PlsrPlatformExitCritical(criticalState);

#if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
&& !defined(PLSR_HOST_TEST)
startCycles = PlsrProfileTimingNow();
#endif
if (PlsrShortProfileTakeRun(&candidate, &entry) == 0U)
if (PlsrShortProfileTakeRunLimited(
&candidate, &entry,
(payingUnderrunDebt != 0U)
? underrunDebt : 0xFFFFFFFFUL) == 0U)
{
return 0U;
}

criticalState = PlsrPlatformEnterCritical();
if ((PlsrProfileQueue.active == 0U)
|| (PlsrProfileQueue.generation != generation)
|| (PlsrProfileQueue.producerEpoch != producerEpoch)
|| (PlsrProfileQueueCount() >= PLSR_PROFILE_QUEUE_CAPACITY))
currentBank = PlsrProfileQueueBank;
queueActive = queue->active;
currentGeneration = queue->generation;
currentProducerEpoch = queue->producerEpoch;
queueWriteIndex = queue->writeIndex;
queueReadIndex = queue->readIndex;
queueCount = queueWriteIndex - queueReadIndex;
if ((currentBank != queueBank)
|| (queueActive == 0U)
|| (currentGeneration != generation)
|| (currentProducerEpoch != producerEpoch)
|| (queueCount >= PLSR_PROFILE_QUEUE_CAPACITY))
{
PlsrPlatformExitCritical(criticalState);
continue;
}
writeIndex = PlsrProfileQueue.writeIndex;
PlsrProfileQueue.entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry;
PlsrCopyShortProfile(&PlsrProfileQueue.producerProfile, &candidate);
PlsrProfileQueue.writeIndex = writeIndex + 1UL;
if (PlsrProfileQueueCount() >= PLSR_PROFILE_LOW_WATER_CLEAR)
PlsrCopyShortProfile(&queue->producerProfile, &candidate);
if (payingUnderrunDebt != 0U)
{
underrunDebt = queue->underrunDebtPulses;
if (underrunDebt < entry.repeatCount)
{
PlsrPlatformExitCritical(criticalState);
continue;
}
queue->underrunDebtPulses =
underrunDebt - entry.repeatCount;
}
else if (PlsrProfileQueueAppendLocked(
queue, &entry) == 0U)
{
PlsrPlatformExitCritical(criticalState);
continue;
}
queueWriteIndex = queue->writeIndex;
queueReadIndex = queue->readIndex;
queueCount = queueWriteIndex - queueReadIndex;
if (queueCount >= PLSR_PROFILE_LOW_WATER_CLEAR)
{
PlsrProfileQueueLowWaterLatched = 0U;
}
if ((candidate.active == 0U)
|| (candidate.nextPeriod >= candidate.pulseCount))
if (((candidate.active == 0U)
|| (candidate.nextPeriod >= candidate.pulseCount))
&& (queue->underrunDebtPulses == 0UL))
{
PlsrProfileQueue.generatorComplete = 1U;
queue->generatorComplete = 1U;
}
PlsrPlatformExitCritical(criticalState);
#if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
@@ -2559,6 +2723,8 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz)
}
PlsrCurrentFrequencyHz = firstFrequencyHz;
PlsrQueuedFrequencyHz = secondFrequencyHz;
PlsrProfileQueue.lastSetting = firstRun.setting;
PlsrProfileQueue.haveLastSetting = 1U;
PlsrDiagnosticQueuedExpectedHz = firstRun.setting.actualFrequencyHz;
PlsrCountedObservedPublished = PlsrPlatformObservedPulses(
(uint8_t)PlsrActiveConfig.pulseOutput);
@@ -3265,6 +3431,7 @@ uint8_t PlsrExecTakeCountedRunIrq(
uint8_t *startsNextSegment)
{
const PLSR_PROFILE_ENTRY *entry;
PLSR_PROFILE_QUEUE *queue;
uint32_t readIndex;
uint32_t nextReadIndex;

@@ -3275,17 +3442,68 @@ uint8_t PlsrExecTakeCountedRunIrq(
{
return PLSR_EXEC_RUN_FAILED;
}
readIndex = PlsrProfileQueue.readIndex;
if (readIndex == PlsrProfileQueue.writeIndex)
queue = &PlsrProfileQueues[PlsrProfileQueueBank];
readIndex = queue->readIndex;
if (readIndex == queue->writeIndex)
{
if (PlsrProfileQueue.generatorComplete != 0U)
uint32_t availablePulses;
uint32_t holdPulses;
uint32_t holdFrequencyHz;

if (queue->generatorComplete != 0U)
{
return PLSR_EXEC_RUN_DONE;
}
PlsrProfileQueueRecordUnderrun();
return PLSR_EXEC_RUN_FAILED;
}
entry = &PlsrProfileQueue.entries[readIndex & PLSR_PROFILE_QUEUE_MASK];
/* A producer miss must not immediately turn the last scheduled edge
into an abrupt stop. Borrow at most 2 ms of still-unplanned logical
pulses and hold the last applied timer setting. The task repays
this debt by advancing (without enqueueing) the same number of
planner pulses, so segment pulse count remains exact. */
availablePulses =
(queue->producerProfile.pulseCount
> queue->producerProfile.nextPeriod)
? queue->producerProfile.pulseCount
- queue->producerProfile.nextPeriod
: 0UL;
if (availablePulses > queue->underrunDebtPulses)
{
availablePulses -= queue->underrunDebtPulses;
}
else
{
availablePulses = 0UL;
}
holdFrequencyHz = queue->lastSetting.actualFrequencyHz;
holdPulses = (uint32_t)(
((uint64_t)holdFrequencyHz * PLSR_UNDERRUN_HOLD_TIME_US
+ 999999ULL) / 1000000ULL);
if (holdPulses == 0UL)
{
holdPulses = 1UL;
}
if (holdPulses > PLSR_UNDERRUN_HOLD_MAX_PULSES)
{
holdPulses = PLSR_UNDERRUN_HOLD_MAX_PULSES;
}
if (holdPulses > availablePulses)
{
holdPulses = availablePulses;
}
if ((queue->active == 0U) || (queue->haveLastSetting == 0U)
|| (holdFrequencyHz == 0UL) || (holdPulses == 0UL))
{
return PLSR_EXEC_RUN_FAILED;
}
queue->underrunDebtPulses += holdPulses;
queue->generation++;
*setting = queue->lastSetting;
*pulseCount = holdPulses;
*startsNextSegment = 0U;
PlsrQueuedFrequencyHz = holdFrequencyHz;
return PLSR_EXEC_RUN_READY;
}
entry = &queue->entries[readIndex & PLSR_PROFILE_QUEUE_MASK];
if (entry->repeatCount == 0UL)
{
return PLSR_EXEC_RUN_FAILED;
@@ -3304,11 +3522,13 @@ uint8_t PlsrExecTakeCountedRunIrq(
*pulseCount = entry->repeatCount;
*startsNextSegment = entry->startsNextSegment;
nextReadIndex = readIndex + 1UL;
PlsrProfileQueue.readIndex = nextReadIndex;
if (PlsrProfileQueue.generatorComplete == 0U)
queue->readIndex = nextReadIndex;
queue->lastSetting = entry->setting;
queue->haveLastSetting = 1U;
if (queue->generatorComplete == 0U)
{
PlsrProfileQueueRecordDepth(
(uint16_t)(PlsrProfileQueue.writeIndex - nextReadIndex));
(uint16_t)(queue->writeIndex - nextReadIndex));
}
/* 记录硬件即将生效的频率(事实镜像),不做任何状态转换。 */
PlsrQueuedFrequencyHz = entry->setting.actualFrequencyHz;
@@ -3461,7 +3681,15 @@ static void PlsrExecServiceCountedBoundaryEvent(void)
PlsrBoundaryPending = 0U;
PlsrBoundaryWasCut = 0U;
PlsrCutRequested = 0U;
PlsrFrequencyUpdatePending = 0U;
if (PlsrFrequencyUpdatePending != 0U)
{
/* An online frequency transaction that met a latched segment marker
follows the hardware into the new segment instead of invalidating
the old handoff metadata. */
PlsrFrequencyUpdateSegment = nextSegment;
PlsrFrequencyUpdateTargetHz =
PlsrActiveConfig.segments[nextSegment - 1U].frequencyHz;
}
PlsrDeferredFrequencyPending = 0U;
PlsrExtEdgePending = 0U;
PlsrExtPreviousLevel =
@@ -4206,7 +4434,8 @@ static uint8_t PlsrExecuteStop(void)
PlsrRemainingPulses = drainPulses;
PlsrPlatformExitCritical(criticalState);
if (PlsrReplanPulseDir(stopTargetHz,
(uint32_t)drainPulses) == 0U)
(uint32_t)drainPulses)
!= PLSR_PLATFORM_SERVICE_READY)
{
PlsrEnterError(PLSR_ERROR_TIMER);
return 1U;
@@ -4401,6 +4630,8 @@ void PlsrPoll1ms(void)
uint32_t pulseDirReplanPulses = 0UL;
uint32_t pollEpoch;
uint16_t fillBudget = PLSR_PROFILE_REFILL_BUDGET;
PLSR_PLATFORM_SERVICE_RESULT pulseDirReplanResult =
PLSR_PLATFORM_SERVICE_READY;

if (PlsrInitialized == 0U)
{
@@ -4558,25 +4789,33 @@ void PlsrPoll1ms(void)
&& (PlsrAbStopArmed == 0U)
&& (PlsrFrequencyUpdateSegment == activeSegmentNumber))
{
PlsrFrequencyUpdatePending = 0U;
activeSegment->frequencyHz = newTargetHz;
PlsrBoundaryRampStarted = 0U;
if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
{
uint64_t remaining = PlsrRemainingPulses;

if ((remaining == 0ULL) || (remaining > 0xFFFFFFFFULL))
if (PlsrCountedHandoffStaged != 0U)
{
/* The marker and its metadata are one published transaction.
Leave both untouched; the boundary consumer retargets this
pending update to the segment that hardware enters. */
}
else if ((remaining == 0ULL) || (remaining > 0xFFFFFFFFULL))
{
PlsrFrequencyUpdatePending = 0U;
pulseDirReplanFailed = 1U;
}
else
{
PlsrFrequencyUpdatePending = 0U;
pulseDirReplanPulses = (uint32_t)remaining;
pulseDirReplanRequested = 1U;
}
}
else
{
PlsrFrequencyUpdatePending = 0U;
PlsrShortProfile.active = 0U;
PlsrProfileQueueInvalidateGeneration();
PlsrRampStart(PlsrCurrentFrequencyHz, newTargetHz);
@@ -4588,11 +4827,29 @@ void PlsrPoll1ms(void)
}
PlsrPlatformExitCritical(criticalState);

if ((pulseDirReplanRequested != 0U)
&& (PlsrReplanPulseDir(newTargetHz,
pulseDirReplanPulses) == 0U))
if (pulseDirReplanRequested != 0U)
{
pulseDirReplanFailed = 1U;
pulseDirReplanResult = PlsrReplanPulseDir(
newTargetHz, pulseDirReplanPulses);
if (pulseDirReplanResult == PLSR_PLATFORM_SERVICE_FAILED)
{
pulseDirReplanFailed = 1U;
}
else if (pulseDirReplanResult == PLSR_PLATFORM_SERVICE_DEFERRED)
{
/* A segment-marker run may already be latched. Keep the old
published stream intact and retry against whichever segment is
active after the boundary event is settled. */
criticalState = PlsrPlatformEnterCritical();
if ((PlsrSegmentEpoch == pollEpoch)
&& (PlsrStopRequested == 0U))
{
PlsrFrequencyUpdateTargetHz = newTargetHz;
PlsrFrequencyUpdateSegment = activeSegmentNumber;
PlsrFrequencyUpdatePending = 1U;
}
PlsrPlatformExitCritical(criticalState);
}
}

if (pulseDirReplanFailed != 0U)
@@ -5133,7 +5390,8 @@ PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,

criticalState = PlsrPlatformEnterCritical();
segmentBeforeDrain = PlsrCurrentSegment;
if ((updateActiveFrequencies != 0U) && (PlsrPulseActive != 0U))
if ((updateActiveFrequencies != 0U) && (PlsrPulseActive != 0U)
&& (PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR))
{
PlsrPlatformDrainPendingPulse(
(uint8_t)PlsrActiveConfig.pulseOutput);
@@ -5173,15 +5431,40 @@ PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
}
}
PlsrPreparedHandoffBank = handoffBank;
PlsrHandoffPlan.valid = 0U;
PlsrProfileQueueInvalidateGeneration();
if ((drainedToDifferentSegment == 0U)
&& (PlsrPulseActive != 0U)
&& (PlsrAbStopArmed == 0U)
&& (PlsrShortProfile.active == 0U)
&& (PlsrRemainingPulses == 1UL))
if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
{
(void)PlsrPrimeHandoff();
/* Publish the new prepared-plan bank without touching the stream
or handoff metadata already visible to the counter IRQ. A
task-context replan replaces the current tail atomically. If
the segment marker was already latched, the request remains
pending and is retargeted by the boundary event. */
if ((PlsrPulseActive != 0U)
&& (PlsrStopRequested == 0U)
&& (PlsrAbStopArmed == 0U)
&& (PlsrRunStatus != PLSR_STATUS_WAITING)
&& (PlsrCurrentSegment != 0U)
&& (PlsrCurrentSegment
<= PlsrActiveConfig.segmentCount))
{
PlsrFrequencyUpdateSegment = PlsrCurrentSegment;
PlsrFrequencyUpdateTargetHz =
PlsrActiveConfig.segments[
PlsrCurrentSegment - 1U].frequencyHz;
PlsrFrequencyUpdatePending = 1U;
}
}
else
{
PlsrHandoffPlan.valid = 0U;
PlsrProfileQueueInvalidateGeneration();
if ((drainedToDifferentSegment == 0U)
&& (PlsrPulseActive != 0U)
&& (PlsrAbStopArmed == 0U)
&& (PlsrShortProfile.active == 0U)
&& (PlsrRemainingPulses == 1UL))
{
(void)PlsrPrimeHandoff();
}
}
if ((drainedToDifferentSegment != 0U)
&& (PlsrPulseActive != 0U)
@@ -5202,6 +5485,7 @@ PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,

if ((updateActiveFrequencies != 0U)
&& (PlsrPulseActive != 0U)
&& (PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
&& (PlsrAbStopArmed == 0U)
&& (PlsrFrequencyUpdatePending == 0U)
&& (PlsrPrepareFutureHandoffQueue() == 0U))


Ładowanie…
Anuluj
Zapisz