Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

1725 righe
48 KiB

  1. #include "plsr_hal_f407.h"
  2. #include "plsr_address_map.h"
  3. #include "plsr_core.h"
  4. #include "plsr_job.h"
  5. #include <string.h>
  6. #ifndef PLSR_HOST_TEST
  7. #include "stm32f4xx.h"
  8. #include "stm32f4xx_hal.h"
  9. #endif
  10. #define PLSR_HW_TIMER_CHANNEL1_BIT (0x0001U)
  11. #define PLSR_HW_TIMER_UPDATE_BIT (0x0001U)
  12. #define PLSR_HW_TIMER_CC1_BIT (0x0002U)
  13. #define PLSR_HW_OUTPUT_POINT_COUNT (21U)
  14. #define PLSR_HW_DBG_SNAPSHOT_COUNT (160U)
  15. #define PLSR_HW_AB_QUARTER_COUNT (4U)
  16. typedef struct
  17. {
  18. uint32_t timerClockHz;
  19. uint8_t directionPoint; /* 0xFF = 无 */
  20. #ifndef PLSR_HOST_TEST
  21. TIM_TypeDef *timer;
  22. GPIO_TypeDef *gpioPort;
  23. uint16_t gpioPin;
  24. uint8_t afMode;
  25. IRQn_Type irq;
  26. #endif
  27. } PLSR_HW_AXIS_MAP;
  28. #ifndef PLSR_HOST_TEST
  29. /* 输出点(Y 点号)→ GPIO 引脚:XDM-60T4-E 原理图。
  30. * 点号 8/9/18/19 不存在(资源层掩码 0x0013FCFF 已约束)。 */
  31. typedef struct
  32. {
  33. GPIO_TypeDef *port;
  34. uint16_t pin;
  35. } PLSR_HW_OUTPUT_PIN;
  36. static const PLSR_HW_OUTPUT_PIN PlsrHwOutputPins[PLSR_HW_OUTPUT_POINT_COUNT] =
  37. {
  38. {GPIOF, GPIO_PIN_6}, /* Y0 */
  39. {GPIOF, GPIO_PIN_8}, /* Y1 */
  40. {GPIOF, GPIO_PIN_7}, /* Y2 */
  41. {GPIOF, GPIO_PIN_9}, /* Y3 */
  42. {GPIOI, GPIO_PIN_8}, /* Y4 */
  43. {GPIOE, GPIO_PIN_6}, /* Y5 */
  44. {GPIOE, GPIO_PIN_5}, /* Y6 */
  45. {GPIOE, GPIO_PIN_4}, /* Y7 */
  46. {NULL, 0U}, /* Y8 */
  47. {NULL, 0U}, /* Y9 */
  48. {GPIOG, GPIO_PIN_7}, /* Y10 */
  49. {GPIOG, GPIO_PIN_6}, /* Y11 */
  50. {GPIOH, GPIO_PIN_9}, /* Y12 */
  51. {GPIOH, GPIO_PIN_8}, /* Y13 */
  52. {GPIOH, GPIO_PIN_7}, /* Y14 */
  53. {GPIOH, GPIO_PIN_6}, /* Y15 */
  54. {GPIOF, GPIO_PIN_11}, /* Y16 */
  55. {GPIOB, GPIO_PIN_0}, /* Y17 */
  56. {NULL, 0U}, /* Y18 */
  57. {NULL, 0U}, /* Y19 */
  58. {GPIOH, GPIO_PIN_5} /* Y20 */
  59. };
  60. #endif
  61. /* Q0~Q3 定时器:XDM-60T4-E。
  62. * PF6=TIM10_CH1(AF3)、PF7=TIM11_CH1(AF3)、PF8=TIM13_CH1(AF9)、PF9=TIM14_CH1(AF9)。
  63. * 定时器时钟由 RCC 实际配置计算(APB2 分频≠1 时定时器时钟×2)。 */
  64. static const PLSR_HW_AXIS_MAP PlsrHwAxisMap[PLSR_HW_AXIS_COUNT] =
  65. {
  66. #ifndef PLSR_HOST_TEST
  67. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM10, GPIOF, GPIO_PIN_6, 3U, TIM1_UP_TIM10_IRQn},
  68. {84000000UL, PLSR_HW_DIR_POINT_NONE, TIM13, GPIOF, GPIO_PIN_8, 9U, TIM8_UP_TIM13_IRQn},
  69. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM11, GPIOF, GPIO_PIN_7, 3U, TIM1_TRG_COM_TIM11_IRQn},
  70. {84000000UL, PLSR_HW_DIR_POINT_NONE, TIM14, GPIOF, GPIO_PIN_9, 9U, TIM8_TRG_COM_TIM14_IRQn}
  71. #else
  72. {168000000UL, PLSR_HW_DIR_POINT_NONE},
  73. {84000000UL, PLSR_HW_DIR_POINT_NONE},
  74. {168000000UL, PLSR_HW_DIR_POINT_NONE},
  75. {84000000UL, PLSR_HW_DIR_POINT_NONE}
  76. #endif
  77. };
  78. #ifndef PLSR_HOST_TEST
  79. static const uint8_t PlsrHwPulsePinIndex[PLSR_HW_AXIS_COUNT] =
  80. {
  81. 6U, 8U, 7U, 9U
  82. };
  83. /* 重定相期间由 GPIO 直接保持物理输出低电平。AFR 配置保持不变,
  84. * 只切换 MODER,因此恢复定时器复用功能只需一次寄存器写入。 */
  85. static void PlsrHwHoldPulsePinLow(uint8_t axis)
  86. {
  87. GPIO_TypeDef *port = PlsrHwAxisMap[axis].gpioPort;
  88. uint32_t shift = (uint32_t)PlsrHwPulsePinIndex[axis] * 2UL;
  89. uint32_t moder;
  90. port->BSRR = (uint32_t)PlsrHwAxisMap[axis].gpioPin << 16U;
  91. moder = port->MODER;
  92. moder &= ~(3UL << shift);
  93. moder |= 1UL << shift;
  94. port->MODER = moder;
  95. __DMB();
  96. }
  97. static void PlsrHwReleasePulsePin(uint8_t axis)
  98. {
  99. GPIO_TypeDef *port = PlsrHwAxisMap[axis].gpioPort;
  100. uint32_t shift = (uint32_t)PlsrHwPulsePinIndex[axis] * 2UL;
  101. uint32_t moder = port->MODER;
  102. moder &= ~(3UL << shift);
  103. moder |= 2UL << shift;
  104. port->MODER = moder;
  105. __DMB();
  106. }
  107. #endif
  108. /* host 测试:模拟定时器寄存器。 */
  109. #ifdef PLSR_HOST_TEST
  110. typedef struct
  111. {
  112. uint32_t cr1;
  113. uint32_t dier;
  114. uint32_t sr;
  115. uint32_t psc;
  116. uint32_t arr;
  117. uint32_t ccr1;
  118. uint32_t cnt;
  119. uint32_t ccmr1;
  120. uint32_t ccer;
  121. uint8_t dirLevel;
  122. } PLSR_HW_TIMER_REGS;
  123. static PLSR_HW_TIMER_REGS PlsrHwTimers[PLSR_HW_AXIS_COUNT];
  124. #endif
  125. typedef struct
  126. {
  127. PLSR_HW_STATE state;
  128. PLSR_OUTPUT_MODE outputMode;
  129. uint32_t currentFrequencyHz;
  130. int64_t targetPulses;
  131. int64_t emittedPulses;
  132. uint16_t directionDelayRemainingMs;
  133. uint8_t directionPoint;
  134. uint8_t configuredDirectionPoint;
  135. uint8_t directionPositive;
  136. uint8_t directionNegativeLogic;
  137. uint8_t directionTerminalOn;
  138. uint8_t directionOutputPending;
  139. uint8_t abQuarter;
  140. uint8_t abCountAxis;
  141. uint8_t abStartupPriming;
  142. uint8_t abOutputPrimed;
  143. uint16_t abActiveBasePsc;
  144. uint16_t abActivePairPsc;
  145. uint16_t abActiveArr;
  146. uint16_t abPendingBasePsc;
  147. uint16_t abPendingPairPsc;
  148. uint16_t abPendingArr;
  149. uint8_t abFrequencyPending;
  150. uint8_t cwActiveAxis;
  151. uint8_t cwStopPending;
  152. } PLSR_HW_AXIS_STATE;
  153. static PLSR_HW_AXIS_STATE PlsrHwAxes[PLSR_HW_AXIS_COUNT];
  154. static uint8_t PlsrHwDirectionBatchActive;
  155. /* 调试快照:当前上板自测只记录 Q0 的 160 ms,避免四轴
  156. * PlsrHwTick 互相混入,同时控制临时 RAM 占用。reason=0 表示段启动,
  157. * reason=3 表示 1 ms HAL tick,reason=4 表示 AB 在 00 边界换频重定相。 */
  158. #ifndef PLSR_HOST_TEST
  159. typedef struct
  160. {
  161. uint8_t reason; /* 0=PwmBegin(UG后) 3=PlsrHwTick(每1ms) */
  162. uint32_t psc;
  163. uint32_t arr;
  164. uint32_t ccr;
  165. uint32_t cnt;
  166. uint32_t frequencyHz;
  167. int64_t emittedPulses;
  168. } PLSR_HW_DBG_SNAP;
  169. static PLSR_HW_DBG_SNAP PlsrHwDbgSnap[PLSR_HW_DBG_SNAPSHOT_COUNT];
  170. static volatile uint16_t PlsrHwDbgCount;
  171. static void PlsrHwDbgCapture(uint8_t axis, uint8_t reason)
  172. {
  173. if (axis != 0U)
  174. {
  175. return;
  176. }
  177. if (reason == 0U)
  178. {
  179. PlsrHwDbgCount = 0U;
  180. }
  181. if (PlsrHwDbgCount < PLSR_HW_DBG_SNAPSHOT_COUNT)
  182. {
  183. PLSR_HW_DBG_SNAP *snap = &PlsrHwDbgSnap[PlsrHwDbgCount++];
  184. snap->reason = reason;
  185. snap->psc = PlsrHwAxisMap[axis].timer->PSC;
  186. snap->arr = PlsrHwAxisMap[axis].timer->ARR;
  187. snap->ccr = PlsrHwAxisMap[axis].timer->CCR1;
  188. snap->cnt = PlsrHwAxisMap[axis].timer->CNT;
  189. snap->frequencyHz = PlsrHwAxes[axis].currentFrequencyHz;
  190. snap->emittedPulses = PlsrHwAxes[axis].emittedPulses;
  191. }
  192. }
  193. #else
  194. #define PlsrHwDbgCapture(axis, reason) ((void)0)
  195. #endif
  196. /* ---- 定时器寄存器访问抽象(host 模拟 / 生产真实) ---- */
  197. static void PlsrHwTimerSetArr(uint8_t axis, uint32_t value)
  198. {
  199. #ifdef PLSR_HOST_TEST
  200. PlsrHwTimers[axis].arr = value;
  201. #else
  202. PlsrHwAxisMap[axis].timer->ARR = value;
  203. #endif
  204. }
  205. static void PlsrHwTimerSetPsc(uint8_t axis, uint32_t value)
  206. {
  207. #ifdef PLSR_HOST_TEST
  208. PlsrHwTimers[axis].psc = value;
  209. #else
  210. PlsrHwAxisMap[axis].timer->PSC = value;
  211. #endif
  212. }
  213. static void PlsrHwTimerSetCcr(uint8_t axis, uint32_t value)
  214. {
  215. #ifdef PLSR_HOST_TEST
  216. PlsrHwTimers[axis].ccr1 = value;
  217. #else
  218. PlsrHwAxisMap[axis].timer->CCR1 = value;
  219. #endif
  220. }
  221. static void PlsrHwTimerSetCnt(uint8_t axis, uint32_t value)
  222. {
  223. #ifdef PLSR_HOST_TEST
  224. PlsrHwTimers[axis].cnt = value;
  225. /* F407 实测语义:CNT 写到活动 CCR1 比较值会置 CC1IF。 */
  226. if (value == PlsrHwTimers[axis].ccr1)
  227. {
  228. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_CC1_BIT;
  229. }
  230. #else
  231. PlsrHwAxisMap[axis].timer->CNT = value;
  232. #endif
  233. }
  234. static void PlsrHwTimerSetCen(uint8_t axis, uint32_t value)
  235. {
  236. #ifdef PLSR_HOST_TEST
  237. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0001UL) | value;
  238. #else
  239. if (value != 0UL)
  240. {
  241. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_CEN;
  242. }
  243. else
  244. {
  245. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_CEN;
  246. }
  247. #endif
  248. }
  249. static void PlsrHwTimerSetCc1e(uint8_t axis, uint32_t value)
  250. {
  251. #ifdef PLSR_HOST_TEST
  252. PlsrHwTimers[axis].ccer = (PlsrHwTimers[axis].ccer & ~0x0001UL) | value;
  253. #else
  254. if (value != 0UL)
  255. {
  256. PlsrHwAxisMap[axis].timer->CCER |= TIM_CCER_CC1E;
  257. }
  258. else
  259. {
  260. PlsrHwAxisMap[axis].timer->CCER &= ~TIM_CCER_CC1E;
  261. }
  262. #endif
  263. }
  264. /* 通道 1 输出模式 = PWM 模式 1(OC1M=110)+ CCR 预装载(OC1PE)。
  265. * 上电复位后 CCMR1=0(冻结),通道输出恒定电平、无方波,必须显式配置。 */
  266. static void PlsrHwTimerSetPwmMode1(uint8_t axis)
  267. {
  268. #ifdef PLSR_HOST_TEST
  269. PlsrHwTimers[axis].ccmr1 = 0x0068UL;
  270. #else
  271. PlsrHwAxisMap[axis].timer->CCMR1 = (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)
  272. | TIM_CCMR1_OC1PE;
  273. #endif
  274. }
  275. /* AB 启动和重定相时先把 OC1REF 钳到低电平,再切到 frozen 保持 00。
  276. * 两路 CNT 就位后从 frozen 切到 PWM1,硬件会按当前 CNT/CCR 重新计算输出,
  277. * 避免 UG 后残留的 OC1REF 高电平经 CC1E 暴露为窄脉冲。 */
  278. static void PlsrHwTimerSetForcedInactive(uint8_t axis)
  279. {
  280. #ifdef PLSR_HOST_TEST
  281. PlsrHwTimers[axis].ccmr1 = 0x0048UL;
  282. #else
  283. PlsrHwAxisMap[axis].timer->CCMR1 = TIM_CCMR1_OC1M_2
  284. | TIM_CCMR1_OC1PE;
  285. #endif
  286. }
  287. static void PlsrHwTimerSetFrozen(uint8_t axis)
  288. {
  289. #ifdef PLSR_HOST_TEST
  290. PlsrHwTimers[axis].ccmr1 = 0x0008UL;
  291. #else
  292. PlsrHwAxisMap[axis].timer->CCMR1 = TIM_CCMR1_OC1PE;
  293. #endif
  294. }
  295. static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value)
  296. {
  297. #ifdef PLSR_HOST_TEST
  298. PlsrHwTimers[axis].dier = (PlsrHwTimers[axis].dier & ~0x0001UL) | value;
  299. #else
  300. if (value != 0UL)
  301. {
  302. PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_UIE;
  303. }
  304. else
  305. {
  306. PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_UIE;
  307. }
  308. #endif
  309. }
  310. static void PlsrHwTimerSetCc1ie(uint8_t axis, uint32_t value)
  311. {
  312. #ifdef PLSR_HOST_TEST
  313. PlsrHwTimers[axis].dier =
  314. (PlsrHwTimers[axis].dier & ~PLSR_HW_TIMER_CC1_BIT)
  315. | ((value != 0UL) ? PLSR_HW_TIMER_CC1_BIT : 0UL);
  316. if ((value != 0UL)
  317. && ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_CC1_BIT) != 0UL))
  318. {
  319. PlsrHwOnTimerUpdate(axis);
  320. }
  321. #else
  322. if (value != 0UL)
  323. {
  324. PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_CC1IE;
  325. }
  326. else
  327. {
  328. PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_CC1IE;
  329. }
  330. #endif
  331. }
  332. static void PlsrHwTimerClearUif(uint8_t axis)
  333. {
  334. #ifdef PLSR_HOST_TEST
  335. PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_UPDATE_BIT;
  336. #else
  337. PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_UIF;
  338. #endif
  339. }
  340. static uint8_t PlsrHwTimerHasUif(uint8_t axis)
  341. {
  342. #ifdef PLSR_HOST_TEST
  343. return ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_UPDATE_BIT) != 0UL)
  344. ? 1U
  345. : 0U;
  346. #else
  347. return ((PlsrHwAxisMap[axis].timer->SR & TIM_SR_UIF) != 0UL) ? 1U : 0U;
  348. #endif
  349. }
  350. static void PlsrHwTimerClearCc1if(uint8_t axis)
  351. {
  352. #ifdef PLSR_HOST_TEST
  353. PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_CC1_BIT;
  354. #else
  355. PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_CC1IF;
  356. #endif
  357. }
  358. static uint8_t PlsrHwTimerHasCc1if(uint8_t axis)
  359. {
  360. #ifdef PLSR_HOST_TEST
  361. return ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_CC1_BIT) != 0UL)
  362. ? 1U
  363. : 0U;
  364. #else
  365. return ((PlsrHwAxisMap[axis].timer->SR & TIM_SR_CC1IF) != 0UL) ? 1U : 0U;
  366. #endif
  367. }
  368. /* ---- DIR 输出 ----
  369. * XDM 为晶体管(NPN 漏型)输出:ON(导通)= 引脚低电平。
  370. * 正逻辑:正向=ON;负逻辑:正向=OFF。逻辑运动方向始终单独保存,
  371. * 不能因电气极性反转而改变位置符号、AB相序或SM方向标志。 */
  372. static void PlsrHwApplyDirLevel(uint8_t axis)
  373. {
  374. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  375. if (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  376. {
  377. return;
  378. }
  379. #ifdef PLSR_HOST_TEST
  380. PlsrHwTimers[axis].dirLevel = state->directionTerminalOn;
  381. state->configuredDirectionPoint = state->directionPoint;
  382. #else
  383. if (state->directionPoint < PLSR_HW_OUTPUT_POINT_COUNT)
  384. {
  385. const PLSR_HW_OUTPUT_PIN *pin =
  386. &PlsrHwOutputPins[state->directionPoint];
  387. GPIO_InitTypeDef gpio;
  388. if (pin->port != NULL)
  389. {
  390. /* DIR 点按需配置为推挽输出(上电默认高阻=截止,安全)。 */
  391. pin->port->BSRR = (state->directionTerminalOn != 0U)
  392. ? ((uint32_t)pin->pin << 16U)
  393. : (uint32_t)pin->pin;
  394. if (state->configuredDirectionPoint != state->directionPoint)
  395. {
  396. gpio.Pin = pin->pin;
  397. gpio.Mode = GPIO_MODE_OUTPUT_PP;
  398. gpio.Pull = GPIO_NOPULL;
  399. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  400. HAL_GPIO_Init(pin->port, &gpio);
  401. state->configuredDirectionPoint = state->directionPoint;
  402. }
  403. /* 漏型输出:ON(导通)= 低电平。 */
  404. }
  405. }
  406. #endif
  407. }
  408. /* ---- PWM 启停 ----
  409. * ARR/CCR 使用预装载(ARPE/OC1PE):运行中调频写入延迟到更新事件生效,
  410. * 避免 ARR 变小瞬间 CNT 超调提前回绕(每段加速会多出 ~ln(f1/f0) 个假脉冲)。
  411. * 首次启动用 EGR.UG 把预装载值加载到影子寄存器,杜绝首个周期用复位值。 */
  412. static void PlsrHwSetDirLevel(uint8_t axis,
  413. uint8_t positive,
  414. uint8_t negativeLogic)
  415. {
  416. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  417. state->directionPositive = (positive != 0U) ? 1U : 0U;
  418. state->directionNegativeLogic =
  419. (negativeLogic != 0U) ? 1U : 0U;
  420. state->directionTerminalOn =
  421. (uint8_t)(state->directionPositive
  422. ^ state->directionNegativeLogic);
  423. if (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  424. {
  425. return;
  426. }
  427. if ((PlsrHwDirectionBatchActive != 0U)
  428. && (state->configuredDirectionPoint == state->directionPoint))
  429. {
  430. state->directionOutputPending = 1U;
  431. return;
  432. }
  433. PlsrHwApplyDirLevel(axis);
  434. }
  435. void PlsrHwBeginDirectionBatch(void)
  436. {
  437. PlsrHwDirectionBatchActive = 1U;
  438. }
  439. void PlsrHwEndDirectionBatch(void)
  440. {
  441. uint8_t axis;
  442. #ifndef PLSR_HOST_TEST
  443. uint32_t interruptState = __get_PRIMASK();
  444. __disable_irq();
  445. __DMB();
  446. #endif
  447. PlsrHwDirectionBatchActive = 0U;
  448. for (axis = 0U; axis < PLSR_HW_AXIS_COUNT; axis++)
  449. {
  450. if (PlsrHwAxes[axis].directionOutputPending != 0U)
  451. {
  452. PlsrHwAxes[axis].directionOutputPending = 0U;
  453. PlsrHwApplyDirLevel(axis);
  454. }
  455. }
  456. #ifndef PLSR_HOST_TEST
  457. __DMB();
  458. if (interruptState == 0UL)
  459. {
  460. __enable_irq();
  461. }
  462. #endif
  463. }
  464. static void PlsrHwTimerSetArpe(uint8_t axis, uint32_t value)
  465. {
  466. #ifdef PLSR_HOST_TEST
  467. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0080UL)
  468. | ((value != 0UL) ? 0x0080UL : 0UL);
  469. #else
  470. if (value != 0UL)
  471. {
  472. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_ARPE;
  473. }
  474. else
  475. {
  476. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_ARPE;
  477. }
  478. #endif
  479. }
  480. /* 生成更新事件:立即加载 ARR/CCR/PSC 影子寄存器(启动时用)。 */
  481. static void PlsrHwTimerSetUg(uint8_t axis)
  482. {
  483. #ifdef PLSR_HOST_TEST
  484. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_UPDATE_BIT;
  485. #else
  486. PlsrHwAxisMap[axis].timer->EGR = TIM_EGR_UG;
  487. #endif
  488. }
  489. /* 配置 PWM 定时器(预装载写入;启动/调频共用,不触碰使能位)。 */
  490. static void PlsrHwConfigurePwm(uint8_t axis, uint32_t frequencyHz)
  491. {
  492. uint16_t psc;
  493. uint16_t arr;
  494. #ifndef PLSR_HOST_TEST
  495. uint32_t interruptState;
  496. #endif
  497. if (PlsrCalculateTimerDivider(PlsrHwAxisMap[axis].timerClockHz,
  498. frequencyHz,
  499. &psc,
  500. &arr) != PLSR_RESULT_OK)
  501. {
  502. return;
  503. }
  504. #ifndef PLSR_HOST_TEST
  505. interruptState = __get_PRIMASK();
  506. __disable_irq();
  507. __DMB();
  508. #endif
  509. PlsrHwTimerSetPsc(axis, psc);
  510. PlsrHwTimerSetArr(axis, arr);
  511. PlsrHwTimerSetCcr(axis, (uint32_t)arr / 2UL); /* 50% 占空比 */
  512. PlsrHwTimerSetPwmMode1(axis);
  513. PlsrHwTimerSetArpe(axis, 1UL);
  514. #ifndef PLSR_HOST_TEST
  515. __DMB();
  516. if (interruptState == 0UL)
  517. {
  518. __enable_irq();
  519. }
  520. #endif
  521. }
  522. /* 首次启动输出:加载影子寄存器后使能更新中断、通道与计数。 */
  523. static void PlsrHwPwmBegin(uint8_t axis)
  524. {
  525. PlsrHwTimerSetUg(axis);
  526. /* UG 只用于加载影子寄存器,不是物理脉冲,不得计数。 */
  527. PlsrHwTimerClearUif(axis);
  528. PlsrHwTimerClearCc1if(axis);
  529. PlsrHwDbgCapture(axis, 0U);
  530. PlsrHwTimerSetCc1ie(axis, 0UL);
  531. PlsrHwTimerSetUie(axis, 1UL);
  532. PlsrHwTimerSetCc1e(axis, 1UL);
  533. PlsrHwTimerSetCen(axis, 1UL);
  534. }
  535. static void PlsrHwStopPwmTimer(uint8_t axis)
  536. {
  537. PlsrHwTimerSetCc1e(axis, 0UL);
  538. PlsrHwTimerSetUie(axis, 0UL);
  539. PlsrHwTimerSetCc1ie(axis, 0UL);
  540. PlsrHwTimerSetCen(axis, 0UL);
  541. PlsrHwTimerClearUif(axis);
  542. PlsrHwTimerClearCc1if(axis);
  543. }
  544. static uint8_t PlsrHwIsAbBaseAxis(uint8_t axis)
  545. {
  546. return ((axis == 0U) || (axis == 2U)) ? 1U : 0U;
  547. }
  548. static uint8_t PlsrHwGetPairedAxis(uint8_t axis)
  549. {
  550. return (uint8_t)(axis + 1U);
  551. }
  552. /* 为 168MHz/84MHz 配对定时器选择相同 ARR,并让前者的 PSC 分频
  553. * 始终是后者的 2 倍。两路获得完全相同的计数时钟与周期,避免
  554. * 独立取整造成 AB 相位随运行时间漂移。 */
  555. static uint8_t PlsrHwCalculateAbDividers(uint8_t axis,
  556. uint32_t frequencyHz,
  557. uint16_t *basePsc,
  558. uint16_t *pairPsc,
  559. uint16_t *arr)
  560. {
  561. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  562. uint64_t baseClock = PlsrHwAxisMap[axis].timerClockHz;
  563. uint64_t pairClock = PlsrHwAxisMap[pairAxis].timerClockHz;
  564. uint64_t ratio;
  565. uint64_t pairDivider;
  566. uint64_t baseDivider;
  567. uint64_t periodTicks;
  568. if ((frequencyHz == 0UL) || (basePsc == NULL) || (pairPsc == NULL)
  569. || (arr == NULL) || (pairClock == 0UL)
  570. || ((baseClock % pairClock) != 0UL))
  571. {
  572. return 0U;
  573. }
  574. ratio = baseClock / pairClock;
  575. if (ratio == 0UL)
  576. {
  577. return 0U;
  578. }
  579. pairDivider = (pairClock
  580. + (uint64_t)frequencyHz * UINT64_C(65536) - 1UL)
  581. / ((uint64_t)frequencyHz * UINT64_C(65536));
  582. if (pairDivider == 0UL)
  583. {
  584. pairDivider = 1UL;
  585. }
  586. baseDivider = pairDivider * ratio;
  587. if ((pairDivider > UINT64_C(65536))
  588. || (baseDivider > UINT64_C(65536)))
  589. {
  590. return 0U;
  591. }
  592. periodTicks = (pairClock
  593. + ((uint64_t)frequencyHz * pairDivider) / 2UL)
  594. / ((uint64_t)frequencyHz * pairDivider);
  595. if ((periodTicks < 4UL) || (periodTicks > UINT64_C(65536)))
  596. {
  597. return 0U;
  598. }
  599. *basePsc = (uint16_t)(baseDivider - 1UL);
  600. *pairPsc = (uint16_t)(pairDivider - 1UL);
  601. *arr = (uint16_t)(periodTicks - 1UL);
  602. return 1U;
  603. }
  604. static void PlsrHwLoadAbPwm(uint8_t axis,
  605. uint16_t basePsc,
  606. uint16_t pairPsc,
  607. uint16_t arr)
  608. {
  609. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  610. uint32_t compare;
  611. compare = ((uint32_t)arr + 1UL) / 2UL;
  612. PlsrHwTimerSetPsc(axis, basePsc);
  613. PlsrHwTimerSetPsc(pairAxis, pairPsc);
  614. PlsrHwTimerSetArr(axis, arr);
  615. PlsrHwTimerSetArr(pairAxis, arr);
  616. PlsrHwTimerSetCcr(axis, compare);
  617. PlsrHwTimerSetCcr(pairAxis, compare);
  618. PlsrHwTimerSetPwmMode1(axis);
  619. PlsrHwTimerSetPwmMode1(pairAxis);
  620. PlsrHwTimerSetArpe(axis, 1UL);
  621. PlsrHwTimerSetArpe(pairAxis, 1UL);
  622. PlsrHwAxes[axis].abActiveBasePsc = basePsc;
  623. PlsrHwAxes[axis].abActivePairPsc = pairPsc;
  624. PlsrHwAxes[axis].abActiveArr = arr;
  625. }
  626. static uint8_t PlsrHwConfigureAbPwm(uint8_t axis, uint32_t frequencyHz)
  627. {
  628. uint16_t basePsc;
  629. uint16_t pairPsc;
  630. uint16_t arr;
  631. if (PlsrHwCalculateAbDividers(axis,
  632. frequencyHz,
  633. &basePsc,
  634. &pairPsc,
  635. &arr) == 0U)
  636. {
  637. return 0U;
  638. }
  639. PlsrHwLoadAbPwm(axis, basePsc, pairPsc, arr);
  640. return 1U;
  641. }
  642. /* 运行中的 AB 调频不能直接写两路 ARR 预装载:两路定时器相差 1/4 周期,
  643. * 各自的 update 时刻也相差 1/4 周期,会短暂使用不同周期并永久积累相位误差。
  644. * 任务上下文只计算并发布最新参数,真正装载由 00 周期边界中断完成。 */
  645. static uint8_t PlsrHwQueueAbFrequency(uint8_t axis, uint32_t frequencyHz)
  646. {
  647. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  648. uint16_t basePsc;
  649. uint16_t pairPsc;
  650. uint16_t arr;
  651. #ifndef PLSR_HOST_TEST
  652. uint32_t interruptState;
  653. #endif
  654. if (PlsrHwCalculateAbDividers(axis,
  655. frequencyHz,
  656. &basePsc,
  657. &pairPsc,
  658. &arr) == 0U)
  659. {
  660. return 0U;
  661. }
  662. #ifndef PLSR_HOST_TEST
  663. interruptState = __get_PRIMASK();
  664. __disable_irq();
  665. __DMB();
  666. #endif
  667. if ((basePsc == state->abActiveBasePsc)
  668. && (pairPsc == state->abActivePairPsc)
  669. && (arr == state->abActiveArr))
  670. {
  671. /* 量化后的分频参数未变化时取消旧请求,避免匀速段每 1ms 重定相。 */
  672. state->abFrequencyPending = 0U;
  673. }
  674. else
  675. {
  676. state->abPendingBasePsc = basePsc;
  677. state->abPendingPairPsc = pairPsc;
  678. state->abPendingArr = arr;
  679. state->abFrequencyPending = 1U;
  680. }
  681. #ifndef PLSR_HOST_TEST
  682. __DMB();
  683. if (interruptState == 0UL)
  684. {
  685. __enable_irq();
  686. }
  687. #endif
  688. return 1U;
  689. }
  690. static void PlsrHwBeginAbOutput(uint8_t axis, uint8_t debugReason)
  691. {
  692. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  693. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  694. uint8_t leadAxis = (state->directionPositive != 0U) ? axis : pairAxis;
  695. uint8_t lagAxis = (state->directionPositive != 0U) ? pairAxis : axis;
  696. uint32_t periodTicks;
  697. uint32_t leadStart;
  698. uint32_t lagStart;
  699. #ifndef PLSR_HOST_TEST
  700. uint32_t interruptState;
  701. #else
  702. (void)debugReason;
  703. #endif
  704. #ifdef PLSR_HOST_TEST
  705. periodTicks = PlsrHwTimers[axis].arr + 1UL;
  706. #else
  707. periodTicks = PlsrHwAxisMap[axis].timer->ARR + 1UL;
  708. #endif
  709. leadStart = (periodTicks * 3UL) / 4UL;
  710. /* 落后相从 CCR 精确起步;切回 PWM 后清 CC1IF,最后才开 CC1IE。 */
  711. lagStart = periodTicks / 2UL;
  712. state->abCountAxis = lagAxis;
  713. state->abQuarter = 0U;
  714. state->abStartupPriming = (state->abOutputPrimed == 0U) ? 1U : 0U;
  715. #ifndef PLSR_HOST_TEST
  716. interruptState = __get_PRIMASK();
  717. __disable_irq();
  718. __DMB();
  719. PlsrHwHoldPulsePinLow(axis);
  720. PlsrHwHoldPulsePinLow(pairAxis);
  721. #endif
  722. PlsrHwTimerSetCen(axis, 0UL);
  723. PlsrHwTimerSetCen(pairAxis, 0UL);
  724. PlsrHwTimerSetCc1e(axis, 0UL);
  725. PlsrHwTimerSetCc1e(pairAxis, 0UL);
  726. PlsrHwTimerSetUie(axis, 0UL);
  727. PlsrHwTimerSetUie(pairAxis, 0UL);
  728. PlsrHwTimerSetCc1ie(axis, 0UL);
  729. PlsrHwTimerSetCc1ie(pairAxis, 0UL);
  730. PlsrHwTimerSetForcedInactive(axis);
  731. PlsrHwTimerSetForcedInactive(pairAxis);
  732. PlsrHwTimerSetFrozen(axis);
  733. PlsrHwTimerSetFrozen(pairAxis);
  734. PlsrHwTimerSetUg(axis);
  735. PlsrHwTimerSetUg(pairAxis);
  736. PlsrHwTimerClearUif(axis);
  737. PlsrHwTimerClearUif(pairAxis);
  738. PlsrHwTimerClearCc1if(axis);
  739. PlsrHwTimerClearCc1if(pairAxis);
  740. PlsrHwTimerSetCnt(leadAxis, leadStart);
  741. PlsrHwTimerSetCnt(lagAxis, lagStart);
  742. #ifdef PLSR_HOST_TEST
  743. PlsrHwTimerSetCc1e(axis, 1UL);
  744. PlsrHwTimerSetCc1e(pairAxis, 1UL);
  745. PlsrHwTimerSetPwmMode1(axis);
  746. PlsrHwTimerSetPwmMode1(pairAxis);
  747. PlsrHwTimerClearCc1if(axis);
  748. PlsrHwTimerClearCc1if(pairAxis);
  749. PlsrHwTimerSetCen(axis, 1UL);
  750. PlsrHwTimerSetCen(pairAxis, 1UL);
  751. PlsrHwTimerClearCc1if(axis);
  752. PlsrHwTimerClearCc1if(pairAxis);
  753. PlsrHwTimerSetCc1ie(lagAxis, 1UL);
  754. #else
  755. PlsrHwTimerSetCc1e(axis, 1UL);
  756. PlsrHwTimerSetCc1e(pairAxis, 1UL);
  757. PlsrHwTimerSetPwmMode1(axis);
  758. PlsrHwTimerSetPwmMode1(pairAxis);
  759. PlsrHwTimerClearCc1if(axis);
  760. PlsrHwTimerClearCc1if(pairAxis);
  761. if (state->abStartupPriming == 0U)
  762. {
  763. /* 完成过首次预热后,段间/调频重定相均从已验证的 00 边界
  764. * 直接交还 AF,不额外吞掉用户周期。 */
  765. PlsrHwReleasePulsePin(axis);
  766. PlsrHwReleasePulsePin(pairAxis);
  767. }
  768. PlsrHwTimerSetCen(axis, 1UL);
  769. PlsrHwTimerSetCen(pairAxis, 1UL);
  770. PlsrHwTimerClearCc1if(axis);
  771. PlsrHwTimerClearCc1if(pairAxis);
  772. PlsrHwTimerSetCc1ie(lagAxis, 1UL);
  773. __DMB();
  774. if (interruptState == 0UL)
  775. {
  776. __enable_irq();
  777. }
  778. #endif
  779. PlsrHwDbgCapture(axis, debugReason);
  780. }
  781. static void PlsrHwConfigureCwCcwPwm(uint8_t axis, uint32_t frequencyHz)
  782. {
  783. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  784. uint8_t activeAxis = state->cwActiveAxis;
  785. uint16_t psc;
  786. uint16_t arr;
  787. #ifndef PLSR_HOST_TEST
  788. uint32_t interruptState;
  789. #endif
  790. if (PlsrCalculateTimerDivider(PlsrHwAxisMap[activeAxis].timerClockHz,
  791. frequencyHz,
  792. &psc,
  793. &arr) != PLSR_RESULT_OK)
  794. {
  795. return;
  796. }
  797. #ifndef PLSR_HOST_TEST
  798. interruptState = __get_PRIMASK();
  799. __disable_irq();
  800. __DMB();
  801. #endif
  802. /* The compare ISR may arm final-pulse shutdown while TIM6 is calculating
  803. * a new divider. Recheck under the same short critical section as the
  804. * preload writes so the tail period can no longer be changed afterwards. */
  805. if (state->cwStopPending == 0U)
  806. {
  807. PlsrHwTimerSetPsc(activeAxis, psc);
  808. PlsrHwTimerSetArr(activeAxis, arr);
  809. PlsrHwTimerSetCcr(activeAxis, (uint32_t)arr / 2UL);
  810. PlsrHwTimerSetPwmMode1(activeAxis);
  811. PlsrHwTimerSetArpe(activeAxis, 1UL);
  812. }
  813. #ifndef PLSR_HOST_TEST
  814. __DMB();
  815. if (interruptState == 0UL)
  816. {
  817. __enable_irq();
  818. }
  819. #endif
  820. }
  821. static void PlsrHwBeginCwCcwOutput(uint8_t axis)
  822. {
  823. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  824. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  825. uint8_t activeAxis = state->cwActiveAxis;
  826. #ifndef PLSR_HOST_TEST
  827. uint32_t interruptState = __get_PRIMASK();
  828. __disable_irq();
  829. __DMB();
  830. #endif
  831. /* Keep both pins in timer AF. On this output chain, switching a channel
  832. * to GPIO-low is observable as an asserted Q edge. CC1E=0 is the tested
  833. * inactive level and avoids the extra start/end edge. */
  834. PlsrHwStopPwmTimer(axis);
  835. PlsrHwStopPwmTimer(pairAxis);
  836. state->cwStopPending = 0U;
  837. PlsrHwTimerSetUg(activeAxis);
  838. PlsrHwTimerClearUif(activeAxis);
  839. PlsrHwTimerClearCc1if(activeAxis);
  840. PlsrHwTimerSetCnt(activeAxis, 0UL);
  841. PlsrHwTimerSetUie(activeAxis, 0UL);
  842. PlsrHwTimerSetCc1ie(activeAxis, 1UL);
  843. PlsrHwTimerSetCc1e(activeAxis, 1UL);
  844. PlsrHwTimerSetCen(activeAxis, 1UL);
  845. #ifndef PLSR_HOST_TEST
  846. __DMB();
  847. if (interruptState == 0UL)
  848. {
  849. __enable_irq();
  850. }
  851. #endif
  852. }
  853. static void PlsrHwStopCwCcwOutput(uint8_t axis)
  854. {
  855. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  856. #ifndef PLSR_HOST_TEST
  857. uint32_t interruptState = __get_PRIMASK();
  858. __disable_irq();
  859. __DMB();
  860. #endif
  861. /* Disable both compare outputs while retaining AF mode; do not force
  862. * either pin through GPIO during the direction handover. */
  863. PlsrHwStopPwmTimer(axis);
  864. PlsrHwStopPwmTimer(pairAxis);
  865. PlsrHwAxes[axis].cwStopPending = 0U;
  866. #ifndef PLSR_HOST_TEST
  867. __DMB();
  868. if (interruptState == 0UL)
  869. {
  870. __enable_irq();
  871. }
  872. #endif
  873. }
  874. static void PlsrHwConfigureActiveOutput(uint8_t axis,
  875. PLSR_OUTPUT_MODE outputMode,
  876. uint32_t frequencyHz)
  877. {
  878. if (outputMode == PLSR_OUTPUT_AB)
  879. {
  880. (void)PlsrHwConfigureAbPwm(axis, frequencyHz);
  881. }
  882. else if (outputMode == PLSR_OUTPUT_CW_CCW)
  883. {
  884. PlsrHwConfigureCwCcwPwm(axis, frequencyHz);
  885. }
  886. else
  887. {
  888. PlsrHwConfigurePwm(axis, frequencyHz);
  889. }
  890. }
  891. static void PlsrHwBeginActiveOutput(uint8_t axis,
  892. PLSR_OUTPUT_MODE outputMode)
  893. {
  894. if (outputMode == PLSR_OUTPUT_AB)
  895. {
  896. PlsrHwBeginAbOutput(axis, 0U);
  897. }
  898. else if (outputMode == PLSR_OUTPUT_CW_CCW)
  899. {
  900. PlsrHwBeginCwCcwOutput(axis);
  901. }
  902. else
  903. {
  904. PlsrHwPwmBegin(axis);
  905. }
  906. }
  907. static void PlsrHwStopActiveOutput(uint8_t axis,
  908. PLSR_OUTPUT_MODE outputMode)
  909. {
  910. if ((outputMode == PLSR_OUTPUT_AB) && (PlsrHwIsAbBaseAxis(axis) != 0U))
  911. {
  912. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  913. #ifndef PLSR_HOST_TEST
  914. uint32_t interruptState = __get_PRIMASK();
  915. __disable_irq();
  916. __DMB();
  917. /* DONE/STOP 后继续由 GPIO 保持 00,禁止已关闭 timer 泄漏残余边沿。 */
  918. PlsrHwHoldPulsePinLow(axis);
  919. PlsrHwHoldPulsePinLow(pairAxis);
  920. #endif
  921. PlsrHwStopPwmTimer(axis);
  922. PlsrHwStopPwmTimer(pairAxis);
  923. PlsrHwAxes[axis].abStartupPriming = 0U;
  924. #ifndef PLSR_HOST_TEST
  925. __DMB();
  926. if (interruptState == 0UL)
  927. {
  928. __enable_irq();
  929. }
  930. #endif
  931. }
  932. else if ((outputMode == PLSR_OUTPUT_CW_CCW)
  933. && (PlsrHwIsAbBaseAxis(axis) != 0U))
  934. {
  935. PlsrHwStopCwCcwOutput(axis);
  936. }
  937. else
  938. {
  939. PlsrHwStopPwmTimer(axis);
  940. }
  941. }
  942. uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber)
  943. {
  944. /* 与资源层一致的合法输出点掩码(Q0~Q7、Q10~Q17、Q20)。 */
  945. const uint32_t validOutputMask = 0x0013FCFFUL;
  946. if (pointNumber >= PLSR_HW_OUTPUT_POINT_COUNT)
  947. {
  948. return 0U;
  949. }
  950. if ((validOutputMask & (1UL << pointNumber)) == 0UL)
  951. {
  952. return 0U;
  953. }
  954. #ifndef PLSR_HOST_TEST
  955. if (PlsrHwOutputPins[pointNumber].port == NULL)
  956. {
  957. return 0U;
  958. }
  959. #endif
  960. return 1U;
  961. }
  962. PLSR_RESULT PlsrHwInit(void)
  963. {
  964. uint8_t axis;
  965. (void)memset(PlsrHwAxes, 0, sizeof(PlsrHwAxes));
  966. PlsrHwDirectionBatchActive = 0U;
  967. for (axis = 0U; axis < PLSR_HW_AXIS_COUNT; axis++)
  968. {
  969. PlsrHwAxes[axis].state = PLSR_HW_STATE_IDLE;
  970. PlsrHwAxes[axis].directionPoint = PLSR_HW_DIR_POINT_NONE;
  971. PlsrHwAxes[axis].configuredDirectionPoint =
  972. PLSR_HW_DIR_POINT_NONE;
  973. #ifdef PLSR_HOST_TEST
  974. (void)memset(&PlsrHwTimers[axis], 0, sizeof(PlsrHwTimers[axis]));
  975. #else
  976. PlsrHwTimerSetCc1e(axis, 0UL);
  977. PlsrHwTimerSetUie(axis, 0UL);
  978. PlsrHwTimerSetCc1ie(axis, 0UL);
  979. PlsrHwTimerSetCen(axis, 0UL);
  980. #endif
  981. }
  982. #ifndef PLSR_HOST_TEST
  983. {
  984. GPIO_InitTypeDef gpio;
  985. uint32_t tim6ClockHz;
  986. uint16_t tim6Psc;
  987. uint16_t tim6Arr;
  988. /* 1. 输出点 GPIO 时钟(DIR 点按需配置时使用)。 */
  989. __HAL_RCC_GPIOF_CLK_ENABLE();
  990. __HAL_RCC_GPIOI_CLK_ENABLE();
  991. __HAL_RCC_GPIOE_CLK_ENABLE();
  992. __HAL_RCC_GPIOG_CLK_ENABLE();
  993. __HAL_RCC_GPIOH_CLK_ENABLE();
  994. __HAL_RCC_GPIOB_CLK_ENABLE();
  995. /* 2. 上电安全:输出点保持复位默认高阻(漏型输出 = 截止 = OFF)。
  996. * 不驱动任何 Y 点,DIR 点仅在 PlsrHwSetDirLevel 时按需配置。 */
  997. /* 3. 定时器时钟。 */
  998. __HAL_RCC_TIM10_CLK_ENABLE();
  999. __HAL_RCC_TIM11_CLK_ENABLE();
  1000. __HAL_RCC_TIM13_CLK_ENABLE();
  1001. __HAL_RCC_TIM14_CLK_ENABLE();
  1002. __HAL_RCC_TIM6_CLK_ENABLE();
  1003. /* Independent 10kHz control clock for S2 refreshCode=2. */
  1004. tim6ClockHz = HAL_RCC_GetPCLK1Freq();
  1005. if ((RCC->CFGR & RCC_CFGR_PPRE1) != RCC_CFGR_PPRE1_DIV1)
  1006. {
  1007. tim6ClockHz *= 2UL;
  1008. }
  1009. if (PlsrCalculateTimerDivider(tim6ClockHz,
  1010. 10000UL,
  1011. &tim6Psc,
  1012. &tim6Arr) != PLSR_RESULT_OK)
  1013. {
  1014. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  1015. }
  1016. TIM6->CR1 = 0UL;
  1017. TIM6->DIER = 0UL;
  1018. TIM6->PSC = tim6Psc;
  1019. TIM6->ARR = tim6Arr;
  1020. TIM6->EGR = TIM_EGR_UG;
  1021. TIM6->SR = 0UL;
  1022. TIM6->DIER = TIM_DIER_UIE;
  1023. HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 2U, 0U);
  1024. HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
  1025. TIM6->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN;
  1026. /* 4. 脉冲点切定时器复用(PF6/7=AF3、PF8/9=AF9)。
  1027. * 定时器通道尚未使能(CC1E=0),输出级断开,无毛刺。 */
  1028. gpio.Mode = GPIO_MODE_AF_PP;
  1029. gpio.Pull = GPIO_NOPULL;
  1030. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  1031. gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7;
  1032. gpio.Alternate = 3U;
  1033. HAL_GPIO_Init(GPIOF, &gpio);
  1034. gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9;
  1035. gpio.Alternate = 9U;
  1036. HAL_GPIO_Init(GPIOF, &gpio);
  1037. /* 5. 更新中断 NVIC:高速计数/尾脉冲层(P3b 统一规划优先级表)。 */
  1038. HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 1U, 0U);
  1039. HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
  1040. HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 1U, 0U);
  1041. HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
  1042. HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 1U, 0U);
  1043. HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
  1044. HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 1U, 0U);
  1045. HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
  1046. }
  1047. #endif
  1048. return PLSR_RESULT_OK;
  1049. }
  1050. PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params)
  1051. {
  1052. PLSR_HW_AXIS_STATE *state;
  1053. uint8_t directionChanged = 0U;
  1054. if ((axis >= PLSR_HW_AXIS_COUNT) || (params == NULL))
  1055. {
  1056. return PLSR_RESULT_INVALID_ARGUMENT;
  1057. }
  1058. if (params->targetPulses <= 0)
  1059. {
  1060. return PLSR_RESULT_INVALID_ARGUMENT;
  1061. }
  1062. if ((uint32_t)params->outputMode > (uint32_t)PLSR_OUTPUT_CW_CCW)
  1063. {
  1064. return PLSR_RESULT_INVALID_ARGUMENT;
  1065. }
  1066. if (((params->outputMode == PLSR_OUTPUT_AB)
  1067. || (params->outputMode == PLSR_OUTPUT_CW_CCW))
  1068. && (PlsrHwIsAbBaseAxis(axis) == 0U))
  1069. {
  1070. return PLSR_RESULT_INVALID_AXIS;
  1071. }
  1072. state = &PlsrHwAxes[axis];
  1073. if (state->state == PLSR_HW_STATE_RUNNING)
  1074. {
  1075. return PLSR_RESULT_BUSY;
  1076. }
  1077. /* 方向延时只在方向发生变化时生效(首次启动/换向/换方向点):
  1078. * 段间同向衔接不再等待 10ms,直接进入 PWM 待启动。 */
  1079. if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  1080. {
  1081. directionChanged =
  1082. (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  1083. || (state->directionPoint != params->directionPoint)
  1084. || (state->directionPositive != params->directionPositive)
  1085. || (state->directionNegativeLogic
  1086. != params->directionNegativeLogic);
  1087. }
  1088. state->outputMode = params->outputMode;
  1089. state->targetPulses = params->targetPulses;
  1090. state->emittedPulses = 0;
  1091. state->currentFrequencyHz = params->frequencyHz;
  1092. state->directionPoint =
  1093. (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  1094. ? params->directionPoint
  1095. : PLSR_HW_DIR_POINT_NONE;
  1096. state->directionDelayRemainingMs =
  1097. ((params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  1098. && (directionChanged != 0U))
  1099. ? params->directionDelayMs
  1100. : 0U;
  1101. state->abQuarter = 0U;
  1102. state->abFrequencyPending = 0U;
  1103. if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  1104. {
  1105. PlsrHwSetDirLevel(axis,
  1106. params->directionPositive,
  1107. params->directionNegativeLogic);
  1108. }
  1109. else
  1110. {
  1111. state->directionPositive =
  1112. (params->directionPositive != 0U) ? 1U : 0U;
  1113. state->directionNegativeLogic = 0U;
  1114. }
  1115. if (params->outputMode == PLSR_OUTPUT_CW_CCW)
  1116. {
  1117. state->cwActiveAxis = (state->directionPositive != 0U)
  1118. ? axis
  1119. : PlsrHwGetPairedAxis(axis);
  1120. }
  1121. state->state = (state->directionDelayRemainingMs > 0U)
  1122. ? PLSR_HW_STATE_DIR_SETTLING
  1123. : PLSR_HW_STATE_PWM_PENDING;
  1124. return PLSR_RESULT_OK;
  1125. }
  1126. PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz)
  1127. {
  1128. PLSR_HW_AXIS_STATE *state;
  1129. if (axis >= PLSR_HW_AXIS_COUNT)
  1130. {
  1131. return PLSR_RESULT_INVALID_ARGUMENT;
  1132. }
  1133. state = &PlsrHwAxes[axis];
  1134. if ((state->outputMode == PLSR_OUTPUT_CW_CCW)
  1135. && (state->cwStopPending != 0U))
  1136. {
  1137. /* Preserve the final physical high width until its natural update
  1138. * boundary; no later profile write may move that boundary. */
  1139. return PLSR_RESULT_OK;
  1140. }
  1141. state->currentFrequencyHz = frequencyHz;
  1142. if (state->state == PLSR_HW_STATE_RUNNING)
  1143. {
  1144. if (frequencyHz > 0UL)
  1145. {
  1146. if (state->outputMode == PLSR_OUTPUT_AB)
  1147. {
  1148. if (PlsrHwQueueAbFrequency(axis, frequencyHz) == 0U)
  1149. {
  1150. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  1151. }
  1152. }
  1153. else
  1154. {
  1155. /* PULSE/DIR 仍由单定时器在自身 update 边界加载预装值。 */
  1156. PlsrHwConfigureActiveOutput(axis,
  1157. state->outputMode,
  1158. frequencyHz);
  1159. }
  1160. }
  1161. else
  1162. {
  1163. PlsrHwStopActiveOutput(axis, state->outputMode);
  1164. }
  1165. }
  1166. else if ((state->state == PLSR_HW_STATE_PWM_PENDING)
  1167. && (frequencyHz > 0UL))
  1168. {
  1169. PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz);
  1170. /* 必须先发布 RUNNING,避免启用 timer IRQ 后观察到 PWM_PENDING。 */
  1171. state->state = PLSR_HW_STATE_RUNNING;
  1172. PlsrHwBeginActiveOutput(axis, state->outputMode);
  1173. }
  1174. return PLSR_RESULT_OK;
  1175. }
  1176. PLSR_RESULT PlsrHwResumePulse(uint8_t axis)
  1177. {
  1178. PLSR_HW_AXIS_STATE *state;
  1179. if (axis >= PLSR_HW_AXIS_COUNT)
  1180. {
  1181. return PLSR_RESULT_INVALID_ARGUMENT;
  1182. }
  1183. state = &PlsrHwAxes[axis];
  1184. if ((state->state != PLSR_HW_STATE_RUNNING)
  1185. || (state->currentFrequencyHz != 0UL)
  1186. || (state->emittedPulses >= state->targetPulses))
  1187. {
  1188. return PLSR_RESULT_INVALID_STATE;
  1189. }
  1190. /* PlsrHwSetFrequency(0) stopped the physical timer but deliberately kept
  1191. * the segment counters. PWM_PENDING makes the next non-zero control-tick
  1192. * update take the normal clean-start path without resetting those counts. */
  1193. state->state = PLSR_HW_STATE_PWM_PENDING;
  1194. return PLSR_RESULT_OK;
  1195. }
  1196. PLSR_RESULT PlsrHwStopPulse(uint8_t axis)
  1197. {
  1198. PLSR_HW_AXIS_STATE *state;
  1199. if (axis >= PLSR_HW_AXIS_COUNT)
  1200. {
  1201. return PLSR_RESULT_INVALID_ARGUMENT;
  1202. }
  1203. state = &PlsrHwAxes[axis];
  1204. if (state->state != PLSR_HW_STATE_IDLE)
  1205. {
  1206. PlsrHwStopActiveOutput(axis, state->outputMode);
  1207. state->abQuarter = 0U;
  1208. state->abFrequencyPending = 0U;
  1209. state->state = PLSR_HW_STATE_IDLE;
  1210. }
  1211. return PLSR_RESULT_OK;
  1212. }
  1213. uint8_t PlsrHwIsPulseActive(uint8_t axis)
  1214. {
  1215. if (axis >= PLSR_HW_AXIS_COUNT)
  1216. {
  1217. return 0U;
  1218. }
  1219. return (PlsrHwAxes[axis].state == PLSR_HW_STATE_RUNNING) ? 1U : 0U;
  1220. }
  1221. PLSR_HW_STATE PlsrHwGetState(uint8_t axis)
  1222. {
  1223. if (axis >= PLSR_HW_AXIS_COUNT)
  1224. {
  1225. return PLSR_HW_STATE_IDLE;
  1226. }
  1227. return PlsrHwAxes[axis].state;
  1228. }
  1229. uint32_t PlsrHwGetTimerClockHz(uint8_t axis)
  1230. {
  1231. if (axis >= PLSR_HW_AXIS_COUNT)
  1232. {
  1233. return 0UL;
  1234. }
  1235. return PlsrHwAxisMap[axis].timerClockHz;
  1236. }
  1237. uint32_t PlsrHwGetCurrentFrequencyHz(uint8_t axis)
  1238. {
  1239. if ((axis >= PLSR_HW_AXIS_COUNT)
  1240. || (PlsrHwAxes[axis].state != PLSR_HW_STATE_RUNNING))
  1241. {
  1242. return 0UL;
  1243. }
  1244. return PlsrHwAxes[axis].currentFrequencyHz;
  1245. }
  1246. /* 硬件已发出的脉冲数(profile 虚拟计数校准用,中断内递增)。 */
  1247. int64_t PlsrHwGetEmittedPulses(uint8_t axis)
  1248. {
  1249. int64_t emittedPulses;
  1250. if (axis >= PLSR_HW_AXIS_COUNT)
  1251. {
  1252. return 0;
  1253. }
  1254. #ifdef PLSR_HOST_TEST
  1255. emittedPulses = PlsrHwAxes[axis].emittedPulses;
  1256. #else
  1257. {
  1258. uint32_t interruptState = __get_PRIMASK();
  1259. __disable_irq();
  1260. __DMB();
  1261. emittedPulses = PlsrHwAxes[axis].emittedPulses;
  1262. __DMB();
  1263. if (interruptState == 0UL)
  1264. {
  1265. __enable_irq();
  1266. }
  1267. }
  1268. #endif
  1269. return emittedPulses;
  1270. }
  1271. uint8_t PlsrHwIsAbStartupPriming(uint8_t axis)
  1272. {
  1273. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1274. {
  1275. return 0U;
  1276. }
  1277. return PlsrHwAxes[axis].abStartupPriming;
  1278. }
  1279. void PlsrHwTick(uint8_t axis)
  1280. {
  1281. PLSR_HW_AXIS_STATE *state;
  1282. if (axis >= PLSR_HW_AXIS_COUNT)
  1283. {
  1284. return;
  1285. }
  1286. state = &PlsrHwAxes[axis];
  1287. /* 调试:每 tick 记录定时器实况(CNT 演化定位第一周期压缩)。 */
  1288. PlsrHwDbgCapture(axis, 3U);
  1289. switch (state->state)
  1290. {
  1291. case PLSR_HW_STATE_DIR_SETTLING:
  1292. if (state->directionDelayRemainingMs > 0U)
  1293. {
  1294. state->directionDelayRemainingMs--;
  1295. }
  1296. if (state->directionDelayRemainingMs == 0U)
  1297. {
  1298. state->state = PLSR_HW_STATE_PWM_PENDING;
  1299. }
  1300. break;
  1301. case PLSR_HW_STATE_PWM_PENDING:
  1302. if (state->currentFrequencyHz > 0UL)
  1303. {
  1304. PlsrHwConfigureActiveOutput(axis,
  1305. state->outputMode,
  1306. state->currentFrequencyHz);
  1307. state->state = PLSR_HW_STATE_RUNNING;
  1308. PlsrHwBeginActiveOutput(axis, state->outputMode);
  1309. }
  1310. break;
  1311. default:
  1312. break;
  1313. }
  1314. }
  1315. /* 输出定时器中断入口:PULSE/DIR 在 update 计数;AB 在落后相
  1316. * CC1 下降沿(四状态回到 00)计一个完整正交周期。 */
  1317. void PlsrHwOnTimerUpdate(uint8_t axis)
  1318. {
  1319. PLSR_HW_AXIS_STATE *state;
  1320. uint8_t ownerAxis;
  1321. uint8_t hasCc1;
  1322. if (axis >= PLSR_HW_AXIS_COUNT)
  1323. {
  1324. return;
  1325. }
  1326. /* CC1IF 无论当前状态如何都必须先清除;否则启动窗口中的杂散
  1327. * compare 标志会让共享 IRQ 持续重入,主线程无法完成 CEN 配置。 */
  1328. hasCc1 = PlsrHwTimerHasCc1if(axis);
  1329. if (hasCc1 != 0U)
  1330. {
  1331. PlsrHwTimerClearCc1if(axis);
  1332. }
  1333. ownerAxis = (uint8_t)(axis & 0xFEU);
  1334. state = &PlsrHwAxes[ownerAxis];
  1335. if ((state->state == PLSR_HW_STATE_RUNNING)
  1336. && (state->outputMode == PLSR_OUTPUT_AB))
  1337. {
  1338. if (PlsrHwTimerHasUif(axis) != 0U)
  1339. {
  1340. PlsrHwTimerClearUif(axis);
  1341. }
  1342. if ((hasCc1 == 0U) || (axis != state->abCountAxis))
  1343. {
  1344. return;
  1345. }
  1346. if (state->abStartupPriming != 0U)
  1347. {
  1348. /* F407 首次切换 OC 模式时 OC1REF 初态不可直接作为物理AB相。
  1349. * GPIO 保持 00 隐藏首个内部周期;落后相下降沿是真实 00
  1350. * 边界,此时再交还 AF,且该隐藏周期绝不能计入 emitted。 */
  1351. state->abStartupPriming = 0U;
  1352. state->abOutputPrimed = 1U;
  1353. #ifndef PLSR_HOST_TEST
  1354. PlsrHwReleasePulsePin(ownerAxis);
  1355. PlsrHwReleasePulsePin(PlsrHwGetPairedAxis(ownerAxis));
  1356. #endif
  1357. return;
  1358. }
  1359. state->emittedPulses++;
  1360. if (state->emittedPulses >= state->targetPulses)
  1361. {
  1362. PlsrHwStopActiveOutput(ownerAxis, state->outputMode);
  1363. state->abQuarter = 0U;
  1364. state->abFrequencyPending = 0U;
  1365. state->state = PLSR_HW_STATE_DONE;
  1366. (void)PlsrPostEvent(ownerAxis, PLSR_EVENT_SEGMENT_COMPLETE);
  1367. }
  1368. else if (state->abFrequencyPending != 0U)
  1369. {
  1370. uint16_t basePsc = state->abPendingBasePsc;
  1371. uint16_t pairPsc = state->abPendingPairPsc;
  1372. uint16_t arr = state->abPendingArr;
  1373. state->abFrequencyPending = 0U;
  1374. PlsrHwLoadAbPwm(ownerAxis, basePsc, pairPsc, arr);
  1375. /* 落后相刚下降,AB=00;两路从同一个完整周期边界重定相。 */
  1376. PlsrHwBeginAbOutput(ownerAxis, 4U);
  1377. }
  1378. return;
  1379. }
  1380. if ((state->state == PLSR_HW_STATE_RUNNING)
  1381. && (state->outputMode == PLSR_OUTPUT_CW_CCW))
  1382. {
  1383. uint8_t hasUif = PlsrHwTimerHasUif(axis);
  1384. if (hasUif != 0U)
  1385. {
  1386. PlsrHwTimerClearUif(axis);
  1387. }
  1388. if (axis != state->cwActiveAxis)
  1389. {
  1390. return;
  1391. }
  1392. if (hasCc1 != 0U)
  1393. {
  1394. state->emittedPulses++;
  1395. if (state->emittedPulses >= state->targetPulses)
  1396. {
  1397. /* The board output is inverted relative to OC1REF: CC1 is
  1398. * the physical rising edge. Arm the tail here, then stop on
  1399. * the following update (physical falling edge). */
  1400. state->cwStopPending = 1U;
  1401. PlsrHwTimerSetCc1ie(axis, 0UL);
  1402. PlsrHwTimerClearUif(axis);
  1403. PlsrHwTimerSetUie(axis, 1UL);
  1404. }
  1405. return;
  1406. }
  1407. if ((hasUif != 0U) && (state->cwStopPending != 0U))
  1408. {
  1409. PlsrHwStopActiveOutput(ownerAxis, state->outputMode);
  1410. state->state = PLSR_HW_STATE_DONE;
  1411. (void)PlsrPostEvent(ownerAxis, PLSR_EVENT_SEGMENT_COMPLETE);
  1412. }
  1413. return;
  1414. }
  1415. if (hasCc1 != 0U)
  1416. {
  1417. /* 非运行态/非 AB 模式的 CC1 仅作为杂散标志消费。 */
  1418. return;
  1419. }
  1420. state = &PlsrHwAxes[axis];
  1421. if (PlsrHwTimerHasUif(axis) == 0U)
  1422. {
  1423. return;
  1424. }
  1425. PlsrHwTimerClearUif(axis);
  1426. if (state->state != PLSR_HW_STATE_RUNNING)
  1427. {
  1428. return;
  1429. }
  1430. if (state->outputMode != PLSR_OUTPUT_PULSE_DIR)
  1431. {
  1432. return;
  1433. }
  1434. state->emittedPulses++;
  1435. if (state->emittedPulses >= state->targetPulses)
  1436. {
  1437. /* 更新时刻 = 周期结束:关通道即完整下降沿后停止,无额外脉冲。 */
  1438. PlsrHwStopActiveOutput(axis, state->outputMode);
  1439. state->state = PLSR_HW_STATE_DONE;
  1440. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  1441. }
  1442. }
  1443. #ifdef PLSR_HOST_TEST
  1444. uint32_t PlsrHwTestGetArr(uint8_t axis)
  1445. {
  1446. return PlsrHwTimers[axis].arr;
  1447. }
  1448. uint32_t PlsrHwTestGetCcr(uint8_t axis)
  1449. {
  1450. return PlsrHwTimers[axis].ccr1;
  1451. }
  1452. uint32_t PlsrHwTestGetCnt(uint8_t axis)
  1453. {
  1454. return PlsrHwTimers[axis].cnt;
  1455. }
  1456. uint32_t PlsrHwTestGetCcmr1(uint8_t axis)
  1457. {
  1458. return PlsrHwTimers[axis].ccmr1;
  1459. }
  1460. uint32_t PlsrHwTestGetCr1(uint8_t axis)
  1461. {
  1462. return PlsrHwTimers[axis].cr1;
  1463. }
  1464. uint32_t PlsrHwTestGetPsc(uint8_t axis)
  1465. {
  1466. return PlsrHwTimers[axis].psc;
  1467. }
  1468. uint8_t PlsrHwTestGetPwmEnabled(uint8_t axis)
  1469. {
  1470. return ((PlsrHwTimers[axis].ccer & PLSR_HW_TIMER_CHANNEL1_BIT) != 0UL)
  1471. ? 1U
  1472. : 0U;
  1473. }
  1474. uint8_t PlsrHwTestGetDirLevel(uint8_t axis)
  1475. {
  1476. return PlsrHwTimers[axis].dirLevel;
  1477. }
  1478. uint8_t PlsrHwTestGetAbPhaseA(uint8_t axis)
  1479. {
  1480. const PLSR_HW_AXIS_STATE *state;
  1481. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1482. {
  1483. return 0U;
  1484. }
  1485. state = &PlsrHwAxes[axis];
  1486. if (state->directionPositive != 0U)
  1487. {
  1488. return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
  1489. ? 1U
  1490. : 0U;
  1491. }
  1492. return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
  1493. ? 1U
  1494. : 0U;
  1495. }
  1496. uint8_t PlsrHwTestGetAbPhaseB(uint8_t axis)
  1497. {
  1498. const PLSR_HW_AXIS_STATE *state;
  1499. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1500. {
  1501. return 0U;
  1502. }
  1503. state = &PlsrHwAxes[axis];
  1504. if (state->directionPositive != 0U)
  1505. {
  1506. return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
  1507. ? 1U
  1508. : 0U;
  1509. }
  1510. return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
  1511. ? 1U
  1512. : 0U;
  1513. }
  1514. uint8_t PlsrHwTestGetAbQuarter(uint8_t axis)
  1515. {
  1516. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1517. {
  1518. return 0U;
  1519. }
  1520. return PlsrHwAxes[axis].abQuarter;
  1521. }
  1522. void PlsrHwTestAdvanceAbQuarter(uint8_t axis)
  1523. {
  1524. PLSR_HW_AXIS_STATE *state;
  1525. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1526. {
  1527. return;
  1528. }
  1529. state = &PlsrHwAxes[axis];
  1530. if ((state->state != PLSR_HW_STATE_RUNNING)
  1531. || (state->outputMode != PLSR_OUTPUT_AB))
  1532. {
  1533. return;
  1534. }
  1535. state->abQuarter = (uint8_t)((state->abQuarter + 1U)
  1536. % PLSR_HW_AB_QUARTER_COUNT);
  1537. if (state->abQuarter == 0U)
  1538. {
  1539. /* 模拟目标板落后相 CC1 下降沿中断,复用生产计数路径。 */
  1540. PlsrHwTimers[state->abCountAxis].sr |= PLSR_HW_TIMER_CC1_BIT;
  1541. PlsrHwOnTimerUpdate(state->abCountAxis);
  1542. }
  1543. }
  1544. void PlsrHwTestTriggerUpdate(uint8_t axis)
  1545. {
  1546. if (axis < PLSR_HW_AXIS_COUNT)
  1547. {
  1548. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_UPDATE_BIT;
  1549. }
  1550. PlsrHwOnTimerUpdate(axis);
  1551. }
  1552. void PlsrHwTestTriggerCompare(uint8_t axis)
  1553. {
  1554. if (axis < PLSR_HW_AXIS_COUNT)
  1555. {
  1556. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_CC1_BIT;
  1557. }
  1558. PlsrHwOnTimerUpdate(axis);
  1559. }
  1560. #endif
  1561. #ifndef PLSR_HOST_TEST
  1562. void TIM1_UP_TIM10_IRQHandler(void)
  1563. {
  1564. PlsrHwOnTimerUpdate(0U);
  1565. }
  1566. void TIM8_UP_TIM13_IRQHandler(void)
  1567. {
  1568. PlsrHwOnTimerUpdate(1U);
  1569. }
  1570. void TIM1_TRG_COM_TIM11_IRQHandler(void)
  1571. {
  1572. PlsrHwOnTimerUpdate(2U);
  1573. }
  1574. void TIM8_TRG_COM_TIM14_IRQHandler(void)
  1575. {
  1576. PlsrHwOnTimerUpdate(3U);
  1577. }
  1578. void TIM6_DAC_IRQHandler(void)
  1579. {
  1580. if ((TIM6->SR & TIM_SR_UIF) != 0UL)
  1581. {
  1582. TIM6->SR &= ~TIM_SR_UIF;
  1583. PlsrControlTick100us();
  1584. }
  1585. }
  1586. #endif