|
|
@@ -11,6 +11,7 @@ |
|
|
|
|
|
|
|
|
#define PLSR_HW_TIMER_CHANNEL1_BIT (0x0001U) |
|
|
#define PLSR_HW_TIMER_CHANNEL1_BIT (0x0001U) |
|
|
#define PLSR_HW_TIMER_UPDATE_BIT (0x0001U) |
|
|
#define PLSR_HW_TIMER_UPDATE_BIT (0x0001U) |
|
|
|
|
|
#define PLSR_HW_TIMER_CC1_BIT (0x0002U) |
|
|
#define PLSR_HW_OUTPUT_POINT_COUNT (21U) |
|
|
#define PLSR_HW_OUTPUT_POINT_COUNT (21U) |
|
|
#define PLSR_HW_DBG_SNAPSHOT_COUNT (160U) |
|
|
#define PLSR_HW_DBG_SNAPSHOT_COUNT (160U) |
|
|
#define PLSR_HW_AB_QUARTER_COUNT (4U) |
|
|
#define PLSR_HW_AB_QUARTER_COUNT (4U) |
|
|
@@ -81,6 +82,41 @@ static const PLSR_HW_AXIS_MAP PlsrHwAxisMap[PLSR_HW_AXIS_COUNT] = |
|
|
#endif |
|
|
#endif |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#ifndef PLSR_HOST_TEST |
|
|
|
|
|
static const uint8_t PlsrHwPulsePinIndex[PLSR_HW_AXIS_COUNT] = |
|
|
|
|
|
{ |
|
|
|
|
|
6U, 8U, 7U, 9U |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/* 重定相期间由 GPIO 直接保持物理输出低电平。AFR 配置保持不变, |
|
|
|
|
|
* 只切换 MODER,因此恢复定时器复用功能只需一次寄存器写入。 */ |
|
|
|
|
|
static void PlsrHwHoldPulsePinLow(uint8_t axis) |
|
|
|
|
|
{ |
|
|
|
|
|
GPIO_TypeDef *port = PlsrHwAxisMap[axis].gpioPort; |
|
|
|
|
|
uint32_t shift = (uint32_t)PlsrHwPulsePinIndex[axis] * 2UL; |
|
|
|
|
|
uint32_t moder; |
|
|
|
|
|
|
|
|
|
|
|
port->BSRR = (uint32_t)PlsrHwAxisMap[axis].gpioPin << 16U; |
|
|
|
|
|
moder = port->MODER; |
|
|
|
|
|
moder &= ~(3UL << shift); |
|
|
|
|
|
moder |= 1UL << shift; |
|
|
|
|
|
port->MODER = moder; |
|
|
|
|
|
__DMB(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void PlsrHwReleasePulsePin(uint8_t axis) |
|
|
|
|
|
{ |
|
|
|
|
|
GPIO_TypeDef *port = PlsrHwAxisMap[axis].gpioPort; |
|
|
|
|
|
uint32_t shift = (uint32_t)PlsrHwPulsePinIndex[axis] * 2UL; |
|
|
|
|
|
uint32_t moder = port->MODER; |
|
|
|
|
|
|
|
|
|
|
|
moder &= ~(3UL << shift); |
|
|
|
|
|
moder |= 2UL << shift; |
|
|
|
|
|
port->MODER = moder; |
|
|
|
|
|
__DMB(); |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
/* host 测试:模拟定时器寄存器。 */ |
|
|
/* host 测试:模拟定时器寄存器。 */ |
|
|
#ifdef PLSR_HOST_TEST |
|
|
#ifdef PLSR_HOST_TEST |
|
|
typedef struct |
|
|
typedef struct |
|
|
@@ -91,6 +127,7 @@ typedef struct |
|
|
uint32_t psc; |
|
|
uint32_t psc; |
|
|
uint32_t arr; |
|
|
uint32_t arr; |
|
|
uint32_t ccr1; |
|
|
uint32_t ccr1; |
|
|
|
|
|
uint32_t cnt; |
|
|
uint32_t ccmr1; |
|
|
uint32_t ccmr1; |
|
|
uint32_t ccer; |
|
|
uint32_t ccer; |
|
|
uint8_t dirLevel; |
|
|
uint8_t dirLevel; |
|
|
@@ -110,13 +147,21 @@ typedef struct |
|
|
uint8_t directionPoint; |
|
|
uint8_t directionPoint; |
|
|
uint8_t directionPositive; |
|
|
uint8_t directionPositive; |
|
|
uint8_t abQuarter; |
|
|
uint8_t abQuarter; |
|
|
|
|
|
uint8_t abCountAxis; |
|
|
|
|
|
uint16_t abActiveBasePsc; |
|
|
|
|
|
uint16_t abActivePairPsc; |
|
|
|
|
|
uint16_t abActiveArr; |
|
|
|
|
|
uint16_t abPendingBasePsc; |
|
|
|
|
|
uint16_t abPendingPairPsc; |
|
|
|
|
|
uint16_t abPendingArr; |
|
|
|
|
|
uint8_t abFrequencyPending; |
|
|
} PLSR_HW_AXIS_STATE; |
|
|
} PLSR_HW_AXIS_STATE; |
|
|
|
|
|
|
|
|
static PLSR_HW_AXIS_STATE PlsrHwAxes[PLSR_HW_AXIS_COUNT]; |
|
|
static PLSR_HW_AXIS_STATE PlsrHwAxes[PLSR_HW_AXIS_COUNT]; |
|
|
|
|
|
|
|
|
/* 调试快照:当前上板自测只记录 Q0 的 160 ms,避免四轴 |
|
|
/* 调试快照:当前上板自测只记录 Q0 的 160 ms,避免四轴 |
|
|
* PlsrHwTick 互相混入,同时控制临时 RAM 占用。reason=0 表示 PwmBegin, |
|
|
|
|
|
* reason=3 表示 1 ms HAL tick。 */ |
|
|
|
|
|
|
|
|
* PlsrHwTick 互相混入,同时控制临时 RAM 占用。reason=0 表示段启动, |
|
|
|
|
|
* reason=3 表示 1 ms HAL tick,reason=4 表示 AB 在 00 边界换频重定相。 */ |
|
|
#ifndef PLSR_HOST_TEST |
|
|
#ifndef PLSR_HOST_TEST |
|
|
typedef struct |
|
|
typedef struct |
|
|
{ |
|
|
{ |
|
|
@@ -187,6 +232,20 @@ static void PlsrHwTimerSetCcr(uint8_t axis, uint32_t value) |
|
|
#endif |
|
|
#endif |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void PlsrHwTimerSetCnt(uint8_t axis, uint32_t value) |
|
|
|
|
|
{ |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
PlsrHwTimers[axis].cnt = value; |
|
|
|
|
|
/* F407 实测语义:CNT 写到活动 CCR1 比较值会置 CC1IF。 */ |
|
|
|
|
|
if (value == PlsrHwTimers[axis].ccr1) |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_CC1_BIT; |
|
|
|
|
|
} |
|
|
|
|
|
#else |
|
|
|
|
|
PlsrHwAxisMap[axis].timer->CNT = value; |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void PlsrHwTimerSetCen(uint8_t axis, uint32_t value) |
|
|
static void PlsrHwTimerSetCen(uint8_t axis, uint32_t value) |
|
|
{ |
|
|
{ |
|
|
#ifdef PLSR_HOST_TEST |
|
|
#ifdef PLSR_HOST_TEST |
|
|
@@ -231,6 +290,28 @@ static void PlsrHwTimerSetPwmMode1(uint8_t axis) |
|
|
#endif |
|
|
#endif |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* AB 启动和重定相时先把 OC1REF 钳到低电平,再切到 frozen 保持 00。 |
|
|
|
|
|
* 两路 CNT 就位后从 frozen 切到 PWM1,硬件会按当前 CNT/CCR 重新计算输出, |
|
|
|
|
|
* 避免 UG 后残留的 OC1REF 高电平经 CC1E 暴露为窄脉冲。 */ |
|
|
|
|
|
static void PlsrHwTimerSetForcedInactive(uint8_t axis) |
|
|
|
|
|
{ |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
PlsrHwTimers[axis].ccmr1 = 0x0048UL; |
|
|
|
|
|
#else |
|
|
|
|
|
PlsrHwAxisMap[axis].timer->CCMR1 = TIM_CCMR1_OC1M_2 |
|
|
|
|
|
| TIM_CCMR1_OC1PE; |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void PlsrHwTimerSetFrozen(uint8_t axis) |
|
|
|
|
|
{ |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
PlsrHwTimers[axis].ccmr1 = 0x0008UL; |
|
|
|
|
|
#else |
|
|
|
|
|
PlsrHwAxisMap[axis].timer->CCMR1 = TIM_CCMR1_OC1PE; |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value) |
|
|
static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value) |
|
|
{ |
|
|
{ |
|
|
#ifdef PLSR_HOST_TEST |
|
|
#ifdef PLSR_HOST_TEST |
|
|
@@ -247,6 +328,29 @@ static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value) |
|
|
#endif |
|
|
#endif |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void PlsrHwTimerSetCc1ie(uint8_t axis, uint32_t value) |
|
|
|
|
|
{ |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
PlsrHwTimers[axis].dier = |
|
|
|
|
|
(PlsrHwTimers[axis].dier & ~PLSR_HW_TIMER_CC1_BIT) |
|
|
|
|
|
| ((value != 0UL) ? PLSR_HW_TIMER_CC1_BIT : 0UL); |
|
|
|
|
|
if ((value != 0UL) |
|
|
|
|
|
&& ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_CC1_BIT) != 0UL)) |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwOnTimerUpdate(axis); |
|
|
|
|
|
} |
|
|
|
|
|
#else |
|
|
|
|
|
if (value != 0UL) |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_CC1IE; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_CC1IE; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void PlsrHwTimerClearUif(uint8_t axis) |
|
|
static void PlsrHwTimerClearUif(uint8_t axis) |
|
|
{ |
|
|
{ |
|
|
#ifdef PLSR_HOST_TEST |
|
|
#ifdef PLSR_HOST_TEST |
|
|
@@ -267,6 +371,26 @@ static uint8_t PlsrHwTimerHasUif(uint8_t axis) |
|
|
#endif |
|
|
#endif |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void PlsrHwTimerClearCc1if(uint8_t axis) |
|
|
|
|
|
{ |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_CC1_BIT; |
|
|
|
|
|
#else |
|
|
|
|
|
PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_CC1IF; |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint8_t PlsrHwTimerHasCc1if(uint8_t axis) |
|
|
|
|
|
{ |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
return ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_CC1_BIT) != 0UL) |
|
|
|
|
|
? 1U |
|
|
|
|
|
: 0U; |
|
|
|
|
|
#else |
|
|
|
|
|
return ((PlsrHwAxisMap[axis].timer->SR & TIM_SR_CC1IF) != 0UL) ? 1U : 0U; |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/* ---- DIR 输出 ---- |
|
|
/* ---- DIR 输出 ---- |
|
|
* XDM 为晶体管(NPN 漏型)输出:ON(导通)= 引脚低电平。 |
|
|
* XDM 为晶体管(NPN 漏型)输出:ON(导通)= 引脚低电平。 |
|
|
* 信捷正逻辑:正向发脉冲时方向端子置 ON(低)。 */ |
|
|
* 信捷正逻辑:正向发脉冲时方向端子置 ON(低)。 */ |
|
|
@@ -365,7 +489,9 @@ static void PlsrHwPwmBegin(uint8_t axis) |
|
|
PlsrHwTimerSetUg(axis); |
|
|
PlsrHwTimerSetUg(axis); |
|
|
/* UG 只用于加载影子寄存器,不是物理脉冲,不得计数。 */ |
|
|
/* UG 只用于加载影子寄存器,不是物理脉冲,不得计数。 */ |
|
|
PlsrHwTimerClearUif(axis); |
|
|
PlsrHwTimerClearUif(axis); |
|
|
|
|
|
PlsrHwTimerClearCc1if(axis); |
|
|
PlsrHwDbgCapture(axis, 0U); |
|
|
PlsrHwDbgCapture(axis, 0U); |
|
|
|
|
|
PlsrHwTimerSetCc1ie(axis, 0UL); |
|
|
PlsrHwTimerSetUie(axis, 1UL); |
|
|
PlsrHwTimerSetUie(axis, 1UL); |
|
|
PlsrHwTimerSetCc1e(axis, 1UL); |
|
|
PlsrHwTimerSetCc1e(axis, 1UL); |
|
|
PlsrHwTimerSetCen(axis, 1UL); |
|
|
PlsrHwTimerSetCen(axis, 1UL); |
|
|
@@ -375,7 +501,10 @@ static void PlsrHwStopPwmTimer(uint8_t axis) |
|
|
{ |
|
|
{ |
|
|
PlsrHwTimerSetCc1e(axis, 0UL); |
|
|
PlsrHwTimerSetCc1e(axis, 0UL); |
|
|
PlsrHwTimerSetUie(axis, 0UL); |
|
|
PlsrHwTimerSetUie(axis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetCc1ie(axis, 0UL); |
|
|
PlsrHwTimerSetCen(axis, 0UL); |
|
|
PlsrHwTimerSetCen(axis, 0UL); |
|
|
|
|
|
PlsrHwTimerClearUif(axis); |
|
|
|
|
|
PlsrHwTimerClearCc1if(axis); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static uint8_t PlsrHwIsAbBaseAxis(uint8_t axis) |
|
|
static uint8_t PlsrHwIsAbBaseAxis(uint8_t axis) |
|
|
@@ -383,56 +512,303 @@ static uint8_t PlsrHwIsAbBaseAxis(uint8_t axis) |
|
|
return ((axis == 0U) || (axis == 2U)) ? 1U : 0U; |
|
|
return ((axis == 0U) || (axis == 2U)) ? 1U : 0U; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
static uint8_t PlsrHwGetPairedAxis(uint8_t axis) |
|
|
static uint8_t PlsrHwGetPairedAxis(uint8_t axis) |
|
|
{ |
|
|
{ |
|
|
return (uint8_t)(axis + 1U); |
|
|
return (uint8_t)(axis + 1U); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 为 168MHz/84MHz 配对定时器选择相同 ARR,并让前者的 PSC 分频 |
|
|
|
|
|
* 始终是后者的 2 倍。两路获得完全相同的计数时钟与周期,避免 |
|
|
|
|
|
* 独立取整造成 AB 相位随运行时间漂移。 */ |
|
|
|
|
|
static uint8_t PlsrHwCalculateAbDividers(uint8_t axis, |
|
|
|
|
|
uint32_t frequencyHz, |
|
|
|
|
|
uint16_t *basePsc, |
|
|
|
|
|
uint16_t *pairPsc, |
|
|
|
|
|
uint16_t *arr) |
|
|
|
|
|
{ |
|
|
|
|
|
uint8_t pairAxis = PlsrHwGetPairedAxis(axis); |
|
|
|
|
|
uint64_t baseClock = PlsrHwAxisMap[axis].timerClockHz; |
|
|
|
|
|
uint64_t pairClock = PlsrHwAxisMap[pairAxis].timerClockHz; |
|
|
|
|
|
uint64_t ratio; |
|
|
|
|
|
uint64_t pairDivider; |
|
|
|
|
|
uint64_t baseDivider; |
|
|
|
|
|
uint64_t periodTicks; |
|
|
|
|
|
|
|
|
|
|
|
if ((frequencyHz == 0UL) || (basePsc == NULL) || (pairPsc == NULL) |
|
|
|
|
|
|| (arr == NULL) || (pairClock == 0UL) |
|
|
|
|
|
|| ((baseClock % pairClock) != 0UL)) |
|
|
|
|
|
{ |
|
|
|
|
|
return 0U; |
|
|
|
|
|
} |
|
|
|
|
|
ratio = baseClock / pairClock; |
|
|
|
|
|
if (ratio == 0UL) |
|
|
|
|
|
{ |
|
|
|
|
|
return 0U; |
|
|
|
|
|
} |
|
|
|
|
|
pairDivider = (pairClock |
|
|
|
|
|
+ (uint64_t)frequencyHz * UINT64_C(65536) - 1UL) |
|
|
|
|
|
/ ((uint64_t)frequencyHz * UINT64_C(65536)); |
|
|
|
|
|
if (pairDivider == 0UL) |
|
|
|
|
|
{ |
|
|
|
|
|
pairDivider = 1UL; |
|
|
|
|
|
} |
|
|
|
|
|
baseDivider = pairDivider * ratio; |
|
|
|
|
|
if ((pairDivider > UINT64_C(65536)) |
|
|
|
|
|
|| (baseDivider > UINT64_C(65536))) |
|
|
|
|
|
{ |
|
|
|
|
|
return 0U; |
|
|
|
|
|
} |
|
|
|
|
|
periodTicks = (pairClock |
|
|
|
|
|
+ ((uint64_t)frequencyHz * pairDivider) / 2UL) |
|
|
|
|
|
/ ((uint64_t)frequencyHz * pairDivider); |
|
|
|
|
|
if ((periodTicks < 4UL) || (periodTicks > UINT64_C(65536))) |
|
|
|
|
|
{ |
|
|
|
|
|
return 0U; |
|
|
|
|
|
} |
|
|
|
|
|
*basePsc = (uint16_t)(baseDivider - 1UL); |
|
|
|
|
|
*pairPsc = (uint16_t)(pairDivider - 1UL); |
|
|
|
|
|
*arr = (uint16_t)(periodTicks - 1UL); |
|
|
|
|
|
return 1U; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void PlsrHwLoadAbPwm(uint8_t axis, |
|
|
|
|
|
uint16_t basePsc, |
|
|
|
|
|
uint16_t pairPsc, |
|
|
|
|
|
uint16_t arr) |
|
|
|
|
|
{ |
|
|
|
|
|
uint8_t pairAxis = PlsrHwGetPairedAxis(axis); |
|
|
|
|
|
uint32_t compare; |
|
|
|
|
|
|
|
|
|
|
|
compare = ((uint32_t)arr + 1UL) / 2UL; |
|
|
|
|
|
PlsrHwTimerSetPsc(axis, basePsc); |
|
|
|
|
|
PlsrHwTimerSetPsc(pairAxis, pairPsc); |
|
|
|
|
|
PlsrHwTimerSetArr(axis, arr); |
|
|
|
|
|
PlsrHwTimerSetArr(pairAxis, arr); |
|
|
|
|
|
PlsrHwTimerSetCcr(axis, compare); |
|
|
|
|
|
PlsrHwTimerSetCcr(pairAxis, compare); |
|
|
|
|
|
PlsrHwTimerSetPwmMode1(axis); |
|
|
|
|
|
PlsrHwTimerSetPwmMode1(pairAxis); |
|
|
|
|
|
PlsrHwTimerSetArpe(axis, 1UL); |
|
|
|
|
|
PlsrHwTimerSetArpe(pairAxis, 1UL); |
|
|
|
|
|
PlsrHwAxes[axis].abActiveBasePsc = basePsc; |
|
|
|
|
|
PlsrHwAxes[axis].abActivePairPsc = pairPsc; |
|
|
|
|
|
PlsrHwAxes[axis].abActiveArr = arr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint8_t PlsrHwConfigureAbPwm(uint8_t axis, uint32_t frequencyHz) |
|
|
|
|
|
{ |
|
|
|
|
|
uint16_t basePsc; |
|
|
|
|
|
uint16_t pairPsc; |
|
|
|
|
|
uint16_t arr; |
|
|
|
|
|
|
|
|
|
|
|
if (PlsrHwCalculateAbDividers(axis, |
|
|
|
|
|
frequencyHz, |
|
|
|
|
|
&basePsc, |
|
|
|
|
|
&pairPsc, |
|
|
|
|
|
&arr) == 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
return 0U; |
|
|
|
|
|
} |
|
|
|
|
|
PlsrHwLoadAbPwm(axis, basePsc, pairPsc, arr); |
|
|
|
|
|
return 1U; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 运行中的 AB 调频不能直接写两路 ARR 预装载:两路定时器相差 1/4 周期, |
|
|
|
|
|
* 各自的 update 时刻也相差 1/4 周期,会短暂使用不同周期并永久积累相位误差。 |
|
|
|
|
|
* 任务上下文只计算并发布最新参数,真正装载由 00 周期边界中断完成。 */ |
|
|
|
|
|
static uint8_t PlsrHwQueueAbFrequency(uint8_t axis, uint32_t frequencyHz) |
|
|
|
|
|
{ |
|
|
|
|
|
PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis]; |
|
|
|
|
|
uint16_t basePsc; |
|
|
|
|
|
uint16_t pairPsc; |
|
|
|
|
|
uint16_t arr; |
|
|
|
|
|
#ifndef PLSR_HOST_TEST |
|
|
|
|
|
uint32_t interruptState; |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
/* P3b-1:AB 正交相序先在 host 模型中闭环。真实 STM32 双定时器的 |
|
|
|
|
|
* 同步启动、相位偏置和安全停止将在 P3b-2 接入。 */ |
|
|
|
|
|
|
|
|
if (PlsrHwCalculateAbDividers(axis, |
|
|
|
|
|
frequencyHz, |
|
|
|
|
|
&basePsc, |
|
|
|
|
|
&pairPsc, |
|
|
|
|
|
&arr) == 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
return 0U; |
|
|
|
|
|
} |
|
|
|
|
|
#ifndef PLSR_HOST_TEST |
|
|
|
|
|
interruptState = __get_PRIMASK(); |
|
|
|
|
|
__disable_irq(); |
|
|
|
|
|
__DMB(); |
|
|
|
|
|
#endif |
|
|
|
|
|
if ((basePsc == state->abActiveBasePsc) |
|
|
|
|
|
&& (pairPsc == state->abActivePairPsc) |
|
|
|
|
|
&& (arr == state->abActiveArr)) |
|
|
|
|
|
{ |
|
|
|
|
|
/* 量化后的分频参数未变化时取消旧请求,避免匀速段每 1ms 重定相。 */ |
|
|
|
|
|
state->abFrequencyPending = 0U; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
state->abPendingBasePsc = basePsc; |
|
|
|
|
|
state->abPendingPairPsc = pairPsc; |
|
|
|
|
|
state->abPendingArr = arr; |
|
|
|
|
|
state->abFrequencyPending = 1U; |
|
|
|
|
|
} |
|
|
|
|
|
#ifndef PLSR_HOST_TEST |
|
|
|
|
|
__DMB(); |
|
|
|
|
|
if (interruptState == 0UL) |
|
|
|
|
|
{ |
|
|
|
|
|
__enable_irq(); |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
return 1U; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void PlsrHwBeginAbOutput(uint8_t axis, uint8_t debugReason) |
|
|
|
|
|
{ |
|
|
|
|
|
PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis]; |
|
|
|
|
|
uint8_t pairAxis = PlsrHwGetPairedAxis(axis); |
|
|
|
|
|
uint8_t leadAxis = (state->directionPositive != 0U) ? axis : pairAxis; |
|
|
|
|
|
uint8_t lagAxis = (state->directionPositive != 0U) ? pairAxis : axis; |
|
|
|
|
|
uint32_t periodTicks; |
|
|
|
|
|
uint32_t leadStart; |
|
|
|
|
|
uint32_t lagStart; |
|
|
|
|
|
#ifndef PLSR_HOST_TEST |
|
|
|
|
|
uint32_t interruptState; |
|
|
|
|
|
#else |
|
|
|
|
|
(void)debugReason; |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
periodTicks = PlsrHwTimers[axis].arr + 1UL; |
|
|
|
|
|
#else |
|
|
|
|
|
periodTicks = PlsrHwAxisMap[axis].timer->ARR + 1UL; |
|
|
|
|
|
#endif |
|
|
|
|
|
leadStart = (periodTicks * 3UL) / 4UL; |
|
|
|
|
|
/* 落后相从 CCR 精确起步;切回 PWM 后清 CC1IF,最后才开 CC1IE。 */ |
|
|
|
|
|
lagStart = periodTicks / 2UL; |
|
|
|
|
|
state->abCountAxis = lagAxis; |
|
|
|
|
|
state->abQuarter = 0U; |
|
|
|
|
|
|
|
|
|
|
|
#ifndef PLSR_HOST_TEST |
|
|
|
|
|
interruptState = __get_PRIMASK(); |
|
|
|
|
|
__disable_irq(); |
|
|
|
|
|
__DMB(); |
|
|
|
|
|
PlsrHwHoldPulsePinLow(axis); |
|
|
|
|
|
PlsrHwHoldPulsePinLow(pairAxis); |
|
|
|
|
|
#endif |
|
|
|
|
|
PlsrHwTimerSetCen(axis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetCen(pairAxis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetCc1e(axis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetCc1e(pairAxis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetUie(axis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetUie(pairAxis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetCc1ie(axis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetCc1ie(pairAxis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetForcedInactive(axis); |
|
|
|
|
|
PlsrHwTimerSetForcedInactive(pairAxis); |
|
|
|
|
|
PlsrHwTimerSetFrozen(axis); |
|
|
|
|
|
PlsrHwTimerSetFrozen(pairAxis); |
|
|
|
|
|
PlsrHwTimerSetUg(axis); |
|
|
|
|
|
PlsrHwTimerSetUg(pairAxis); |
|
|
|
|
|
PlsrHwTimerClearUif(axis); |
|
|
|
|
|
PlsrHwTimerClearUif(pairAxis); |
|
|
|
|
|
PlsrHwTimerClearCc1if(axis); |
|
|
|
|
|
PlsrHwTimerClearCc1if(pairAxis); |
|
|
|
|
|
PlsrHwTimerSetCnt(leadAxis, leadStart); |
|
|
|
|
|
PlsrHwTimerSetCnt(lagAxis, lagStart); |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
PlsrHwTimerSetCc1e(axis, 1UL); |
|
|
|
|
|
PlsrHwTimerSetCc1e(pairAxis, 1UL); |
|
|
|
|
|
PlsrHwTimerSetPwmMode1(axis); |
|
|
|
|
|
PlsrHwTimerSetPwmMode1(pairAxis); |
|
|
|
|
|
PlsrHwTimerClearCc1if(axis); |
|
|
|
|
|
PlsrHwTimerClearCc1if(pairAxis); |
|
|
|
|
|
PlsrHwTimerSetCen(axis, 1UL); |
|
|
|
|
|
PlsrHwTimerSetCen(pairAxis, 1UL); |
|
|
|
|
|
PlsrHwTimerClearCc1if(axis); |
|
|
|
|
|
PlsrHwTimerClearCc1if(pairAxis); |
|
|
|
|
|
PlsrHwTimerSetCc1ie(lagAxis, 1UL); |
|
|
|
|
|
#else |
|
|
|
|
|
PlsrHwTimerSetCc1e(axis, 1UL); |
|
|
|
|
|
PlsrHwTimerSetCc1e(pairAxis, 1UL); |
|
|
|
|
|
PlsrHwTimerSetPwmMode1(axis); |
|
|
|
|
|
PlsrHwTimerSetPwmMode1(pairAxis); |
|
|
|
|
|
/* OCREF 已在低电平位置稳定后再把物理引脚交还定时器。 */ |
|
|
|
|
|
PlsrHwTimerClearCc1if(axis); |
|
|
|
|
|
PlsrHwTimerClearCc1if(pairAxis); |
|
|
|
|
|
PlsrHwReleasePulsePin(axis); |
|
|
|
|
|
PlsrHwReleasePulsePin(pairAxis); |
|
|
|
|
|
PlsrHwTimerSetCen(axis, 1UL); |
|
|
|
|
|
PlsrHwTimerSetCen(pairAxis, 1UL); |
|
|
|
|
|
/* 最后才允许落后相计数中断。 */ |
|
|
|
|
|
PlsrHwTimerClearCc1if(axis); |
|
|
|
|
|
PlsrHwTimerClearCc1if(pairAxis); |
|
|
|
|
|
PlsrHwTimerSetCc1ie(lagAxis, 1UL); |
|
|
|
|
|
__DMB(); |
|
|
|
|
|
if (interruptState == 0UL) |
|
|
|
|
|
{ |
|
|
|
|
|
__enable_irq(); |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
PlsrHwDbgCapture(axis, debugReason); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void PlsrHwConfigureActiveOutput(uint8_t axis, |
|
|
static void PlsrHwConfigureActiveOutput(uint8_t axis, |
|
|
PLSR_OUTPUT_MODE outputMode, |
|
|
PLSR_OUTPUT_MODE outputMode, |
|
|
uint32_t frequencyHz) |
|
|
uint32_t frequencyHz) |
|
|
{ |
|
|
{ |
|
|
PlsrHwConfigurePwm(axis, frequencyHz); |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
if (outputMode == PLSR_OUTPUT_AB) |
|
|
if (outputMode == PLSR_OUTPUT_AB) |
|
|
{ |
|
|
{ |
|
|
PlsrHwConfigurePwm(PlsrHwGetPairedAxis(axis), frequencyHz); |
|
|
|
|
|
|
|
|
(void)PlsrHwConfigureAbPwm(axis, frequencyHz); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwConfigurePwm(axis, frequencyHz); |
|
|
} |
|
|
} |
|
|
#else |
|
|
|
|
|
(void)outputMode; |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void PlsrHwBeginActiveOutput(uint8_t axis, |
|
|
static void PlsrHwBeginActiveOutput(uint8_t axis, |
|
|
PLSR_OUTPUT_MODE outputMode) |
|
|
PLSR_OUTPUT_MODE outputMode) |
|
|
{ |
|
|
{ |
|
|
PlsrHwPwmBegin(axis); |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
if (outputMode == PLSR_OUTPUT_AB) |
|
|
if (outputMode == PLSR_OUTPUT_AB) |
|
|
{ |
|
|
{ |
|
|
PlsrHwPwmBegin(PlsrHwGetPairedAxis(axis)); |
|
|
|
|
|
|
|
|
PlsrHwBeginAbOutput(axis, 0U); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwPwmBegin(axis); |
|
|
} |
|
|
} |
|
|
#else |
|
|
|
|
|
(void)outputMode; |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void PlsrHwStopActiveOutput(uint8_t axis, |
|
|
static void PlsrHwStopActiveOutput(uint8_t axis, |
|
|
PLSR_OUTPUT_MODE outputMode) |
|
|
PLSR_OUTPUT_MODE outputMode) |
|
|
{ |
|
|
{ |
|
|
PlsrHwStopPwmTimer(axis); |
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
|
|
if ((outputMode == PLSR_OUTPUT_AB) && (PlsrHwIsAbBaseAxis(axis) != 0U)) |
|
|
if ((outputMode == PLSR_OUTPUT_AB) && (PlsrHwIsAbBaseAxis(axis) != 0U)) |
|
|
{ |
|
|
{ |
|
|
PlsrHwStopPwmTimer(PlsrHwGetPairedAxis(axis)); |
|
|
|
|
|
} |
|
|
|
|
|
#else |
|
|
|
|
|
(void)outputMode; |
|
|
|
|
|
|
|
|
uint8_t pairAxis = PlsrHwGetPairedAxis(axis); |
|
|
|
|
|
#ifndef PLSR_HOST_TEST |
|
|
|
|
|
uint32_t interruptState = __get_PRIMASK(); |
|
|
|
|
|
|
|
|
|
|
|
__disable_irq(); |
|
|
|
|
|
__DMB(); |
|
|
|
|
|
/* DONE/STOP 后继续由 GPIO 保持 00,禁止已关闭 timer 泄漏残余边沿。 */ |
|
|
|
|
|
PlsrHwHoldPulsePinLow(axis); |
|
|
|
|
|
PlsrHwHoldPulsePinLow(pairAxis); |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
PlsrHwStopPwmTimer(axis); |
|
|
|
|
|
PlsrHwStopPwmTimer(pairAxis); |
|
|
|
|
|
#ifndef PLSR_HOST_TEST |
|
|
|
|
|
__DMB(); |
|
|
|
|
|
if (interruptState == 0UL) |
|
|
|
|
|
{ |
|
|
|
|
|
__enable_irq(); |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwStopPwmTimer(axis); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber) |
|
|
uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber) |
|
|
@@ -471,6 +847,7 @@ PLSR_RESULT PlsrHwInit(void) |
|
|
#else |
|
|
#else |
|
|
PlsrHwTimerSetCc1e(axis, 0UL); |
|
|
PlsrHwTimerSetCc1e(axis, 0UL); |
|
|
PlsrHwTimerSetUie(axis, 0UL); |
|
|
PlsrHwTimerSetUie(axis, 0UL); |
|
|
|
|
|
PlsrHwTimerSetCc1ie(axis, 0UL); |
|
|
PlsrHwTimerSetCen(axis, 0UL); |
|
|
PlsrHwTimerSetCen(axis, 0UL); |
|
|
#endif |
|
|
#endif |
|
|
} |
|
|
} |
|
|
@@ -548,14 +925,6 @@ PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params) |
|
|
{ |
|
|
{ |
|
|
return PLSR_RESULT_NOT_SUPPORTED; |
|
|
return PLSR_RESULT_NOT_SUPPORTED; |
|
|
} |
|
|
} |
|
|
#ifndef PLSR_HOST_TEST |
|
|
|
|
|
if (params->outputMode == PLSR_OUTPUT_AB) |
|
|
|
|
|
{ |
|
|
|
|
|
/* P3b-1 只交付可验证的 host 相序模型;禁止目标板误输出成 |
|
|
|
|
|
* 单路 PULSE/DIR。P3b-2 接入双定时器后移除此保护。 */ |
|
|
|
|
|
return PLSR_RESULT_NOT_SUPPORTED; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
state = &PlsrHwAxes[axis]; |
|
|
state = &PlsrHwAxes[axis]; |
|
|
if (state->state == PLSR_HW_STATE_RUNNING) |
|
|
if (state->state == PLSR_HW_STATE_RUNNING) |
|
|
{ |
|
|
{ |
|
|
@@ -586,6 +955,7 @@ PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params) |
|
|
? params->directionDelayMs |
|
|
? params->directionDelayMs |
|
|
: 0U; |
|
|
: 0U; |
|
|
state->abQuarter = 0U; |
|
|
state->abQuarter = 0U; |
|
|
|
|
|
state->abFrequencyPending = 0U; |
|
|
if (params->outputMode == PLSR_OUTPUT_PULSE_DIR) |
|
|
if (params->outputMode == PLSR_OUTPUT_PULSE_DIR) |
|
|
{ |
|
|
{ |
|
|
PlsrHwSetDirLevel(axis, params->directionPositive); |
|
|
PlsrHwSetDirLevel(axis, params->directionPositive); |
|
|
@@ -615,8 +985,20 @@ PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz) |
|
|
{ |
|
|
{ |
|
|
if (frequencyHz > 0UL) |
|
|
if (frequencyHz > 0UL) |
|
|
{ |
|
|
{ |
|
|
/* 运行中调频:预装载写入,更新事件时生效,不触碰使能位。 */ |
|
|
|
|
|
PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz); |
|
|
|
|
|
|
|
|
if (state->outputMode == PLSR_OUTPUT_AB) |
|
|
|
|
|
{ |
|
|
|
|
|
if (PlsrHwQueueAbFrequency(axis, frequencyHz) == 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
return PLSR_RESULT_DIVIDER_UNREPRESENTABLE; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
/* PULSE/DIR 仍由单定时器在自身 update 边界加载预装值。 */ |
|
|
|
|
|
PlsrHwConfigureActiveOutput(axis, |
|
|
|
|
|
state->outputMode, |
|
|
|
|
|
frequencyHz); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
@@ -627,8 +1009,9 @@ PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz) |
|
|
&& (frequencyHz > 0UL)) |
|
|
&& (frequencyHz > 0UL)) |
|
|
{ |
|
|
{ |
|
|
PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz); |
|
|
PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz); |
|
|
PlsrHwBeginActiveOutput(axis, state->outputMode); |
|
|
|
|
|
|
|
|
/* 必须先发布 RUNNING,避免启用 timer IRQ 后观察到 PWM_PENDING。 */ |
|
|
state->state = PLSR_HW_STATE_RUNNING; |
|
|
state->state = PLSR_HW_STATE_RUNNING; |
|
|
|
|
|
PlsrHwBeginActiveOutput(axis, state->outputMode); |
|
|
} |
|
|
} |
|
|
return PLSR_RESULT_OK; |
|
|
return PLSR_RESULT_OK; |
|
|
} |
|
|
} |
|
|
@@ -646,6 +1029,7 @@ PLSR_RESULT PlsrHwStopPulse(uint8_t axis) |
|
|
{ |
|
|
{ |
|
|
PlsrHwStopActiveOutput(axis, state->outputMode); |
|
|
PlsrHwStopActiveOutput(axis, state->outputMode); |
|
|
state->abQuarter = 0U; |
|
|
state->abQuarter = 0U; |
|
|
|
|
|
state->abFrequencyPending = 0U; |
|
|
state->state = PLSR_HW_STATE_IDLE; |
|
|
state->state = PLSR_HW_STATE_IDLE; |
|
|
} |
|
|
} |
|
|
return PLSR_RESULT_OK; |
|
|
return PLSR_RESULT_OK; |
|
|
@@ -736,8 +1120,8 @@ void PlsrHwTick(uint8_t axis) |
|
|
PlsrHwConfigureActiveOutput(axis, |
|
|
PlsrHwConfigureActiveOutput(axis, |
|
|
state->outputMode, |
|
|
state->outputMode, |
|
|
state->currentFrequencyHz); |
|
|
state->currentFrequencyHz); |
|
|
PlsrHwBeginActiveOutput(axis, state->outputMode); |
|
|
|
|
|
state->state = PLSR_HW_STATE_RUNNING; |
|
|
state->state = PLSR_HW_STATE_RUNNING; |
|
|
|
|
|
PlsrHwBeginActiveOutput(axis, state->outputMode); |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
@@ -746,15 +1130,68 @@ void PlsrHwTick(uint8_t axis) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* 输出定时器更新中断:每周期末触发一次(=1 个脉冲)。 */ |
|
|
|
|
|
|
|
|
/* 输出定时器中断入口:PULSE/DIR 在 update 计数;AB 在落后相 |
|
|
|
|
|
* CC1 下降沿(四状态回到 00)计一个完整正交周期。 */ |
|
|
void PlsrHwOnTimerUpdate(uint8_t axis) |
|
|
void PlsrHwOnTimerUpdate(uint8_t axis) |
|
|
{ |
|
|
{ |
|
|
PLSR_HW_AXIS_STATE *state; |
|
|
PLSR_HW_AXIS_STATE *state; |
|
|
|
|
|
uint8_t ownerAxis; |
|
|
|
|
|
uint8_t hasCc1; |
|
|
|
|
|
|
|
|
if (axis >= PLSR_HW_AXIS_COUNT) |
|
|
if (axis >= PLSR_HW_AXIS_COUNT) |
|
|
{ |
|
|
{ |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* CC1IF 无论当前状态如何都必须先清除;否则启动窗口中的杂散 |
|
|
|
|
|
* compare 标志会让共享 IRQ 持续重入,主线程无法完成 CEN 配置。 */ |
|
|
|
|
|
hasCc1 = PlsrHwTimerHasCc1if(axis); |
|
|
|
|
|
if (hasCc1 != 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwTimerClearCc1if(axis); |
|
|
|
|
|
} |
|
|
|
|
|
ownerAxis = (uint8_t)(axis & 0xFEU); |
|
|
|
|
|
state = &PlsrHwAxes[ownerAxis]; |
|
|
|
|
|
if ((state->state == PLSR_HW_STATE_RUNNING) |
|
|
|
|
|
&& (state->outputMode == PLSR_OUTPUT_AB)) |
|
|
|
|
|
{ |
|
|
|
|
|
if (PlsrHwTimerHasUif(axis) != 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwTimerClearUif(axis); |
|
|
|
|
|
} |
|
|
|
|
|
if ((hasCc1 == 0U) || (axis != state->abCountAxis)) |
|
|
|
|
|
{ |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
state->emittedPulses++; |
|
|
|
|
|
if (state->emittedPulses >= state->targetPulses) |
|
|
|
|
|
{ |
|
|
|
|
|
PlsrHwStopActiveOutput(ownerAxis, state->outputMode); |
|
|
|
|
|
state->abQuarter = 0U; |
|
|
|
|
|
state->abFrequencyPending = 0U; |
|
|
|
|
|
state->state = PLSR_HW_STATE_DONE; |
|
|
|
|
|
(void)PlsrPostEvent(ownerAxis, PLSR_EVENT_SEGMENT_COMPLETE); |
|
|
|
|
|
} |
|
|
|
|
|
else if (state->abFrequencyPending != 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
uint16_t basePsc = state->abPendingBasePsc; |
|
|
|
|
|
uint16_t pairPsc = state->abPendingPairPsc; |
|
|
|
|
|
uint16_t arr = state->abPendingArr; |
|
|
|
|
|
|
|
|
|
|
|
state->abFrequencyPending = 0U; |
|
|
|
|
|
PlsrHwLoadAbPwm(ownerAxis, basePsc, pairPsc, arr); |
|
|
|
|
|
/* 落后相刚下降,AB=00;两路从同一个完整周期边界重定相。 */ |
|
|
|
|
|
PlsrHwBeginAbOutput(ownerAxis, 4U); |
|
|
|
|
|
} |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (hasCc1 != 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
/* 非运行态/非 AB 模式的 CC1 仅作为杂散标志消费。 */ |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
state = &PlsrHwAxes[axis]; |
|
|
state = &PlsrHwAxes[axis]; |
|
|
if (PlsrHwTimerHasUif(axis) == 0U) |
|
|
if (PlsrHwTimerHasUif(axis) == 0U) |
|
|
{ |
|
|
{ |
|
|
@@ -767,8 +1204,6 @@ void PlsrHwOnTimerUpdate(uint8_t axis) |
|
|
} |
|
|
} |
|
|
if (state->outputMode != PLSR_OUTPUT_PULSE_DIR) |
|
|
if (state->outputMode != PLSR_OUTPUT_PULSE_DIR) |
|
|
{ |
|
|
{ |
|
|
/* AB host 模型按四分之一周期推进,不能把任一物理定时器的 |
|
|
|
|
|
* update 直接当成完整 AB 指令脉冲。 */ |
|
|
|
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@@ -793,6 +1228,11 @@ uint32_t PlsrHwTestGetCcr(uint8_t axis) |
|
|
return PlsrHwTimers[axis].ccr1; |
|
|
return PlsrHwTimers[axis].ccr1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint32_t PlsrHwTestGetCnt(uint8_t axis) |
|
|
|
|
|
{ |
|
|
|
|
|
return PlsrHwTimers[axis].cnt; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
uint32_t PlsrHwTestGetCcmr1(uint8_t axis) |
|
|
uint32_t PlsrHwTestGetCcmr1(uint8_t axis) |
|
|
{ |
|
|
{ |
|
|
return PlsrHwTimers[axis].ccmr1; |
|
|
return PlsrHwTimers[axis].ccmr1; |
|
|
@@ -888,14 +1328,9 @@ void PlsrHwTestAdvanceAbQuarter(uint8_t axis) |
|
|
% PLSR_HW_AB_QUARTER_COUNT); |
|
|
% PLSR_HW_AB_QUARTER_COUNT); |
|
|
if (state->abQuarter == 0U) |
|
|
if (state->abQuarter == 0U) |
|
|
{ |
|
|
{ |
|
|
state->emittedPulses++; |
|
|
|
|
|
if (state->emittedPulses >= state->targetPulses) |
|
|
|
|
|
{ |
|
|
|
|
|
/* 仅在完整 00 边界停机,禁止留下半个正交周期。 */ |
|
|
|
|
|
PlsrHwStopActiveOutput(axis, state->outputMode); |
|
|
|
|
|
state->state = PLSR_HW_STATE_DONE; |
|
|
|
|
|
(void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/* 模拟目标板落后相 CC1 下降沿中断,复用生产计数路径。 */ |
|
|
|
|
|
PlsrHwTimers[state->abCountAxis].sr |= PLSR_HW_TIMER_CC1_BIT; |
|
|
|
|
|
PlsrHwOnTimerUpdate(state->abCountAxis); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|