|
|
|
@@ -1580,8 +1580,8 @@ static void PlsrFiniteArmNextStepPrepare(uint8_t pulseOutput, |
|
|
|
TIM_TypeDef *counter, |
|
|
|
uint32_t blockPulses); |
|
|
|
static void PlsrFiniteRetargetAtFallingEdge(uint8_t pulseOutput); |
|
|
|
static void PlsrFiniteCutAtFallingEdge(uint8_t pulseOutput); |
|
|
|
static void PlsrFiniteStopAtFallingEdge(uint8_t pulseOutput); |
|
|
|
static void PlsrFiniteCutAtIdleBoundary(uint8_t pulseOutput); |
|
|
|
static void PlsrFiniteStopAtIdleBoundary(uint8_t pulseOutput); |
|
|
|
|
|
|
|
static uint8_t PlsrFinalArmJobOutput(uint8_t pulseOutput) |
|
|
|
{ |
|
|
|
@@ -2370,11 +2370,86 @@ static uint64_t PlsrCounterCurrentRaw(uint8_t pulseOutput) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Return completed pulses in the active PUL/DIR run. The one-pulse block |
|
|
|
preload is an implementation detail, and a pending counter update means |
|
|
|
the current block has completed even if its IRQ has not run yet. */ |
|
|
|
static uint32_t PlsrFiniteCompletedPulsesSnapshot(uint8_t pulseOutput) |
|
|
|
{ |
|
|
|
uint8_t index = PlsrCounterIndexByOutput[pulseOutput]; |
|
|
|
TIM_TypeDef *counter; |
|
|
|
uint32_t target; |
|
|
|
uint32_t remainingBefore; |
|
|
|
uint32_t remainingAfter; |
|
|
|
uint32_t statusBefore; |
|
|
|
uint32_t statusAfter; |
|
|
|
uint32_t count; |
|
|
|
uint32_t blockCount; |
|
|
|
uint32_t completed; |
|
|
|
|
|
|
|
if (index >= PLSR_COUNTER_COUNT) |
|
|
|
{ |
|
|
|
return 0UL; |
|
|
|
} |
|
|
|
counter = PlsrCounters[index]; |
|
|
|
for (;;) |
|
|
|
{ |
|
|
|
remainingBefore = PlsrFiniteRemainingPulses[pulseOutput]; |
|
|
|
statusBefore = counter->SR & TIM_SR_UIF; |
|
|
|
count = (uint16_t)counter->CNT; |
|
|
|
statusAfter = counter->SR & TIM_SR_UIF; |
|
|
|
remainingAfter = PlsrFiniteRemainingPulses[pulseOutput]; |
|
|
|
if ((remainingBefore == remainingAfter) |
|
|
|
&& (statusBefore == statusAfter)) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
target = PlsrFiniteTargetPulses[pulseOutput]; |
|
|
|
if (remainingAfter > target) |
|
|
|
{ |
|
|
|
return 0UL; |
|
|
|
} |
|
|
|
completed = target - remainingAfter; |
|
|
|
if (statusAfter != 0UL) |
|
|
|
{ |
|
|
|
blockCount = (remainingAfter > PLSR_COUNTER_BLOCK_PULSES) |
|
|
|
? PLSR_COUNTER_BLOCK_PULSES : remainingAfter; |
|
|
|
if (count > (remainingAfter - blockCount)) |
|
|
|
{ |
|
|
|
count = remainingAfter - blockCount; |
|
|
|
} |
|
|
|
blockCount += count; |
|
|
|
} |
|
|
|
else if (count >= PlsrFiniteCounterPreload[pulseOutput]) |
|
|
|
{ |
|
|
|
blockCount = count - PlsrFiniteCounterPreload[pulseOutput]; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
blockCount = 0UL; |
|
|
|
} |
|
|
|
if (blockCount > remainingAfter) |
|
|
|
{ |
|
|
|
blockCount = remainingAfter; |
|
|
|
} |
|
|
|
return completed + blockCount; |
|
|
|
} |
|
|
|
|
|
|
|
static uint64_t PlsrCounterSnapshot(uint8_t pulseOutput) |
|
|
|
{ |
|
|
|
uint64_t current = PlsrCounterCurrentRaw(pulseOutput); |
|
|
|
uint64_t current; |
|
|
|
uint64_t observed; |
|
|
|
|
|
|
|
if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_PULSE_DIR) |
|
|
|
&& (PlsrFiniteActive[pulseOutput] != 0U)) |
|
|
|
{ |
|
|
|
current = PlsrFiniteCompletedPulsesSnapshot(pulseOutput); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
current = PlsrCounterCurrentRaw(pulseOutput); |
|
|
|
} |
|
|
|
if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_AB) |
|
|
|
&& (current > 0UL)) |
|
|
|
{ |
|
|
|
@@ -3451,6 +3526,8 @@ uint8_t PlsrPlatformRetargetFiniteStop(uint8_t pulseOutput, |
|
|
|
uint8_t PlsrPlatformRequestFiniteCut(uint8_t pulseOutput) |
|
|
|
{ |
|
|
|
TIM_TypeDef *timer; |
|
|
|
uint32_t timerCompare; |
|
|
|
uint32_t timerCount; |
|
|
|
uint32_t criticalState; |
|
|
|
|
|
|
|
if (pulseOutput > 3U) |
|
|
|
@@ -3461,8 +3538,7 @@ uint8_t PlsrPlatformRequestFiniteCut(uint8_t pulseOutput) |
|
|
|
criticalState = PlsrPlatformEnterCritical(); |
|
|
|
if ((PlsrFiniteActive[pulseOutput] == 0U) |
|
|
|
|| (PlsrFiniteStreamActive[pulseOutput] == 0U) |
|
|
|
|| (PlsrCounterIndexByOutput[pulseOutput] >= PLSR_COUNTER_COUNT) |
|
|
|
|| (PlsrFiniteRetargetPending[pulseOutput] != 0U)) |
|
|
|
|| (PlsrCounterIndexByOutput[pulseOutput] >= PLSR_COUNTER_COUNT)) |
|
|
|
{ |
|
|
|
PlsrPlatformExitCritical(criticalState); |
|
|
|
return 0U; |
|
|
|
@@ -3473,17 +3549,35 @@ uint8_t PlsrPlatformRequestFiniteCut(uint8_t pulseOutput) |
|
|
|
return 1U; |
|
|
|
} |
|
|
|
|
|
|
|
/* Do not allow a run already staged by the producer to cross the cut. |
|
|
|
CC1 reaches the physical pulse's falling edge, where the output is |
|
|
|
idle and can be stopped without shortening the high or low width. */ |
|
|
|
/* EXT supersedes an unpublished retarget and any producer-staged run. */ |
|
|
|
PlsrFiniteRetargetPending[pulseOutput] = 0U; |
|
|
|
PlsrFiniteRetargetDrainPulses[pulseOutput] = 0UL; |
|
|
|
PlsrFiniteStreamNextValid[pulseOutput] = 0U; |
|
|
|
PlsrFiniteStreamNextStartsSegment[pulseOutput] = 0U; |
|
|
|
PlsrFiniteStreamSourceDone[pulseOutput] = 1U; |
|
|
|
PlsrFiniteStreamSourceFault[pulseOutput] = 0U; |
|
|
|
PlsrFiniteTailStopPending[pulseOutput] = 1U; |
|
|
|
timer = PlsrTimerMap[pulseOutput].timer; |
|
|
|
timer->DIER &= ~TIM_DIER_CC1IE; |
|
|
|
timer->SR = ~TIM_SR_CC1IF; |
|
|
|
timer->DIER |= TIM_DIER_CC1IE; |
|
|
|
|
|
|
|
/* PWM1 is idle high before CCR1 and active low after CCR1. Freeze the |
|
|
|
source briefly so the phase decision cannot turn a full pulse into a |
|
|
|
short glitch. A low pulse is resumed and allowed to finish at update. */ |
|
|
|
timer->CR1 &= ~TIM_CR1_CEN; |
|
|
|
__DSB(); |
|
|
|
timerCount = timer->CNT; |
|
|
|
timerCompare = PlsrTimerActiveSetting[pulseOutput].compare; |
|
|
|
if (timerCount < timerCompare) |
|
|
|
{ |
|
|
|
PlsrFiniteCutAtIdleBoundary(pulseOutput); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
timer->SR = ~TIM_SR_UIF; |
|
|
|
timer->DIER |= TIM_DIER_UIE; |
|
|
|
timer->CR1 |= TIM_CR1_CEN; |
|
|
|
} |
|
|
|
__DMB(); |
|
|
|
PlsrPlatformExitCritical(criticalState); |
|
|
|
return 1U; |
|
|
|
@@ -4689,7 +4783,8 @@ static void PlsrHandleTimerIrq(uint8_t pulseOutput) |
|
|
|
&& (PlsrFiniteTailStopPending[pulseOutput] != 0U)) |
|
|
|
{ |
|
|
|
timer->SR = ~TIM_SR_CC1IF; |
|
|
|
PlsrFiniteCutAtFallingEdge(pulseOutput); |
|
|
|
timer->DIER &= ~TIM_DIER_CC1IE; |
|
|
|
timer->DIER |= TIM_DIER_UIE; |
|
|
|
goto irq_done; |
|
|
|
} |
|
|
|
#if PLSR_DEBUG_TIMING |
|
|
|
@@ -4762,6 +4857,12 @@ static void PlsrHandleTimerIrq(uint8_t pulseOutput) |
|
|
|
&& ((timer->DIER & TIM_DIER_UIE) != 0UL)) |
|
|
|
{ |
|
|
|
timer->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF); |
|
|
|
if ((PlsrTimerOutputMode[pulseOutput] == PLSR_OUTPUT_PULSE_DIR) |
|
|
|
&& (PlsrFiniteTailStopPending[pulseOutput] != 0U)) |
|
|
|
{ |
|
|
|
PlsrFiniteCutAtIdleBoundary(pulseOutput); |
|
|
|
goto irq_done; |
|
|
|
} |
|
|
|
if ((PlsrFiniteActive[pulseOutput] != 0U) |
|
|
|
&& (PlsrFiniteFrequencyPending[pulseOutput] != 0U)) |
|
|
|
{ |
|
|
|
@@ -5210,13 +5311,9 @@ static void PlsrFiniteCounterIrq(uint8_t pulseOutput, |
|
|
|
counter->CR1 &= ~TIM_CR1_CEN; |
|
|
|
counter->SMCR &= ~(TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0); |
|
|
|
|
|
|
|
/* |
|
|
|
* An OC rising edge is the terminal pulse's falling edge because the |
|
|
|
* output stage is active low. The target-count update IRQ therefore is |
|
|
|
* already the safe idle boundary: stop here before CCR1 can start an |
|
|
|
* extra terminal pulse. |
|
|
|
*/ |
|
|
|
PlsrFiniteStopAtFallingEdge(pulseOutput); |
|
|
|
/* The counter update is sourced by the PWM edge that returns the MCU pin |
|
|
|
high. The terminal pulse is complete and the output is safely idle. */ |
|
|
|
PlsrFiniteStopAtIdleBoundary(pulseOutput); |
|
|
|
} |
|
|
|
|
|
|
|
static void PlsrFiniteRetargetAtFallingEdge(uint8_t pulseOutput) |
|
|
|
@@ -5265,32 +5362,16 @@ static void PlsrFiniteRetargetAtFallingEdge(uint8_t pulseOutput) |
|
|
|
PlsrCounterBegin(pulseOutput); |
|
|
|
} |
|
|
|
|
|
|
|
static void PlsrFiniteCutAtFallingEdge(uint8_t pulseOutput) |
|
|
|
static void PlsrFiniteCutAtIdleBoundary(uint8_t pulseOutput) |
|
|
|
{ |
|
|
|
uint8_t counterIndex = PlsrCounterIndexByOutput[pulseOutput]; |
|
|
|
TIM_TypeDef *counter = PlsrCounters[counterIndex]; |
|
|
|
uint32_t blockCount; |
|
|
|
uint32_t completed; |
|
|
|
|
|
|
|
/* Freeze the external counter at the same falling edge that makes the |
|
|
|
pulse output idle, then convert the partial current run into the |
|
|
|
terminal run consumed by PlsrPlatformTakeFiniteCompletion(). */ |
|
|
|
/* The source output is high here. Freeze the slave counter and publish |
|
|
|
exactly the completed full pulses from the partial current run. */ |
|
|
|
PlsrCounterSuspend(pulseOutput); |
|
|
|
blockCount = (uint16_t)counter->CNT; |
|
|
|
if (blockCount >= PlsrFiniteCounterPreload[pulseOutput]) |
|
|
|
{ |
|
|
|
blockCount -= PlsrFiniteCounterPreload[pulseOutput]; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
blockCount = 0UL; |
|
|
|
} |
|
|
|
completed = PlsrFiniteTargetPulses[pulseOutput] |
|
|
|
- PlsrFiniteRemainingPulses[pulseOutput] + blockCount; |
|
|
|
if (completed > PlsrFiniteTargetPulses[pulseOutput]) |
|
|
|
{ |
|
|
|
completed = PlsrFiniteTargetPulses[pulseOutput]; |
|
|
|
} |
|
|
|
completed = PlsrFiniteCompletedPulsesSnapshot(pulseOutput); |
|
|
|
|
|
|
|
PlsrObservedPulseBase[pulseOutput] += completed; |
|
|
|
PlsrObservedPulsePublished[pulseOutput] = |
|
|
|
@@ -5306,10 +5387,10 @@ static void PlsrFiniteCutAtFallingEdge(uint8_t pulseOutput) |
|
|
|
PlsrCounterOverflowPulses[counterIndex] = 0UL; |
|
|
|
counter->CNT = 0UL; |
|
|
|
counter->SR = 0UL; |
|
|
|
PlsrFiniteStopAtFallingEdge(pulseOutput); |
|
|
|
PlsrFiniteStopAtIdleBoundary(pulseOutput); |
|
|
|
} |
|
|
|
|
|
|
|
static void PlsrFiniteStopAtFallingEdge(uint8_t pulseOutput) |
|
|
|
static void PlsrFiniteStopAtIdleBoundary(uint8_t pulseOutput) |
|
|
|
{ |
|
|
|
TIM_TypeDef *timer = PlsrTimerMap[pulseOutput].timer; |
|
|
|
|
|
|
|
|