Quellcode durchsuchen

变频代码

codex/plsr-2026-minimal
ywh vor 1 Monat
Ursprung
Commit
f4a2216504
5 geänderte Dateien mit 270 neuen und 46 gelöschten Zeilen
  1. BIN
      HostComputer/__pycache__/bin_to_time_freq.cpython-314.pyc
  2. +33
    -12
      HostComputer/bin_to_time_freq.py
  3. +196
    -15
      PLSR/Src/plsr.c
  4. +1
    -0
      PLSR/Src/plsr_platform.h
  5. +40
    -19
      PLSR/Src/plsr_platform_f407.c

BIN
HostComputer/__pycache__/bin_to_time_freq.cpython-314.pyc Datei anzeigen


+ 33
- 12
HostComputer/bin_to_time_freq.py Datei anzeigen

@@ -111,8 +111,12 @@ def plot_show(path, fs, thresh, ymax, save_path=None):
fig, ax = plt.subplots(figsize=(15, 7))
fig.subplots_adjust(bottom=0.10, top=0.92)

# 全脉冲散点
ax.plot(t * 1000, freq, '.', ms=1.5, color='C0', alpha=0.5, zorder=1)
# 全脉冲散点:复用 artist,重绘时按可见范围抽稀(大文件流畅)
MAX_VISIBLE_POINTS = 5000 # 可见范围内最多绘制的点数,超过则等间隔抽稀
(scatter,) = ax.plot([], [], '.', ms=1.5, color='C0', alpha=0.5, zorder=1)
tx_ms = t * 1000
x_full = tx_ms
y_full = freq
ax.set_xlim(0.0, (t[-1] + hi_w[-1]) * 1000 * 1.02)
ax.set_ylim(0, ymax if ymax > 0 else freq.max() * 1.08)
ax.set_title("%s 时频曲线(%d 脉冲,活动时长 %.0f ms)" % (
@@ -145,6 +149,19 @@ def plot_show(path, fs, thresh, ymax, save_path=None):
zorder=6, visible=False)
hover_last = {'idx': -1, 'visible': False}

# 可见范围内抽稀绘制散点(大文件性能优化)
def update_scatter():
x0, x1 = ax.get_xlim()
mask = (x_full >= x0) & (x_full <= x1)
n_vis = int(np.count_nonzero(mask))
if n_vis > MAX_VISIBLE_POINTS:
# 等间隔抽稀:取 n_vis 中的 MAX_VISIBLE_POINTS 个
step = (n_vis + MAX_VISIBLE_POINTS - 1) // MAX_VISIBLE_POINTS
idx = np.flatnonzero(mask)[::step]
else:
idx = np.flatnonzero(mask)
scatter.set_data(x_full[idx], y_full[idx])

def on_scroll(event):
if event.inaxes is not ax or event.xdata is None:
return
@@ -167,6 +184,7 @@ def plot_show(path, fs, thresh, ymax, save_path=None):
if n1 - n0 < 1e-6:
return
ax.set_xlim(n0, n1)
update_scatter()
fig.canvas.draw_idle()

def on_press(event):
@@ -187,28 +205,29 @@ def plot_show(path, fs, thresh, ymax, save_path=None):
dy = event.ydata - state['press_y']
ax.set_xlim(x0 - dx, x1 - dx)
ax.set_ylim(y0 - dy, y1 - dy)
update_scatter()
fig.canvas.draw_idle()
return
# 悬停:找可见范围内距鼠标最近的脉冲点(屏幕像素距离 < 20px 才高亮)
x0, x1 = ax.get_xlim()
tx_ms = t * 1000
mask = (tx_ms >= x0) & (tx_ms <= x1)
mask = (x_full >= x0) & (x_full <= x1)
if not np.any(mask):
hl_marker.set_visible(False)
hl_text.set_visible(False)
if hover_last['visible']:
hl_marker.set_visible(False)
hl_text.set_visible(False)
fig.canvas.draw_idle()
hover_last['visible'] = False
fig.canvas.draw_idle()
return
px, py = ax.transData.transform(np.column_stack([tx_ms[mask], freq[mask]])).T
px, py = ax.transData.transform(np.column_stack([x_full[mask], y_full[mask]])).T
dist = np.hypot(px - event.x, py - event.y)
k = int(np.argmin(dist))
if dist[k] <= 20.0:
idx = int(np.flatnonzero(mask)[k])
hl_marker.set_data([tx_ms[idx]], [freq[idx]])
hl_marker.set_data([x_full[idx]], [y_full[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))
% (idx + 1, x_full[idx], y_full[idx]))
hl_text.set_position((x_full[idx] + (x1 - x0) * 0.01,
y_full[idx] + (ax.get_ylim()[1] - ax.get_ylim()[0]) * 0.02))
hl_marker.set_visible(True)
hl_text.set_visible(True)
if hover_last['idx'] != idx or not hover_last['visible']:
@@ -229,8 +248,10 @@ def plot_show(path, fs, thresh, ymax, save_path=None):
if event.dblclick:
ax.set_xlim(0.0, (t[-1] + hi_w[-1]) * 1000 * 1.02)
ax.set_ylim(0, ymax if ymax > 0 else freq.max() * 1.08)
update_scatter()
fig.canvas.draw_idle()

update_scatter()
fig.canvas.mpl_connect('scroll_event', on_scroll)
fig.canvas.mpl_connect('button_press_event', on_press)
fig.canvas.mpl_connect('button_release_event', on_release)


+ 196
- 15
PLSR/Src/plsr.c Datei anzeigen

@@ -73,6 +73,9 @@
#define PLSR_REPLAN_PREFIX_ITEMS (512U)
#define PLSR_REPLAN_PREFIX_TIME_US (5000ULL)
#define PLSR_REPLAN_BUILD_ITEMS (400U)
/* Cap equal-frequency counted runs so an online update never waits behind an
arbitrarily long steady run. At low speed one complete pulse is the limit. */
#define PLSR_COUNTED_RUN_MAX_TIME_US (2000ULL)
#define PLSR_BOUNDARY_EVENT_CAPACITY (2U)
#if ((PLSR_BOUNDARY_EVENT_CAPACITY == 0U) \
|| ((PLSR_BOUNDARY_EVENT_CAPACITY \
@@ -171,6 +174,7 @@ typedef struct
typedef struct
{
uint64_t magnitude;
uint64_t commandMagnitude;
uint32_t firstFrequencyHz;
uint32_t secondFrequencyHz;
uint32_t firstRequestedFrequencyHz;
@@ -191,6 +195,7 @@ typedef struct
typedef struct
{
uint64_t magnitude;
uint64_t commandMagnitude;
uint32_t firstFrequencyHz;
uint32_t completedPulses;
uint8_t nextSegment;
@@ -269,6 +274,9 @@ static PLSR_CONFIG PlsrActiveConfig;
static PLSR_CONFIG PlsrCandidateConfig;
static volatile int32_t PlsrPosition;
static volatile uint64_t PlsrRemainingPulses;
/* Full configured displacement still available in the active segment. ACT
may publish a shorter execution profile without discarding this ceiling. */
static volatile uint64_t PlsrCommandRemainingPulses;
static volatile uint8_t PlsrPulseActive;
static volatile uint8_t PlsrCutRequested;
static volatile uint8_t PlsrActTimedCutPlanned;
@@ -424,10 +432,15 @@ static uint8_t PlsrShortProfileTakeRunLimited(
PLSR_SHORT_PROFILE *profile,
PLSR_PROFILE_ENTRY *entry,
uint32_t maximumRepeats);
static uint32_t PlsrProfileRunLimit(uint32_t frequencyHz);
static uint8_t PlsrLimitProfileToActTime(
PLSR_SHORT_PROFILE *profile,
uint16_t actTimeMs,
uint8_t *timedCutPlanned);
static uint8_t PlsrLimitProfileToActTimeUs(
PLSR_SHORT_PROFILE *profile,
uint32_t actTimeUs,
uint8_t *timedCutPlanned);
static void PlsrProfileRecordPlannerStatus(
const PLSR_SHORT_PROFILE *profile);
static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
@@ -1894,9 +1907,9 @@ static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
block.exitHz = 0UL;
block.pulseBudget = (uint32_t)pulseCount;
block.referenceSpeedHz = PlsrActiveConfig.defaultSpeedHz;
block.accelerationTimeMs = PlsrActiveConfig.accelerationTimeMs;
block.decelerationTimeMs = PlsrActiveConfig.decelerationTimeMs;
block.curveMode = PlsrActiveConfig.curveMode;
block.accelerationTimeMs = frequencyConfig->accelerationTimeMs;
block.decelerationTimeMs = frequencyConfig->decelerationTimeMs;
block.curveMode = frequencyConfig->curveMode;
block.pulseOutput = (uint8_t)PlsrActiveConfig.pulseOutput;
block.boundary = PLSR_BOUNDARY_STOP;

@@ -1916,7 +1929,9 @@ static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
}
else if (nextSegment == 0U)
{
block.exitHz = PlsrEffectiveStopFrequency(targetFrequencyHz);
block.exitHz = (frequencyConfig->decelerationTimeMs == 0U)
? targetFrequencyHz
: PlsrActiveConfig.stopSpeedHz;
}
else if (segment->waitType == PLSR_EXT_OR_COMPLETE)
{
@@ -1956,6 +1971,27 @@ static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile,
return PlsrShortProfileTakeRunLimited(profile, entry, 0xFFFFFFFFUL);
}

static uint32_t PlsrProfileRunLimit(uint32_t frequencyHz)
{
uint64_t limit;

if (PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
{
return 0xFFFFFFFFUL;
}
if (frequencyHz == 0UL)
{
return 1UL;
}
limit = ((uint64_t)frequencyHz * PLSR_COUNTED_RUN_MAX_TIME_US
+ 999999ULL) / 1000000ULL;
if (limit == 0ULL)
{
return 1UL;
}
return (limit > 0xFFFFFFFFULL) ? 0xFFFFFFFFUL : (uint32_t)limit;
}

static uint8_t PlsrShortProfileTakeRunLimited(
PLSR_SHORT_PROFILE *profile,
PLSR_PROFILE_ENTRY *entry,
@@ -1978,6 +2014,15 @@ static uint8_t PlsrShortProfileTakeRunLimited(
}
profile->pendingRepeats = profile->pendingItem.repeatCount;
}
{
uint32_t runLimit = PlsrProfileRunLimit(
profile->pendingItem.setting.actualFrequencyHz);

if (maximumRepeats > runLimit)
{
maximumRepeats = runLimit;
}
}
repeatCount = profile->pendingRepeats;
if (repeatCount > profile->pulseCount - profile->nextPeriod)
{
@@ -2017,6 +2062,15 @@ static uint8_t PlsrLimitProfileToActTime(
PLSR_SHORT_PROFILE *profile,
uint16_t actTimeMs,
uint8_t *timedCutPlanned)
{
return PlsrLimitProfileToActTimeUs(
profile, (uint32_t)actTimeMs * 1000UL, timedCutPlanned);
}

static uint8_t PlsrLimitProfileToActTimeUs(
PLSR_SHORT_PROFILE *profile,
uint32_t actTimeUs,
uint8_t *timedCutPlanned)
{
PLSR_PLANNER_TIME_PREDICTION prediction;

@@ -2025,8 +2079,7 @@ static uint8_t PlsrLimitProfileToActTime(
return 0U;
}
*timedCutPlanned = 0U;
if (PlsrPlannerPredictTime(&profile->planner,
(uint32_t)actTimeMs * 1000UL,
if (PlsrPlannerPredictTime(&profile->planner, actTimeUs,
&prediction) == 0U)
{
return 0U;
@@ -2062,8 +2115,11 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
PLSR_SHORT_PROFILE replacement;
PLSR_SHORT_PROFILE candidate;
PLSR_PROFILE_ENTRY entry;
uint64_t committedTimeUs;
uint64_t prefixTimeUs = 0ULL;
uint64_t prefixTimeLimitUs = PLSR_REPLAN_PREFIX_TIME_US;
uint64_t prefixPulses = 0ULL;
uint64_t remainingActTimeUs = 0ULL;
uint32_t committedPulses;
uint32_t tailFrequencyHz;
uint32_t sourceGeneration;
@@ -2078,6 +2134,7 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
uint32_t sourceIndex;
uint32_t criticalState;
uint32_t epoch;
uint32_t segmentElapsedMs;
uint8_t segmentNumber;
uint8_t handoffBank;
uint8_t sourceBank;
@@ -2085,6 +2142,8 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
uint8_t boundaryWriteIndex;
uint8_t pipelineStartsNextSegment = 0U;
uint8_t tailWasClipped = 0U;
uint8_t actTimeLimited = 0U;
uint8_t actTimedCutPlanned = 0U;
uint16_t fillBudget = PLSR_REPLAN_BUILD_ITEMS;

criticalState = PlsrPlatformEnterCritical();
@@ -2097,6 +2156,7 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
snapshotWriteIndex = source->writeIndex;
epoch = PlsrSegmentEpoch;
segmentNumber = PlsrCurrentSegment;
segmentElapsedMs = PlsrSegmentElapsedMs;
handoffBank = PlsrPreparedHandoffBank;
boundaryWriteIndex = PlsrCountedBoundaryWriteIndex;
if ((PlsrPulseActive == 0U) || (segmentNumber == 0U)
@@ -2111,9 +2171,23 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
PlsrPlatformExitCritical(criticalState);
return PLSR_PLATFORM_SERVICE_DEFERRED;
}
if ((forceTerminalExit == 0U)
&& (PlsrActiveConfig.segments[segmentNumber - 1U].waitType
== PLSR_ACT_TIME))
{
uint32_t actTimeMs =
PlsrActiveConfig.segments[segmentNumber - 1U].actTimeMs;

actTimeLimited = 1U;
if (actTimeMs > segmentElapsedMs)
{
remainingActTimeUs =
(uint64_t)(actTimeMs - segmentElapsedMs) * 1000ULL;
}
}
if (PlsrPlatformFinitePipelineSnapshot(
(uint8_t)PlsrActiveConfig.pulseOutput,
&committedPulses, &tailFrequencyHz,
&committedPulses, &committedTimeUs, &tailFrequencyHz,
&pipelineStartsNextSegment) == 0U)
{
PlsrPlatformExitCritical(criticalState);
@@ -2133,6 +2207,19 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
totalPulses = committedPulses;
}
availablePlanPulses = totalPulses - committedPulses;
if (actTimeLimited != 0U)
{
if (committedTimeUs >= remainingActTimeUs)
{
prefixTimeLimitUs = 0ULL;
actTimedCutPlanned = 1U;
}
else if ((remainingActTimeUs - committedTimeUs)
< prefixTimeLimitUs)
{
prefixTimeLimitUs = remainingActTimeUs - committedTimeUs;
}
}

destination->readIndex = 0UL;
destination->writeIndex = 0UL;
@@ -2150,7 +2237,7 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
while ((sourceIndex != snapshotWriteIndex)
&& (prefixCount < PLSR_REPLAN_PREFIX_ITEMS)
&& (prefixPulses < availablePlanPulses)
&& (prefixTimeUs < PLSR_REPLAN_PREFIX_TIME_US))
&& (prefixTimeUs < prefixTimeLimitUs))
{
uint32_t remainingPrefixPulses =
availablePlanPulses - (uint32_t)prefixPulses;
@@ -2170,7 +2257,7 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
return PLSR_PLATFORM_SERVICE_FAILED;
}
remainingPrefixTimeUs =
PLSR_REPLAN_PREFIX_TIME_US - prefixTimeUs;
prefixTimeLimitUs - prefixTimeUs;
timeLimitedPulses =
(remainingPrefixTimeUs * frequencyHz + 999999ULL) / 1000000ULL;
if (timeLimitedPulses == 0ULL)
@@ -2198,6 +2285,13 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
}

replacementPulses = availablePlanPulses - (uint32_t)prefixPulses;
if ((actTimeLimited != 0U)
&& ((committedTimeUs + prefixTimeUs) >= remainingActTimeUs))
{
replacementPulses = 0UL;
totalPulses = committedPulses + (uint32_t)prefixPulses;
actTimedCutPlanned = 1U;
}
replacementStartIndex = prefixCount;
if (replacementPulses != 0UL)
{
@@ -2211,6 +2305,24 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
{
return PLSR_PLATFORM_SERVICE_FAILED;
}
if (actTimeLimited != 0U)
{
uint64_t consumedTimeUs = committedTimeUs + prefixTimeUs;
uint64_t replacementTimeUs =
(remainingActTimeUs > consumedTimeUs)
? remainingActTimeUs - consumedTimeUs : 0ULL;

if ((replacementTimeUs > 0xFFFFFFFFULL)
|| (PlsrLimitProfileToActTimeUs(
&replacement, (uint32_t)replacementTimeUs,
&actTimedCutPlanned) == 0U))
{
return PLSR_PLATFORM_SERVICE_FAILED;
}
replacementPulses = replacement.pulseCount;
totalPulses = committedPulses + (uint32_t)prefixPulses
+ replacementPulses;
}
PlsrCopyShortProfile(&destination->producerProfile, &replacement);
destination->active = 1U;
candidate = replacement;
@@ -2229,6 +2341,11 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
&& (PlsrTimerSettingsEqual(
&destination->entries[prefixCount - 1UL].setting,
&entry.setting) != 0U)
&& (entry.repeatCount <= PlsrProfileRunLimit(
entry.setting.actualFrequencyHz))
&& (destination->entries[prefixCount - 1UL].repeatCount
<= (PlsrProfileRunLimit(entry.setting.actualFrequencyHz)
- entry.repeatCount))
&& (destination->entries[prefixCount - 1UL].repeatCount
<= (0xFFFFFFFFUL - entry.repeatCount)))
{
@@ -2278,7 +2395,7 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
PlsrRamp.active = 0U;
PlsrHandoffPlan.valid = 0U;
PlsrCountedHandoffStaged = 0U;
PlsrActTimedCutPlanned = 0U;
PlsrActTimedCutPlanned = actTimedCutPlanned;
PlsrProfileQueueBank = destinationBank;
PlsrCopyShortProfile(&PlsrShortProfile,
&destination->producerProfile);
@@ -2489,6 +2606,12 @@ static uint8_t PlsrProfileQueueAppendLocked(
&& (entry->startsNextSegment == 0U)
&& (PlsrTimerSettingsEqual(
&previous->setting, &entry->setting) != 0U)
&& (entry->repeatCount <= PlsrProfileRunLimit(
previous->setting.actualFrequencyHz))
&& (previous->repeatCount
<= (PlsrProfileRunLimit(
previous->setting.actualFrequencyHz)
- entry->repeatCount))
&& (previous->repeatCount
<= (0xFFFFFFFFUL - entry->repeatCount)))
{
@@ -3476,6 +3599,10 @@ static PLSR_PLATFORM_SERVICE_RESULT PlsrTryStartPreparedTimedSegment(
PlsrDirectionDelayActive = 0U;
PlsrDirectionDelayRemainingMs = 0U;
PlsrRemainingPulses = magnitude;
PlsrCommandRemainingPulses =
(resolvedDisplacement < 0)
? (uint64_t)(-resolvedDisplacement)
: (uint64_t)resolvedDisplacement;
PlsrCountPositive = positive;
PlsrActTimedCutPlanned = PlsrTimedStart.nextActTimedCut;
PlsrTimedStart.pendingActivation = 1U;
@@ -3782,6 +3909,7 @@ static uint8_t PlsrStartSegment(uint8_t segmentNumber,

criticalState = PlsrPlatformEnterCritical();
PlsrRemainingPulses = magnitude;
PlsrCommandRemainingPulses = magnitude;
PlsrCountPositive = positive;
PlsrPlatformExitCritical(criticalState);

@@ -3890,6 +4018,7 @@ static void PlsrFinishCompleted(void)
PlsrDisarmWaitSignal();
PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
PlsrRemainingPulses = 0UL;
PlsrCommandRemainingPulses = 0ULL;
PlsrPulseActive = 0U;
PlsrCutRequested = 0U;
PlsrActTimedCutPlanned = 0U;
@@ -3931,6 +4060,7 @@ static void PlsrFinishStopped(void)
PlsrDiagnosticFinishSegment(0U);
PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
PlsrRemainingPulses = 0UL;
PlsrCommandRemainingPulses = 0ULL;
PlsrPulseActive = 0U;
PlsrCutRequested = 0U;
PlsrActTimedCutPlanned = 0U;
@@ -3972,6 +4102,7 @@ static void PlsrEnterError(PLSR_ERROR error)
PlsrDiagnosticFinishSegment(0U);
PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
PlsrRemainingPulses = 0UL;
PlsrCommandRemainingPulses = 0ULL;
PlsrPulseActive = 0U;
PlsrCutRequested = 0U;
PlsrActTimedCutPlanned = 0U;
@@ -4123,6 +4254,7 @@ static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment,

plan->magnitude = (displacement < 0) ? (uint64_t)(-displacement)
: (uint64_t)displacement;
plan->commandMagnitude = plan->magnitude;
if (carryFrequencyHz == 0UL)
{
carryFrequencyHz =
@@ -4419,6 +4551,14 @@ static uint8_t PlsrSyncCountedProgress(void)
PlsrPosition = (int32_t)nextPosition;
}
PlsrRemainingPulses = remaining - delta;
if (delta >= PlsrCommandRemainingPulses)
{
PlsrCommandRemainingPulses = 0ULL;
}
else
{
PlsrCommandRemainingPulses -= delta;
}
PlsrCountedObservedPublished = observed;
PlsrPositionCheckpointDirty = 1U;
return 1U;
@@ -4569,6 +4709,7 @@ void PlsrExecCountedSegmentBoundaryIrq(uint8_t pulseOutput,
event = &PlsrCountedBoundaryEvents[
writeIndex & (PLSR_BOUNDARY_EVENT_CAPACITY - 1U)];
event->magnitude = PlsrHandoffPlan.magnitude;
event->commandMagnitude = PlsrHandoffPlan.commandMagnitude;
event->firstFrequencyHz = PlsrHandoffPlan.firstFrequencyHz;
event->completedPulses = completedPulses;
event->nextSegment = PlsrHandoffPlan.nextSegment;
@@ -4701,6 +4842,7 @@ static void PlsrExecServiceCountedBoundaryEvent(void)
PlsrSegmentEpoch++;
PlsrCurrentSegment = nextSegment;
PlsrRemainingPulses = event.magnitude;
PlsrCommandRemainingPulses = event.commandMagnitude;
PlsrCountPositive = event.positive;
PlsrCurrentFrequencyHz = event.firstFrequencyHz;
PlsrBoundaryFrequencyHz = event.firstFrequencyHz;
@@ -4938,6 +5080,7 @@ static PLSR_PLATFORM_QUEUE_RESULT PlsrTryContinuousHandoff(void)
PlsrSegmentEpoch);
PlsrCurrentSegment = nextSegment;
PlsrRemainingPulses = magnitude;
PlsrCommandRemainingPulses = PlsrHandoffPlan.commandMagnitude;
PlsrCountPositive = positive;
PlsrActTimedCutPlanned = PlsrHandoffPlan.nextActTimedCut;
PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
@@ -5426,6 +5569,7 @@ uint8_t PlsrInit(void)
sizeof(PlsrPreparedHandoffPlans));
PlsrPreparedHandoffBank = 0U;
PlsrRemainingPulses = 0UL;
PlsrCommandRemainingPulses = 0ULL;
PlsrPulseActive = 0U;
PlsrCutRequested = 0U;
PlsrActTimedCutPlanned = 0U;
@@ -5644,6 +5788,7 @@ static uint8_t PlsrExecuteStop(void)
drainPulses = 1ULL;
}
PlsrRemainingPulses = drainPulses;
PlsrCommandRemainingPulses = drainPulses;
PlsrPlatformExitCritical(criticalState);
if (PlsrReplanPulseDir(stopTargetHz,
(uint32_t)drainPulses, 1U)
@@ -5683,6 +5828,7 @@ static void PlsrExecuteClear(void)
PlsrPosition = 0L;
PlsrPositionValid = 1U;
PlsrRemainingPulses = 0UL;
PlsrCommandRemainingPulses = 0ULL;
PlsrPlatformExitCritical(criticalState);
PlsrPlatformCheckpointPosition(0L, 1U, 0U);
PlsrCountOverflowPending = 0U;
@@ -6031,7 +6177,9 @@ void PlsrPoll1ms(void)
PlsrBoundaryRampStarted = 0U;
if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
{
uint64_t remaining = PlsrRemainingPulses;
uint64_t remaining =
(activeSegment->waitType == PLSR_ACT_TIME)
? PlsrCommandRemainingPulses : PlsrRemainingPulses;

if (PlsrCountedHandoffStaged != 0U)
{
@@ -6039,6 +6187,12 @@ void PlsrPoll1ms(void)
Leave both untouched; the boundary consumer retargets this
pending update to the segment that hardware enters. */
}
else if ((activeSegment->waitType == PLSR_ACT_TIME)
&& (PlsrSegmentElapsedMs >= activeSegment->actTimeMs))
{
/* The normal deadline path below owns the full-pulse cut. */
PlsrFrequencyUpdatePending = 0U;
}
else if ((remaining == 0ULL) || (remaining > 0xFFFFFFFFULL))
{
PlsrFrequencyUpdatePending = 0U;
@@ -6235,6 +6389,10 @@ void PlsrPulseTimerIrq(uint8_t pulseOutput)
{
remainingPulses--;
PlsrRemainingPulses = remainingPulses;
if (PlsrCommandRemainingPulses != 0ULL)
{
PlsrCommandRemainingPulses--;
}
}

if ((remainingPulses == 0UL) || (PlsrCutRequested != 0U)
@@ -6467,6 +6625,7 @@ PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
uint32_t criticalState;
uint8_t handoffBank = 0U;
uint8_t updateActiveFrequencies = 0U;
uint8_t updateActivePlannerParameters = 0U;
uint8_t drainedToDifferentSegment = 0U;
uint8_t segmentBeforeDrain;
uint32_t drainedSegmentTargetHz = 0UL;
@@ -6622,8 +6781,19 @@ PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
updateActiveFrequencies = 1U;
}
}
if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
&& ((PlsrCandidateConfig.accelerationTimeMs
!= PlsrShadowConfig.accelerationTimeMs)
|| (PlsrCandidateConfig.decelerationTimeMs
!= PlsrShadowConfig.decelerationTimeMs)
|| (PlsrCandidateConfig.curveMode
!= PlsrShadowConfig.curveMode)))
{
updateActivePlannerParameters = 1U;
}
}
if (updateActiveFrequencies != 0U)
if ((updateActiveFrequencies != 0U)
|| (updateActivePlannerParameters != 0U))
{
handoffBank = PlsrBuildHandoffPlanBank(&PlsrCandidateConfig);
}
@@ -6646,9 +6816,18 @@ PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
}
}
PlsrShadowConfig = PlsrCandidateConfig;
if (updateActiveFrequencies != 0U)
if ((updateActiveFrequencies != 0U)
|| (updateActivePlannerParameters != 0U))
{
PlsrInvalidateTimedStartLocked();
if (updateActivePlannerParameters != 0U)
{
PlsrActiveConfig.accelerationTimeMs =
PlsrCandidateConfig.accelerationTimeMs;
PlsrActiveConfig.decelerationTimeMs =
PlsrCandidateConfig.decelerationTimeMs;
PlsrActiveConfig.curveMode = PlsrCandidateConfig.curveMode;
}
for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
{
uint8_t frequencyChanged =
@@ -6672,7 +6851,8 @@ PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
}
}
PlsrPreparedHandoffBank = handoffBank;
if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
if ((updateActiveFrequencies != 0U)
&& (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR))
{
/* Publish the new prepared-plan bank without touching the stream
or handoff metadata already visible to the counter IRQ. A
@@ -6694,7 +6874,7 @@ PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
PlsrFrequencyUpdatePending = 1U;
}
}
else
else if (updateActiveFrequencies != 0U)
{
PlsrHandoffPlan.valid = 0U;
PlsrProfileQueueInvalidateGeneration();
@@ -6781,6 +6961,7 @@ void PlsrTestSetPosition(int32_t position, uint8_t positionValid)
PlsrPosition = position;
PlsrPositionValid = (positionValid != 0U) ? 1U : 0U;
PlsrRemainingPulses = 0UL;
PlsrCommandRemainingPulses = 0ULL;
PlsrPositionCheckpointDirty = 0U;
PlsrPlatformExitCritical(criticalState);
PlsrPlatformCheckpointPosition(position, PlsrPositionValid, 0U);


+ 1
- 0
PLSR/Src/plsr_platform.h Datei anzeigen

@@ -94,6 +94,7 @@ uint8_t PlsrPlatformFiniteRetargetReady(uint8_t pulseOutput,
uint32_t *activeFrequencyHz);
uint8_t PlsrPlatformFinitePipelineSnapshot(uint8_t pulseOutput,
uint32_t *committedPulses,
uint64_t *committedTimeUs,
uint32_t *tailFrequencyHz,
uint8_t *startsNextSegment);
uint8_t PlsrPlatformFiniteProgress(uint8_t pulseOutput,


+ 40
- 19
PLSR/Src/plsr_platform_f407.c Datei anzeigen

@@ -552,21 +552,31 @@ uint8_t PlsrPlatformFiniteRetargetReady(uint8_t pulseOutput,

uint8_t PlsrPlatformFinitePipelineSnapshot(uint8_t pulseOutput,
uint32_t *committedPulses,
uint64_t *committedTimeUs,
uint32_t *tailFrequencyHz,
uint8_t *startsNextSegment)
{
uint32_t remaining;
uint32_t frequencyHz;

if ((pulseOutput > 3U) || (committedPulses == NULL)
|| (tailFrequencyHz == NULL) || (startsNextSegment == NULL)
|| (committedTimeUs == NULL) || (tailFrequencyHz == NULL)
|| (startsNextSegment == NULL)
|| (PlsrHostFiniteActive[pulseOutput] == 0U))
{
return 0U;
}
remaining = PlsrHostFiniteTarget[pulseOutput]
- PlsrHostFiniteEmitted[pulseOutput];
frequencyHz = PlsrHostFrequency[pulseOutput];
if (frequencyHz == 0UL)
{
return 0U;
}
*committedPulses = remaining;
*tailFrequencyHz = PlsrHostQueuedFrequency[pulseOutput];
*committedTimeUs = ((uint64_t)remaining * 1000000ULL
+ frequencyHz - 1UL) / frequencyHz;
*tailFrequencyHz = frequencyHz;
*startsNextSegment = 0U;
return 1U;
}
@@ -3604,16 +3614,19 @@ uint8_t PlsrPlatformFiniteRetargetReady(uint8_t pulseOutput,

uint8_t PlsrPlatformFinitePipelineSnapshot(uint8_t pulseOutput,
uint32_t *committedPulses,
uint64_t *committedTimeUs,
uint32_t *tailFrequencyHz,
uint8_t *startsNextSegment)
{
TIM_TypeDef *counter;
uint32_t criticalState;
uint32_t blockCount;
uint32_t completed;
uint32_t frequencyHz;
uint32_t remaining;
uint64_t timeUs;

if ((pulseOutput > 3U) || (committedPulses == NULL)
|| (tailFrequencyHz == NULL) || (startsNextSegment == NULL))
|| (committedTimeUs == NULL) || (tailFrequencyHz == NULL)
|| (startsNextSegment == NULL))
{
return 0U;
}
@@ -3625,23 +3638,22 @@ uint8_t PlsrPlatformFinitePipelineSnapshot(uint8_t pulseOutput,
PlsrPlatformExitCritical(criticalState);
return 0U;
}
counter = PlsrCounters[PlsrCounterIndexByOutput[pulseOutput]];
blockCount = (uint16_t)counter->CNT;
if (blockCount >= PlsrFiniteCounterPreload[pulseOutput])
{
blockCount -= PlsrFiniteCounterPreload[pulseOutput];
}
else
completed = PlsrFiniteCompletedPulsesSnapshot(pulseOutput);
remaining = PlsrFiniteTargetPulses[pulseOutput];
if (completed > remaining)
{
blockCount = 0UL;
completed = remaining;
}
remaining = PlsrFiniteRemainingPulses[pulseOutput];
if (blockCount > remaining)
remaining -= completed;
frequencyHz = PlsrTimerActiveFrequencyHz[pulseOutput];
if (frequencyHz == 0UL)
{
blockCount = remaining;
PlsrPlatformExitCritical(criticalState);
return 0U;
}
remaining -= blockCount;
*tailFrequencyHz = PlsrTimerActiveFrequencyHz[pulseOutput];
timeUs = ((uint64_t)remaining * 1000000ULL
+ frequencyHz - 1UL) / frequencyHz;
*tailFrequencyHz = frequencyHz;
*startsNextSegment = 0U;
if (PlsrFiniteStreamNextValid[pulseOutput] != 0U)
{
@@ -3649,12 +3661,21 @@ uint8_t PlsrPlatformFinitePipelineSnapshot(uint8_t pulseOutput,

remaining = (nextPulses > (0xFFFFFFFFUL - remaining))
? 0xFFFFFFFFUL : remaining + nextPulses;
*tailFrequencyHz =
frequencyHz =
PlsrFiniteStreamNextSetting[pulseOutput].actualFrequencyHz;
if (frequencyHz == 0UL)
{
PlsrPlatformExitCritical(criticalState);
return 0U;
}
timeUs += ((uint64_t)nextPulses * 1000000ULL
+ frequencyHz - 1UL) / frequencyHz;
*tailFrequencyHz = frequencyHz;
*startsNextSegment =
PlsrFiniteStreamNextStartsSegment[pulseOutput];
}
*committedPulses = remaining;
*committedTimeUs = timeUs;
PlsrPlatformExitCritical(criticalState);
return 1U;
}


Laden…
Abbrechen
Speichern