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.
 
 
 
 
 
 

1368 righe
38 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 directionPositive;
  135. uint8_t abQuarter;
  136. uint8_t abCountAxis;
  137. uint16_t abActiveBasePsc;
  138. uint16_t abActivePairPsc;
  139. uint16_t abActiveArr;
  140. uint16_t abPendingBasePsc;
  141. uint16_t abPendingPairPsc;
  142. uint16_t abPendingArr;
  143. uint8_t abFrequencyPending;
  144. } PLSR_HW_AXIS_STATE;
  145. static PLSR_HW_AXIS_STATE PlsrHwAxes[PLSR_HW_AXIS_COUNT];
  146. /* 调试快照:当前上板自测只记录 Q0 的 160 ms,避免四轴
  147. * PlsrHwTick 互相混入,同时控制临时 RAM 占用。reason=0 表示段启动,
  148. * reason=3 表示 1 ms HAL tick,reason=4 表示 AB 在 00 边界换频重定相。 */
  149. #ifndef PLSR_HOST_TEST
  150. typedef struct
  151. {
  152. uint8_t reason; /* 0=PwmBegin(UG后) 3=PlsrHwTick(每1ms) */
  153. uint32_t psc;
  154. uint32_t arr;
  155. uint32_t ccr;
  156. uint32_t cnt;
  157. uint32_t frequencyHz;
  158. int64_t emittedPulses;
  159. } PLSR_HW_DBG_SNAP;
  160. static PLSR_HW_DBG_SNAP PlsrHwDbgSnap[PLSR_HW_DBG_SNAPSHOT_COUNT];
  161. static volatile uint16_t PlsrHwDbgCount;
  162. static void PlsrHwDbgCapture(uint8_t axis, uint8_t reason)
  163. {
  164. if (axis != 0U)
  165. {
  166. return;
  167. }
  168. if (reason == 0U)
  169. {
  170. PlsrHwDbgCount = 0U;
  171. }
  172. if (PlsrHwDbgCount < PLSR_HW_DBG_SNAPSHOT_COUNT)
  173. {
  174. PLSR_HW_DBG_SNAP *snap = &PlsrHwDbgSnap[PlsrHwDbgCount++];
  175. snap->reason = reason;
  176. snap->psc = PlsrHwAxisMap[axis].timer->PSC;
  177. snap->arr = PlsrHwAxisMap[axis].timer->ARR;
  178. snap->ccr = PlsrHwAxisMap[axis].timer->CCR1;
  179. snap->cnt = PlsrHwAxisMap[axis].timer->CNT;
  180. snap->frequencyHz = PlsrHwAxes[axis].currentFrequencyHz;
  181. snap->emittedPulses = PlsrHwAxes[axis].emittedPulses;
  182. }
  183. }
  184. #else
  185. #define PlsrHwDbgCapture(axis, reason) ((void)0)
  186. #endif
  187. /* ---- 定时器寄存器访问抽象(host 模拟 / 生产真实) ---- */
  188. static void PlsrHwTimerSetArr(uint8_t axis, uint32_t value)
  189. {
  190. #ifdef PLSR_HOST_TEST
  191. PlsrHwTimers[axis].arr = value;
  192. #else
  193. PlsrHwAxisMap[axis].timer->ARR = value;
  194. #endif
  195. }
  196. static void PlsrHwTimerSetPsc(uint8_t axis, uint32_t value)
  197. {
  198. #ifdef PLSR_HOST_TEST
  199. PlsrHwTimers[axis].psc = value;
  200. #else
  201. PlsrHwAxisMap[axis].timer->PSC = value;
  202. #endif
  203. }
  204. static void PlsrHwTimerSetCcr(uint8_t axis, uint32_t value)
  205. {
  206. #ifdef PLSR_HOST_TEST
  207. PlsrHwTimers[axis].ccr1 = value;
  208. #else
  209. PlsrHwAxisMap[axis].timer->CCR1 = value;
  210. #endif
  211. }
  212. static void PlsrHwTimerSetCnt(uint8_t axis, uint32_t value)
  213. {
  214. #ifdef PLSR_HOST_TEST
  215. PlsrHwTimers[axis].cnt = value;
  216. /* F407 实测语义:CNT 写到活动 CCR1 比较值会置 CC1IF。 */
  217. if (value == PlsrHwTimers[axis].ccr1)
  218. {
  219. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_CC1_BIT;
  220. }
  221. #else
  222. PlsrHwAxisMap[axis].timer->CNT = value;
  223. #endif
  224. }
  225. static void PlsrHwTimerSetCen(uint8_t axis, uint32_t value)
  226. {
  227. #ifdef PLSR_HOST_TEST
  228. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0001UL) | value;
  229. #else
  230. if (value != 0UL)
  231. {
  232. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_CEN;
  233. }
  234. else
  235. {
  236. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_CEN;
  237. }
  238. #endif
  239. }
  240. static void PlsrHwTimerSetCc1e(uint8_t axis, uint32_t value)
  241. {
  242. #ifdef PLSR_HOST_TEST
  243. PlsrHwTimers[axis].ccer = (PlsrHwTimers[axis].ccer & ~0x0001UL) | value;
  244. #else
  245. if (value != 0UL)
  246. {
  247. PlsrHwAxisMap[axis].timer->CCER |= TIM_CCER_CC1E;
  248. }
  249. else
  250. {
  251. PlsrHwAxisMap[axis].timer->CCER &= ~TIM_CCER_CC1E;
  252. }
  253. #endif
  254. }
  255. /* 通道 1 输出模式 = PWM 模式 1(OC1M=110)+ CCR 预装载(OC1PE)。
  256. * 上电复位后 CCMR1=0(冻结),通道输出恒定电平、无方波,必须显式配置。 */
  257. static void PlsrHwTimerSetPwmMode1(uint8_t axis)
  258. {
  259. #ifdef PLSR_HOST_TEST
  260. PlsrHwTimers[axis].ccmr1 = 0x0068UL;
  261. #else
  262. PlsrHwAxisMap[axis].timer->CCMR1 = (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)
  263. | TIM_CCMR1_OC1PE;
  264. #endif
  265. }
  266. /* AB 启动和重定相时先把 OC1REF 钳到低电平,再切到 frozen 保持 00。
  267. * 两路 CNT 就位后从 frozen 切到 PWM1,硬件会按当前 CNT/CCR 重新计算输出,
  268. * 避免 UG 后残留的 OC1REF 高电平经 CC1E 暴露为窄脉冲。 */
  269. static void PlsrHwTimerSetForcedInactive(uint8_t axis)
  270. {
  271. #ifdef PLSR_HOST_TEST
  272. PlsrHwTimers[axis].ccmr1 = 0x0048UL;
  273. #else
  274. PlsrHwAxisMap[axis].timer->CCMR1 = TIM_CCMR1_OC1M_2
  275. | TIM_CCMR1_OC1PE;
  276. #endif
  277. }
  278. static void PlsrHwTimerSetFrozen(uint8_t axis)
  279. {
  280. #ifdef PLSR_HOST_TEST
  281. PlsrHwTimers[axis].ccmr1 = 0x0008UL;
  282. #else
  283. PlsrHwAxisMap[axis].timer->CCMR1 = TIM_CCMR1_OC1PE;
  284. #endif
  285. }
  286. static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value)
  287. {
  288. #ifdef PLSR_HOST_TEST
  289. PlsrHwTimers[axis].dier = (PlsrHwTimers[axis].dier & ~0x0001UL) | value;
  290. #else
  291. if (value != 0UL)
  292. {
  293. PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_UIE;
  294. }
  295. else
  296. {
  297. PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_UIE;
  298. }
  299. #endif
  300. }
  301. static void PlsrHwTimerSetCc1ie(uint8_t axis, uint32_t value)
  302. {
  303. #ifdef PLSR_HOST_TEST
  304. PlsrHwTimers[axis].dier =
  305. (PlsrHwTimers[axis].dier & ~PLSR_HW_TIMER_CC1_BIT)
  306. | ((value != 0UL) ? PLSR_HW_TIMER_CC1_BIT : 0UL);
  307. if ((value != 0UL)
  308. && ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_CC1_BIT) != 0UL))
  309. {
  310. PlsrHwOnTimerUpdate(axis);
  311. }
  312. #else
  313. if (value != 0UL)
  314. {
  315. PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_CC1IE;
  316. }
  317. else
  318. {
  319. PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_CC1IE;
  320. }
  321. #endif
  322. }
  323. static void PlsrHwTimerClearUif(uint8_t axis)
  324. {
  325. #ifdef PLSR_HOST_TEST
  326. PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_UPDATE_BIT;
  327. #else
  328. PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_UIF;
  329. #endif
  330. }
  331. static uint8_t PlsrHwTimerHasUif(uint8_t axis)
  332. {
  333. #ifdef PLSR_HOST_TEST
  334. return ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_UPDATE_BIT) != 0UL)
  335. ? 1U
  336. : 0U;
  337. #else
  338. return ((PlsrHwAxisMap[axis].timer->SR & TIM_SR_UIF) != 0UL) ? 1U : 0U;
  339. #endif
  340. }
  341. static void PlsrHwTimerClearCc1if(uint8_t axis)
  342. {
  343. #ifdef PLSR_HOST_TEST
  344. PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_CC1_BIT;
  345. #else
  346. PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_CC1IF;
  347. #endif
  348. }
  349. static uint8_t PlsrHwTimerHasCc1if(uint8_t axis)
  350. {
  351. #ifdef PLSR_HOST_TEST
  352. return ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_CC1_BIT) != 0UL)
  353. ? 1U
  354. : 0U;
  355. #else
  356. return ((PlsrHwAxisMap[axis].timer->SR & TIM_SR_CC1IF) != 0UL) ? 1U : 0U;
  357. #endif
  358. }
  359. /* ---- DIR 输出 ----
  360. * XDM 为晶体管(NPN 漏型)输出:ON(导通)= 引脚低电平。
  361. * 信捷正逻辑:正向发脉冲时方向端子置 ON(低)。 */
  362. static void PlsrHwSetDirLevel(uint8_t axis, uint8_t positive)
  363. {
  364. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  365. state->directionPositive = (positive != 0U) ? 1U : 0U;
  366. if (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  367. {
  368. return;
  369. }
  370. #ifdef PLSR_HOST_TEST
  371. PlsrHwTimers[axis].dirLevel = (positive != 0U) ? 1U : 0U;
  372. #else
  373. if (state->directionPoint < PLSR_HW_OUTPUT_POINT_COUNT)
  374. {
  375. const PLSR_HW_OUTPUT_PIN *pin =
  376. &PlsrHwOutputPins[state->directionPoint];
  377. GPIO_InitTypeDef gpio;
  378. if (pin->port != NULL)
  379. {
  380. /* DIR 点按需配置为推挽输出(上电默认高阻=截止,安全)。 */
  381. gpio.Pin = pin->pin;
  382. gpio.Mode = GPIO_MODE_OUTPUT_PP;
  383. gpio.Pull = GPIO_NOPULL;
  384. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  385. HAL_GPIO_Init(pin->port, &gpio);
  386. /* 漏型输出:ON(导通)= 低电平。 */
  387. HAL_GPIO_WritePin(pin->port,
  388. pin->pin,
  389. (positive != 0U) ? GPIO_PIN_RESET
  390. : GPIO_PIN_SET);
  391. }
  392. }
  393. #endif
  394. }
  395. /* ---- PWM 启停 ----
  396. * ARR/CCR 使用预装载(ARPE/OC1PE):运行中调频写入延迟到更新事件生效,
  397. * 避免 ARR 变小瞬间 CNT 超调提前回绕(每段加速会多出 ~ln(f1/f0) 个假脉冲)。
  398. * 首次启动用 EGR.UG 把预装载值加载到影子寄存器,杜绝首个周期用复位值。 */
  399. static void PlsrHwTimerSetArpe(uint8_t axis, uint32_t value)
  400. {
  401. #ifdef PLSR_HOST_TEST
  402. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0080UL)
  403. | ((value != 0UL) ? 0x0080UL : 0UL);
  404. #else
  405. if (value != 0UL)
  406. {
  407. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_ARPE;
  408. }
  409. else
  410. {
  411. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_ARPE;
  412. }
  413. #endif
  414. }
  415. /* 生成更新事件:立即加载 ARR/CCR/PSC 影子寄存器(启动时用)。 */
  416. static void PlsrHwTimerSetUg(uint8_t axis)
  417. {
  418. #ifdef PLSR_HOST_TEST
  419. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_UPDATE_BIT;
  420. #else
  421. PlsrHwAxisMap[axis].timer->EGR = TIM_EGR_UG;
  422. #endif
  423. }
  424. /* 配置 PWM 定时器(预装载写入;启动/调频共用,不触碰使能位)。 */
  425. static void PlsrHwConfigurePwm(uint8_t axis, uint32_t frequencyHz)
  426. {
  427. uint16_t psc;
  428. uint16_t arr;
  429. if (PlsrCalculateTimerDivider(PlsrHwAxisMap[axis].timerClockHz,
  430. frequencyHz,
  431. &psc,
  432. &arr) != PLSR_RESULT_OK)
  433. {
  434. return;
  435. }
  436. PlsrHwTimerSetPsc(axis, psc);
  437. PlsrHwTimerSetArr(axis, arr);
  438. PlsrHwTimerSetCcr(axis, (uint32_t)arr / 2UL); /* 50% 占空比 */
  439. PlsrHwTimerSetPwmMode1(axis);
  440. PlsrHwTimerSetArpe(axis, 1UL);
  441. }
  442. /* 首次启动输出:加载影子寄存器后使能更新中断、通道与计数。 */
  443. static void PlsrHwPwmBegin(uint8_t axis)
  444. {
  445. PlsrHwTimerSetUg(axis);
  446. /* UG 只用于加载影子寄存器,不是物理脉冲,不得计数。 */
  447. PlsrHwTimerClearUif(axis);
  448. PlsrHwTimerClearCc1if(axis);
  449. PlsrHwDbgCapture(axis, 0U);
  450. PlsrHwTimerSetCc1ie(axis, 0UL);
  451. PlsrHwTimerSetUie(axis, 1UL);
  452. PlsrHwTimerSetCc1e(axis, 1UL);
  453. PlsrHwTimerSetCen(axis, 1UL);
  454. }
  455. static void PlsrHwStopPwmTimer(uint8_t axis)
  456. {
  457. PlsrHwTimerSetCc1e(axis, 0UL);
  458. PlsrHwTimerSetUie(axis, 0UL);
  459. PlsrHwTimerSetCc1ie(axis, 0UL);
  460. PlsrHwTimerSetCen(axis, 0UL);
  461. PlsrHwTimerClearUif(axis);
  462. PlsrHwTimerClearCc1if(axis);
  463. }
  464. static uint8_t PlsrHwIsAbBaseAxis(uint8_t axis)
  465. {
  466. return ((axis == 0U) || (axis == 2U)) ? 1U : 0U;
  467. }
  468. static uint8_t PlsrHwGetPairedAxis(uint8_t axis)
  469. {
  470. return (uint8_t)(axis + 1U);
  471. }
  472. /* 为 168MHz/84MHz 配对定时器选择相同 ARR,并让前者的 PSC 分频
  473. * 始终是后者的 2 倍。两路获得完全相同的计数时钟与周期,避免
  474. * 独立取整造成 AB 相位随运行时间漂移。 */
  475. static uint8_t PlsrHwCalculateAbDividers(uint8_t axis,
  476. uint32_t frequencyHz,
  477. uint16_t *basePsc,
  478. uint16_t *pairPsc,
  479. uint16_t *arr)
  480. {
  481. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  482. uint64_t baseClock = PlsrHwAxisMap[axis].timerClockHz;
  483. uint64_t pairClock = PlsrHwAxisMap[pairAxis].timerClockHz;
  484. uint64_t ratio;
  485. uint64_t pairDivider;
  486. uint64_t baseDivider;
  487. uint64_t periodTicks;
  488. if ((frequencyHz == 0UL) || (basePsc == NULL) || (pairPsc == NULL)
  489. || (arr == NULL) || (pairClock == 0UL)
  490. || ((baseClock % pairClock) != 0UL))
  491. {
  492. return 0U;
  493. }
  494. ratio = baseClock / pairClock;
  495. if (ratio == 0UL)
  496. {
  497. return 0U;
  498. }
  499. pairDivider = (pairClock
  500. + (uint64_t)frequencyHz * UINT64_C(65536) - 1UL)
  501. / ((uint64_t)frequencyHz * UINT64_C(65536));
  502. if (pairDivider == 0UL)
  503. {
  504. pairDivider = 1UL;
  505. }
  506. baseDivider = pairDivider * ratio;
  507. if ((pairDivider > UINT64_C(65536))
  508. || (baseDivider > UINT64_C(65536)))
  509. {
  510. return 0U;
  511. }
  512. periodTicks = (pairClock
  513. + ((uint64_t)frequencyHz * pairDivider) / 2UL)
  514. / ((uint64_t)frequencyHz * pairDivider);
  515. if ((periodTicks < 4UL) || (periodTicks > UINT64_C(65536)))
  516. {
  517. return 0U;
  518. }
  519. *basePsc = (uint16_t)(baseDivider - 1UL);
  520. *pairPsc = (uint16_t)(pairDivider - 1UL);
  521. *arr = (uint16_t)(periodTicks - 1UL);
  522. return 1U;
  523. }
  524. static void PlsrHwLoadAbPwm(uint8_t axis,
  525. uint16_t basePsc,
  526. uint16_t pairPsc,
  527. uint16_t arr)
  528. {
  529. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  530. uint32_t compare;
  531. compare = ((uint32_t)arr + 1UL) / 2UL;
  532. PlsrHwTimerSetPsc(axis, basePsc);
  533. PlsrHwTimerSetPsc(pairAxis, pairPsc);
  534. PlsrHwTimerSetArr(axis, arr);
  535. PlsrHwTimerSetArr(pairAxis, arr);
  536. PlsrHwTimerSetCcr(axis, compare);
  537. PlsrHwTimerSetCcr(pairAxis, compare);
  538. PlsrHwTimerSetPwmMode1(axis);
  539. PlsrHwTimerSetPwmMode1(pairAxis);
  540. PlsrHwTimerSetArpe(axis, 1UL);
  541. PlsrHwTimerSetArpe(pairAxis, 1UL);
  542. PlsrHwAxes[axis].abActiveBasePsc = basePsc;
  543. PlsrHwAxes[axis].abActivePairPsc = pairPsc;
  544. PlsrHwAxes[axis].abActiveArr = arr;
  545. }
  546. static uint8_t PlsrHwConfigureAbPwm(uint8_t axis, uint32_t frequencyHz)
  547. {
  548. uint16_t basePsc;
  549. uint16_t pairPsc;
  550. uint16_t arr;
  551. if (PlsrHwCalculateAbDividers(axis,
  552. frequencyHz,
  553. &basePsc,
  554. &pairPsc,
  555. &arr) == 0U)
  556. {
  557. return 0U;
  558. }
  559. PlsrHwLoadAbPwm(axis, basePsc, pairPsc, arr);
  560. return 1U;
  561. }
  562. /* 运行中的 AB 调频不能直接写两路 ARR 预装载:两路定时器相差 1/4 周期,
  563. * 各自的 update 时刻也相差 1/4 周期,会短暂使用不同周期并永久积累相位误差。
  564. * 任务上下文只计算并发布最新参数,真正装载由 00 周期边界中断完成。 */
  565. static uint8_t PlsrHwQueueAbFrequency(uint8_t axis, uint32_t frequencyHz)
  566. {
  567. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  568. uint16_t basePsc;
  569. uint16_t pairPsc;
  570. uint16_t arr;
  571. #ifndef PLSR_HOST_TEST
  572. uint32_t interruptState;
  573. #endif
  574. if (PlsrHwCalculateAbDividers(axis,
  575. frequencyHz,
  576. &basePsc,
  577. &pairPsc,
  578. &arr) == 0U)
  579. {
  580. return 0U;
  581. }
  582. #ifndef PLSR_HOST_TEST
  583. interruptState = __get_PRIMASK();
  584. __disable_irq();
  585. __DMB();
  586. #endif
  587. if ((basePsc == state->abActiveBasePsc)
  588. && (pairPsc == state->abActivePairPsc)
  589. && (arr == state->abActiveArr))
  590. {
  591. /* 量化后的分频参数未变化时取消旧请求,避免匀速段每 1ms 重定相。 */
  592. state->abFrequencyPending = 0U;
  593. }
  594. else
  595. {
  596. state->abPendingBasePsc = basePsc;
  597. state->abPendingPairPsc = pairPsc;
  598. state->abPendingArr = arr;
  599. state->abFrequencyPending = 1U;
  600. }
  601. #ifndef PLSR_HOST_TEST
  602. __DMB();
  603. if (interruptState == 0UL)
  604. {
  605. __enable_irq();
  606. }
  607. #endif
  608. return 1U;
  609. }
  610. static void PlsrHwBeginAbOutput(uint8_t axis, uint8_t debugReason)
  611. {
  612. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  613. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  614. uint8_t leadAxis = (state->directionPositive != 0U) ? axis : pairAxis;
  615. uint8_t lagAxis = (state->directionPositive != 0U) ? pairAxis : axis;
  616. uint32_t periodTicks;
  617. uint32_t leadStart;
  618. uint32_t lagStart;
  619. #ifndef PLSR_HOST_TEST
  620. uint32_t interruptState;
  621. #else
  622. (void)debugReason;
  623. #endif
  624. #ifdef PLSR_HOST_TEST
  625. periodTicks = PlsrHwTimers[axis].arr + 1UL;
  626. #else
  627. periodTicks = PlsrHwAxisMap[axis].timer->ARR + 1UL;
  628. #endif
  629. leadStart = (periodTicks * 3UL) / 4UL;
  630. /* 落后相从 CCR 精确起步;切回 PWM 后清 CC1IF,最后才开 CC1IE。 */
  631. lagStart = periodTicks / 2UL;
  632. state->abCountAxis = lagAxis;
  633. state->abQuarter = 0U;
  634. #ifndef PLSR_HOST_TEST
  635. interruptState = __get_PRIMASK();
  636. __disable_irq();
  637. __DMB();
  638. PlsrHwHoldPulsePinLow(axis);
  639. PlsrHwHoldPulsePinLow(pairAxis);
  640. #endif
  641. PlsrHwTimerSetCen(axis, 0UL);
  642. PlsrHwTimerSetCen(pairAxis, 0UL);
  643. PlsrHwTimerSetCc1e(axis, 0UL);
  644. PlsrHwTimerSetCc1e(pairAxis, 0UL);
  645. PlsrHwTimerSetUie(axis, 0UL);
  646. PlsrHwTimerSetUie(pairAxis, 0UL);
  647. PlsrHwTimerSetCc1ie(axis, 0UL);
  648. PlsrHwTimerSetCc1ie(pairAxis, 0UL);
  649. PlsrHwTimerSetForcedInactive(axis);
  650. PlsrHwTimerSetForcedInactive(pairAxis);
  651. PlsrHwTimerSetFrozen(axis);
  652. PlsrHwTimerSetFrozen(pairAxis);
  653. PlsrHwTimerSetUg(axis);
  654. PlsrHwTimerSetUg(pairAxis);
  655. PlsrHwTimerClearUif(axis);
  656. PlsrHwTimerClearUif(pairAxis);
  657. PlsrHwTimerClearCc1if(axis);
  658. PlsrHwTimerClearCc1if(pairAxis);
  659. PlsrHwTimerSetCnt(leadAxis, leadStart);
  660. PlsrHwTimerSetCnt(lagAxis, lagStart);
  661. #ifdef PLSR_HOST_TEST
  662. PlsrHwTimerSetCc1e(axis, 1UL);
  663. PlsrHwTimerSetCc1e(pairAxis, 1UL);
  664. PlsrHwTimerSetPwmMode1(axis);
  665. PlsrHwTimerSetPwmMode1(pairAxis);
  666. PlsrHwTimerClearCc1if(axis);
  667. PlsrHwTimerClearCc1if(pairAxis);
  668. PlsrHwTimerSetCen(axis, 1UL);
  669. PlsrHwTimerSetCen(pairAxis, 1UL);
  670. PlsrHwTimerClearCc1if(axis);
  671. PlsrHwTimerClearCc1if(pairAxis);
  672. PlsrHwTimerSetCc1ie(lagAxis, 1UL);
  673. #else
  674. PlsrHwTimerSetCc1e(axis, 1UL);
  675. PlsrHwTimerSetCc1e(pairAxis, 1UL);
  676. PlsrHwTimerSetPwmMode1(axis);
  677. PlsrHwTimerSetPwmMode1(pairAxis);
  678. /* OCREF 已在低电平位置稳定后再把物理引脚交还定时器。 */
  679. PlsrHwTimerClearCc1if(axis);
  680. PlsrHwTimerClearCc1if(pairAxis);
  681. PlsrHwReleasePulsePin(axis);
  682. PlsrHwReleasePulsePin(pairAxis);
  683. PlsrHwTimerSetCen(axis, 1UL);
  684. PlsrHwTimerSetCen(pairAxis, 1UL);
  685. /* 最后才允许落后相计数中断。 */
  686. PlsrHwTimerClearCc1if(axis);
  687. PlsrHwTimerClearCc1if(pairAxis);
  688. PlsrHwTimerSetCc1ie(lagAxis, 1UL);
  689. __DMB();
  690. if (interruptState == 0UL)
  691. {
  692. __enable_irq();
  693. }
  694. #endif
  695. PlsrHwDbgCapture(axis, debugReason);
  696. }
  697. static void PlsrHwConfigureActiveOutput(uint8_t axis,
  698. PLSR_OUTPUT_MODE outputMode,
  699. uint32_t frequencyHz)
  700. {
  701. if (outputMode == PLSR_OUTPUT_AB)
  702. {
  703. (void)PlsrHwConfigureAbPwm(axis, frequencyHz);
  704. }
  705. else
  706. {
  707. PlsrHwConfigurePwm(axis, frequencyHz);
  708. }
  709. }
  710. static void PlsrHwBeginActiveOutput(uint8_t axis,
  711. PLSR_OUTPUT_MODE outputMode)
  712. {
  713. if (outputMode == PLSR_OUTPUT_AB)
  714. {
  715. PlsrHwBeginAbOutput(axis, 0U);
  716. }
  717. else
  718. {
  719. PlsrHwPwmBegin(axis);
  720. }
  721. }
  722. static void PlsrHwStopActiveOutput(uint8_t axis,
  723. PLSR_OUTPUT_MODE outputMode)
  724. {
  725. if ((outputMode == PLSR_OUTPUT_AB) && (PlsrHwIsAbBaseAxis(axis) != 0U))
  726. {
  727. uint8_t pairAxis = PlsrHwGetPairedAxis(axis);
  728. #ifndef PLSR_HOST_TEST
  729. uint32_t interruptState = __get_PRIMASK();
  730. __disable_irq();
  731. __DMB();
  732. /* DONE/STOP 后继续由 GPIO 保持 00,禁止已关闭 timer 泄漏残余边沿。 */
  733. PlsrHwHoldPulsePinLow(axis);
  734. PlsrHwHoldPulsePinLow(pairAxis);
  735. #endif
  736. PlsrHwStopPwmTimer(axis);
  737. PlsrHwStopPwmTimer(pairAxis);
  738. #ifndef PLSR_HOST_TEST
  739. __DMB();
  740. if (interruptState == 0UL)
  741. {
  742. __enable_irq();
  743. }
  744. #endif
  745. }
  746. else
  747. {
  748. PlsrHwStopPwmTimer(axis);
  749. }
  750. }
  751. uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber)
  752. {
  753. /* 与资源层一致的合法输出点掩码(Q0~Q7、Q10~Q17、Q20)。 */
  754. const uint32_t validOutputMask = 0x0013FCFFUL;
  755. if (pointNumber >= PLSR_HW_OUTPUT_POINT_COUNT)
  756. {
  757. return 0U;
  758. }
  759. if ((validOutputMask & (1UL << pointNumber)) == 0UL)
  760. {
  761. return 0U;
  762. }
  763. #ifndef PLSR_HOST_TEST
  764. if (PlsrHwOutputPins[pointNumber].port == NULL)
  765. {
  766. return 0U;
  767. }
  768. #endif
  769. return 1U;
  770. }
  771. PLSR_RESULT PlsrHwInit(void)
  772. {
  773. uint8_t axis;
  774. (void)memset(PlsrHwAxes, 0, sizeof(PlsrHwAxes));
  775. for (axis = 0U; axis < PLSR_HW_AXIS_COUNT; axis++)
  776. {
  777. PlsrHwAxes[axis].state = PLSR_HW_STATE_IDLE;
  778. PlsrHwAxes[axis].directionPoint = PLSR_HW_DIR_POINT_NONE;
  779. #ifdef PLSR_HOST_TEST
  780. (void)memset(&PlsrHwTimers[axis], 0, sizeof(PlsrHwTimers[axis]));
  781. #else
  782. PlsrHwTimerSetCc1e(axis, 0UL);
  783. PlsrHwTimerSetUie(axis, 0UL);
  784. PlsrHwTimerSetCc1ie(axis, 0UL);
  785. PlsrHwTimerSetCen(axis, 0UL);
  786. #endif
  787. }
  788. #ifndef PLSR_HOST_TEST
  789. {
  790. GPIO_InitTypeDef gpio;
  791. /* 1. 输出点 GPIO 时钟(DIR 点按需配置时使用)。 */
  792. __HAL_RCC_GPIOF_CLK_ENABLE();
  793. __HAL_RCC_GPIOI_CLK_ENABLE();
  794. __HAL_RCC_GPIOE_CLK_ENABLE();
  795. __HAL_RCC_GPIOG_CLK_ENABLE();
  796. __HAL_RCC_GPIOH_CLK_ENABLE();
  797. __HAL_RCC_GPIOB_CLK_ENABLE();
  798. /* 2. 上电安全:输出点保持复位默认高阻(漏型输出 = 截止 = OFF)。
  799. * 不驱动任何 Y 点,DIR 点仅在 PlsrHwSetDirLevel 时按需配置。 */
  800. /* 3. 定时器时钟。 */
  801. __HAL_RCC_TIM10_CLK_ENABLE();
  802. __HAL_RCC_TIM11_CLK_ENABLE();
  803. __HAL_RCC_TIM13_CLK_ENABLE();
  804. __HAL_RCC_TIM14_CLK_ENABLE();
  805. /* 4. 脉冲点切定时器复用(PF6/7=AF3、PF8/9=AF9)。
  806. * 定时器通道尚未使能(CC1E=0),输出级断开,无毛刺。 */
  807. gpio.Mode = GPIO_MODE_AF_PP;
  808. gpio.Pull = GPIO_NOPULL;
  809. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  810. gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7;
  811. gpio.Alternate = 3U;
  812. HAL_GPIO_Init(GPIOF, &gpio);
  813. gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9;
  814. gpio.Alternate = 9U;
  815. HAL_GPIO_Init(GPIOF, &gpio);
  816. /* 5. 更新中断 NVIC:高速计数/尾脉冲层(P3b 统一规划优先级表)。 */
  817. HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 1U, 0U);
  818. HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
  819. HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 1U, 0U);
  820. HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
  821. HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 1U, 0U);
  822. HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
  823. HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 1U, 0U);
  824. HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
  825. }
  826. #endif
  827. return PLSR_RESULT_OK;
  828. }
  829. PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params)
  830. {
  831. PLSR_HW_AXIS_STATE *state;
  832. uint8_t directionChanged = 0U;
  833. if ((axis >= PLSR_HW_AXIS_COUNT) || (params == NULL))
  834. {
  835. return PLSR_RESULT_INVALID_ARGUMENT;
  836. }
  837. if (params->targetPulses <= 0)
  838. {
  839. return PLSR_RESULT_INVALID_ARGUMENT;
  840. }
  841. if ((uint32_t)params->outputMode > (uint32_t)PLSR_OUTPUT_CW_CCW)
  842. {
  843. return PLSR_RESULT_INVALID_ARGUMENT;
  844. }
  845. if ((params->outputMode == PLSR_OUTPUT_AB)
  846. && (PlsrHwIsAbBaseAxis(axis) == 0U))
  847. {
  848. return PLSR_RESULT_INVALID_AXIS;
  849. }
  850. if (params->outputMode == PLSR_OUTPUT_CW_CCW)
  851. {
  852. return PLSR_RESULT_NOT_SUPPORTED;
  853. }
  854. state = &PlsrHwAxes[axis];
  855. if (state->state == PLSR_HW_STATE_RUNNING)
  856. {
  857. return PLSR_RESULT_BUSY;
  858. }
  859. /* 方向延时只在方向发生变化时生效(首次启动/换向/换方向点):
  860. * 段间同向衔接不再等待 10ms,直接进入 PWM 待启动。 */
  861. if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  862. {
  863. directionChanged =
  864. (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  865. || (state->directionPoint != params->directionPoint)
  866. || (state->directionPositive != params->directionPositive);
  867. }
  868. state->outputMode = params->outputMode;
  869. state->targetPulses = params->targetPulses;
  870. state->emittedPulses = 0;
  871. state->currentFrequencyHz = params->frequencyHz;
  872. state->directionPoint =
  873. (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  874. ? params->directionPoint
  875. : PLSR_HW_DIR_POINT_NONE;
  876. state->directionDelayRemainingMs =
  877. ((params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  878. && (directionChanged != 0U))
  879. ? params->directionDelayMs
  880. : 0U;
  881. state->abQuarter = 0U;
  882. state->abFrequencyPending = 0U;
  883. if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  884. {
  885. PlsrHwSetDirLevel(axis, params->directionPositive);
  886. }
  887. else
  888. {
  889. state->directionPositive =
  890. (params->directionPositive != 0U) ? 1U : 0U;
  891. }
  892. state->state = (state->directionDelayRemainingMs > 0U)
  893. ? PLSR_HW_STATE_DIR_SETTLING
  894. : PLSR_HW_STATE_PWM_PENDING;
  895. return PLSR_RESULT_OK;
  896. }
  897. PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz)
  898. {
  899. PLSR_HW_AXIS_STATE *state;
  900. if (axis >= PLSR_HW_AXIS_COUNT)
  901. {
  902. return PLSR_RESULT_INVALID_ARGUMENT;
  903. }
  904. state = &PlsrHwAxes[axis];
  905. state->currentFrequencyHz = frequencyHz;
  906. if (state->state == PLSR_HW_STATE_RUNNING)
  907. {
  908. if (frequencyHz > 0UL)
  909. {
  910. if (state->outputMode == PLSR_OUTPUT_AB)
  911. {
  912. if (PlsrHwQueueAbFrequency(axis, frequencyHz) == 0U)
  913. {
  914. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  915. }
  916. }
  917. else
  918. {
  919. /* PULSE/DIR 仍由单定时器在自身 update 边界加载预装值。 */
  920. PlsrHwConfigureActiveOutput(axis,
  921. state->outputMode,
  922. frequencyHz);
  923. }
  924. }
  925. else
  926. {
  927. PlsrHwStopActiveOutput(axis, state->outputMode);
  928. }
  929. }
  930. else if ((state->state == PLSR_HW_STATE_PWM_PENDING)
  931. && (frequencyHz > 0UL))
  932. {
  933. PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz);
  934. /* 必须先发布 RUNNING,避免启用 timer IRQ 后观察到 PWM_PENDING。 */
  935. state->state = PLSR_HW_STATE_RUNNING;
  936. PlsrHwBeginActiveOutput(axis, state->outputMode);
  937. }
  938. return PLSR_RESULT_OK;
  939. }
  940. PLSR_RESULT PlsrHwStopPulse(uint8_t axis)
  941. {
  942. PLSR_HW_AXIS_STATE *state;
  943. if (axis >= PLSR_HW_AXIS_COUNT)
  944. {
  945. return PLSR_RESULT_INVALID_ARGUMENT;
  946. }
  947. state = &PlsrHwAxes[axis];
  948. if (state->state != PLSR_HW_STATE_IDLE)
  949. {
  950. PlsrHwStopActiveOutput(axis, state->outputMode);
  951. state->abQuarter = 0U;
  952. state->abFrequencyPending = 0U;
  953. state->state = PLSR_HW_STATE_IDLE;
  954. }
  955. return PLSR_RESULT_OK;
  956. }
  957. uint8_t PlsrHwIsPulseActive(uint8_t axis)
  958. {
  959. if (axis >= PLSR_HW_AXIS_COUNT)
  960. {
  961. return 0U;
  962. }
  963. return (PlsrHwAxes[axis].state == PLSR_HW_STATE_RUNNING) ? 1U : 0U;
  964. }
  965. PLSR_HW_STATE PlsrHwGetState(uint8_t axis)
  966. {
  967. if (axis >= PLSR_HW_AXIS_COUNT)
  968. {
  969. return PLSR_HW_STATE_IDLE;
  970. }
  971. return PlsrHwAxes[axis].state;
  972. }
  973. uint32_t PlsrHwGetTimerClockHz(uint8_t axis)
  974. {
  975. if (axis >= PLSR_HW_AXIS_COUNT)
  976. {
  977. return 0UL;
  978. }
  979. return PlsrHwAxisMap[axis].timerClockHz;
  980. }
  981. /* 硬件已发出的脉冲数(profile 虚拟计数校准用,中断内递增)。 */
  982. int64_t PlsrHwGetEmittedPulses(uint8_t axis)
  983. {
  984. int64_t emittedPulses;
  985. if (axis >= PLSR_HW_AXIS_COUNT)
  986. {
  987. return 0;
  988. }
  989. #ifdef PLSR_HOST_TEST
  990. emittedPulses = PlsrHwAxes[axis].emittedPulses;
  991. #else
  992. {
  993. uint32_t interruptState = __get_PRIMASK();
  994. __disable_irq();
  995. __DMB();
  996. emittedPulses = PlsrHwAxes[axis].emittedPulses;
  997. __DMB();
  998. if (interruptState == 0UL)
  999. {
  1000. __enable_irq();
  1001. }
  1002. }
  1003. #endif
  1004. return emittedPulses;
  1005. }
  1006. void PlsrHwTick(uint8_t axis)
  1007. {
  1008. PLSR_HW_AXIS_STATE *state;
  1009. if (axis >= PLSR_HW_AXIS_COUNT)
  1010. {
  1011. return;
  1012. }
  1013. state = &PlsrHwAxes[axis];
  1014. /* 调试:每 tick 记录定时器实况(CNT 演化定位第一周期压缩)。 */
  1015. PlsrHwDbgCapture(axis, 3U);
  1016. switch (state->state)
  1017. {
  1018. case PLSR_HW_STATE_DIR_SETTLING:
  1019. if (state->directionDelayRemainingMs > 0U)
  1020. {
  1021. state->directionDelayRemainingMs--;
  1022. }
  1023. if (state->directionDelayRemainingMs == 0U)
  1024. {
  1025. state->state = PLSR_HW_STATE_PWM_PENDING;
  1026. }
  1027. break;
  1028. case PLSR_HW_STATE_PWM_PENDING:
  1029. if (state->currentFrequencyHz > 0UL)
  1030. {
  1031. PlsrHwConfigureActiveOutput(axis,
  1032. state->outputMode,
  1033. state->currentFrequencyHz);
  1034. state->state = PLSR_HW_STATE_RUNNING;
  1035. PlsrHwBeginActiveOutput(axis, state->outputMode);
  1036. }
  1037. break;
  1038. default:
  1039. break;
  1040. }
  1041. }
  1042. /* 输出定时器中断入口:PULSE/DIR 在 update 计数;AB 在落后相
  1043. * CC1 下降沿(四状态回到 00)计一个完整正交周期。 */
  1044. void PlsrHwOnTimerUpdate(uint8_t axis)
  1045. {
  1046. PLSR_HW_AXIS_STATE *state;
  1047. uint8_t ownerAxis;
  1048. uint8_t hasCc1;
  1049. if (axis >= PLSR_HW_AXIS_COUNT)
  1050. {
  1051. return;
  1052. }
  1053. /* CC1IF 无论当前状态如何都必须先清除;否则启动窗口中的杂散
  1054. * compare 标志会让共享 IRQ 持续重入,主线程无法完成 CEN 配置。 */
  1055. hasCc1 = PlsrHwTimerHasCc1if(axis);
  1056. if (hasCc1 != 0U)
  1057. {
  1058. PlsrHwTimerClearCc1if(axis);
  1059. }
  1060. ownerAxis = (uint8_t)(axis & 0xFEU);
  1061. state = &PlsrHwAxes[ownerAxis];
  1062. if ((state->state == PLSR_HW_STATE_RUNNING)
  1063. && (state->outputMode == PLSR_OUTPUT_AB))
  1064. {
  1065. if (PlsrHwTimerHasUif(axis) != 0U)
  1066. {
  1067. PlsrHwTimerClearUif(axis);
  1068. }
  1069. if ((hasCc1 == 0U) || (axis != state->abCountAxis))
  1070. {
  1071. return;
  1072. }
  1073. state->emittedPulses++;
  1074. if (state->emittedPulses >= state->targetPulses)
  1075. {
  1076. PlsrHwStopActiveOutput(ownerAxis, state->outputMode);
  1077. state->abQuarter = 0U;
  1078. state->abFrequencyPending = 0U;
  1079. state->state = PLSR_HW_STATE_DONE;
  1080. (void)PlsrPostEvent(ownerAxis, PLSR_EVENT_SEGMENT_COMPLETE);
  1081. }
  1082. else if (state->abFrequencyPending != 0U)
  1083. {
  1084. uint16_t basePsc = state->abPendingBasePsc;
  1085. uint16_t pairPsc = state->abPendingPairPsc;
  1086. uint16_t arr = state->abPendingArr;
  1087. state->abFrequencyPending = 0U;
  1088. PlsrHwLoadAbPwm(ownerAxis, basePsc, pairPsc, arr);
  1089. /* 落后相刚下降,AB=00;两路从同一个完整周期边界重定相。 */
  1090. PlsrHwBeginAbOutput(ownerAxis, 4U);
  1091. }
  1092. return;
  1093. }
  1094. if (hasCc1 != 0U)
  1095. {
  1096. /* 非运行态/非 AB 模式的 CC1 仅作为杂散标志消费。 */
  1097. return;
  1098. }
  1099. state = &PlsrHwAxes[axis];
  1100. if (PlsrHwTimerHasUif(axis) == 0U)
  1101. {
  1102. return;
  1103. }
  1104. PlsrHwTimerClearUif(axis);
  1105. if (state->state != PLSR_HW_STATE_RUNNING)
  1106. {
  1107. return;
  1108. }
  1109. if (state->outputMode != PLSR_OUTPUT_PULSE_DIR)
  1110. {
  1111. return;
  1112. }
  1113. state->emittedPulses++;
  1114. if (state->emittedPulses >= state->targetPulses)
  1115. {
  1116. /* 更新时刻 = 周期结束:关通道即完整下降沿后停止,无额外脉冲。 */
  1117. PlsrHwStopActiveOutput(axis, state->outputMode);
  1118. state->state = PLSR_HW_STATE_DONE;
  1119. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  1120. }
  1121. }
  1122. #ifdef PLSR_HOST_TEST
  1123. uint32_t PlsrHwTestGetArr(uint8_t axis)
  1124. {
  1125. return PlsrHwTimers[axis].arr;
  1126. }
  1127. uint32_t PlsrHwTestGetCcr(uint8_t axis)
  1128. {
  1129. return PlsrHwTimers[axis].ccr1;
  1130. }
  1131. uint32_t PlsrHwTestGetCnt(uint8_t axis)
  1132. {
  1133. return PlsrHwTimers[axis].cnt;
  1134. }
  1135. uint32_t PlsrHwTestGetCcmr1(uint8_t axis)
  1136. {
  1137. return PlsrHwTimers[axis].ccmr1;
  1138. }
  1139. uint32_t PlsrHwTestGetCr1(uint8_t axis)
  1140. {
  1141. return PlsrHwTimers[axis].cr1;
  1142. }
  1143. uint32_t PlsrHwTestGetPsc(uint8_t axis)
  1144. {
  1145. return PlsrHwTimers[axis].psc;
  1146. }
  1147. uint8_t PlsrHwTestGetPwmEnabled(uint8_t axis)
  1148. {
  1149. return ((PlsrHwTimers[axis].ccer & PLSR_HW_TIMER_CHANNEL1_BIT) != 0UL)
  1150. ? 1U
  1151. : 0U;
  1152. }
  1153. uint8_t PlsrHwTestGetDirLevel(uint8_t axis)
  1154. {
  1155. return PlsrHwTimers[axis].dirLevel;
  1156. }
  1157. uint8_t PlsrHwTestGetAbPhaseA(uint8_t axis)
  1158. {
  1159. const PLSR_HW_AXIS_STATE *state;
  1160. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1161. {
  1162. return 0U;
  1163. }
  1164. state = &PlsrHwAxes[axis];
  1165. if (state->directionPositive != 0U)
  1166. {
  1167. return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
  1168. ? 1U
  1169. : 0U;
  1170. }
  1171. return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
  1172. ? 1U
  1173. : 0U;
  1174. }
  1175. uint8_t PlsrHwTestGetAbPhaseB(uint8_t axis)
  1176. {
  1177. const PLSR_HW_AXIS_STATE *state;
  1178. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1179. {
  1180. return 0U;
  1181. }
  1182. state = &PlsrHwAxes[axis];
  1183. if (state->directionPositive != 0U)
  1184. {
  1185. return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
  1186. ? 1U
  1187. : 0U;
  1188. }
  1189. return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
  1190. ? 1U
  1191. : 0U;
  1192. }
  1193. uint8_t PlsrHwTestGetAbQuarter(uint8_t axis)
  1194. {
  1195. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1196. {
  1197. return 0U;
  1198. }
  1199. return PlsrHwAxes[axis].abQuarter;
  1200. }
  1201. void PlsrHwTestAdvanceAbQuarter(uint8_t axis)
  1202. {
  1203. PLSR_HW_AXIS_STATE *state;
  1204. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  1205. {
  1206. return;
  1207. }
  1208. state = &PlsrHwAxes[axis];
  1209. if ((state->state != PLSR_HW_STATE_RUNNING)
  1210. || (state->outputMode != PLSR_OUTPUT_AB))
  1211. {
  1212. return;
  1213. }
  1214. state->abQuarter = (uint8_t)((state->abQuarter + 1U)
  1215. % PLSR_HW_AB_QUARTER_COUNT);
  1216. if (state->abQuarter == 0U)
  1217. {
  1218. /* 模拟目标板落后相 CC1 下降沿中断,复用生产计数路径。 */
  1219. PlsrHwTimers[state->abCountAxis].sr |= PLSR_HW_TIMER_CC1_BIT;
  1220. PlsrHwOnTimerUpdate(state->abCountAxis);
  1221. }
  1222. }
  1223. void PlsrHwTestTriggerUpdate(uint8_t axis)
  1224. {
  1225. if (axis < PLSR_HW_AXIS_COUNT)
  1226. {
  1227. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_UPDATE_BIT;
  1228. }
  1229. PlsrHwOnTimerUpdate(axis);
  1230. }
  1231. #endif
  1232. #ifndef PLSR_HOST_TEST
  1233. void TIM1_UP_TIM10_IRQHandler(void)
  1234. {
  1235. PlsrHwOnTimerUpdate(0U);
  1236. }
  1237. void TIM8_UP_TIM13_IRQHandler(void)
  1238. {
  1239. PlsrHwOnTimerUpdate(1U);
  1240. }
  1241. void TIM1_TRG_COM_TIM11_IRQHandler(void)
  1242. {
  1243. PlsrHwOnTimerUpdate(2U);
  1244. }
  1245. void TIM8_TRG_COM_TIM14_IRQHandler(void)
  1246. {
  1247. PlsrHwOnTimerUpdate(3U);
  1248. }
  1249. #endif