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

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