Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

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