You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2762 lines
80 KiB

  1. #include "plsr_hal_f407.h"
  2. #include "plsr_address_map.h"
  3. #include "plsr_build_config.h"
  4. #include "plsr_core.h"
  5. #include "plsr_job.h"
  6. #include <string.h>
  7. #ifndef PLSR_HOST_TEST
  8. #include "stm32f4xx.h"
  9. #include "stm32f4xx_hal.h"
  10. #endif
  11. #define PLSR_HW_TIMER_CHANNEL1_BIT (0x0001U)
  12. #define PLSR_HW_TIMER_UPDATE_BIT (0x0001U)
  13. #define PLSR_HW_TIMER_CC1_BIT (0x0002U)
  14. #define PLSR_HW_OUTPUT_POINT_COUNT (21U)
  15. #define PLSR_HW_DBG_SNAPSHOT_COUNT (160U)
  16. #define PLSR_HW_AB_QUARTER_COUNT (4U)
  17. #define PLSR_HW_COUNTER_COUNT (2U)
  18. #define PLSR_HW_COUNTER_NONE (0xFFU)
  19. #define PLSR_HW_COUNTER_BLOCK_PULSES (UINT64_C(65536))
  20. typedef struct
  21. {
  22. uint32_t timerClockHz;
  23. uint8_t directionPoint; /* 0xFF = 无 */
  24. #ifndef PLSR_HOST_TEST
  25. TIM_TypeDef *timer;
  26. GPIO_TypeDef *gpioPort;
  27. uint16_t gpioPin;
  28. uint8_t afMode;
  29. IRQn_Type irq;
  30. #endif
  31. } PLSR_HW_AXIS_MAP;
  32. #ifndef PLSR_HOST_TEST
  33. /* 输出点(Y 点号)→ GPIO 引脚:XDM-60T4-E 原理图。
  34. * 点号 8/9/18/19 不存在(资源层掩码 0x0013FCFF 已约束)。 */
  35. typedef struct
  36. {
  37. GPIO_TypeDef *port;
  38. uint16_t pin;
  39. } PLSR_HW_OUTPUT_PIN;
  40. static const PLSR_HW_OUTPUT_PIN PlsrHwOutputPins[PLSR_HW_OUTPUT_POINT_COUNT] =
  41. {
  42. {GPIOF, GPIO_PIN_6}, /* Y0 */
  43. {GPIOF, GPIO_PIN_8}, /* Y1 */
  44. {GPIOF, GPIO_PIN_7}, /* Y2 */
  45. {GPIOF, GPIO_PIN_9}, /* Y3 */
  46. {GPIOI, GPIO_PIN_8}, /* Y4 */
  47. {GPIOE, GPIO_PIN_6}, /* Y5 */
  48. {GPIOE, GPIO_PIN_5}, /* Y6 */
  49. {GPIOE, GPIO_PIN_4}, /* Y7 */
  50. {NULL, 0U}, /* Y8 */
  51. {NULL, 0U}, /* Y9 */
  52. {GPIOG, GPIO_PIN_7}, /* Y10 */
  53. {GPIOG, GPIO_PIN_6}, /* Y11 */
  54. {GPIOH, GPIO_PIN_9}, /* Y12 */
  55. {GPIOH, GPIO_PIN_8}, /* Y13 */
  56. {GPIOH, GPIO_PIN_7}, /* Y14 */
  57. {GPIOH, GPIO_PIN_6}, /* Y15 */
  58. {GPIOF, GPIO_PIN_11}, /* Y16 */
  59. {GPIOB, GPIO_PIN_0}, /* Y17 */
  60. {NULL, 0U}, /* Y18 */
  61. {NULL, 0U}, /* Y19 */
  62. {GPIOH, GPIO_PIN_5} /* Y20 */
  63. };
  64. #endif
  65. /* Q0~Q3 定时器:XDM-60T4-E。
  66. * PF6=TIM10_CH1(AF3)、PF7=TIM11_CH1(AF3)、PF8=TIM13_CH1(AF9)、PF9=TIM14_CH1(AF9)。
  67. * 定时器时钟由 RCC 实际配置计算(APB2 分频≠1 时定时器时钟×2)。 */
  68. static const PLSR_HW_AXIS_MAP PlsrHwAxisMap[PLSR_HW_AXIS_COUNT] =
  69. {
  70. #ifndef PLSR_HOST_TEST
  71. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM10, GPIOF, GPIO_PIN_6, 3U, TIM1_UP_TIM10_IRQn},
  72. {84000000UL, PLSR_HW_DIR_POINT_NONE, TIM13, GPIOF, GPIO_PIN_8, 9U, TIM8_UP_TIM13_IRQn},
  73. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM11, GPIOF, GPIO_PIN_7, 3U, TIM1_TRG_COM_TIM11_IRQn},
  74. {84000000UL, PLSR_HW_DIR_POINT_NONE, TIM14, GPIOF, GPIO_PIN_9, 9U, TIM8_TRG_COM_TIM14_IRQn}
  75. #else
  76. {168000000UL, PLSR_HW_DIR_POINT_NONE},
  77. {84000000UL, PLSR_HW_DIR_POINT_NONE},
  78. {168000000UL, PLSR_HW_DIR_POINT_NONE},
  79. {84000000UL, PLSR_HW_DIR_POINT_NONE}
  80. #endif
  81. };
  82. #ifndef PLSR_HOST_TEST
  83. static const uint8_t PlsrHwPulsePinIndex[PLSR_HW_AXIS_COUNT] =
  84. {
  85. 6U, 8U, 7U, 9U
  86. };
  87. /* 重定相期间由 GPIO 直接保持物理输出低电平。AFR 配置保持不变,
  88. * 只切换 MODER,因此恢复定时器复用功能只需一次寄存器写入。 */
  89. static void PlsrHwHoldPulsePinLow(uint8_t axis)
  90. {
  91. GPIO_TypeDef *port = PlsrHwAxisMap[axis].gpioPort;
  92. uint32_t shift = (uint32_t)PlsrHwPulsePinIndex[axis] * 2UL;
  93. uint32_t moder;
  94. port->BSRR = (uint32_t)PlsrHwAxisMap[axis].gpioPin << 16U;
  95. moder = port->MODER;
  96. moder &= ~(3UL << shift);
  97. moder |= 1UL << shift;
  98. port->MODER = moder;
  99. __DMB();
  100. }
  101. static void PlsrHwReleasePulsePin(uint8_t axis)
  102. {
  103. GPIO_TypeDef *port = PlsrHwAxisMap[axis].gpioPort;
  104. uint32_t shift = (uint32_t)PlsrHwPulsePinIndex[axis] * 2UL;
  105. uint32_t moder = port->MODER;
  106. moder &= ~(3UL << shift);
  107. moder |= 2UL << shift;
  108. port->MODER = moder;
  109. __DMB();
  110. }
  111. #endif
  112. /* host 测试:模拟定时器寄存器。 */
  113. #ifdef PLSR_HOST_TEST
  114. typedef struct
  115. {
  116. uint32_t cr1;
  117. uint32_t dier;
  118. uint32_t sr;
  119. uint32_t psc;
  120. uint32_t arr;
  121. uint32_t ccr1;
  122. uint32_t cnt;
  123. uint32_t ccmr1;
  124. uint32_t ccer;
  125. uint8_t dirLevel;
  126. } PLSR_HW_TIMER_REGS;
  127. static PLSR_HW_TIMER_REGS PlsrHwTimers[PLSR_HW_AXIS_COUNT];
  128. #endif
  129. typedef struct
  130. {
  131. PLSR_HW_STATE state;
  132. PLSR_OUTPUT_MODE outputMode;
  133. uint32_t currentFrequencyHz;
  134. int64_t targetPulses;
  135. int64_t emittedPulses;
  136. uint16_t directionDelayRemainingMs;
  137. uint8_t directionPoint;
  138. uint8_t configuredDirectionPoint;
  139. uint8_t directionPositive;
  140. uint8_t directionNegativeLogic;
  141. uint8_t directionTerminalOn;
  142. uint8_t directionOutputPending;
  143. uint8_t abQuarter;
  144. uint8_t abCountAxis;
  145. uint8_t abStartupPriming;
  146. uint16_t abActiveBasePsc;
  147. uint16_t abActivePairPsc;
  148. uint16_t abActiveArr;
  149. uint16_t abPendingBasePsc;
  150. uint16_t abPendingPairPsc;
  151. uint16_t abPendingArr;
  152. uint8_t abFrequencyPending;
  153. uint8_t abStopArmed;
  154. uint8_t abFastGated;
  155. uint8_t abPausePending;
  156. uint8_t abPauseGated;
  157. uint8_t abCompletionDeferred;
  158. uint8_t counterSourceAxis;
  159. uint32_t abCounterBoundaryCnt;
  160. uint8_t cwActiveAxis;
  161. uint8_t cwStopPending;
  162. uint8_t counterIndex;
  163. uint8_t hardwareCounterActive;
  164. uint8_t hardwareCounterConfigured;
  165. uint64_t counterBlockPulses;
  166. } PLSR_HW_AXIS_STATE;
  167. static PLSR_HW_AXIS_STATE PlsrHwAxes[PLSR_HW_AXIS_COUNT];
  168. static uint8_t PlsrHwDirectionBatchActive;
  169. static uint8_t PlsrHwCounterOwners[PLSR_HW_COUNTER_COUNT];
  170. static volatile uint32_t PlsrHwMaxOutputIsrCycles;
  171. static volatile uint32_t PlsrHwMaxCounterIsrCycles;
  172. static volatile uint32_t PlsrHwMaxControlIsrCycles;
  173. static volatile uint32_t PlsrHwMaxAbGateCycles;
  174. #ifndef PLSR_HOST_TEST
  175. static volatile uint8_t PlsrHwAbGateMeasurePending;
  176. #endif
  177. static volatile uint64_t PlsrHwTotalIsrCycles;
  178. static volatile uint32_t PlsrHwIsrBusyStarted;
  179. static volatile uint8_t PlsrHwIsrNesting;
  180. #ifndef PLSR_HOST_TEST
  181. static TIM_TypeDef * const PlsrHwCounters[PLSR_HW_COUNTER_COUNT] =
  182. {
  183. TIM9, TIM12
  184. };
  185. #endif
  186. static void PlsrHwCounterBegin(uint8_t axis);
  187. static void PlsrHwCounterSuspend(uint8_t axis);
  188. static void PlsrHwFinishDeferredAbWork(uint8_t axis);
  189. #ifdef PLSR_HOST_TEST
  190. static uint8_t PlsrHwTestLateAbFlagAxis = PLSR_HW_COUNTER_NONE;
  191. static uint32_t PlsrHwTestAbFullGateCount;
  192. #endif
  193. #ifndef PLSR_HOST_TEST
  194. static uint32_t PlsrHwCycleBegin(void)
  195. {
  196. uint32_t started = DWT->CYCCNT;
  197. if (PlsrHwIsrNesting == 0U)
  198. {
  199. PlsrHwIsrBusyStarted = started;
  200. }
  201. PlsrHwIsrNesting++;
  202. return started;
  203. }
  204. static void PlsrHwRecordMaxCycles(volatile uint32_t *maximum,
  205. uint32_t started)
  206. {
  207. uint32_t finished = DWT->CYCCNT;
  208. uint32_t elapsed = finished - started;
  209. if (elapsed > *maximum)
  210. {
  211. *maximum = elapsed;
  212. }
  213. if (PlsrHwIsrNesting > 0U)
  214. {
  215. PlsrHwIsrNesting--;
  216. if (PlsrHwIsrNesting == 0U)
  217. {
  218. uint32_t busyStarted = PlsrHwIsrBusyStarted;
  219. uint64_t totalCycles = PlsrHwTotalIsrCycles;
  220. /* Count a nested TIM6/high-speed interrupt window once. */
  221. totalCycles += finished - busyStarted;
  222. PlsrHwTotalIsrCycles = totalCycles;
  223. }
  224. }
  225. }
  226. #endif
  227. /* 调试快照:当前上板自测只记录 Q0 的 160 ms,避免四轴
  228. * PlsrHwTick 互相混入,同时控制临时 RAM 占用。reason=0 表示段启动,
  229. * reason=3 表示 1 ms HAL tick,reason=4 表示 AB 在 00 边界换频重定相。 */
  230. #if !defined(PLSR_HOST_TEST) && (PLSR_ENABLE_HW_TRACE != 0U)
  231. typedef struct
  232. {
  233. uint8_t reason; /* 0=PwmBegin(UG后) 3=PlsrHwTick(每1ms) */
  234. uint32_t psc;
  235. uint32_t arr;
  236. uint32_t ccr;
  237. uint32_t cnt;
  238. uint32_t frequencyHz;
  239. int64_t emittedPulses;
  240. } PLSR_HW_DBG_SNAP;
  241. static PLSR_HW_DBG_SNAP PlsrHwDbgSnap[PLSR_HW_DBG_SNAPSHOT_COUNT];
  242. static volatile uint16_t PlsrHwDbgCount;
  243. static void PlsrHwDbgCapture(uint8_t axis, uint8_t reason)
  244. {
  245. if (axis != 0U)
  246. {
  247. return;
  248. }
  249. if (reason == 0U)
  250. {
  251. PlsrHwDbgCount = 0U;
  252. }
  253. if (PlsrHwDbgCount < PLSR_HW_DBG_SNAPSHOT_COUNT)
  254. {
  255. PLSR_HW_DBG_SNAP *snap = &PlsrHwDbgSnap[PlsrHwDbgCount++];
  256. snap->reason = reason;
  257. snap->psc = PlsrHwAxisMap[axis].timer->PSC;
  258. snap->arr = PlsrHwAxisMap[axis].timer->ARR;
  259. snap->ccr = PlsrHwAxisMap[axis].timer->CCR1;
  260. snap->cnt = PlsrHwAxisMap[axis].timer->CNT;
  261. snap->frequencyHz = PlsrHwAxes[axis].currentFrequencyHz;
  262. snap->emittedPulses = PlsrHwAxes[axis].emittedPulses;
  263. }
  264. }
  265. #else
  266. #define PlsrHwDbgCapture(axis, reason) ((void)0)
  267. #endif
  268. /* ---- 定时器寄存器访问抽象(host 模拟 / 生产真实) ---- */
  269. static void PlsrHwTimerSetArr(uint8_t axis, uint32_t value)
  270. {
  271. #ifdef PLSR_HOST_TEST
  272. PlsrHwTimers[axis].arr = value;
  273. #else
  274. PlsrHwAxisMap[axis].timer->ARR = value;
  275. #endif
  276. }
  277. static void PlsrHwTimerSetPsc(uint8_t axis, uint32_t value)
  278. {
  279. #ifdef PLSR_HOST_TEST
  280. PlsrHwTimers[axis].psc = value;
  281. #else
  282. PlsrHwAxisMap[axis].timer->PSC = value;
  283. #endif
  284. }
  285. static void PlsrHwTimerSetCcr(uint8_t axis, uint32_t value)
  286. {
  287. #ifdef PLSR_HOST_TEST
  288. PlsrHwTimers[axis].ccr1 = value;
  289. #else
  290. PlsrHwAxisMap[axis].timer->CCR1 = value;
  291. #endif
  292. }
  293. static uint32_t PlsrHwTimerGetCcr(uint8_t axis)
  294. {
  295. #ifdef PLSR_HOST_TEST
  296. return PlsrHwTimers[axis].ccr1;
  297. #else
  298. return PlsrHwAxisMap[axis].timer->CCR1;
  299. #endif
  300. }
  301. static void PlsrHwTimerSetCnt(uint8_t axis, uint32_t value)
  302. {
  303. #ifdef PLSR_HOST_TEST
  304. PlsrHwTimers[axis].cnt = value;
  305. /* F407 实测语义:CNT 写到活动 CCR1 比较值会置 CC1IF。 */
  306. if (value == PlsrHwTimers[axis].ccr1)
  307. {
  308. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_CC1_BIT;
  309. }
  310. #else
  311. PlsrHwAxisMap[axis].timer->CNT = value;
  312. #endif
  313. }
  314. static void PlsrHwTimerSetCen(uint8_t axis, uint32_t value)
  315. {
  316. #ifdef PLSR_HOST_TEST
  317. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0001UL) | value;
  318. #else
  319. if (value != 0UL)
  320. {
  321. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_CEN;
  322. }
  323. else
  324. {
  325. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_CEN;
  326. }
  327. #endif
  328. }
  329. static void PlsrHwTimerSetCc1e(uint8_t axis, uint32_t value)
  330. {
  331. #ifdef PLSR_HOST_TEST
  332. PlsrHwTimers[axis].ccer = (PlsrHwTimers[axis].ccer & ~0x0001UL) | value;
  333. #else
  334. if (value != 0UL)
  335. {
  336. PlsrHwAxisMap[axis].timer->CCER |= TIM_CCER_CC1E;
  337. }
  338. else
  339. {
  340. PlsrHwAxisMap[axis].timer->CCER &= ~TIM_CCER_CC1E;
  341. }
  342. #endif
  343. }
  344. /* 通道 1 输出模式 = PWM 模式 1(OC1M=110)+ CCR 预装载(OC1PE)。
  345. * 上电复位后 CCMR1=0(冻结),通道输出恒定电平、无方波,必须显式配置。 */
  346. static void PlsrHwTimerSetPwmMode1(uint8_t axis)
  347. {
  348. #ifdef PLSR_HOST_TEST
  349. PlsrHwTimers[axis].ccmr1 = 0x0068UL;
  350. #else
  351. PlsrHwAxisMap[axis].timer->CCMR1 = (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)
  352. | TIM_CCMR1_OC1PE;
  353. #endif
  354. }
  355. /* AB 启动和重定相时先把 OC1REF 钳到低电平,再切到 frozen 保持 00。
  356. * 两路 CNT 就位后从 frozen 切到 PWM1,硬件会按当前 CNT/CCR 重新计算输出,
  357. * 避免 UG 后残留的 OC1REF 高电平经 CC1E 暴露为窄脉冲。 */
  358. static void PlsrHwTimerSetForcedInactive(uint8_t axis)
  359. {
  360. #ifdef PLSR_HOST_TEST
  361. PlsrHwTimers[axis].ccmr1 = 0x0048UL;
  362. #else
  363. PlsrHwAxisMap[axis].timer->CCMR1 = TIM_CCMR1_OC1M_2
  364. | TIM_CCMR1_OC1PE;
  365. #endif
  366. }
  367. static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value)
  368. {
  369. #ifdef PLSR_HOST_TEST
  370. PlsrHwTimers[axis].dier = (PlsrHwTimers[axis].dier & ~0x0001UL) | value;
  371. #else
  372. if (value != 0UL)
  373. {
  374. PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_UIE;
  375. }
  376. else
  377. {
  378. PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_UIE;
  379. }
  380. #endif
  381. }
  382. static void PlsrHwTimerSetCc1ie(uint8_t axis, uint32_t value)
  383. {
  384. #ifdef PLSR_HOST_TEST
  385. PlsrHwTimers[axis].dier =
  386. (PlsrHwTimers[axis].dier & ~PLSR_HW_TIMER_CC1_BIT)
  387. | ((value != 0UL) ? PLSR_HW_TIMER_CC1_BIT : 0UL);
  388. if ((value != 0UL)
  389. && ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_CC1_BIT) != 0UL))
  390. {
  391. PlsrHwOnTimerUpdate(axis);
  392. }
  393. #else
  394. if (value != 0UL)
  395. {
  396. PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_CC1IE;
  397. }
  398. else
  399. {
  400. PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_CC1IE;
  401. }
  402. #endif
  403. }
  404. static void PlsrHwTimerClearUif(uint8_t axis)
  405. {
  406. #ifdef PLSR_HOST_TEST
  407. PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_UPDATE_BIT;
  408. #else
  409. PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_UIF;
  410. #endif
  411. }
  412. static uint8_t PlsrHwTimerHasUif(uint8_t axis)
  413. {
  414. #ifdef PLSR_HOST_TEST
  415. return ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_UPDATE_BIT) != 0UL)
  416. ? 1U
  417. : 0U;
  418. #else
  419. return ((PlsrHwAxisMap[axis].timer->SR & TIM_SR_UIF) != 0UL) ? 1U : 0U;
  420. #endif
  421. }
  422. static void PlsrHwTimerClearCc1if(uint8_t axis)
  423. {
  424. #ifdef PLSR_HOST_TEST
  425. PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_CC1_BIT;
  426. #else
  427. PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_CC1IF;
  428. #endif
  429. }
  430. static uint8_t PlsrHwTimerHasCc1if(uint8_t axis)
  431. {
  432. #ifdef PLSR_HOST_TEST
  433. return ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_CC1_BIT) != 0UL)
  434. ? 1U
  435. : 0U;
  436. #else
  437. return ((PlsrHwAxisMap[axis].timer->SR & TIM_SR_CC1IF) != 0UL) ? 1U : 0U;
  438. #endif
  439. }
  440. /* ---- DIR 输出 ----
  441. * XDM 为晶体管(NPN 漏型)输出:ON(导通)= 引脚低电平。
  442. * 正逻辑:正向=ON;负逻辑:正向=OFF。逻辑运动方向始终单独保存,
  443. * 不能因电气极性反转而改变位置符号、AB相序或SM方向标志。 */
  444. static void PlsrHwApplyDirLevel(uint8_t axis)
  445. {
  446. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  447. if (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  448. {
  449. return;
  450. }
  451. #ifdef PLSR_HOST_TEST
  452. PlsrHwTimers[axis].dirLevel = state->directionTerminalOn;
  453. state->configuredDirectionPoint = state->directionPoint;
  454. #else
  455. if (state->directionPoint < PLSR_HW_OUTPUT_POINT_COUNT)
  456. {
  457. const PLSR_HW_OUTPUT_PIN *pin =
  458. &PlsrHwOutputPins[state->directionPoint];
  459. GPIO_InitTypeDef gpio;
  460. if (pin->port != NULL)
  461. {
  462. /* DIR 点按需配置为推挽输出(上电默认高阻=截止,安全)。 */
  463. pin->port->BSRR = (state->directionTerminalOn != 0U)
  464. ? ((uint32_t)pin->pin << 16U)
  465. : (uint32_t)pin->pin;
  466. if (state->configuredDirectionPoint != state->directionPoint)
  467. {
  468. gpio.Pin = pin->pin;
  469. gpio.Mode = GPIO_MODE_OUTPUT_PP;
  470. gpio.Pull = GPIO_NOPULL;
  471. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  472. HAL_GPIO_Init(pin->port, &gpio);
  473. state->configuredDirectionPoint = state->directionPoint;
  474. }
  475. /* 漏型输出:ON(导通)= 低电平。 */
  476. }
  477. }
  478. #endif
  479. }
  480. /* ---- PWM 启停 ----
  481. * ARR/CCR 使用预装载(ARPE/OC1PE):运行中调频写入延迟到更新事件生效,
  482. * 避免 ARR 变小瞬间 CNT 超调提前回绕(每段加速会多出 ~ln(f1/f0) 个假脉冲)。
  483. * 首次启动用 EGR.UG 把预装载值加载到影子寄存器,杜绝首个周期用复位值。 */
  484. static void PlsrHwSetDirLevel(uint8_t axis,
  485. uint8_t positive,
  486. uint8_t negativeLogic)
  487. {
  488. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  489. state->directionPositive = (positive != 0U) ? 1U : 0U;
  490. state->directionNegativeLogic =
  491. (negativeLogic != 0U) ? 1U : 0U;
  492. state->directionTerminalOn =
  493. (uint8_t)(state->directionPositive
  494. ^ state->directionNegativeLogic);
  495. if (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  496. {
  497. return;
  498. }
  499. if ((PlsrHwDirectionBatchActive != 0U)
  500. && (state->configuredDirectionPoint == state->directionPoint))
  501. {
  502. state->directionOutputPending = 1U;
  503. return;
  504. }
  505. PlsrHwApplyDirLevel(axis);
  506. }
  507. void PlsrHwBeginDirectionBatch(void)
  508. {
  509. PlsrHwDirectionBatchActive = 1U;
  510. }
  511. void PlsrHwEndDirectionBatch(void)
  512. {
  513. uint8_t axis;
  514. #ifndef PLSR_HOST_TEST
  515. uint32_t interruptState = __get_PRIMASK();
  516. __disable_irq();
  517. __DMB();
  518. #endif
  519. PlsrHwDirectionBatchActive = 0U;
  520. for (axis = 0U; axis < PLSR_HW_AXIS_COUNT; axis++)
  521. {
  522. if (PlsrHwAxes[axis].directionOutputPending != 0U)
  523. {
  524. PlsrHwAxes[axis].directionOutputPending = 0U;
  525. PlsrHwApplyDirLevel(axis);
  526. }
  527. }
  528. #ifndef PLSR_HOST_TEST
  529. __DMB();
  530. if (interruptState == 0UL)
  531. {
  532. __enable_irq();
  533. }
  534. #endif
  535. }
  536. static void PlsrHwTimerSetArpe(uint8_t axis, uint32_t value)
  537. {
  538. #ifdef PLSR_HOST_TEST
  539. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0080UL)
  540. | ((value != 0UL) ? 0x0080UL : 0UL);
  541. #else
  542. if (value != 0UL)
  543. {
  544. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_ARPE;
  545. }
  546. else
  547. {
  548. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_ARPE;
  549. }
  550. #endif
  551. }
  552. /* 生成更新事件:立即加载 ARR/CCR/PSC 影子寄存器(启动时用)。 */
  553. static void PlsrHwTimerSetUg(uint8_t axis)
  554. {
  555. #ifdef PLSR_HOST_TEST
  556. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_UPDATE_BIT;
  557. #else
  558. PlsrHwAxisMap[axis].timer->EGR = TIM_EGR_UG;
  559. #endif
  560. }
  561. /* 配置 PWM 定时器(预装载写入;启动/调频共用,不触碰使能位)。 */
  562. static void PlsrHwConfigurePwm(uint8_t axis, uint32_t frequencyHz)
  563. {
  564. uint16_t psc;
  565. uint16_t arr;
  566. #ifndef PLSR_HOST_TEST
  567. uint32_t interruptState;
  568. #endif
  569. if (PlsrCalculateTimerDivider(PlsrHwAxisMap[axis].timerClockHz,
  570. frequencyHz,
  571. &psc,
  572. &arr) != PLSR_RESULT_OK)
  573. {
  574. return;
  575. }
  576. #ifndef PLSR_HOST_TEST
  577. interruptState = __get_PRIMASK();
  578. __disable_irq();
  579. __DMB();
  580. #endif
  581. PlsrHwTimerSetPsc(axis, psc);
  582. PlsrHwTimerSetArr(axis, arr);
  583. PlsrHwTimerSetCcr(axis, (uint32_t)arr / 2UL); /* 50% 占空比 */
  584. PlsrHwTimerSetPwmMode1(axis);
  585. PlsrHwTimerSetArpe(axis, 1UL);
  586. #ifndef PLSR_HOST_TEST
  587. __DMB();
  588. if (interruptState == 0UL)
  589. {
  590. __enable_irq();
  591. }
  592. #endif
  593. }
  594. /* 首次启动输出:加载影子寄存器后使能更新中断、通道与计数。 */
  595. static void PlsrHwPwmBegin(uint8_t axis)
  596. {
  597. /* Stop the slave before changing the source OCREF phase. This is also
  598. * required when a paused hardware-counted segment is resumed. */
  599. PlsrHwCounterSuspend(axis);
  600. PlsrHwTimerSetUg(axis);
  601. if (PlsrHwAxes[axis].hardwareCounterActive != 0U)
  602. {
  603. /* PWM1 is inactive when CNT >= CCR1. Arm the ITR slave from that
  604. * known-low OCREF phase, then expose the first complete terminal high
  605. * half-cycle through CC1E. Starting at CNT=0 leaves OCREF high while
  606. * SMS is enabled; TIM9/TIM12 count that internal startup level as one
  607. * event even though no complete terminal pulse has occurred. */
  608. PlsrHwTimerSetCnt(axis, PlsrHwTimerGetCcr(axis));
  609. }
  610. /* UG 只用于加载影子寄存器,不是物理脉冲,不得计数。 */
  611. PlsrHwTimerClearUif(axis);
  612. PlsrHwTimerClearCc1if(axis);
  613. /* The slave trigger was selected while OCREF was forced low. Enable its
  614. * external-clock mode only after the source PWM and startup UG are stable. */
  615. PlsrHwCounterBegin(axis);
  616. PlsrHwDbgCapture(axis, 0U);
  617. PlsrHwTimerSetCc1ie(axis, 0UL);
  618. /* TIM9/TIM12 count OC events in hardware. Only the two fallback axes
  619. * retain a per-period output-timer interrupt. */
  620. PlsrHwTimerSetUie(axis,
  621. (PlsrHwAxes[axis].hardwareCounterActive != 0U)
  622. ? 0UL
  623. : 1UL);
  624. PlsrHwTimerSetCc1e(axis, 1UL);
  625. PlsrHwTimerSetCen(axis, 1UL);
  626. }
  627. static void PlsrHwStopPwmTimer(uint8_t axis)
  628. {
  629. /* Freeze the ITR slave before changing OCREF/CC1E so a stop or pause
  630. * transition cannot be mistaken for a physical pulse boundary. */
  631. PlsrHwCounterSuspend(axis);
  632. PlsrHwTimerSetCc1e(axis, 0UL);
  633. PlsrHwTimerSetUie(axis, 0UL);
  634. PlsrHwTimerSetCc1ie(axis, 0UL);
  635. PlsrHwTimerSetCen(axis, 0UL);
  636. PlsrHwTimerClearUif(axis);
  637. PlsrHwTimerClearCc1if(axis);
  638. }
  639. static uint8_t PlsrHwIsAbBaseAxis(uint8_t axis)
  640. {
  641. return ((axis == 0U) || (axis == 2U)) ? 1U : 0U;
  642. }
  643. static uint8_t PlsrHwGetPairedAxis(uint8_t axis)
  644. {
  645. return (uint8_t)(axis + 1U);
  646. }
  647. /* 为 168MHz/84MHz 配对定时器选择相同 ARR,并让前者的 PSC 分频
  648. * 始终是后者的 2 倍。两路获得完全相同的计数时钟与周期,避免
  649. * 独立取整造成 AB 相位随运行时间漂移。 */
  650. static uint8_t PlsrHwCalculateAbDividers(uint8_t axis,
  651. uint32_t frequencyHz,
  652. uint16_t *basePsc,
  653. uint16_t *pairPsc,
  654. uint16_t *arr)
  655. {
  656. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  657. uint64_t baseClock = PlsrHwAxisMap[axis].timerClockHz;
  658. uint64_t pairClock = PlsrHwAxisMap[pairAxis].timerClockHz;
  659. uint64_t ratio;
  660. uint64_t pairDivider;
  661. uint64_t baseDivider;
  662. uint64_t periodTicks;
  663. if ((frequencyHz == 0UL) || (basePsc == NULL) || (pairPsc == NULL)
  664. || (arr == NULL) || (pairClock == 0UL)
  665. || ((baseClock % pairClock) != 0UL))
  666. {
  667. return 0U;
  668. }
  669. ratio = baseClock / pairClock;
  670. if (ratio == 0UL)
  671. {
  672. return 0U;
  673. }
  674. pairDivider = (pairClock
  675. + (uint64_t)frequencyHz * UINT64_C(65536) - 1UL)
  676. / ((uint64_t)frequencyHz * UINT64_C(65536));
  677. if (pairDivider == 0UL)
  678. {
  679. pairDivider = 1UL;
  680. }
  681. baseDivider = pairDivider * ratio;
  682. if ((pairDivider > UINT64_C(65536))
  683. || (baseDivider > UINT64_C(65536)))
  684. {
  685. return 0U;
  686. }
  687. periodTicks = (pairClock
  688. + ((uint64_t)frequencyHz * pairDivider) / 2UL)
  689. / ((uint64_t)frequencyHz * pairDivider);
  690. if ((periodTicks < 4UL) || (periodTicks > UINT64_C(65536)))
  691. {
  692. return 0U;
  693. }
  694. *basePsc = (uint16_t)(baseDivider - 1UL);
  695. *pairPsc = (uint16_t)(pairDivider - 1UL);
  696. *arr = (uint16_t)(periodTicks - 1UL);
  697. return 1U;
  698. }
  699. static void PlsrHwLoadAbPwm(uint8_t axis,
  700. uint16_t basePsc,
  701. uint16_t pairPsc,
  702. uint16_t arr)
  703. {
  704. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  705. uint32_t compare;
  706. compare = ((uint32_t)arr + 1UL) / 2UL;
  707. PlsrHwTimerSetPsc(axis, basePsc);
  708. PlsrHwTimerSetPsc(pairAxis, pairPsc);
  709. PlsrHwTimerSetArr(axis, arr);
  710. PlsrHwTimerSetArr(pairAxis, arr);
  711. PlsrHwTimerSetCcr(axis, compare);
  712. PlsrHwTimerSetCcr(pairAxis, compare);
  713. PlsrHwTimerSetPwmMode1(axis);
  714. PlsrHwTimerSetPwmMode1(pairAxis);
  715. PlsrHwTimerSetArpe(axis, 1UL);
  716. PlsrHwTimerSetArpe(pairAxis, 1UL);
  717. PlsrHwAxes[axis].abActiveBasePsc = basePsc;
  718. PlsrHwAxes[axis].abActivePairPsc = pairPsc;
  719. PlsrHwAxes[axis].abActiveArr = arr;
  720. }
  721. static uint8_t PlsrHwConfigureAbPwm(uint8_t axis, uint32_t frequencyHz)
  722. {
  723. uint16_t basePsc;
  724. uint16_t pairPsc;
  725. uint16_t arr;
  726. if (PlsrHwCalculateAbDividers(axis,
  727. frequencyHz,
  728. &basePsc,
  729. &pairPsc,
  730. &arr) == 0U)
  731. {
  732. return 0U;
  733. }
  734. PlsrHwLoadAbPwm(axis, basePsc, pairPsc, arr);
  735. return 1U;
  736. }
  737. /* 运行中的 AB 调频不能直接写两路 ARR 预装载:两路定时器相差 1/4 周期,
  738. * 各自的 update 时刻也相差 1/4 周期,会短暂使用不同周期并永久积累相位误差。
  739. * 任务上下文只计算并发布最新参数,真正装载由 00 周期边界中断完成。 */
  740. static uint8_t PlsrHwQueueAbFrequency(uint8_t axis, uint32_t frequencyHz)
  741. {
  742. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  743. uint16_t basePsc;
  744. uint16_t pairPsc;
  745. uint16_t arr;
  746. #ifndef PLSR_HOST_TEST
  747. uint32_t interruptState;
  748. #endif
  749. if (PlsrHwCalculateAbDividers(axis,
  750. frequencyHz,
  751. &basePsc,
  752. &pairPsc,
  753. &arr) == 0U)
  754. {
  755. return 0U;
  756. }
  757. #ifndef PLSR_HOST_TEST
  758. interruptState = __get_PRIMASK();
  759. __disable_irq();
  760. __DMB();
  761. #endif
  762. if ((basePsc == state->abActiveBasePsc)
  763. && (pairPsc == state->abActivePairPsc)
  764. && (arr == state->abActiveArr))
  765. {
  766. /* 量化后的分频参数未变化时取消旧请求,避免匀速段每 1ms 重定相。 */
  767. state->abFrequencyPending = 0U;
  768. if ((state->hardwareCounterActive != 0U)
  769. && (state->abStopArmed == 0U)
  770. && (state->abPausePending == 0U))
  771. {
  772. PlsrHwTimerSetCc1ie(state->abCountAxis, 0UL);
  773. }
  774. }
  775. else
  776. {
  777. state->abPendingBasePsc = basePsc;
  778. state->abPendingPairPsc = pairPsc;
  779. state->abPendingArr = arr;
  780. state->abFrequencyPending = 1U;
  781. if (state->hardwareCounterActive != 0U)
  782. {
  783. /* Hardware counting keeps the per-cycle CC interrupt disabled.
  784. * Wake it as a one-shot to apply this request at the next 00. */
  785. PlsrHwTimerClearCc1if(state->abCountAxis);
  786. PlsrHwTimerSetCc1ie(state->abCountAxis, 1UL);
  787. }
  788. }
  789. #ifndef PLSR_HOST_TEST
  790. __DMB();
  791. if (interruptState == 0UL)
  792. {
  793. __enable_irq();
  794. }
  795. #endif
  796. return 1U;
  797. }
  798. static void PlsrHwBeginAbOutput(uint8_t axis, uint8_t debugReason)
  799. {
  800. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  801. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  802. uint8_t leadAxis = (state->directionPositive != 0U) ? axis : pairAxis;
  803. uint8_t lagAxis = (state->directionPositive != 0U) ? pairAxis : axis;
  804. uint32_t periodTicks;
  805. uint32_t leadStart;
  806. uint32_t lagStart;
  807. #ifndef PLSR_HOST_TEST
  808. uint32_t interruptState;
  809. #else
  810. (void)debugReason;
  811. #endif
  812. #ifdef PLSR_HOST_TEST
  813. periodTicks = PlsrHwTimers[axis].arr + 1UL;
  814. #else
  815. periodTicks = PlsrHwAxisMap[axis].timer->ARR + 1UL;
  816. #endif
  817. leadStart = (periodTicks * 3UL) / 4UL + 1UL;
  818. if (leadStart >= periodTicks)
  819. {
  820. leadStart = periodTicks - 1UL;
  821. }
  822. /* Both counters must be strictly beyond CCR while GPIO is handed back to
  823. * AF. CNT==CCR can leave the compare/OCREF state implementation-defined
  824. * at the mux boundary and previously exposed one simultaneous A/B edge. */
  825. lagStart = periodTicks / 2UL + 1UL;
  826. if (lagStart >= periodTicks)
  827. {
  828. lagStart = periodTicks - 1UL;
  829. }
  830. state->abCountAxis = lagAxis;
  831. state->counterSourceAxis = (axis == 0U) ? axis : pairAxis;
  832. state->abCounterBoundaryCnt =
  833. (state->counterSourceAxis == leadAxis)
  834. ? leadStart - 1UL
  835. : periodTicks / 2UL;
  836. state->abQuarter = 0U;
  837. state->abStartupPriming = 0U;
  838. state->abFastGated = 0U;
  839. #ifndef PLSR_HOST_TEST
  840. interruptState = __get_PRIMASK();
  841. __disable_irq();
  842. __DMB();
  843. PlsrHwCounterSuspend(axis);
  844. PlsrHwHoldPulsePinLow(axis);
  845. PlsrHwHoldPulsePinLow(pairAxis);
  846. #endif
  847. PlsrHwTimerSetCen(axis, 0UL);
  848. PlsrHwTimerSetCen(pairAxis, 0UL);
  849. PlsrHwTimerSetCc1e(axis, 0UL);
  850. PlsrHwTimerSetCc1e(pairAxis, 0UL);
  851. PlsrHwTimerSetUie(axis, 0UL);
  852. PlsrHwTimerSetUie(pairAxis, 0UL);
  853. PlsrHwTimerSetCc1ie(axis, 0UL);
  854. PlsrHwTimerSetCc1ie(pairAxis, 0UL);
  855. PlsrHwTimerSetForcedInactive(axis);
  856. PlsrHwTimerSetForcedInactive(pairAxis);
  857. PlsrHwTimerSetUg(axis);
  858. PlsrHwTimerSetUg(pairAxis);
  859. PlsrHwTimerClearUif(axis);
  860. PlsrHwTimerClearUif(pairAxis);
  861. PlsrHwTimerClearCc1if(axis);
  862. PlsrHwTimerClearCc1if(pairAxis);
  863. PlsrHwTimerSetCnt(leadAxis, leadStart);
  864. PlsrHwTimerSetCnt(lagAxis, lagStart);
  865. /* Enable the forced-inactive channels while GPIO still owns the pins.
  866. * AF handoff and the later PWM1 selection therefore preserve the same 00
  867. * electrical level at every mux point. */
  868. PlsrHwTimerSetCc1e(axis, 1UL);
  869. PlsrHwTimerSetCc1e(pairAxis, 1UL);
  870. #ifndef PLSR_HOST_TEST
  871. __DMB();
  872. /* CC1E is enabled, but forced-inactive drives the same idle level as
  873. * the GPIO hold. Hand the pins to AF now, before either timer can run. */
  874. PlsrHwReleasePulsePin(axis);
  875. PlsrHwReleasePulsePin(pairAxis);
  876. #endif
  877. #ifdef PLSR_HOST_TEST
  878. PlsrHwTimerSetPwmMode1(axis);
  879. PlsrHwTimerSetPwmMode1(pairAxis);
  880. PlsrHwTimerClearCc1if(axis);
  881. PlsrHwTimerClearCc1if(pairAxis);
  882. PlsrHwCounterBegin(axis);
  883. PlsrHwTimerSetCen(axis, 1UL);
  884. PlsrHwTimerSetCen(pairAxis, 1UL);
  885. PlsrHwTimerClearCc1if(axis);
  886. PlsrHwTimerClearCc1if(pairAxis);
  887. PlsrHwTimerSetCc1ie(
  888. lagAxis,
  889. ((state->hardwareCounterActive != 0U)
  890. && (state->abStopArmed == 0U))
  891. ? 0UL
  892. : 1UL);
  893. #else
  894. PlsrHwTimerSetPwmMode1(axis);
  895. PlsrHwTimerSetPwmMode1(pairAxis);
  896. PlsrHwTimerClearCc1if(axis);
  897. PlsrHwTimerClearCc1if(pairAxis);
  898. PlsrHwCounterBegin(axis);
  899. PlsrHwTimerSetCen(axis, 1UL);
  900. PlsrHwTimerSetCen(pairAxis, 1UL);
  901. PlsrHwTimerClearCc1if(axis);
  902. PlsrHwTimerClearCc1if(pairAxis);
  903. PlsrHwTimerSetCc1ie(
  904. lagAxis,
  905. ((state->hardwareCounterActive != 0U)
  906. && (state->abStopArmed == 0U))
  907. ? 0UL
  908. : 1UL);
  909. __DMB();
  910. if (interruptState == 0UL)
  911. {
  912. __enable_irq();
  913. }
  914. #endif
  915. PlsrHwDbgCapture(axis, debugReason);
  916. }
  917. static void PlsrHwConfigureCwCcwPwm(uint8_t axis, uint32_t frequencyHz)
  918. {
  919. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  920. uint8_t activeAxis = state->cwActiveAxis;
  921. uint16_t psc;
  922. uint16_t arr;
  923. #ifndef PLSR_HOST_TEST
  924. uint32_t interruptState;
  925. #endif
  926. if (PlsrCalculateTimerDivider(PlsrHwAxisMap[activeAxis].timerClockHz,
  927. frequencyHz,
  928. &psc,
  929. &arr) != PLSR_RESULT_OK)
  930. {
  931. return;
  932. }
  933. #ifndef PLSR_HOST_TEST
  934. interruptState = __get_PRIMASK();
  935. __disable_irq();
  936. __DMB();
  937. #endif
  938. /* The compare ISR may arm final-pulse shutdown while TIM6 is calculating
  939. * a new divider. Recheck under the same short critical section as the
  940. * preload writes so the tail period can no longer be changed afterwards. */
  941. if (state->cwStopPending == 0U)
  942. {
  943. PlsrHwTimerSetPsc(activeAxis, psc);
  944. PlsrHwTimerSetArr(activeAxis, arr);
  945. PlsrHwTimerSetCcr(activeAxis, (uint32_t)arr / 2UL);
  946. PlsrHwTimerSetPwmMode1(activeAxis);
  947. PlsrHwTimerSetArpe(activeAxis, 1UL);
  948. }
  949. #ifndef PLSR_HOST_TEST
  950. __DMB();
  951. if (interruptState == 0UL)
  952. {
  953. __enable_irq();
  954. }
  955. #endif
  956. }
  957. static void PlsrHwBeginCwCcwOutput(uint8_t axis)
  958. {
  959. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  960. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  961. uint8_t activeAxis = state->cwActiveAxis;
  962. #ifndef PLSR_HOST_TEST
  963. uint32_t interruptState = __get_PRIMASK();
  964. __disable_irq();
  965. __DMB();
  966. #endif
  967. /* Keep both pins in timer AF. On this output chain, switching a channel
  968. * to GPIO-low is observable as an asserted Q edge. CC1E=0 is the tested
  969. * inactive level and avoids the extra start/end edge. */
  970. PlsrHwStopPwmTimer(axis);
  971. PlsrHwStopPwmTimer(pairAxis);
  972. state->cwStopPending = 0U;
  973. PlsrHwTimerSetUg(activeAxis);
  974. PlsrHwTimerClearUif(activeAxis);
  975. PlsrHwTimerClearCc1if(activeAxis);
  976. PlsrHwTimerSetCnt(activeAxis, 0UL);
  977. PlsrHwTimerSetUie(activeAxis, 0UL);
  978. PlsrHwTimerSetCc1ie(activeAxis, 1UL);
  979. PlsrHwTimerSetCc1e(activeAxis, 1UL);
  980. PlsrHwTimerSetCen(activeAxis, 1UL);
  981. #ifndef PLSR_HOST_TEST
  982. __DMB();
  983. if (interruptState == 0UL)
  984. {
  985. __enable_irq();
  986. }
  987. #endif
  988. }
  989. static void PlsrHwStopCwCcwOutput(uint8_t axis)
  990. {
  991. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  992. #ifndef PLSR_HOST_TEST
  993. uint32_t interruptState = __get_PRIMASK();
  994. __disable_irq();
  995. __DMB();
  996. #endif
  997. /* Disable both compare outputs while retaining AF mode; do not force
  998. * either pin through GPIO during the direction handover. */
  999. PlsrHwStopPwmTimer(axis);
  1000. PlsrHwStopPwmTimer(pairAxis);
  1001. PlsrHwAxes[axis].cwStopPending = 0U;
  1002. #ifndef PLSR_HOST_TEST
  1003. __DMB();
  1004. if (interruptState == 0UL)
  1005. {
  1006. __enable_irq();
  1007. }
  1008. #endif
  1009. }
  1010. static void PlsrHwConfigureActiveOutput(uint8_t axis,
  1011. PLSR_OUTPUT_MODE outputMode,
  1012. uint32_t frequencyHz)
  1013. {
  1014. if (outputMode == PLSR_OUTPUT_AB)
  1015. {
  1016. (void)PlsrHwConfigureAbPwm(axis, frequencyHz);
  1017. }
  1018. else if (outputMode == PLSR_OUTPUT_CW_CCW)
  1019. {
  1020. PlsrHwConfigureCwCcwPwm(axis, frequencyHz);
  1021. }
  1022. else
  1023. {
  1024. PlsrHwConfigurePwm(axis, frequencyHz);
  1025. }
  1026. }
  1027. static void PlsrHwBeginActiveOutput(uint8_t axis,
  1028. PLSR_OUTPUT_MODE outputMode)
  1029. {
  1030. if (outputMode == PLSR_OUTPUT_AB)
  1031. {
  1032. PlsrHwBeginAbOutput(axis, 0U);
  1033. }
  1034. else if (outputMode == PLSR_OUTPUT_CW_CCW)
  1035. {
  1036. PlsrHwBeginCwCcwOutput(axis);
  1037. }
  1038. else
  1039. {
  1040. PlsrHwPwmBegin(axis);
  1041. }
  1042. }
  1043. static void PlsrHwStopActiveOutput(uint8_t axis,
  1044. PLSR_OUTPUT_MODE outputMode)
  1045. {
  1046. if ((outputMode == PLSR_OUTPUT_AB) && (PlsrHwIsAbBaseAxis(axis) != 0U))
  1047. {
  1048. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  1049. #ifndef PLSR_HOST_TEST
  1050. uint32_t interruptState = __get_PRIMASK();
  1051. __disable_irq();
  1052. __DMB();
  1053. /* DONE/STOP 后继续由 GPIO 保持 00,禁止已关闭 timer 泄漏残余边沿。 */
  1054. PlsrHwHoldPulsePinLow(axis);
  1055. PlsrHwHoldPulsePinLow(pairAxis);
  1056. #endif
  1057. PlsrHwStopPwmTimer(axis);
  1058. PlsrHwStopPwmTimer(pairAxis);
  1059. PlsrHwAxes[axis].abStartupPriming = 0U;
  1060. #ifndef PLSR_HOST_TEST
  1061. __DMB();
  1062. if (interruptState == 0UL)
  1063. {
  1064. __enable_irq();
  1065. }
  1066. #endif
  1067. }
  1068. else if ((outputMode == PLSR_OUTPUT_CW_CCW)
  1069. && (PlsrHwIsAbBaseAxis(axis) != 0U))
  1070. {
  1071. PlsrHwStopCwCcwOutput(axis);
  1072. }
  1073. else
  1074. {
  1075. PlsrHwStopPwmTimer(axis);
  1076. }
  1077. }
  1078. static uint8_t PlsrHwCounterIndexForAxis(uint8_t axis)
  1079. {
  1080. return (uint8_t)(axis & 1U);
  1081. }
  1082. static uint8_t PlsrHwCounterTryAcquire(uint8_t axis,
  1083. PLSR_OUTPUT_MODE outputMode)
  1084. {
  1085. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1086. uint8_t counterIndex;
  1087. uint8_t acquired = 0U;
  1088. #ifndef PLSR_HOST_TEST
  1089. uint32_t interruptState;
  1090. #endif
  1091. state->counterIndex = PLSR_HW_COUNTER_NONE;
  1092. state->hardwareCounterActive = 0U;
  1093. state->hardwareCounterConfigured = 0U;
  1094. state->counterBlockPulses = 0UL;
  1095. if ((outputMode != PLSR_OUTPUT_PULSE_DIR)
  1096. && (outputMode != PLSR_OUTPUT_AB))
  1097. {
  1098. return 0U;
  1099. }
  1100. if (outputMode == PLSR_OUTPUT_AB)
  1101. {
  1102. /* One counter per fixed AB pair: Q0/Q1 -> TIM9, Q2/Q3 -> TIM12.
  1103. * Very short jobs retain the existing per-cycle ISR because a
  1104. * target-1 guard compare cannot be armed at raw count zero. */
  1105. if ((PlsrHwIsAbBaseAxis(axis) == 0U) || (state->targetPulses < 2))
  1106. {
  1107. return 0U;
  1108. }
  1109. counterIndex = (uint8_t)(axis >> 1U);
  1110. }
  1111. else
  1112. {
  1113. counterIndex = PlsrHwCounterIndexForAxis(axis);
  1114. }
  1115. #ifndef PLSR_HOST_TEST
  1116. interruptState = __get_PRIMASK();
  1117. __disable_irq();
  1118. __DMB();
  1119. #endif
  1120. if (PlsrHwCounterOwners[counterIndex] == PLSR_HW_COUNTER_NONE)
  1121. {
  1122. PlsrHwCounterOwners[counterIndex] = axis;
  1123. state->counterIndex = counterIndex;
  1124. state->hardwareCounterActive = 1U;
  1125. acquired = 1U;
  1126. }
  1127. #ifndef PLSR_HOST_TEST
  1128. __DMB();
  1129. if (interruptState == 0UL)
  1130. {
  1131. __enable_irq();
  1132. }
  1133. #endif
  1134. return acquired;
  1135. }
  1136. static void PlsrHwCounterRelease(uint8_t axis)
  1137. {
  1138. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1139. #ifndef PLSR_HOST_TEST
  1140. uint32_t interruptState = __get_PRIMASK();
  1141. __disable_irq();
  1142. __DMB();
  1143. #endif
  1144. if (state->counterIndex < PLSR_HW_COUNTER_COUNT)
  1145. {
  1146. #ifndef PLSR_HOST_TEST
  1147. TIM_TypeDef *counter = PlsrHwCounters[state->counterIndex];
  1148. counter->CR1 = 0UL;
  1149. counter->DIER = 0UL;
  1150. counter->SMCR = 0UL;
  1151. counter->SR = 0UL;
  1152. #endif
  1153. if (PlsrHwCounterOwners[state->counterIndex] == axis)
  1154. {
  1155. PlsrHwCounterOwners[state->counterIndex] =
  1156. PLSR_HW_COUNTER_NONE;
  1157. }
  1158. }
  1159. state->counterIndex = PLSR_HW_COUNTER_NONE;
  1160. state->hardwareCounterActive = 0U;
  1161. state->hardwareCounterConfigured = 0U;
  1162. state->counterBlockPulses = 0UL;
  1163. #ifndef PLSR_HOST_TEST
  1164. __DMB();
  1165. if (interruptState == 0UL)
  1166. {
  1167. __enable_irq();
  1168. }
  1169. #endif
  1170. }
  1171. static void PlsrHwCounterConfigure(uint8_t axis)
  1172. {
  1173. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1174. state->counterBlockPulses = 0UL;
  1175. #ifndef PLSR_HOST_TEST
  1176. if (state->counterIndex < PLSR_HW_COUNTER_COUNT)
  1177. {
  1178. TIM_TypeDef *counter = PlsrHwCounters[state->counterIndex];
  1179. uint32_t triggerSelection = ((axis & 2U) == 0U)
  1180. ? TIM_SMCR_TS_1
  1181. : (TIM_SMCR_TS_1 | TIM_SMCR_TS_0);
  1182. uint64_t comparePulses = (uint64_t)state->targetPulses;
  1183. /* PULSE/DIR owns one source timer and can force it inactive here. AB
  1184. * owns a pair; its atomic startup routine establishes both OCREF lows
  1185. * immediately before CounterBegin instead. */
  1186. if (state->outputMode == PLSR_OUTPUT_PULSE_DIR)
  1187. {
  1188. PlsrHwTimerSetCen(axis, 0UL);
  1189. PlsrHwTimerSetCc1e(axis, 0UL);
  1190. PlsrHwTimerSetForcedInactive(axis);
  1191. PlsrHwTimerSetUg(axis);
  1192. PlsrHwTimerClearUif(axis);
  1193. PlsrHwTimerClearCc1if(axis);
  1194. }
  1195. else
  1196. {
  1197. /* Wake the lag-CC1 one complete cycle before the target boundary.
  1198. * It verifies raw>=target at 00, avoiding ISR-latency overshoot. */
  1199. comparePulses--;
  1200. }
  1201. counter->CR1 = 0UL;
  1202. counter->DIER = 0UL;
  1203. counter->SMCR = 0UL;
  1204. counter->PSC = 0UL;
  1205. counter->ARR = 0xFFFFUL;
  1206. counter->CCR1 = (uint32_t)(comparePulses & UINT64_C(0xFFFF));
  1207. counter->CNT = 0UL;
  1208. counter->EGR = TIM_EGR_UG;
  1209. counter->SR = 0UL;
  1210. counter->SMCR = triggerSelection;
  1211. counter->DIER = TIM_DIER_UIE | TIM_DIER_CC1IE;
  1212. }
  1213. #endif
  1214. }
  1215. static void PlsrHwCounterBegin(uint8_t axis)
  1216. {
  1217. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1218. if (state->hardwareCounterActive == 0U)
  1219. {
  1220. return;
  1221. }
  1222. if (state->hardwareCounterConfigured == 0U)
  1223. {
  1224. return;
  1225. }
  1226. #ifndef PLSR_HOST_TEST
  1227. if (state->counterIndex < PLSR_HW_COUNTER_COUNT)
  1228. {
  1229. TIM_TypeDef *counter = PlsrHwCounters[state->counterIndex];
  1230. counter->SMCR |= TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0;
  1231. counter->CR1 |= TIM_CR1_CEN;
  1232. }
  1233. #endif
  1234. }
  1235. static void PlsrHwCounterSuspend(uint8_t axis)
  1236. {
  1237. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1238. if ((state->hardwareCounterActive == 0U)
  1239. || (state->hardwareCounterConfigured == 0U))
  1240. {
  1241. return;
  1242. }
  1243. #ifndef PLSR_HOST_TEST
  1244. if (state->counterIndex < PLSR_HW_COUNTER_COUNT)
  1245. {
  1246. TIM_TypeDef *counter = PlsrHwCounters[state->counterIndex];
  1247. counter->CR1 &= ~TIM_CR1_CEN;
  1248. counter->SMCR &= ~(TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0);
  1249. }
  1250. #endif
  1251. }
  1252. static void PlsrHwCounterRebase(uint8_t axis, uint64_t pulses)
  1253. {
  1254. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1255. if ((state->hardwareCounterActive == 0U)
  1256. || (state->hardwareCounterConfigured == 0U))
  1257. {
  1258. return;
  1259. }
  1260. #ifdef PLSR_HOST_TEST
  1261. state->counterBlockPulses = pulses;
  1262. #else
  1263. state->counterBlockPulses =
  1264. pulses & ~(PLSR_HW_COUNTER_BLOCK_PULSES - UINT64_C(1));
  1265. if (state->counterIndex < PLSR_HW_COUNTER_COUNT)
  1266. {
  1267. TIM_TypeDef *counter = PlsrHwCounters[state->counterIndex];
  1268. counter->CNT = (uint16_t)pulses;
  1269. counter->SR = 0UL;
  1270. }
  1271. #endif
  1272. }
  1273. static uint64_t PlsrHwCounterRawSnapshot(uint8_t axis)
  1274. {
  1275. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1276. uint64_t pulses = state->counterBlockPulses;
  1277. #ifndef PLSR_HOST_TEST
  1278. if (state->counterIndex < PLSR_HW_COUNTER_COUNT)
  1279. {
  1280. TIM_TypeDef *counter = PlsrHwCounters[state->counterIndex];
  1281. pulses += (uint16_t)counter->CNT;
  1282. /* Cover the short window after wrap and before the block ISR. */
  1283. if ((counter->SR & TIM_SR_UIF) != 0UL)
  1284. {
  1285. pulses += PLSR_HW_COUNTER_BLOCK_PULSES;
  1286. }
  1287. }
  1288. #else
  1289. pulses = (state->outputMode == PLSR_OUTPUT_AB)
  1290. ? state->counterBlockPulses
  1291. : (uint64_t)state->emittedPulses;
  1292. #endif
  1293. return pulses;
  1294. }
  1295. static uint64_t PlsrHwCounterSnapshot(uint8_t axis)
  1296. {
  1297. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1298. uint64_t pulses = PlsrHwCounterRawSnapshot(axis);
  1299. #ifndef PLSR_HOST_TEST
  1300. if ((state->outputMode == PLSR_OUTPUT_AB) && (pulses > 0UL)
  1301. && (state->counterSourceAxis < PLSR_HW_AXIS_COUNT))
  1302. {
  1303. uint64_t verifiedPulses;
  1304. uint32_t sourceCnt;
  1305. uint8_t attempt;
  1306. /* The ITR source rises inside an AB cycle, before the following 00
  1307. * boundary. A stable raw/CNT/raw snapshot identifies that interval
  1308. * and publishes only complete four-state cycles. */
  1309. for (attempt = 0U; attempt < 2U; attempt++)
  1310. {
  1311. pulses = PlsrHwCounterRawSnapshot(axis);
  1312. sourceCnt = PlsrHwAxisMap[state->counterSourceAxis].timer->CNT;
  1313. verifiedPulses = PlsrHwCounterRawSnapshot(axis);
  1314. if (pulses == verifiedPulses)
  1315. {
  1316. if ((sourceCnt < state->abCounterBoundaryCnt)
  1317. && (pulses > 0UL))
  1318. {
  1319. pulses--;
  1320. }
  1321. break;
  1322. }
  1323. pulses = verifiedPulses;
  1324. }
  1325. }
  1326. #else
  1327. if ((state->outputMode == PLSR_OUTPUT_AB) && (pulses > 0UL))
  1328. {
  1329. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  1330. uint8_t leadAxis = (state->directionPositive != 0U)
  1331. ? axis
  1332. : pairAxis;
  1333. uint8_t sourceQuarter = (state->counterSourceAxis == leadAxis)
  1334. ? 1U
  1335. : 2U;
  1336. if ((state->abQuarter >= sourceQuarter)
  1337. && (state->abQuarter != 0U))
  1338. {
  1339. pulses--;
  1340. }
  1341. }
  1342. #endif
  1343. if (pulses > (uint64_t)state->targetPulses)
  1344. {
  1345. pulses = (uint64_t)state->targetPulses;
  1346. }
  1347. return pulses;
  1348. }
  1349. /* AB terminal and pause IRQs only freeze the two phase timers at a verified
  1350. * 00 boundary. GPIO handoff, counter release/rebase and event publication
  1351. * are deliberately deferred to PlsrHwTick so an equal-priority second AB
  1352. * boundary can be serviced before its next quarter-period transition. */
  1353. static void PlsrHwFinishDeferredAbWork(uint8_t axis)
  1354. {
  1355. PLSR_HW_AXIS_STATE *state;
  1356. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1357. {
  1358. return;
  1359. }
  1360. state = &PlsrHwAxes[axis];
  1361. if (state->abPauseGated != 0U)
  1362. {
  1363. uint64_t completedPulses =
  1364. (state->hardwareCounterActive != 0U)
  1365. ? PlsrHwCounterSnapshot(axis)
  1366. : (uint64_t)state->emittedPulses;
  1367. state->emittedPulses = (int64_t)completedPulses;
  1368. PlsrHwStopActiveOutput(axis, state->outputMode);
  1369. if (state->hardwareCounterActive != 0U)
  1370. {
  1371. PlsrHwCounterRebase(axis, completedPulses);
  1372. }
  1373. state->abQuarter = 0U;
  1374. state->abFrequencyPending = 0U;
  1375. state->abPauseGated = 0U;
  1376. state->abStopArmed =
  1377. (completedPulses
  1378. >= (uint64_t)(state->targetPulses - 1))
  1379. ? 1U
  1380. : 0U;
  1381. }
  1382. if (state->abCompletionDeferred != 0U)
  1383. {
  1384. state->emittedPulses = state->targetPulses;
  1385. PlsrHwStopActiveOutput(axis, state->outputMode);
  1386. PlsrHwCounterRelease(axis);
  1387. state->abQuarter = 0U;
  1388. state->abFrequencyPending = 0U;
  1389. state->abStopArmed = 0U;
  1390. state->abFastGated = 0U;
  1391. state->abCompletionDeferred = 0U;
  1392. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  1393. }
  1394. }
  1395. uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber)
  1396. {
  1397. /* 与资源层一致的合法输出点掩码(Q0~Q7、Q10~Q17、Q20)。 */
  1398. const uint32_t validOutputMask = 0x0013FCFFUL;
  1399. if (pointNumber >= PLSR_HW_OUTPUT_POINT_COUNT)
  1400. {
  1401. return 0U;
  1402. }
  1403. if ((validOutputMask & (1UL << pointNumber)) == 0UL)
  1404. {
  1405. return 0U;
  1406. }
  1407. #ifndef PLSR_HOST_TEST
  1408. if (PlsrHwOutputPins[pointNumber].port == NULL)
  1409. {
  1410. return 0U;
  1411. }
  1412. #endif
  1413. return 1U;
  1414. }
  1415. PLSR_RESULT PlsrHwInit(void)
  1416. {
  1417. uint8_t axis;
  1418. uint8_t counterIndex;
  1419. (void)memset(PlsrHwAxes, 0, sizeof(PlsrHwAxes));
  1420. PlsrHwDirectionBatchActive = 0U;
  1421. PlsrHwMaxOutputIsrCycles = 0UL;
  1422. PlsrHwMaxCounterIsrCycles = 0UL;
  1423. PlsrHwMaxControlIsrCycles = 0UL;
  1424. PlsrHwMaxAbGateCycles = 0UL;
  1425. #ifndef PLSR_HOST_TEST
  1426. PlsrHwAbGateMeasurePending = 0U;
  1427. #endif
  1428. PlsrHwTotalIsrCycles = 0UL;
  1429. PlsrHwIsrBusyStarted = 0UL;
  1430. PlsrHwIsrNesting = 0U;
  1431. #ifdef PLSR_HOST_TEST
  1432. PlsrHwTestLateAbFlagAxis = PLSR_HW_COUNTER_NONE;
  1433. PlsrHwTestAbFullGateCount = 0UL;
  1434. #endif
  1435. for (counterIndex = 0U;
  1436. counterIndex < PLSR_HW_COUNTER_COUNT;
  1437. counterIndex++)
  1438. {
  1439. PlsrHwCounterOwners[counterIndex] = PLSR_HW_COUNTER_NONE;
  1440. }
  1441. for (axis = 0U; axis < PLSR_HW_AXIS_COUNT; axis++)
  1442. {
  1443. PlsrHwAxes[axis].state = PLSR_HW_STATE_IDLE;
  1444. PlsrHwAxes[axis].directionPoint = PLSR_HW_DIR_POINT_NONE;
  1445. PlsrHwAxes[axis].counterIndex = PLSR_HW_COUNTER_NONE;
  1446. PlsrHwAxes[axis].configuredDirectionPoint =
  1447. PLSR_HW_DIR_POINT_NONE;
  1448. #ifdef PLSR_HOST_TEST
  1449. (void)memset(&PlsrHwTimers[axis], 0, sizeof(PlsrHwTimers[axis]));
  1450. #else
  1451. PlsrHwTimerSetCc1e(axis, 0UL);
  1452. PlsrHwTimerSetUie(axis, 0UL);
  1453. PlsrHwTimerSetCc1ie(axis, 0UL);
  1454. PlsrHwTimerSetCen(axis, 0UL);
  1455. #endif
  1456. }
  1457. #ifndef PLSR_HOST_TEST
  1458. {
  1459. GPIO_InitTypeDef gpio;
  1460. uint32_t tim6ClockHz;
  1461. uint16_t tim6Psc;
  1462. uint16_t tim6Arr;
  1463. CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
  1464. DWT->CYCCNT = 0UL;
  1465. DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
  1466. /* 1. 输出点 GPIO 时钟(DIR 点按需配置时使用)。 */
  1467. __HAL_RCC_GPIOF_CLK_ENABLE();
  1468. __HAL_RCC_GPIOI_CLK_ENABLE();
  1469. __HAL_RCC_GPIOE_CLK_ENABLE();
  1470. __HAL_RCC_GPIOG_CLK_ENABLE();
  1471. __HAL_RCC_GPIOH_CLK_ENABLE();
  1472. __HAL_RCC_GPIOB_CLK_ENABLE();
  1473. /* 2. 上电安全:输出点保持复位默认高阻(漏型输出 = 截止 = OFF)。
  1474. * 不驱动任何 Y 点,DIR 点仅在 PlsrHwSetDirLevel 时按需配置。 */
  1475. /* 3. 定时器时钟。 */
  1476. __HAL_RCC_TIM10_CLK_ENABLE();
  1477. __HAL_RCC_TIM11_CLK_ENABLE();
  1478. __HAL_RCC_TIM13_CLK_ENABLE();
  1479. __HAL_RCC_TIM14_CLK_ENABLE();
  1480. __HAL_RCC_TIM6_CLK_ENABLE();
  1481. __HAL_RCC_TIM9_CLK_ENABLE();
  1482. __HAL_RCC_TIM12_CLK_ENABLE();
  1483. /* Independent 10kHz control clock for S2 refreshCode=2. */
  1484. tim6ClockHz = HAL_RCC_GetPCLK1Freq();
  1485. if ((RCC->CFGR & RCC_CFGR_PPRE1) != RCC_CFGR_PPRE1_DIV1)
  1486. {
  1487. tim6ClockHz *= 2UL;
  1488. }
  1489. if (PlsrCalculateTimerDivider(tim6ClockHz,
  1490. 10000UL,
  1491. &tim6Psc,
  1492. &tim6Arr) != PLSR_RESULT_OK)
  1493. {
  1494. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  1495. }
  1496. TIM6->CR1 = 0UL;
  1497. TIM6->DIER = 0UL;
  1498. TIM6->PSC = tim6Psc;
  1499. TIM6->ARR = tim6Arr;
  1500. TIM6->EGR = TIM_EGR_UG;
  1501. TIM6->SR = 0UL;
  1502. TIM6->DIER = TIM_DIER_UIE;
  1503. HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 2U, 0U);
  1504. HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
  1505. TIM6->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN;
  1506. /* 4. 脉冲点切定时器复用(PF6/7=AF3、PF8/9=AF9)。
  1507. * 定时器通道尚未使能(CC1E=0),输出级断开,无毛刺。 */
  1508. gpio.Mode = GPIO_MODE_AF_PP;
  1509. gpio.Pull = GPIO_NOPULL;
  1510. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  1511. gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7;
  1512. gpio.Alternate = 3U;
  1513. HAL_GPIO_Init(GPIOF, &gpio);
  1514. gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9;
  1515. gpio.Alternate = 9U;
  1516. HAL_GPIO_Init(GPIOF, &gpio);
  1517. /* 5. 更新中断 NVIC:高速计数/尾脉冲层(P3b 统一规划优先级表)。 */
  1518. HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 1U, 0U);
  1519. HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
  1520. HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 1U, 0U);
  1521. HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
  1522. HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 1U, 0U);
  1523. HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
  1524. HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 1U, 0U);
  1525. HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
  1526. HAL_NVIC_SetPriority(TIM1_BRK_TIM9_IRQn, 1U, 0U);
  1527. HAL_NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn);
  1528. HAL_NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 1U, 0U);
  1529. HAL_NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
  1530. }
  1531. #endif
  1532. return PLSR_RESULT_OK;
  1533. }
  1534. PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params)
  1535. {
  1536. PLSR_HW_AXIS_STATE *state;
  1537. uint8_t directionChanged = 0U;
  1538. if ((axis >= PLSR_HW_AXIS_COUNT) || (params == NULL))
  1539. {
  1540. return PLSR_RESULT_INVALID_ARGUMENT;
  1541. }
  1542. if (params->targetPulses <= 0)
  1543. {
  1544. return PLSR_RESULT_INVALID_ARGUMENT;
  1545. }
  1546. if ((uint32_t)params->outputMode > (uint32_t)PLSR_OUTPUT_CW_CCW)
  1547. {
  1548. return PLSR_RESULT_INVALID_ARGUMENT;
  1549. }
  1550. if (((params->outputMode == PLSR_OUTPUT_AB)
  1551. || (params->outputMode == PLSR_OUTPUT_CW_CCW))
  1552. && (PlsrHwIsAbBaseAxis(axis) == 0U))
  1553. {
  1554. return PLSR_RESULT_INVALID_AXIS;
  1555. }
  1556. state = &PlsrHwAxes[axis];
  1557. if ((state->state == PLSR_HW_STATE_RUNNING)
  1558. || (state->abCompletionDeferred != 0U)
  1559. || (state->abPauseGated != 0U))
  1560. {
  1561. return PLSR_RESULT_BUSY;
  1562. }
  1563. /* A caller may replace a prepared-but-not-started segment. Return its
  1564. * counter lease first, otherwise the paired axis would fall back forever. */
  1565. if (state->hardwareCounterActive != 0U)
  1566. {
  1567. PlsrHwCounterRelease(axis);
  1568. }
  1569. /* 方向延时只在方向发生变化时生效(首次启动/换向/换方向点):
  1570. * 段间同向衔接不再等待 10ms,直接进入 PWM 待启动。 */
  1571. if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  1572. {
  1573. directionChanged =
  1574. (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  1575. || (state->directionPoint != params->directionPoint)
  1576. || (state->directionPositive != params->directionPositive)
  1577. || (state->directionNegativeLogic
  1578. != params->directionNegativeLogic);
  1579. }
  1580. state->outputMode = params->outputMode;
  1581. state->targetPulses = params->targetPulses;
  1582. state->emittedPulses = 0;
  1583. state->currentFrequencyHz = params->frequencyHz;
  1584. state->directionPoint =
  1585. (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  1586. ? params->directionPoint
  1587. : PLSR_HW_DIR_POINT_NONE;
  1588. state->directionDelayRemainingMs =
  1589. ((params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  1590. && (directionChanged != 0U))
  1591. ? params->directionDelayMs
  1592. : 0U;
  1593. state->abQuarter = 0U;
  1594. state->abFrequencyPending = 0U;
  1595. state->abStopArmed = 0U;
  1596. state->abFastGated = 0U;
  1597. state->abPausePending = 0U;
  1598. state->abPauseGated = 0U;
  1599. state->abCompletionDeferred = 0U;
  1600. if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  1601. {
  1602. PlsrHwSetDirLevel(axis,
  1603. params->directionPositive,
  1604. params->directionNegativeLogic);
  1605. }
  1606. else
  1607. {
  1608. state->directionPositive =
  1609. (params->directionPositive != 0U) ? 1U : 0U;
  1610. state->directionNegativeLogic = 0U;
  1611. }
  1612. if (params->outputMode == PLSR_OUTPUT_CW_CCW)
  1613. {
  1614. state->cwActiveAxis = (state->directionPositive != 0U)
  1615. ? axis
  1616. : PlsrHwGetPairedAxis(axis);
  1617. }
  1618. (void)PlsrHwCounterTryAcquire(axis, params->outputMode);
  1619. if (state->hardwareCounterActive != 0U)
  1620. {
  1621. PlsrHwCounterConfigure(axis);
  1622. state->hardwareCounterConfigured = 1U;
  1623. }
  1624. state->state = (state->directionDelayRemainingMs > 0U)
  1625. ? PLSR_HW_STATE_DIR_SETTLING
  1626. : PLSR_HW_STATE_PWM_PENDING;
  1627. return PLSR_RESULT_OK;
  1628. }
  1629. PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz)
  1630. {
  1631. PLSR_HW_AXIS_STATE *state;
  1632. if (axis >= PLSR_HW_AXIS_COUNT)
  1633. {
  1634. return PLSR_RESULT_INVALID_ARGUMENT;
  1635. }
  1636. state = &PlsrHwAxes[axis];
  1637. if ((state->outputMode == PLSR_OUTPUT_CW_CCW)
  1638. && (state->cwStopPending != 0U))
  1639. {
  1640. /* Preserve the final physical high width until its natural update
  1641. * boundary; no later profile write may move that boundary. */
  1642. return PLSR_RESULT_OK;
  1643. }
  1644. if ((state->state == PLSR_HW_STATE_RUNNING)
  1645. && (frequencyHz == state->currentFrequencyHz))
  1646. {
  1647. /* Cruise ticks commonly request the same frequency for every axis.
  1648. * Recomputing PSC/ARR performs two 64-bit divisions and rewrites the
  1649. * same preload registers without changing the waveform. */
  1650. return PLSR_RESULT_OK;
  1651. }
  1652. state->currentFrequencyHz = frequencyHz;
  1653. if (state->state == PLSR_HW_STATE_RUNNING)
  1654. {
  1655. if (frequencyHz > 0UL)
  1656. {
  1657. if (state->outputMode == PLSR_OUTPUT_AB)
  1658. {
  1659. if (PlsrHwQueueAbFrequency(axis, frequencyHz) == 0U)
  1660. {
  1661. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  1662. }
  1663. }
  1664. else
  1665. {
  1666. /* PULSE/DIR 仍由单定时器在自身 update 边界加载预装值。 */
  1667. PlsrHwConfigureActiveOutput(axis,
  1668. state->outputMode,
  1669. frequencyHz);
  1670. }
  1671. }
  1672. else
  1673. {
  1674. if (state->outputMode == PLSR_OUTPUT_AB)
  1675. {
  1676. #ifndef PLSR_HOST_TEST
  1677. uint32_t interruptState = __get_PRIMASK();
  1678. __disable_irq();
  1679. __DMB();
  1680. #endif
  1681. /* PAUSE is a controlled AB stop. Keep both timers running
  1682. * until the lag compare reaches the next real 00 boundary;
  1683. * forcing GPIO low here would discard and later re-emit an
  1684. * already-started cycle, adding one terminal edge. */
  1685. state->abFrequencyPending = 0U;
  1686. state->abPausePending = 1U;
  1687. PlsrHwTimerClearCc1if(state->abCountAxis);
  1688. PlsrHwTimerSetCc1ie(state->abCountAxis, 1UL);
  1689. #ifndef PLSR_HOST_TEST
  1690. __DMB();
  1691. if (interruptState == 0UL)
  1692. {
  1693. __enable_irq();
  1694. }
  1695. #endif
  1696. }
  1697. else
  1698. {
  1699. PlsrHwStopActiveOutput(axis, state->outputMode);
  1700. }
  1701. }
  1702. }
  1703. else if ((state->state == PLSR_HW_STATE_PWM_PENDING)
  1704. && (frequencyHz > 0UL))
  1705. {
  1706. PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz);
  1707. /* 必须先发布 RUNNING,避免启用 timer IRQ 后观察到 PWM_PENDING。 */
  1708. state->state = PLSR_HW_STATE_RUNNING;
  1709. PlsrHwBeginActiveOutput(axis, state->outputMode);
  1710. }
  1711. return PLSR_RESULT_OK;
  1712. }
  1713. PLSR_RESULT PlsrHwResumePulse(uint8_t axis)
  1714. {
  1715. PLSR_HW_AXIS_STATE *state;
  1716. if (axis >= PLSR_HW_AXIS_COUNT)
  1717. {
  1718. return PLSR_RESULT_INVALID_ARGUMENT;
  1719. }
  1720. state = &PlsrHwAxes[axis];
  1721. if ((state->state != PLSR_HW_STATE_RUNNING)
  1722. || (state->currentFrequencyHz != 0UL)
  1723. || (state->abPausePending != 0U)
  1724. || (state->abPauseGated != 0U)
  1725. || (PlsrHwGetEmittedPulses(axis) >= state->targetPulses))
  1726. {
  1727. return PLSR_RESULT_INVALID_STATE;
  1728. }
  1729. /* The pause boundary worker stopped the physical timers at 00 and kept
  1730. * the completed-cycle count. PWM_PENDING makes the next non-zero control
  1731. * tick use the clean-start path without resetting that count. */
  1732. state->state = PLSR_HW_STATE_PWM_PENDING;
  1733. return PLSR_RESULT_OK;
  1734. }
  1735. PLSR_RESULT PlsrHwStopPulse(uint8_t axis)
  1736. {
  1737. PLSR_HW_AXIS_STATE *state;
  1738. if (axis >= PLSR_HW_AXIS_COUNT)
  1739. {
  1740. return PLSR_RESULT_INVALID_ARGUMENT;
  1741. }
  1742. state = &PlsrHwAxes[axis];
  1743. if (state->state != PLSR_HW_STATE_IDLE)
  1744. {
  1745. if (state->hardwareCounterActive != 0U)
  1746. {
  1747. state->emittedPulses =
  1748. (int64_t)PlsrHwCounterSnapshot(axis);
  1749. }
  1750. PlsrHwStopActiveOutput(axis, state->outputMode);
  1751. PlsrHwCounterRelease(axis);
  1752. state->abQuarter = 0U;
  1753. state->abFrequencyPending = 0U;
  1754. state->abStopArmed = 0U;
  1755. state->abFastGated = 0U;
  1756. state->abPausePending = 0U;
  1757. state->abPauseGated = 0U;
  1758. state->abCompletionDeferred = 0U;
  1759. state->state = PLSR_HW_STATE_IDLE;
  1760. }
  1761. return PLSR_RESULT_OK;
  1762. }
  1763. uint8_t PlsrHwIsPulseActive(uint8_t axis)
  1764. {
  1765. if (axis >= PLSR_HW_AXIS_COUNT)
  1766. {
  1767. return 0U;
  1768. }
  1769. return (PlsrHwAxes[axis].state == PLSR_HW_STATE_RUNNING) ? 1U : 0U;
  1770. }
  1771. PLSR_HW_STATE PlsrHwGetState(uint8_t axis)
  1772. {
  1773. if (axis >= PLSR_HW_AXIS_COUNT)
  1774. {
  1775. return PLSR_HW_STATE_IDLE;
  1776. }
  1777. return PlsrHwAxes[axis].state;
  1778. }
  1779. uint32_t PlsrHwGetTimerClockHz(uint8_t axis)
  1780. {
  1781. if (axis >= PLSR_HW_AXIS_COUNT)
  1782. {
  1783. return 0UL;
  1784. }
  1785. return PlsrHwAxisMap[axis].timerClockHz;
  1786. }
  1787. uint32_t PlsrHwGetCurrentFrequencyHz(uint8_t axis)
  1788. {
  1789. if ((axis >= PLSR_HW_AXIS_COUNT)
  1790. || (PlsrHwAxes[axis].state != PLSR_HW_STATE_RUNNING))
  1791. {
  1792. return 0UL;
  1793. }
  1794. return PlsrHwAxes[axis].currentFrequencyHz;
  1795. }
  1796. /* 硬件已发出的脉冲数(profile 虚拟计数校准用,中断内递增)。 */
  1797. int64_t PlsrHwGetEmittedPulses(uint8_t axis)
  1798. {
  1799. int64_t emittedPulses;
  1800. if (axis >= PLSR_HW_AXIS_COUNT)
  1801. {
  1802. return 0;
  1803. }
  1804. #ifdef PLSR_HOST_TEST
  1805. emittedPulses = (PlsrHwAxes[axis].hardwareCounterActive != 0U)
  1806. ? (int64_t)PlsrHwCounterSnapshot(axis)
  1807. : PlsrHwAxes[axis].emittedPulses;
  1808. #else
  1809. {
  1810. uint32_t interruptState = __get_PRIMASK();
  1811. __disable_irq();
  1812. __DMB();
  1813. emittedPulses = (PlsrHwAxes[axis].hardwareCounterActive != 0U)
  1814. ? (int64_t)PlsrHwCounterSnapshot(axis)
  1815. : PlsrHwAxes[axis].emittedPulses;
  1816. __DMB();
  1817. if (interruptState == 0UL)
  1818. {
  1819. __enable_irq();
  1820. }
  1821. }
  1822. #endif
  1823. return emittedPulses;
  1824. }
  1825. uint8_t PlsrHwIsAbStartupPriming(uint8_t axis)
  1826. {
  1827. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1828. {
  1829. return 0U;
  1830. }
  1831. return PlsrHwAxes[axis].abStartupPriming;
  1832. }
  1833. uint8_t PlsrHwUsesHardwareCounter(uint8_t axis)
  1834. {
  1835. if (axis >= PLSR_HW_AXIS_COUNT)
  1836. {
  1837. return 0U;
  1838. }
  1839. return PlsrHwAxes[axis].hardwareCounterActive;
  1840. }
  1841. uint32_t PlsrHwGetMaxOutputIsrCycles(void)
  1842. {
  1843. return PlsrHwMaxOutputIsrCycles;
  1844. }
  1845. uint32_t PlsrHwGetMaxCounterIsrCycles(void)
  1846. {
  1847. return PlsrHwMaxCounterIsrCycles;
  1848. }
  1849. uint32_t PlsrHwGetMaxControlIsrCycles(void)
  1850. {
  1851. return PlsrHwMaxControlIsrCycles;
  1852. }
  1853. uint32_t PlsrHwGetMaxAbGateCycles(void)
  1854. {
  1855. return PlsrHwMaxAbGateCycles;
  1856. }
  1857. void PlsrHwGetCycleSnapshot(uint32_t *cycleCount,
  1858. uint64_t *plsrIsrCycles)
  1859. {
  1860. #ifdef PLSR_HOST_TEST
  1861. if (cycleCount != NULL)
  1862. {
  1863. *cycleCount = 0UL;
  1864. }
  1865. if (plsrIsrCycles != NULL)
  1866. {
  1867. *plsrIsrCycles = 0UL;
  1868. }
  1869. #else
  1870. uint32_t interruptState = __get_PRIMASK();
  1871. __disable_irq();
  1872. __DMB();
  1873. if (cycleCount != NULL)
  1874. {
  1875. *cycleCount = DWT->CYCCNT;
  1876. }
  1877. if (plsrIsrCycles != NULL)
  1878. {
  1879. *plsrIsrCycles = PlsrHwTotalIsrCycles;
  1880. }
  1881. __DMB();
  1882. if (interruptState == 0UL)
  1883. {
  1884. __enable_irq();
  1885. }
  1886. #endif
  1887. }
  1888. void PlsrHwTick(uint8_t axis)
  1889. {
  1890. PLSR_HW_AXIS_STATE *state;
  1891. if (axis >= PLSR_HW_AXIS_COUNT)
  1892. {
  1893. return;
  1894. }
  1895. state = &PlsrHwAxes[axis];
  1896. if ((state->abPauseGated != 0U)
  1897. || (state->abCompletionDeferred != 0U))
  1898. {
  1899. PlsrHwFinishDeferredAbWork(axis);
  1900. }
  1901. /* 调试:每 tick 记录定时器实况(CNT 演化定位第一周期压缩)。 */
  1902. PlsrHwDbgCapture(axis, 3U);
  1903. switch (state->state)
  1904. {
  1905. case PLSR_HW_STATE_DIR_SETTLING:
  1906. if (state->directionDelayRemainingMs > 0U)
  1907. {
  1908. state->directionDelayRemainingMs--;
  1909. }
  1910. if (state->directionDelayRemainingMs == 0U)
  1911. {
  1912. state->state = PLSR_HW_STATE_PWM_PENDING;
  1913. }
  1914. break;
  1915. case PLSR_HW_STATE_PWM_PENDING:
  1916. if (state->currentFrequencyHz > 0UL)
  1917. {
  1918. PlsrHwConfigureActiveOutput(axis,
  1919. state->outputMode,
  1920. state->currentFrequencyHz);
  1921. state->state = PLSR_HW_STATE_RUNNING;
  1922. PlsrHwBeginActiveOutput(axis, state->outputMode);
  1923. }
  1924. break;
  1925. default:
  1926. break;
  1927. }
  1928. }
  1929. static void PlsrHwFastGateAbPair(uint8_t axis)
  1930. {
  1931. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  1932. PlsrHwTimerSetCen(axis, 0UL);
  1933. PlsrHwTimerSetCen(pairAxis, 0UL);
  1934. PlsrHwCounterSuspend(axis);
  1935. }
  1936. static void PlsrHwDeferAbCompletion(uint8_t axis)
  1937. {
  1938. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1939. state->emittedPulses = state->targetPulses;
  1940. state->abQuarter = 0U;
  1941. state->abFrequencyPending = 0U;
  1942. state->abStopArmed = 0U;
  1943. state->abPausePending = 0U;
  1944. state->abPauseGated = 0U;
  1945. state->abCompletionDeferred = 1U;
  1946. state->state = PLSR_HW_STATE_DONE;
  1947. }
  1948. static void PlsrHwRecordFullAbGateTime(void)
  1949. {
  1950. #ifndef PLSR_HOST_TEST
  1951. /* The wrapper records the endpoint after the common ISR accounting, just
  1952. * before exception return. Measuring here would omit that equal-priority
  1953. * blocking tail and could understate the 2.5us near-simultaneous window. */
  1954. PlsrHwAbGateMeasurePending = 1U;
  1955. #else
  1956. PlsrHwTestAbFullGateCount++;
  1957. #endif
  1958. }
  1959. #ifndef PLSR_HOST_TEST
  1960. static void PlsrHwFinishAbGateMeasurement(uint32_t started)
  1961. {
  1962. if (PlsrHwAbGateMeasurePending != 0U)
  1963. {
  1964. uint32_t finished;
  1965. uint32_t elapsed;
  1966. PlsrHwAbGateMeasurePending = 0U;
  1967. finished = DWT->CYCCNT;
  1968. elapsed = finished - started;
  1969. if (elapsed > PlsrHwMaxAbGateCycles)
  1970. {
  1971. PlsrHwMaxAbGateCycles = elapsed;
  1972. }
  1973. }
  1974. }
  1975. #endif
  1976. static uint8_t PlsrHwGateArmedAbOutputs(void)
  1977. {
  1978. static const uint8_t baseAxes[2] = {0U, 2U};
  1979. uint8_t gated = 0U;
  1980. uint8_t index;
  1981. /* Both AB pairs use equal-priority IRQs. Scan and gate every pair before
  1982. * doing any event publication so two simultaneous 100kHz completions
  1983. * cannot make the second pair run an extra quarter while its IRQ waits. */
  1984. for (index = 0U; index < 2U; index++)
  1985. {
  1986. uint8_t axis = baseAxes[index];
  1987. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  1988. if ((state->state == PLSR_HW_STATE_RUNNING)
  1989. && (state->outputMode == PLSR_OUTPUT_AB)
  1990. && (state->abStopArmed != 0U)
  1991. && (state->abFastGated == 0U)
  1992. && (PlsrHwTimerHasCc1if(state->abCountAxis) != 0U)
  1993. && (PlsrHwCounterRawSnapshot(axis)
  1994. >= (uint64_t)state->targetPulses))
  1995. {
  1996. /* This entry is the verified 00 boundary. Stop both counters
  1997. * first, but keep CC1E driving the frozen 00 until the slower path
  1998. * hands the pins to GPIO. */
  1999. PlsrHwFastGateAbPair(axis);
  2000. state->abFastGated = 1U;
  2001. gated = 1U;
  2002. }
  2003. }
  2004. return gated;
  2005. }
  2006. /* 输出定时器中断入口:PULSE/DIR 在 update 计数;AB 在落后相
  2007. * CC1 下降沿(四状态回到 00)计一个完整正交周期。 */
  2008. void PlsrHwOnTimerUpdate(uint8_t axis)
  2009. {
  2010. PLSR_HW_AXIS_STATE *state;
  2011. uint8_t ownerAxis;
  2012. uint8_t hasCc1;
  2013. uint8_t abGated;
  2014. if (axis >= PLSR_HW_AXIS_COUNT)
  2015. {
  2016. return;
  2017. }
  2018. abGated = PlsrHwGateArmedAbOutputs();
  2019. #ifdef PLSR_HOST_TEST
  2020. /* Model the second equal-priority lag flag arriving after the first scan
  2021. * but before any completion bookkeeping. */
  2022. if (PlsrHwTestLateAbFlagAxis < PLSR_HW_AXIS_COUNT)
  2023. {
  2024. PlsrHwTimers[PlsrHwTestLateAbFlagAxis].sr |=
  2025. PLSR_HW_TIMER_CC1_BIT;
  2026. PlsrHwTestLateAbFlagAxis = PLSR_HW_COUNTER_NONE;
  2027. abGated = 1U;
  2028. }
  2029. #endif
  2030. /* Completion cleanup is deferred. This second scan closes the injected
  2031. * arrival window; a still-later flag gets CPU back before its next jump. */
  2032. if (abGated != 0U)
  2033. {
  2034. (void)PlsrHwGateArmedAbOutputs();
  2035. }
  2036. /* CC1IF 无论当前状态如何都必须先清除;否则启动窗口中的杂散
  2037. * compare 标志会让共享 IRQ 持续重入,主线程无法完成 CEN 配置。 */
  2038. hasCc1 = PlsrHwTimerHasCc1if(axis);
  2039. if (hasCc1 != 0U)
  2040. {
  2041. PlsrHwTimerClearCc1if(axis);
  2042. }
  2043. ownerAxis = (uint8_t)(axis & 0xFEU);
  2044. state = &PlsrHwAxes[ownerAxis];
  2045. if ((state->state == PLSR_HW_STATE_RUNNING)
  2046. && (state->outputMode == PLSR_OUTPUT_AB))
  2047. {
  2048. if (PlsrHwTimerHasUif(axis) != 0U)
  2049. {
  2050. PlsrHwTimerClearUif(axis);
  2051. }
  2052. if ((hasCc1 == 0U) || (axis != state->abCountAxis))
  2053. {
  2054. return;
  2055. }
  2056. if (state->abFastGated != 0U)
  2057. {
  2058. PlsrHwDeferAbCompletion(ownerAxis);
  2059. PlsrHwRecordFullAbGateTime();
  2060. return;
  2061. }
  2062. if (state->abPausePending != 0U)
  2063. {
  2064. uint8_t targetReached;
  2065. targetReached =
  2066. (state->hardwareCounterActive != 0U)
  2067. ? ((PlsrHwCounterRawSnapshot(ownerAxis)
  2068. >= (uint64_t)state->targetPulses)
  2069. ? 1U
  2070. : 0U)
  2071. : (((uint64_t)state->emittedPulses + 1UL
  2072. >= (uint64_t)state->targetPulses)
  2073. ? 1U
  2074. : 0U);
  2075. PlsrHwFastGateAbPair(ownerAxis);
  2076. if (targetReached != 0U)
  2077. {
  2078. PlsrHwDeferAbCompletion(ownerAxis);
  2079. }
  2080. else
  2081. {
  2082. if (state->hardwareCounterActive == 0U)
  2083. {
  2084. state->emittedPulses++;
  2085. }
  2086. state->abQuarter = 0U;
  2087. state->abFrequencyPending = 0U;
  2088. state->abPausePending = 0U;
  2089. state->abPauseGated = 1U;
  2090. }
  2091. PlsrHwRecordFullAbGateTime();
  2092. return;
  2093. }
  2094. if (state->hardwareCounterActive != 0U)
  2095. {
  2096. /* One-shot 00 interrupt for a queued frequency change or for the
  2097. * target guard. Counting itself remains entirely in TIM9/12. */
  2098. if (state->abFrequencyPending != 0U)
  2099. {
  2100. uint16_t basePsc = state->abPendingBasePsc;
  2101. uint16_t pairPsc = state->abPendingPairPsc;
  2102. uint16_t arr = state->abPendingArr;
  2103. uint8_t pairAxis = PlsrHwGetPairedAxis(ownerAxis);
  2104. /* This CC1 is 00. Gate first; divider calculation and timer
  2105. * reloading are intentionally outside the 2.5us edge window. */
  2106. PlsrHwTimerSetCen(ownerAxis, 0UL);
  2107. PlsrHwTimerSetCen(pairAxis, 0UL);
  2108. PlsrHwCounterSuspend(ownerAxis);
  2109. state->abFrequencyPending = 0U;
  2110. PlsrHwLoadAbPwm(ownerAxis, basePsc, pairPsc, arr);
  2111. PlsrHwBeginAbOutput(ownerAxis, 4U);
  2112. }
  2113. else if (state->abStopArmed == 0U)
  2114. {
  2115. PlsrHwTimerSetCc1ie(state->abCountAxis, 0UL);
  2116. }
  2117. return;
  2118. }
  2119. state->emittedPulses++;
  2120. if (state->emittedPulses >= state->targetPulses)
  2121. {
  2122. PlsrHwFastGateAbPair(ownerAxis);
  2123. PlsrHwDeferAbCompletion(ownerAxis);
  2124. PlsrHwRecordFullAbGateTime();
  2125. }
  2126. else if (state->abFrequencyPending != 0U)
  2127. {
  2128. uint16_t basePsc = state->abPendingBasePsc;
  2129. uint16_t pairPsc = state->abPendingPairPsc;
  2130. uint16_t arr = state->abPendingArr;
  2131. state->abFrequencyPending = 0U;
  2132. PlsrHwLoadAbPwm(ownerAxis, basePsc, pairPsc, arr);
  2133. /* 落后相刚下降,AB=00;两路从同一个完整周期边界重定相。 */
  2134. PlsrHwBeginAbOutput(ownerAxis, 4U);
  2135. }
  2136. return;
  2137. }
  2138. if ((state->state == PLSR_HW_STATE_RUNNING)
  2139. && (state->outputMode == PLSR_OUTPUT_CW_CCW))
  2140. {
  2141. uint8_t hasUif = PlsrHwTimerHasUif(axis);
  2142. if (hasUif != 0U)
  2143. {
  2144. PlsrHwTimerClearUif(axis);
  2145. }
  2146. if (axis != state->cwActiveAxis)
  2147. {
  2148. return;
  2149. }
  2150. if (hasCc1 != 0U)
  2151. {
  2152. state->emittedPulses++;
  2153. if (state->emittedPulses >= state->targetPulses)
  2154. {
  2155. /* The board output is inverted relative to OC1REF: CC1 is
  2156. * the physical rising edge. Arm the tail here, then stop on
  2157. * the following update (physical falling edge). */
  2158. state->cwStopPending = 1U;
  2159. PlsrHwTimerSetCc1ie(axis, 0UL);
  2160. PlsrHwTimerClearUif(axis);
  2161. PlsrHwTimerSetUie(axis, 1UL);
  2162. }
  2163. return;
  2164. }
  2165. if ((hasUif != 0U) && (state->cwStopPending != 0U))
  2166. {
  2167. PlsrHwStopActiveOutput(ownerAxis, state->outputMode);
  2168. state->state = PLSR_HW_STATE_DONE;
  2169. (void)PlsrPostEvent(ownerAxis, PLSR_EVENT_SEGMENT_COMPLETE);
  2170. }
  2171. return;
  2172. }
  2173. state = &PlsrHwAxes[axis];
  2174. if ((hasCc1 != 0U)
  2175. && !((state->state == PLSR_HW_STATE_RUNNING)
  2176. && (state->outputMode == PLSR_OUTPUT_PULSE_DIR)))
  2177. {
  2178. /* 非运行态或其他模式的 CC1 仅作为杂散标志消费。PULSE/DIR
  2179. * 的 CC1IE 关闭,但半周期比较仍会置 CC1IF;更新 IRQ 必须
  2180. * 在同一次入口继续消费 UIF,不能留下 UIF 再触发第二次 ISR。 */
  2181. return;
  2182. }
  2183. if (PlsrHwTimerHasUif(axis) == 0U)
  2184. {
  2185. return;
  2186. }
  2187. PlsrHwTimerClearUif(axis);
  2188. if (state->state != PLSR_HW_STATE_RUNNING)
  2189. {
  2190. return;
  2191. }
  2192. if (state->outputMode != PLSR_OUTPUT_PULSE_DIR)
  2193. {
  2194. return;
  2195. }
  2196. #ifndef PLSR_HOST_TEST
  2197. if (state->hardwareCounterActive != 0U)
  2198. {
  2199. /* A hardware-counted axis has UIE disabled. Ignore any stale update
  2200. * flag rather than counting the same OC event in software as well. */
  2201. return;
  2202. }
  2203. #endif
  2204. state->emittedPulses++;
  2205. if (state->emittedPulses >= state->targetPulses)
  2206. {
  2207. /* 更新时刻 = 周期结束:关通道即完整下降沿后停止,无额外脉冲。 */
  2208. PlsrHwStopActiveOutput(axis, state->outputMode);
  2209. state->state = PLSR_HW_STATE_DONE;
  2210. PlsrHwCounterRelease(axis);
  2211. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  2212. }
  2213. }
  2214. #ifdef PLSR_HOST_TEST
  2215. uint32_t PlsrHwTestGetArr(uint8_t axis)
  2216. {
  2217. return PlsrHwTimers[axis].arr;
  2218. }
  2219. uint32_t PlsrHwTestGetCcr(uint8_t axis)
  2220. {
  2221. return PlsrHwTimers[axis].ccr1;
  2222. }
  2223. uint32_t PlsrHwTestGetCnt(uint8_t axis)
  2224. {
  2225. return PlsrHwTimers[axis].cnt;
  2226. }
  2227. uint32_t PlsrHwTestGetCcmr1(uint8_t axis)
  2228. {
  2229. return PlsrHwTimers[axis].ccmr1;
  2230. }
  2231. uint32_t PlsrHwTestGetCr1(uint8_t axis)
  2232. {
  2233. return PlsrHwTimers[axis].cr1;
  2234. }
  2235. uint32_t PlsrHwTestGetPsc(uint8_t axis)
  2236. {
  2237. return PlsrHwTimers[axis].psc;
  2238. }
  2239. uint8_t PlsrHwTestGetPwmEnabled(uint8_t axis)
  2240. {
  2241. return ((PlsrHwTimers[axis].ccer & PLSR_HW_TIMER_CHANNEL1_BIT) != 0UL)
  2242. ? 1U
  2243. : 0U;
  2244. }
  2245. uint8_t PlsrHwTestGetDirLevel(uint8_t axis)
  2246. {
  2247. return PlsrHwTimers[axis].dirLevel;
  2248. }
  2249. uint8_t PlsrHwTestGetAbPhaseA(uint8_t axis)
  2250. {
  2251. const PLSR_HW_AXIS_STATE *state;
  2252. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  2253. {
  2254. return 0U;
  2255. }
  2256. state = &PlsrHwAxes[axis];
  2257. if (state->directionPositive != 0U)
  2258. {
  2259. return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
  2260. ? 1U
  2261. : 0U;
  2262. }
  2263. return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
  2264. ? 1U
  2265. : 0U;
  2266. }
  2267. uint8_t PlsrHwTestGetAbPhaseB(uint8_t axis)
  2268. {
  2269. const PLSR_HW_AXIS_STATE *state;
  2270. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  2271. {
  2272. return 0U;
  2273. }
  2274. state = &PlsrHwAxes[axis];
  2275. if (state->directionPositive != 0U)
  2276. {
  2277. return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
  2278. ? 1U
  2279. : 0U;
  2280. }
  2281. return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
  2282. ? 1U
  2283. : 0U;
  2284. }
  2285. uint8_t PlsrHwTestGetAbQuarter(uint8_t axis)
  2286. {
  2287. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  2288. {
  2289. return 0U;
  2290. }
  2291. return PlsrHwAxes[axis].abQuarter;
  2292. }
  2293. uint32_t PlsrHwTestGetAbFullGateCount(void)
  2294. {
  2295. return PlsrHwTestAbFullGateCount;
  2296. }
  2297. void PlsrHwTestAdvanceAbQuarter(uint8_t axis)
  2298. {
  2299. PLSR_HW_AXIS_STATE *state;
  2300. uint8_t countAxis;
  2301. uint8_t leadAxis;
  2302. uint8_t sourceQuarter;
  2303. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  2304. {
  2305. return;
  2306. }
  2307. state = &PlsrHwAxes[axis];
  2308. if ((state->state != PLSR_HW_STATE_RUNNING)
  2309. || (state->outputMode != PLSR_OUTPUT_AB))
  2310. {
  2311. return;
  2312. }
  2313. countAxis = state->abCountAxis;
  2314. leadAxis = (state->directionPositive != 0U)
  2315. ? axis
  2316. : PlsrHwGetPairedAxis(axis);
  2317. sourceQuarter = (state->counterSourceAxis == leadAxis) ? 1U : 2U;
  2318. state->abQuarter = (uint8_t)((state->abQuarter + 1U)
  2319. % PLSR_HW_AB_QUARTER_COUNT);
  2320. if ((state->hardwareCounterActive != 0U)
  2321. && (state->abQuarter == sourceQuarter))
  2322. {
  2323. state->counterBlockPulses++;
  2324. if ((state->abStopArmed == 0U)
  2325. && (state->counterBlockPulses
  2326. >= (uint64_t)(state->targetPulses - 1)))
  2327. {
  2328. /* Host model of the target-1 TIM9/TIM12 compare. */
  2329. state->abStopArmed = 1U;
  2330. PlsrHwTimerClearCc1if(countAxis);
  2331. PlsrHwTimerSetCc1ie(countAxis, 1UL);
  2332. }
  2333. }
  2334. if (state->abQuarter == 0U)
  2335. {
  2336. /* 模拟目标板落后相 CC1 下降沿中断,复用生产计数路径。 */
  2337. /* Model the lag CC IRQ only while it is enabled. This detects a
  2338. * regression that accidentally restores one interrupt per AB cycle. */
  2339. if ((PlsrHwTimers[countAxis].dier & PLSR_HW_TIMER_CC1_BIT) != 0UL)
  2340. {
  2341. PlsrHwTimers[countAxis].sr |= PLSR_HW_TIMER_CC1_BIT;
  2342. PlsrHwOnTimerUpdate(countAxis);
  2343. }
  2344. }
  2345. }
  2346. void PlsrHwTestSignalDualAbFinalBoundary(uint8_t firstAxis)
  2347. {
  2348. static const uint8_t baseAxes[2] = {0U, 2U};
  2349. uint8_t index;
  2350. uint8_t firstCountAxis;
  2351. if ((firstAxis != 0U) && (firstAxis != 2U))
  2352. {
  2353. return;
  2354. }
  2355. for (index = 0U; index < 2U; index++)
  2356. {
  2357. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[baseAxes[index]];
  2358. if ((state->state != PLSR_HW_STATE_RUNNING)
  2359. || (state->outputMode != PLSR_OUTPUT_AB)
  2360. || (state->hardwareCounterActive == 0U))
  2361. {
  2362. return;
  2363. }
  2364. }
  2365. for (index = 0U; index < 2U; index++)
  2366. {
  2367. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[baseAxes[index]];
  2368. state->counterBlockPulses = (uint64_t)state->targetPulses;
  2369. state->abQuarter = 0U;
  2370. state->abStopArmed = 1U;
  2371. PlsrHwTimerSetCc1ie(state->abCountAxis, 1UL);
  2372. PlsrHwTimers[state->abCountAxis].sr |= PLSR_HW_TIMER_CC1_BIT;
  2373. }
  2374. firstCountAxis = PlsrHwAxes[firstAxis].abCountAxis;
  2375. PlsrHwOnTimerUpdate(firstCountAxis);
  2376. }
  2377. void PlsrHwTestSignalDualAbStaggeredFinalBoundary(uint8_t firstAxis)
  2378. {
  2379. static const uint8_t baseAxes[2] = {0U, 2U};
  2380. uint8_t firstCountAxis;
  2381. uint8_t secondAxis;
  2382. uint8_t secondCountAxis;
  2383. uint8_t index;
  2384. if ((firstAxis != 0U) && (firstAxis != 2U))
  2385. {
  2386. return;
  2387. }
  2388. secondAxis = (firstAxis == 0U) ? 2U : 0U;
  2389. for (index = 0U; index < 2U; index++)
  2390. {
  2391. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[baseAxes[index]];
  2392. if ((state->state != PLSR_HW_STATE_RUNNING)
  2393. || (state->outputMode != PLSR_OUTPUT_AB)
  2394. || (state->hardwareCounterActive == 0U))
  2395. {
  2396. return;
  2397. }
  2398. state->counterBlockPulses = (uint64_t)state->targetPulses;
  2399. state->abQuarter = 0U;
  2400. state->abStopArmed = 1U;
  2401. PlsrHwTimerSetCc1ie(state->abCountAxis, 1UL);
  2402. }
  2403. firstCountAxis = PlsrHwAxes[firstAxis].abCountAxis;
  2404. secondCountAxis = PlsrHwAxes[secondAxis].abCountAxis;
  2405. PlsrHwTimers[firstCountAxis].sr |= PLSR_HW_TIMER_CC1_BIT;
  2406. PlsrHwTestLateAbFlagAxis = secondCountAxis;
  2407. PlsrHwOnTimerUpdate(firstCountAxis);
  2408. }
  2409. void PlsrHwTestTriggerUpdate(uint8_t axis)
  2410. {
  2411. if (axis < PLSR_HW_AXIS_COUNT)
  2412. {
  2413. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_UPDATE_BIT;
  2414. }
  2415. PlsrHwOnTimerUpdate(axis);
  2416. }
  2417. void PlsrHwTestTriggerUpdateAndCompare(uint8_t axis)
  2418. {
  2419. if (axis < PLSR_HW_AXIS_COUNT)
  2420. {
  2421. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_UPDATE_BIT
  2422. | PLSR_HW_TIMER_CC1_BIT;
  2423. }
  2424. PlsrHwOnTimerUpdate(axis);
  2425. }
  2426. void PlsrHwTestTriggerCompare(uint8_t axis)
  2427. {
  2428. if (axis < PLSR_HW_AXIS_COUNT)
  2429. {
  2430. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_CC1_BIT;
  2431. }
  2432. PlsrHwOnTimerUpdate(axis);
  2433. }
  2434. #endif
  2435. #ifndef PLSR_HOST_TEST
  2436. static void PlsrHwOnCounterInterrupt(uint8_t counterIndex)
  2437. {
  2438. TIM_TypeDef *counter;
  2439. PLSR_HW_AXIS_STATE *state;
  2440. uint32_t flags;
  2441. uint64_t pulses;
  2442. uint8_t axis;
  2443. if (counterIndex >= PLSR_HW_COUNTER_COUNT)
  2444. {
  2445. return;
  2446. }
  2447. counter = PlsrHwCounters[counterIndex];
  2448. flags = counter->SR & (TIM_SR_UIF | TIM_SR_CC1IF);
  2449. counter->SR = ~(TIM_SR_UIF | TIM_SR_CC1IF);
  2450. axis = PlsrHwCounterOwners[counterIndex];
  2451. if ((flags == 0UL) || (axis >= PLSR_HW_AXIS_COUNT))
  2452. {
  2453. return;
  2454. }
  2455. state = &PlsrHwAxes[axis];
  2456. if ((state->hardwareCounterActive == 0U)
  2457. || (state->counterIndex != counterIndex)
  2458. || (state->state != PLSR_HW_STATE_RUNNING))
  2459. {
  2460. return;
  2461. }
  2462. if ((flags & TIM_SR_UIF) != 0UL)
  2463. {
  2464. state->counterBlockPulses += PLSR_HW_COUNTER_BLOCK_PULSES;
  2465. }
  2466. pulses = state->counterBlockPulses + (uint16_t)counter->CNT;
  2467. if (state->outputMode == PLSR_OUTPUT_AB)
  2468. {
  2469. uint64_t guard = (uint64_t)state->targetPulses - 1UL;
  2470. if (((flags & TIM_SR_CC1IF) != 0UL) && (pulses >= guard))
  2471. {
  2472. /* Wake the lag-CC1 one cycle early. It remains enabled until a
  2473. * 00 boundary observes raw>=target and fast-gates both phases. */
  2474. state->abStopArmed = 1U;
  2475. PlsrHwTimerClearCc1if(state->abCountAxis);
  2476. PlsrHwTimerSetCc1ie(state->abCountAxis, 1UL);
  2477. }
  2478. return;
  2479. }
  2480. if (((flags & TIM_SR_CC1IF) != 0UL)
  2481. && (pulses >= (uint64_t)state->targetPulses))
  2482. {
  2483. /* TIMx_OC rises at the PWM update boundary. On this board that is
  2484. * the physical falling edge, so the target pulse is already complete
  2485. * and both the counter and PWM may be stopped without truncation. */
  2486. state->emittedPulses = state->targetPulses;
  2487. PlsrHwStopActiveOutput(axis, state->outputMode);
  2488. state->state = PLSR_HW_STATE_DONE;
  2489. PlsrHwCounterRelease(axis);
  2490. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  2491. }
  2492. }
  2493. void TIM1_UP_TIM10_IRQHandler(void)
  2494. {
  2495. uint32_t started = PlsrHwCycleBegin();
  2496. PlsrHwOnTimerUpdate(0U);
  2497. PlsrHwRecordMaxCycles(&PlsrHwMaxOutputIsrCycles, started);
  2498. PlsrHwFinishAbGateMeasurement(started);
  2499. }
  2500. void TIM8_UP_TIM13_IRQHandler(void)
  2501. {
  2502. uint32_t started = PlsrHwCycleBegin();
  2503. PlsrHwOnTimerUpdate(1U);
  2504. PlsrHwRecordMaxCycles(&PlsrHwMaxOutputIsrCycles, started);
  2505. PlsrHwFinishAbGateMeasurement(started);
  2506. }
  2507. void TIM1_TRG_COM_TIM11_IRQHandler(void)
  2508. {
  2509. uint32_t started = PlsrHwCycleBegin();
  2510. PlsrHwOnTimerUpdate(2U);
  2511. PlsrHwRecordMaxCycles(&PlsrHwMaxOutputIsrCycles, started);
  2512. PlsrHwFinishAbGateMeasurement(started);
  2513. }
  2514. void TIM8_TRG_COM_TIM14_IRQHandler(void)
  2515. {
  2516. uint32_t started = PlsrHwCycleBegin();
  2517. PlsrHwOnTimerUpdate(3U);
  2518. PlsrHwRecordMaxCycles(&PlsrHwMaxOutputIsrCycles, started);
  2519. PlsrHwFinishAbGateMeasurement(started);
  2520. }
  2521. void TIM1_BRK_TIM9_IRQHandler(void)
  2522. {
  2523. uint32_t started = PlsrHwCycleBegin();
  2524. PlsrHwOnCounterInterrupt(0U);
  2525. PlsrHwRecordMaxCycles(&PlsrHwMaxCounterIsrCycles, started);
  2526. }
  2527. void TIM8_BRK_TIM12_IRQHandler(void)
  2528. {
  2529. uint32_t started = PlsrHwCycleBegin();
  2530. PlsrHwOnCounterInterrupt(1U);
  2531. PlsrHwRecordMaxCycles(&PlsrHwMaxCounterIsrCycles, started);
  2532. }
  2533. void TIM6_DAC_IRQHandler(void)
  2534. {
  2535. uint32_t started = PlsrHwCycleBegin();
  2536. if ((TIM6->SR & TIM_SR_UIF) != 0UL)
  2537. {
  2538. TIM6->SR &= ~TIM_SR_UIF;
  2539. PlsrControlTick100us();
  2540. }
  2541. PlsrHwRecordMaxCycles(&PlsrHwMaxControlIsrCycles, started);
  2542. }
  2543. #endif