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

933 lines
25 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_OUTPUT_POINT_COUNT (21U)
  13. #define PLSR_HW_DBG_SNAPSHOT_COUNT (160U)
  14. #define PLSR_HW_AB_QUARTER_COUNT (4U)
  15. typedef struct
  16. {
  17. uint32_t timerClockHz;
  18. uint8_t directionPoint; /* 0xFF = 无 */
  19. #ifndef PLSR_HOST_TEST
  20. TIM_TypeDef *timer;
  21. GPIO_TypeDef *gpioPort;
  22. uint16_t gpioPin;
  23. uint8_t afMode;
  24. IRQn_Type irq;
  25. #endif
  26. } PLSR_HW_AXIS_MAP;
  27. #ifndef PLSR_HOST_TEST
  28. /* 输出点(Y 点号)→ GPIO 引脚:XDM-60T4-E 原理图。
  29. * 点号 8/9/18/19 不存在(资源层掩码 0x0013FCFF 已约束)。 */
  30. typedef struct
  31. {
  32. GPIO_TypeDef *port;
  33. uint16_t pin;
  34. } PLSR_HW_OUTPUT_PIN;
  35. static const PLSR_HW_OUTPUT_PIN PlsrHwOutputPins[PLSR_HW_OUTPUT_POINT_COUNT] =
  36. {
  37. {GPIOF, GPIO_PIN_6}, /* Y0 */
  38. {GPIOF, GPIO_PIN_8}, /* Y1 */
  39. {GPIOF, GPIO_PIN_7}, /* Y2 */
  40. {GPIOF, GPIO_PIN_9}, /* Y3 */
  41. {GPIOI, GPIO_PIN_8}, /* Y4 */
  42. {GPIOE, GPIO_PIN_6}, /* Y5 */
  43. {GPIOE, GPIO_PIN_5}, /* Y6 */
  44. {GPIOE, GPIO_PIN_4}, /* Y7 */
  45. {NULL, 0U}, /* Y8 */
  46. {NULL, 0U}, /* Y9 */
  47. {GPIOG, GPIO_PIN_7}, /* Y10 */
  48. {GPIOG, GPIO_PIN_6}, /* Y11 */
  49. {GPIOH, GPIO_PIN_9}, /* Y12 */
  50. {GPIOH, GPIO_PIN_8}, /* Y13 */
  51. {GPIOH, GPIO_PIN_7}, /* Y14 */
  52. {GPIOH, GPIO_PIN_6}, /* Y15 */
  53. {GPIOF, GPIO_PIN_11}, /* Y16 */
  54. {GPIOB, GPIO_PIN_0}, /* Y17 */
  55. {NULL, 0U}, /* Y18 */
  56. {NULL, 0U}, /* Y19 */
  57. {GPIOH, GPIO_PIN_5} /* Y20 */
  58. };
  59. #endif
  60. /* Q0~Q3 定时器:XDM-60T4-E。
  61. * PF6=TIM10_CH1(AF3)、PF7=TIM11_CH1(AF3)、PF8=TIM13_CH1(AF9)、PF9=TIM14_CH1(AF9)。
  62. * 定时器时钟由 RCC 实际配置计算(APB2 分频≠1 时定时器时钟×2)。 */
  63. static const PLSR_HW_AXIS_MAP PlsrHwAxisMap[PLSR_HW_AXIS_COUNT] =
  64. {
  65. #ifndef PLSR_HOST_TEST
  66. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM10, GPIOF, GPIO_PIN_6, 3U, TIM1_UP_TIM10_IRQn},
  67. {84000000UL, PLSR_HW_DIR_POINT_NONE, TIM13, GPIOF, GPIO_PIN_8, 9U, TIM8_UP_TIM13_IRQn},
  68. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM11, GPIOF, GPIO_PIN_7, 3U, TIM1_TRG_COM_TIM11_IRQn},
  69. {84000000UL, PLSR_HW_DIR_POINT_NONE, TIM14, GPIOF, GPIO_PIN_9, 9U, TIM8_TRG_COM_TIM14_IRQn}
  70. #else
  71. {168000000UL, PLSR_HW_DIR_POINT_NONE},
  72. {84000000UL, PLSR_HW_DIR_POINT_NONE},
  73. {168000000UL, PLSR_HW_DIR_POINT_NONE},
  74. {84000000UL, PLSR_HW_DIR_POINT_NONE}
  75. #endif
  76. };
  77. /* host 测试:模拟定时器寄存器。 */
  78. #ifdef PLSR_HOST_TEST
  79. typedef struct
  80. {
  81. uint32_t cr1;
  82. uint32_t dier;
  83. uint32_t sr;
  84. uint32_t psc;
  85. uint32_t arr;
  86. uint32_t ccr1;
  87. uint32_t ccmr1;
  88. uint32_t ccer;
  89. uint8_t dirLevel;
  90. } PLSR_HW_TIMER_REGS;
  91. static PLSR_HW_TIMER_REGS PlsrHwTimers[PLSR_HW_AXIS_COUNT];
  92. #endif
  93. typedef struct
  94. {
  95. PLSR_HW_STATE state;
  96. PLSR_OUTPUT_MODE outputMode;
  97. uint32_t currentFrequencyHz;
  98. int64_t targetPulses;
  99. int64_t emittedPulses;
  100. uint16_t directionDelayRemainingMs;
  101. uint8_t directionPoint;
  102. uint8_t directionPositive;
  103. uint8_t abQuarter;
  104. } PLSR_HW_AXIS_STATE;
  105. static PLSR_HW_AXIS_STATE PlsrHwAxes[PLSR_HW_AXIS_COUNT];
  106. /* 调试快照:当前上板自测只记录 Q0 的 160 ms,避免四轴
  107. * PlsrHwTick 互相混入,同时控制临时 RAM 占用。reason=0 表示 PwmBegin,
  108. * reason=3 表示 1 ms HAL tick。 */
  109. #ifndef PLSR_HOST_TEST
  110. typedef struct
  111. {
  112. uint8_t reason; /* 0=PwmBegin(UG后) 3=PlsrHwTick(每1ms) */
  113. uint32_t psc;
  114. uint32_t arr;
  115. uint32_t ccr;
  116. uint32_t cnt;
  117. uint32_t frequencyHz;
  118. int64_t emittedPulses;
  119. } PLSR_HW_DBG_SNAP;
  120. static PLSR_HW_DBG_SNAP PlsrHwDbgSnap[PLSR_HW_DBG_SNAPSHOT_COUNT];
  121. static volatile uint16_t PlsrHwDbgCount;
  122. static void PlsrHwDbgCapture(uint8_t axis, uint8_t reason)
  123. {
  124. if (axis != 0U)
  125. {
  126. return;
  127. }
  128. if (reason == 0U)
  129. {
  130. PlsrHwDbgCount = 0U;
  131. }
  132. if (PlsrHwDbgCount < PLSR_HW_DBG_SNAPSHOT_COUNT)
  133. {
  134. PLSR_HW_DBG_SNAP *snap = &PlsrHwDbgSnap[PlsrHwDbgCount++];
  135. snap->reason = reason;
  136. snap->psc = PlsrHwAxisMap[axis].timer->PSC;
  137. snap->arr = PlsrHwAxisMap[axis].timer->ARR;
  138. snap->ccr = PlsrHwAxisMap[axis].timer->CCR1;
  139. snap->cnt = PlsrHwAxisMap[axis].timer->CNT;
  140. snap->frequencyHz = PlsrHwAxes[axis].currentFrequencyHz;
  141. snap->emittedPulses = PlsrHwAxes[axis].emittedPulses;
  142. }
  143. }
  144. #else
  145. #define PlsrHwDbgCapture(axis, reason) ((void)0)
  146. #endif
  147. /* ---- 定时器寄存器访问抽象(host 模拟 / 生产真实) ---- */
  148. static void PlsrHwTimerSetArr(uint8_t axis, uint32_t value)
  149. {
  150. #ifdef PLSR_HOST_TEST
  151. PlsrHwTimers[axis].arr = value;
  152. #else
  153. PlsrHwAxisMap[axis].timer->ARR = value;
  154. #endif
  155. }
  156. static void PlsrHwTimerSetPsc(uint8_t axis, uint32_t value)
  157. {
  158. #ifdef PLSR_HOST_TEST
  159. PlsrHwTimers[axis].psc = value;
  160. #else
  161. PlsrHwAxisMap[axis].timer->PSC = value;
  162. #endif
  163. }
  164. static void PlsrHwTimerSetCcr(uint8_t axis, uint32_t value)
  165. {
  166. #ifdef PLSR_HOST_TEST
  167. PlsrHwTimers[axis].ccr1 = value;
  168. #else
  169. PlsrHwAxisMap[axis].timer->CCR1 = value;
  170. #endif
  171. }
  172. static void PlsrHwTimerSetCen(uint8_t axis, uint32_t value)
  173. {
  174. #ifdef PLSR_HOST_TEST
  175. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0001UL) | value;
  176. #else
  177. if (value != 0UL)
  178. {
  179. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_CEN;
  180. }
  181. else
  182. {
  183. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_CEN;
  184. }
  185. #endif
  186. }
  187. static void PlsrHwTimerSetCc1e(uint8_t axis, uint32_t value)
  188. {
  189. #ifdef PLSR_HOST_TEST
  190. PlsrHwTimers[axis].ccer = (PlsrHwTimers[axis].ccer & ~0x0001UL) | value;
  191. #else
  192. if (value != 0UL)
  193. {
  194. PlsrHwAxisMap[axis].timer->CCER |= TIM_CCER_CC1E;
  195. }
  196. else
  197. {
  198. PlsrHwAxisMap[axis].timer->CCER &= ~TIM_CCER_CC1E;
  199. }
  200. #endif
  201. }
  202. /* 通道 1 输出模式 = PWM 模式 1(OC1M=110)+ CCR 预装载(OC1PE)。
  203. * 上电复位后 CCMR1=0(冻结),通道输出恒定电平、无方波,必须显式配置。 */
  204. static void PlsrHwTimerSetPwmMode1(uint8_t axis)
  205. {
  206. #ifdef PLSR_HOST_TEST
  207. PlsrHwTimers[axis].ccmr1 = 0x0068UL;
  208. #else
  209. PlsrHwAxisMap[axis].timer->CCMR1 = (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)
  210. | TIM_CCMR1_OC1PE;
  211. #endif
  212. }
  213. static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value)
  214. {
  215. #ifdef PLSR_HOST_TEST
  216. PlsrHwTimers[axis].dier = (PlsrHwTimers[axis].dier & ~0x0001UL) | value;
  217. #else
  218. if (value != 0UL)
  219. {
  220. PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_UIE;
  221. }
  222. else
  223. {
  224. PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_UIE;
  225. }
  226. #endif
  227. }
  228. static void PlsrHwTimerClearUif(uint8_t axis)
  229. {
  230. #ifdef PLSR_HOST_TEST
  231. PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_UPDATE_BIT;
  232. #else
  233. PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_UIF;
  234. #endif
  235. }
  236. static uint8_t PlsrHwTimerHasUif(uint8_t axis)
  237. {
  238. #ifdef PLSR_HOST_TEST
  239. return ((PlsrHwTimers[axis].sr & PLSR_HW_TIMER_UPDATE_BIT) != 0UL)
  240. ? 1U
  241. : 0U;
  242. #else
  243. return ((PlsrHwAxisMap[axis].timer->SR & TIM_SR_UIF) != 0UL) ? 1U : 0U;
  244. #endif
  245. }
  246. /* ---- DIR 输出 ----
  247. * XDM 为晶体管(NPN 漏型)输出:ON(导通)= 引脚低电平。
  248. * 信捷正逻辑:正向发脉冲时方向端子置 ON(低)。 */
  249. static void PlsrHwSetDirLevel(uint8_t axis, uint8_t positive)
  250. {
  251. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  252. state->directionPositive = (positive != 0U) ? 1U : 0U;
  253. if (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  254. {
  255. return;
  256. }
  257. #ifdef PLSR_HOST_TEST
  258. PlsrHwTimers[axis].dirLevel = (positive != 0U) ? 1U : 0U;
  259. #else
  260. if (state->directionPoint < PLSR_HW_OUTPUT_POINT_COUNT)
  261. {
  262. const PLSR_HW_OUTPUT_PIN *pin =
  263. &PlsrHwOutputPins[state->directionPoint];
  264. GPIO_InitTypeDef gpio;
  265. if (pin->port != NULL)
  266. {
  267. /* DIR 点按需配置为推挽输出(上电默认高阻=截止,安全)。 */
  268. gpio.Pin = pin->pin;
  269. gpio.Mode = GPIO_MODE_OUTPUT_PP;
  270. gpio.Pull = GPIO_NOPULL;
  271. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  272. HAL_GPIO_Init(pin->port, &gpio);
  273. /* 漏型输出:ON(导通)= 低电平。 */
  274. HAL_GPIO_WritePin(pin->port,
  275. pin->pin,
  276. (positive != 0U) ? GPIO_PIN_RESET
  277. : GPIO_PIN_SET);
  278. }
  279. }
  280. #endif
  281. }
  282. /* ---- PWM 启停 ----
  283. * ARR/CCR 使用预装载(ARPE/OC1PE):运行中调频写入延迟到更新事件生效,
  284. * 避免 ARR 变小瞬间 CNT 超调提前回绕(每段加速会多出 ~ln(f1/f0) 个假脉冲)。
  285. * 首次启动用 EGR.UG 把预装载值加载到影子寄存器,杜绝首个周期用复位值。 */
  286. static void PlsrHwTimerSetArpe(uint8_t axis, uint32_t value)
  287. {
  288. #ifdef PLSR_HOST_TEST
  289. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0080UL)
  290. | ((value != 0UL) ? 0x0080UL : 0UL);
  291. #else
  292. if (value != 0UL)
  293. {
  294. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_ARPE;
  295. }
  296. else
  297. {
  298. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_ARPE;
  299. }
  300. #endif
  301. }
  302. /* 生成更新事件:立即加载 ARR/CCR/PSC 影子寄存器(启动时用)。 */
  303. static void PlsrHwTimerSetUg(uint8_t axis)
  304. {
  305. #ifdef PLSR_HOST_TEST
  306. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_UPDATE_BIT;
  307. #else
  308. PlsrHwAxisMap[axis].timer->EGR = TIM_EGR_UG;
  309. #endif
  310. }
  311. /* 配置 PWM 定时器(预装载写入;启动/调频共用,不触碰使能位)。 */
  312. static void PlsrHwConfigurePwm(uint8_t axis, uint32_t frequencyHz)
  313. {
  314. uint16_t psc;
  315. uint16_t arr;
  316. if (PlsrCalculateTimerDivider(PlsrHwAxisMap[axis].timerClockHz,
  317. frequencyHz,
  318. &psc,
  319. &arr) != PLSR_RESULT_OK)
  320. {
  321. return;
  322. }
  323. PlsrHwTimerSetPsc(axis, psc);
  324. PlsrHwTimerSetArr(axis, arr);
  325. PlsrHwTimerSetCcr(axis, (uint32_t)arr / 2UL); /* 50% 占空比 */
  326. PlsrHwTimerSetPwmMode1(axis);
  327. PlsrHwTimerSetArpe(axis, 1UL);
  328. }
  329. /* 首次启动输出:加载影子寄存器后使能更新中断、通道与计数。 */
  330. static void PlsrHwPwmBegin(uint8_t axis)
  331. {
  332. PlsrHwTimerSetUg(axis);
  333. /* UG 只用于加载影子寄存器,不是物理脉冲,不得计数。 */
  334. PlsrHwTimerClearUif(axis);
  335. PlsrHwDbgCapture(axis, 0U);
  336. PlsrHwTimerSetUie(axis, 1UL);
  337. PlsrHwTimerSetCc1e(axis, 1UL);
  338. PlsrHwTimerSetCen(axis, 1UL);
  339. }
  340. static void PlsrHwStopPwmTimer(uint8_t axis)
  341. {
  342. PlsrHwTimerSetCc1e(axis, 0UL);
  343. PlsrHwTimerSetUie(axis, 0UL);
  344. PlsrHwTimerSetCen(axis, 0UL);
  345. }
  346. static uint8_t PlsrHwIsAbBaseAxis(uint8_t axis)
  347. {
  348. return ((axis == 0U) || (axis == 2U)) ? 1U : 0U;
  349. }
  350. #ifdef PLSR_HOST_TEST
  351. static uint8_t PlsrHwGetPairedAxis(uint8_t axis)
  352. {
  353. return (uint8_t)(axis + 1U);
  354. }
  355. #endif
  356. /* P3b-1:AB 正交相序先在 host 模型中闭环。真实 STM32 双定时器的
  357. * 同步启动、相位偏置和安全停止将在 P3b-2 接入。 */
  358. static void PlsrHwConfigureActiveOutput(uint8_t axis,
  359. PLSR_OUTPUT_MODE outputMode,
  360. uint32_t frequencyHz)
  361. {
  362. PlsrHwConfigurePwm(axis, frequencyHz);
  363. #ifdef PLSR_HOST_TEST
  364. if (outputMode == PLSR_OUTPUT_AB)
  365. {
  366. PlsrHwConfigurePwm(PlsrHwGetPairedAxis(axis), frequencyHz);
  367. }
  368. #else
  369. (void)outputMode;
  370. #endif
  371. }
  372. static void PlsrHwBeginActiveOutput(uint8_t axis,
  373. PLSR_OUTPUT_MODE outputMode)
  374. {
  375. PlsrHwPwmBegin(axis);
  376. #ifdef PLSR_HOST_TEST
  377. if (outputMode == PLSR_OUTPUT_AB)
  378. {
  379. PlsrHwPwmBegin(PlsrHwGetPairedAxis(axis));
  380. }
  381. #else
  382. (void)outputMode;
  383. #endif
  384. }
  385. static void PlsrHwStopActiveOutput(uint8_t axis,
  386. PLSR_OUTPUT_MODE outputMode)
  387. {
  388. PlsrHwStopPwmTimer(axis);
  389. #ifdef PLSR_HOST_TEST
  390. if ((outputMode == PLSR_OUTPUT_AB) && (PlsrHwIsAbBaseAxis(axis) != 0U))
  391. {
  392. PlsrHwStopPwmTimer(PlsrHwGetPairedAxis(axis));
  393. }
  394. #else
  395. (void)outputMode;
  396. #endif
  397. }
  398. uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber)
  399. {
  400. /* 与资源层一致的合法输出点掩码(Q0~Q7、Q10~Q17、Q20)。 */
  401. const uint32_t validOutputMask = 0x0013FCFFUL;
  402. if (pointNumber >= PLSR_HW_OUTPUT_POINT_COUNT)
  403. {
  404. return 0U;
  405. }
  406. if ((validOutputMask & (1UL << pointNumber)) == 0UL)
  407. {
  408. return 0U;
  409. }
  410. #ifndef PLSR_HOST_TEST
  411. if (PlsrHwOutputPins[pointNumber].port == NULL)
  412. {
  413. return 0U;
  414. }
  415. #endif
  416. return 1U;
  417. }
  418. PLSR_RESULT PlsrHwInit(void)
  419. {
  420. uint8_t axis;
  421. (void)memset(PlsrHwAxes, 0, sizeof(PlsrHwAxes));
  422. for (axis = 0U; axis < PLSR_HW_AXIS_COUNT; axis++)
  423. {
  424. PlsrHwAxes[axis].state = PLSR_HW_STATE_IDLE;
  425. PlsrHwAxes[axis].directionPoint = PLSR_HW_DIR_POINT_NONE;
  426. #ifdef PLSR_HOST_TEST
  427. (void)memset(&PlsrHwTimers[axis], 0, sizeof(PlsrHwTimers[axis]));
  428. #else
  429. PlsrHwTimerSetCc1e(axis, 0UL);
  430. PlsrHwTimerSetUie(axis, 0UL);
  431. PlsrHwTimerSetCen(axis, 0UL);
  432. #endif
  433. }
  434. #ifndef PLSR_HOST_TEST
  435. {
  436. GPIO_InitTypeDef gpio;
  437. /* 1. 输出点 GPIO 时钟(DIR 点按需配置时使用)。 */
  438. __HAL_RCC_GPIOF_CLK_ENABLE();
  439. __HAL_RCC_GPIOI_CLK_ENABLE();
  440. __HAL_RCC_GPIOE_CLK_ENABLE();
  441. __HAL_RCC_GPIOG_CLK_ENABLE();
  442. __HAL_RCC_GPIOH_CLK_ENABLE();
  443. __HAL_RCC_GPIOB_CLK_ENABLE();
  444. /* 2. 上电安全:输出点保持复位默认高阻(漏型输出 = 截止 = OFF)。
  445. * 不驱动任何 Y 点,DIR 点仅在 PlsrHwSetDirLevel 时按需配置。 */
  446. /* 3. 定时器时钟。 */
  447. __HAL_RCC_TIM10_CLK_ENABLE();
  448. __HAL_RCC_TIM11_CLK_ENABLE();
  449. __HAL_RCC_TIM13_CLK_ENABLE();
  450. __HAL_RCC_TIM14_CLK_ENABLE();
  451. /* 4. 脉冲点切定时器复用(PF6/7=AF3、PF8/9=AF9)。
  452. * 定时器通道尚未使能(CC1E=0),输出级断开,无毛刺。 */
  453. gpio.Mode = GPIO_MODE_AF_PP;
  454. gpio.Pull = GPIO_NOPULL;
  455. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  456. gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7;
  457. gpio.Alternate = 3U;
  458. HAL_GPIO_Init(GPIOF, &gpio);
  459. gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9;
  460. gpio.Alternate = 9U;
  461. HAL_GPIO_Init(GPIOF, &gpio);
  462. /* 5. 更新中断 NVIC:高速计数/尾脉冲层(P3b 统一规划优先级表)。 */
  463. HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 1U, 0U);
  464. HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
  465. HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 1U, 0U);
  466. HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
  467. HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 1U, 0U);
  468. HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
  469. HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 1U, 0U);
  470. HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
  471. }
  472. #endif
  473. return PLSR_RESULT_OK;
  474. }
  475. PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params)
  476. {
  477. PLSR_HW_AXIS_STATE *state;
  478. uint8_t directionChanged = 0U;
  479. if ((axis >= PLSR_HW_AXIS_COUNT) || (params == NULL))
  480. {
  481. return PLSR_RESULT_INVALID_ARGUMENT;
  482. }
  483. if (params->targetPulses <= 0)
  484. {
  485. return PLSR_RESULT_INVALID_ARGUMENT;
  486. }
  487. if ((uint32_t)params->outputMode > (uint32_t)PLSR_OUTPUT_CW_CCW)
  488. {
  489. return PLSR_RESULT_INVALID_ARGUMENT;
  490. }
  491. if ((params->outputMode == PLSR_OUTPUT_AB)
  492. && (PlsrHwIsAbBaseAxis(axis) == 0U))
  493. {
  494. return PLSR_RESULT_INVALID_AXIS;
  495. }
  496. if (params->outputMode == PLSR_OUTPUT_CW_CCW)
  497. {
  498. return PLSR_RESULT_NOT_SUPPORTED;
  499. }
  500. #ifndef PLSR_HOST_TEST
  501. if (params->outputMode == PLSR_OUTPUT_AB)
  502. {
  503. /* P3b-1 只交付可验证的 host 相序模型;禁止目标板误输出成
  504. * 单路 PULSE/DIR。P3b-2 接入双定时器后移除此保护。 */
  505. return PLSR_RESULT_NOT_SUPPORTED;
  506. }
  507. #endif
  508. state = &PlsrHwAxes[axis];
  509. if (state->state == PLSR_HW_STATE_RUNNING)
  510. {
  511. return PLSR_RESULT_BUSY;
  512. }
  513. /* 方向延时只在方向发生变化时生效(首次启动/换向/换方向点):
  514. * 段间同向衔接不再等待 10ms,直接进入 PWM 待启动。 */
  515. if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  516. {
  517. directionChanged =
  518. (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  519. || (state->directionPoint != params->directionPoint)
  520. || (state->directionPositive != params->directionPositive);
  521. }
  522. state->outputMode = params->outputMode;
  523. state->targetPulses = params->targetPulses;
  524. state->emittedPulses = 0;
  525. state->currentFrequencyHz = params->frequencyHz;
  526. state->directionPoint =
  527. (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  528. ? params->directionPoint
  529. : PLSR_HW_DIR_POINT_NONE;
  530. state->directionDelayRemainingMs =
  531. ((params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  532. && (directionChanged != 0U))
  533. ? params->directionDelayMs
  534. : 0U;
  535. state->abQuarter = 0U;
  536. if (params->outputMode == PLSR_OUTPUT_PULSE_DIR)
  537. {
  538. PlsrHwSetDirLevel(axis, params->directionPositive);
  539. }
  540. else
  541. {
  542. state->directionPositive =
  543. (params->directionPositive != 0U) ? 1U : 0U;
  544. }
  545. state->state = (state->directionDelayRemainingMs > 0U)
  546. ? PLSR_HW_STATE_DIR_SETTLING
  547. : PLSR_HW_STATE_PWM_PENDING;
  548. return PLSR_RESULT_OK;
  549. }
  550. PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz)
  551. {
  552. PLSR_HW_AXIS_STATE *state;
  553. if (axis >= PLSR_HW_AXIS_COUNT)
  554. {
  555. return PLSR_RESULT_INVALID_ARGUMENT;
  556. }
  557. state = &PlsrHwAxes[axis];
  558. state->currentFrequencyHz = frequencyHz;
  559. if (state->state == PLSR_HW_STATE_RUNNING)
  560. {
  561. if (frequencyHz > 0UL)
  562. {
  563. /* 运行中调频:预装载写入,更新事件时生效,不触碰使能位。 */
  564. PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz);
  565. }
  566. else
  567. {
  568. PlsrHwStopActiveOutput(axis, state->outputMode);
  569. }
  570. }
  571. else if ((state->state == PLSR_HW_STATE_PWM_PENDING)
  572. && (frequencyHz > 0UL))
  573. {
  574. PlsrHwConfigureActiveOutput(axis, state->outputMode, frequencyHz);
  575. PlsrHwBeginActiveOutput(axis, state->outputMode);
  576. state->state = PLSR_HW_STATE_RUNNING;
  577. }
  578. return PLSR_RESULT_OK;
  579. }
  580. PLSR_RESULT PlsrHwStopPulse(uint8_t axis)
  581. {
  582. PLSR_HW_AXIS_STATE *state;
  583. if (axis >= PLSR_HW_AXIS_COUNT)
  584. {
  585. return PLSR_RESULT_INVALID_ARGUMENT;
  586. }
  587. state = &PlsrHwAxes[axis];
  588. if (state->state != PLSR_HW_STATE_IDLE)
  589. {
  590. PlsrHwStopActiveOutput(axis, state->outputMode);
  591. state->abQuarter = 0U;
  592. state->state = PLSR_HW_STATE_IDLE;
  593. }
  594. return PLSR_RESULT_OK;
  595. }
  596. uint8_t PlsrHwIsPulseActive(uint8_t axis)
  597. {
  598. if (axis >= PLSR_HW_AXIS_COUNT)
  599. {
  600. return 0U;
  601. }
  602. return (PlsrHwAxes[axis].state == PLSR_HW_STATE_RUNNING) ? 1U : 0U;
  603. }
  604. PLSR_HW_STATE PlsrHwGetState(uint8_t axis)
  605. {
  606. if (axis >= PLSR_HW_AXIS_COUNT)
  607. {
  608. return PLSR_HW_STATE_IDLE;
  609. }
  610. return PlsrHwAxes[axis].state;
  611. }
  612. uint32_t PlsrHwGetTimerClockHz(uint8_t axis)
  613. {
  614. if (axis >= PLSR_HW_AXIS_COUNT)
  615. {
  616. return 0UL;
  617. }
  618. return PlsrHwAxisMap[axis].timerClockHz;
  619. }
  620. /* 硬件已发出的脉冲数(profile 虚拟计数校准用,中断内递增)。 */
  621. int64_t PlsrHwGetEmittedPulses(uint8_t axis)
  622. {
  623. int64_t emittedPulses;
  624. if (axis >= PLSR_HW_AXIS_COUNT)
  625. {
  626. return 0;
  627. }
  628. #ifdef PLSR_HOST_TEST
  629. emittedPulses = PlsrHwAxes[axis].emittedPulses;
  630. #else
  631. {
  632. uint32_t interruptState = __get_PRIMASK();
  633. __disable_irq();
  634. __DMB();
  635. emittedPulses = PlsrHwAxes[axis].emittedPulses;
  636. __DMB();
  637. if (interruptState == 0UL)
  638. {
  639. __enable_irq();
  640. }
  641. }
  642. #endif
  643. return emittedPulses;
  644. }
  645. void PlsrHwTick(uint8_t axis)
  646. {
  647. PLSR_HW_AXIS_STATE *state;
  648. if (axis >= PLSR_HW_AXIS_COUNT)
  649. {
  650. return;
  651. }
  652. state = &PlsrHwAxes[axis];
  653. /* 调试:每 tick 记录定时器实况(CNT 演化定位第一周期压缩)。 */
  654. PlsrHwDbgCapture(axis, 3U);
  655. switch (state->state)
  656. {
  657. case PLSR_HW_STATE_DIR_SETTLING:
  658. if (state->directionDelayRemainingMs > 0U)
  659. {
  660. state->directionDelayRemainingMs--;
  661. }
  662. if (state->directionDelayRemainingMs == 0U)
  663. {
  664. state->state = PLSR_HW_STATE_PWM_PENDING;
  665. }
  666. break;
  667. case PLSR_HW_STATE_PWM_PENDING:
  668. if (state->currentFrequencyHz > 0UL)
  669. {
  670. PlsrHwConfigureActiveOutput(axis,
  671. state->outputMode,
  672. state->currentFrequencyHz);
  673. PlsrHwBeginActiveOutput(axis, state->outputMode);
  674. state->state = PLSR_HW_STATE_RUNNING;
  675. }
  676. break;
  677. default:
  678. break;
  679. }
  680. }
  681. /* 输出定时器更新中断:每周期末触发一次(=1 个脉冲)。 */
  682. void PlsrHwOnTimerUpdate(uint8_t axis)
  683. {
  684. PLSR_HW_AXIS_STATE *state;
  685. if (axis >= PLSR_HW_AXIS_COUNT)
  686. {
  687. return;
  688. }
  689. state = &PlsrHwAxes[axis];
  690. if (PlsrHwTimerHasUif(axis) == 0U)
  691. {
  692. return;
  693. }
  694. PlsrHwTimerClearUif(axis);
  695. if (state->state != PLSR_HW_STATE_RUNNING)
  696. {
  697. return;
  698. }
  699. if (state->outputMode != PLSR_OUTPUT_PULSE_DIR)
  700. {
  701. /* AB host 模型按四分之一周期推进,不能把任一物理定时器的
  702. * update 直接当成完整 AB 指令脉冲。 */
  703. return;
  704. }
  705. state->emittedPulses++;
  706. if (state->emittedPulses >= state->targetPulses)
  707. {
  708. /* 更新时刻 = 周期结束:关通道即完整下降沿后停止,无额外脉冲。 */
  709. PlsrHwStopActiveOutput(axis, state->outputMode);
  710. state->state = PLSR_HW_STATE_DONE;
  711. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  712. }
  713. }
  714. #ifdef PLSR_HOST_TEST
  715. uint32_t PlsrHwTestGetArr(uint8_t axis)
  716. {
  717. return PlsrHwTimers[axis].arr;
  718. }
  719. uint32_t PlsrHwTestGetCcr(uint8_t axis)
  720. {
  721. return PlsrHwTimers[axis].ccr1;
  722. }
  723. uint32_t PlsrHwTestGetCcmr1(uint8_t axis)
  724. {
  725. return PlsrHwTimers[axis].ccmr1;
  726. }
  727. uint32_t PlsrHwTestGetCr1(uint8_t axis)
  728. {
  729. return PlsrHwTimers[axis].cr1;
  730. }
  731. uint32_t PlsrHwTestGetPsc(uint8_t axis)
  732. {
  733. return PlsrHwTimers[axis].psc;
  734. }
  735. uint8_t PlsrHwTestGetPwmEnabled(uint8_t axis)
  736. {
  737. return ((PlsrHwTimers[axis].ccer & PLSR_HW_TIMER_CHANNEL1_BIT) != 0UL)
  738. ? 1U
  739. : 0U;
  740. }
  741. uint8_t PlsrHwTestGetDirLevel(uint8_t axis)
  742. {
  743. return PlsrHwTimers[axis].dirLevel;
  744. }
  745. uint8_t PlsrHwTestGetAbPhaseA(uint8_t axis)
  746. {
  747. const PLSR_HW_AXIS_STATE *state;
  748. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  749. {
  750. return 0U;
  751. }
  752. state = &PlsrHwAxes[axis];
  753. if (state->directionPositive != 0U)
  754. {
  755. return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
  756. ? 1U
  757. : 0U;
  758. }
  759. return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
  760. ? 1U
  761. : 0U;
  762. }
  763. uint8_t PlsrHwTestGetAbPhaseB(uint8_t axis)
  764. {
  765. const PLSR_HW_AXIS_STATE *state;
  766. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  767. {
  768. return 0U;
  769. }
  770. state = &PlsrHwAxes[axis];
  771. if (state->directionPositive != 0U)
  772. {
  773. return ((state->abQuarter == 2U) || (state->abQuarter == 3U))
  774. ? 1U
  775. : 0U;
  776. }
  777. return ((state->abQuarter == 1U) || (state->abQuarter == 2U))
  778. ? 1U
  779. : 0U;
  780. }
  781. uint8_t PlsrHwTestGetAbQuarter(uint8_t axis)
  782. {
  783. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  784. {
  785. return 0U;
  786. }
  787. return PlsrHwAxes[axis].abQuarter;
  788. }
  789. void PlsrHwTestAdvanceAbQuarter(uint8_t axis)
  790. {
  791. PLSR_HW_AXIS_STATE *state;
  792. if ((axis >= PLSR_HW_AXIS_COUNT) || (PlsrHwIsAbBaseAxis(axis) == 0U))
  793. {
  794. return;
  795. }
  796. state = &PlsrHwAxes[axis];
  797. if ((state->state != PLSR_HW_STATE_RUNNING)
  798. || (state->outputMode != PLSR_OUTPUT_AB))
  799. {
  800. return;
  801. }
  802. state->abQuarter = (uint8_t)((state->abQuarter + 1U)
  803. % PLSR_HW_AB_QUARTER_COUNT);
  804. if (state->abQuarter == 0U)
  805. {
  806. state->emittedPulses++;
  807. if (state->emittedPulses >= state->targetPulses)
  808. {
  809. /* 仅在完整 00 边界停机,禁止留下半个正交周期。 */
  810. PlsrHwStopActiveOutput(axis, state->outputMode);
  811. state->state = PLSR_HW_STATE_DONE;
  812. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  813. }
  814. }
  815. }
  816. void PlsrHwTestTriggerUpdate(uint8_t axis)
  817. {
  818. if (axis < PLSR_HW_AXIS_COUNT)
  819. {
  820. PlsrHwTimers[axis].sr |= PLSR_HW_TIMER_UPDATE_BIT;
  821. }
  822. PlsrHwOnTimerUpdate(axis);
  823. }
  824. #endif
  825. #ifndef PLSR_HOST_TEST
  826. void TIM1_UP_TIM10_IRQHandler(void)
  827. {
  828. PlsrHwOnTimerUpdate(0U);
  829. }
  830. void TIM8_UP_TIM13_IRQHandler(void)
  831. {
  832. PlsrHwOnTimerUpdate(1U);
  833. }
  834. void TIM1_TRG_COM_TIM11_IRQHandler(void)
  835. {
  836. PlsrHwOnTimerUpdate(2U);
  837. }
  838. void TIM8_TRG_COM_TIM14_IRQHandler(void)
  839. {
  840. PlsrHwOnTimerUpdate(3U);
  841. }
  842. #endif