25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

647 lines
17 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. typedef struct
  14. {
  15. uint32_t timerClockHz;
  16. uint8_t directionPoint; /* 0xFF = 无 */
  17. #ifndef PLSR_HOST_TEST
  18. TIM_TypeDef *timer;
  19. GPIO_TypeDef *gpioPort;
  20. uint16_t gpioPin;
  21. uint8_t afMode;
  22. IRQn_Type irq;
  23. #endif
  24. } PLSR_HW_AXIS_MAP;
  25. #ifndef PLSR_HOST_TEST
  26. /* 输出点(Y 点号)→ GPIO 引脚:XDM-60T4-E 原理图。
  27. * 点号 8/9/18/19 不存在(资源层掩码 0x0013FCFF 已约束)。 */
  28. typedef struct
  29. {
  30. GPIO_TypeDef *port;
  31. uint16_t pin;
  32. } PLSR_HW_OUTPUT_PIN;
  33. static const PLSR_HW_OUTPUT_PIN PlsrHwOutputPins[PLSR_HW_OUTPUT_POINT_COUNT] =
  34. {
  35. {GPIOF, GPIO_PIN_6}, /* Y0 */
  36. {GPIOF, GPIO_PIN_8}, /* Y1 */
  37. {GPIOF, GPIO_PIN_7}, /* Y2 */
  38. {GPIOF, GPIO_PIN_9}, /* Y3 */
  39. {GPIOI, GPIO_PIN_8}, /* Y4 */
  40. {GPIOE, GPIO_PIN_6}, /* Y5 */
  41. {GPIOE, GPIO_PIN_5}, /* Y6 */
  42. {GPIOE, GPIO_PIN_4}, /* Y7 */
  43. {NULL, 0U}, /* Y8 */
  44. {NULL, 0U}, /* Y9 */
  45. {GPIOG, GPIO_PIN_7}, /* Y10 */
  46. {GPIOG, GPIO_PIN_6}, /* Y11 */
  47. {GPIOH, GPIO_PIN_9}, /* Y12 */
  48. {GPIOH, GPIO_PIN_8}, /* Y13 */
  49. {GPIOH, GPIO_PIN_7}, /* Y14 */
  50. {GPIOH, GPIO_PIN_6}, /* Y15 */
  51. {GPIOF, GPIO_PIN_11}, /* Y16 */
  52. {GPIOB, GPIO_PIN_0}, /* Y17 */
  53. {NULL, 0U}, /* Y18 */
  54. {NULL, 0U}, /* Y19 */
  55. {GPIOH, GPIO_PIN_5} /* Y20 */
  56. };
  57. #endif
  58. /* Q0~Q3 定时器:XDM-60T4-E。
  59. * PF6=TIM10_CH1(AF3)、PF7=TIM11_CH1(AF3)、PF8=TIM13_CH1(AF9)、PF9=TIM14_CH1(AF9)。
  60. * 定时器时钟由 RCC 实际配置计算(APB2 分频≠1 时定时器时钟×2)。 */
  61. static const PLSR_HW_AXIS_MAP PlsrHwAxisMap[PLSR_HW_AXIS_COUNT] =
  62. {
  63. #ifndef PLSR_HOST_TEST
  64. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM10, GPIOF, GPIO_PIN_6, 3U, TIM1_UP_TIM10_IRQn},
  65. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM13, GPIOF, GPIO_PIN_8, 9U, TIM8_UP_TIM13_IRQn},
  66. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM11, GPIOF, GPIO_PIN_7, 3U, TIM1_TRG_COM_TIM11_IRQn},
  67. {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM14, GPIOF, GPIO_PIN_9, 9U, TIM8_TRG_COM_TIM14_IRQn}
  68. #else
  69. {168000000UL, PLSR_HW_DIR_POINT_NONE},
  70. {168000000UL, PLSR_HW_DIR_POINT_NONE},
  71. {168000000UL, PLSR_HW_DIR_POINT_NONE},
  72. {168000000UL, PLSR_HW_DIR_POINT_NONE}
  73. #endif
  74. };
  75. /* host 测试:模拟定时器寄存器。 */
  76. #ifdef PLSR_HOST_TEST
  77. typedef struct
  78. {
  79. uint32_t cr1;
  80. uint32_t dier;
  81. uint32_t sr;
  82. uint32_t psc;
  83. uint32_t arr;
  84. uint32_t ccr1;
  85. uint32_t ccmr1;
  86. uint32_t ccer;
  87. uint8_t dirLevel;
  88. } PLSR_HW_TIMER_REGS;
  89. static PLSR_HW_TIMER_REGS PlsrHwTimers[PLSR_HW_AXIS_COUNT];
  90. #endif
  91. typedef struct
  92. {
  93. PLSR_HW_STATE state;
  94. uint32_t currentFrequencyHz;
  95. int64_t targetPulses;
  96. int64_t emittedPulses;
  97. uint16_t directionDelayRemainingMs;
  98. uint8_t directionPoint;
  99. uint8_t directionPositive;
  100. } PLSR_HW_AXIS_STATE;
  101. static PLSR_HW_AXIS_STATE PlsrHwAxes[PLSR_HW_AXIS_COUNT];
  102. /* ---- 定时器寄存器访问抽象(host 模拟 / 生产真实) ---- */
  103. static void PlsrHwTimerSetArr(uint8_t axis, uint32_t value)
  104. {
  105. #ifdef PLSR_HOST_TEST
  106. PlsrHwTimers[axis].arr = value;
  107. #else
  108. PlsrHwAxisMap[axis].timer->ARR = value;
  109. #endif
  110. }
  111. static void PlsrHwTimerSetPsc(uint8_t axis, uint32_t value)
  112. {
  113. #ifdef PLSR_HOST_TEST
  114. PlsrHwTimers[axis].psc = value;
  115. #else
  116. PlsrHwAxisMap[axis].timer->PSC = value;
  117. #endif
  118. }
  119. static void PlsrHwTimerSetCcr(uint8_t axis, uint32_t value)
  120. {
  121. #ifdef PLSR_HOST_TEST
  122. PlsrHwTimers[axis].ccr1 = value;
  123. #else
  124. PlsrHwAxisMap[axis].timer->CCR1 = value;
  125. #endif
  126. }
  127. static void PlsrHwTimerSetCen(uint8_t axis, uint32_t value)
  128. {
  129. #ifdef PLSR_HOST_TEST
  130. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0001UL) | value;
  131. #else
  132. if (value != 0UL)
  133. {
  134. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_CEN;
  135. }
  136. else
  137. {
  138. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_CEN;
  139. }
  140. #endif
  141. }
  142. static void PlsrHwTimerSetCc1e(uint8_t axis, uint32_t value)
  143. {
  144. #ifdef PLSR_HOST_TEST
  145. PlsrHwTimers[axis].ccer = (PlsrHwTimers[axis].ccer & ~0x0001UL) | value;
  146. #else
  147. if (value != 0UL)
  148. {
  149. PlsrHwAxisMap[axis].timer->CCER |= TIM_CCER_CC1E;
  150. }
  151. else
  152. {
  153. PlsrHwAxisMap[axis].timer->CCER &= ~TIM_CCER_CC1E;
  154. }
  155. #endif
  156. }
  157. /* 通道 1 输出模式 = PWM 模式 1(OC1M=110)+ CCR 预装载(OC1PE)。
  158. * 上电复位后 CCMR1=0(冻结),通道输出恒定电平、无方波,必须显式配置。 */
  159. static void PlsrHwTimerSetPwmMode1(uint8_t axis)
  160. {
  161. #ifdef PLSR_HOST_TEST
  162. PlsrHwTimers[axis].ccmr1 = 0x0068UL;
  163. #else
  164. PlsrHwAxisMap[axis].timer->CCMR1 = (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2)
  165. | TIM_CCMR1_OC1PE;
  166. #endif
  167. }
  168. static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value)
  169. {
  170. #ifdef PLSR_HOST_TEST
  171. PlsrHwTimers[axis].dier = (PlsrHwTimers[axis].dier & ~0x0001UL) | value;
  172. #else
  173. if (value != 0UL)
  174. {
  175. PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_UIE;
  176. }
  177. else
  178. {
  179. PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_UIE;
  180. }
  181. #endif
  182. }
  183. static void PlsrHwTimerClearUif(uint8_t axis)
  184. {
  185. #ifdef PLSR_HOST_TEST
  186. PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_UPDATE_BIT;
  187. #else
  188. PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_UIF;
  189. #endif
  190. }
  191. /* ---- DIR 输出 ----
  192. * XDM 为晶体管(NPN 漏型)输出:ON(导通)= 引脚低电平。
  193. * 信捷正逻辑:正向发脉冲时方向端子置 ON(低)。 */
  194. static void PlsrHwSetDirLevel(uint8_t axis, uint8_t positive)
  195. {
  196. PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis];
  197. state->directionPositive = (positive != 0U) ? 1U : 0U;
  198. if (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  199. {
  200. return;
  201. }
  202. #ifdef PLSR_HOST_TEST
  203. PlsrHwTimers[axis].dirLevel = (positive != 0U) ? 1U : 0U;
  204. #else
  205. if (state->directionPoint < PLSR_HW_OUTPUT_POINT_COUNT)
  206. {
  207. const PLSR_HW_OUTPUT_PIN *pin =
  208. &PlsrHwOutputPins[state->directionPoint];
  209. GPIO_InitTypeDef gpio;
  210. if (pin->port != NULL)
  211. {
  212. /* DIR 点按需配置为推挽输出(上电默认高阻=截止,安全)。 */
  213. gpio.Pin = pin->pin;
  214. gpio.Mode = GPIO_MODE_OUTPUT_PP;
  215. gpio.Pull = GPIO_NOPULL;
  216. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  217. HAL_GPIO_Init(pin->port, &gpio);
  218. /* 漏型输出:ON(导通)= 低电平。 */
  219. HAL_GPIO_WritePin(pin->port,
  220. pin->pin,
  221. (positive != 0U) ? GPIO_PIN_RESET
  222. : GPIO_PIN_SET);
  223. }
  224. }
  225. #endif
  226. }
  227. /* ---- PWM 启停 ----
  228. * ARR/CCR 使用预装载(ARPE/OC1PE):运行中调频写入延迟到更新事件生效,
  229. * 避免 ARR 变小瞬间 CNT 超调提前回绕(每段加速会多出 ~ln(f1/f0) 个假脉冲)。
  230. * 首次启动用 EGR.UG 把预装载值加载到影子寄存器,杜绝首个周期用复位值。 */
  231. static void PlsrHwTimerSetArpe(uint8_t axis, uint32_t value)
  232. {
  233. #ifdef PLSR_HOST_TEST
  234. PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0080UL)
  235. | ((value != 0UL) ? 0x0080UL : 0UL);
  236. #else
  237. if (value != 0UL)
  238. {
  239. PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_ARPE;
  240. }
  241. else
  242. {
  243. PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_ARPE;
  244. }
  245. #endif
  246. }
  247. /* 生成更新事件:立即加载 ARR/CCR/PSC 影子寄存器(启动时用)。 */
  248. static void PlsrHwTimerSetUg(uint8_t axis)
  249. {
  250. #ifdef PLSR_HOST_TEST
  251. PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_UPDATE_BIT;
  252. #else
  253. PlsrHwAxisMap[axis].timer->EGR = TIM_EGR_UG;
  254. #endif
  255. }
  256. /* 配置 PWM 定时器(预装载写入;启动/调频共用,不触碰使能位)。 */
  257. static void PlsrHwConfigurePwm(uint8_t axis, uint32_t frequencyHz)
  258. {
  259. uint16_t psc;
  260. uint16_t arr;
  261. if (PlsrCalculateTimerDivider(PlsrHwAxisMap[axis].timerClockHz,
  262. frequencyHz,
  263. &psc,
  264. &arr) != PLSR_RESULT_OK)
  265. {
  266. return;
  267. }
  268. PlsrHwTimerSetPsc(axis, psc);
  269. PlsrHwTimerSetArr(axis, arr);
  270. PlsrHwTimerSetCcr(axis, (uint32_t)arr / 2UL); /* 50% 占空比 */
  271. PlsrHwTimerSetPwmMode1(axis);
  272. PlsrHwTimerSetArpe(axis, 1UL);
  273. }
  274. /* 首次启动输出:加载影子寄存器后使能更新中断、通道与计数。 */
  275. static void PlsrHwPwmBegin(uint8_t axis)
  276. {
  277. PlsrHwTimerSetUg(axis);
  278. PlsrHwTimerSetUie(axis, 1UL);
  279. PlsrHwTimerSetCc1e(axis, 1UL);
  280. PlsrHwTimerSetCen(axis, 1UL);
  281. }
  282. static void PlsrHwStopPwmTimer(uint8_t axis)
  283. {
  284. PlsrHwTimerSetCc1e(axis, 0UL);
  285. PlsrHwTimerSetUie(axis, 0UL);
  286. PlsrHwTimerSetCen(axis, 0UL);
  287. }
  288. uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber)
  289. {
  290. /* 与资源层一致的合法输出点掩码(Q0~Q7、Q10~Q17、Q20)。 */
  291. const uint32_t validOutputMask = 0x0013FCFFUL;
  292. if (pointNumber >= PLSR_HW_OUTPUT_POINT_COUNT)
  293. {
  294. return 0U;
  295. }
  296. if ((validOutputMask & (1UL << pointNumber)) == 0UL)
  297. {
  298. return 0U;
  299. }
  300. #ifndef PLSR_HOST_TEST
  301. if (PlsrHwOutputPins[pointNumber].port == NULL)
  302. {
  303. return 0U;
  304. }
  305. #endif
  306. return 1U;
  307. }
  308. PLSR_RESULT PlsrHwInit(void)
  309. {
  310. uint8_t axis;
  311. (void)memset(PlsrHwAxes, 0, sizeof(PlsrHwAxes));
  312. for (axis = 0U; axis < PLSR_HW_AXIS_COUNT; axis++)
  313. {
  314. PlsrHwAxes[axis].state = PLSR_HW_STATE_IDLE;
  315. PlsrHwAxes[axis].directionPoint = PLSR_HW_DIR_POINT_NONE;
  316. #ifdef PLSR_HOST_TEST
  317. (void)memset(&PlsrHwTimers[axis], 0, sizeof(PlsrHwTimers[axis]));
  318. #else
  319. PlsrHwTimerSetCc1e(axis, 0UL);
  320. PlsrHwTimerSetUie(axis, 0UL);
  321. PlsrHwTimerSetCen(axis, 0UL);
  322. #endif
  323. }
  324. #ifndef PLSR_HOST_TEST
  325. {
  326. GPIO_InitTypeDef gpio;
  327. /* 1. 输出点 GPIO 时钟(DIR 点按需配置时使用)。 */
  328. __HAL_RCC_GPIOF_CLK_ENABLE();
  329. __HAL_RCC_GPIOI_CLK_ENABLE();
  330. __HAL_RCC_GPIOE_CLK_ENABLE();
  331. __HAL_RCC_GPIOG_CLK_ENABLE();
  332. __HAL_RCC_GPIOH_CLK_ENABLE();
  333. __HAL_RCC_GPIOB_CLK_ENABLE();
  334. /* 2. 上电安全:输出点保持复位默认高阻(漏型输出 = 截止 = OFF)。
  335. * 不驱动任何 Y 点,DIR 点仅在 PlsrHwSetDirLevel 时按需配置。 */
  336. /* 3. 定时器时钟。 */
  337. __HAL_RCC_TIM10_CLK_ENABLE();
  338. __HAL_RCC_TIM11_CLK_ENABLE();
  339. __HAL_RCC_TIM13_CLK_ENABLE();
  340. __HAL_RCC_TIM14_CLK_ENABLE();
  341. /* 4. 脉冲点切定时器复用(PF6/7=AF3、PF8/9=AF9)。
  342. * 定时器通道尚未使能(CC1E=0),输出级断开,无毛刺。 */
  343. gpio.Mode = GPIO_MODE_AF_PP;
  344. gpio.Pull = GPIO_NOPULL;
  345. gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  346. gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7;
  347. gpio.Alternate = 3U;
  348. HAL_GPIO_Init(GPIOF, &gpio);
  349. gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9;
  350. gpio.Alternate = 9U;
  351. HAL_GPIO_Init(GPIOF, &gpio);
  352. /* 5. 更新中断 NVIC:高速计数/尾脉冲层(P3b 统一规划优先级表)。 */
  353. HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 1U, 0U);
  354. HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
  355. HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 1U, 0U);
  356. HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
  357. HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 1U, 0U);
  358. HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
  359. HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 1U, 0U);
  360. HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
  361. }
  362. #endif
  363. return PLSR_RESULT_OK;
  364. }
  365. PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params)
  366. {
  367. PLSR_HW_AXIS_STATE *state;
  368. uint8_t directionChanged;
  369. if ((axis >= PLSR_HW_AXIS_COUNT) || (params == NULL))
  370. {
  371. return PLSR_RESULT_INVALID_ARGUMENT;
  372. }
  373. if (params->targetPulses <= 0)
  374. {
  375. return PLSR_RESULT_INVALID_ARGUMENT;
  376. }
  377. state = &PlsrHwAxes[axis];
  378. if (state->state == PLSR_HW_STATE_RUNNING)
  379. {
  380. return PLSR_RESULT_BUSY;
  381. }
  382. /* 方向延时只在方向发生变化时生效(首次启动/换向/换方向点):
  383. * 段间同向衔接不再等待 10ms,直接进入 PWM 待启动。 */
  384. directionChanged = (state->directionPoint == PLSR_HW_DIR_POINT_NONE)
  385. || (state->directionPoint != params->directionPoint)
  386. || (state->directionPositive != params->directionPositive);
  387. state->targetPulses = params->targetPulses;
  388. state->emittedPulses = 0;
  389. state->currentFrequencyHz = params->frequencyHz;
  390. state->directionPoint = params->directionPoint;
  391. state->directionDelayRemainingMs =
  392. (directionChanged != 0U) ? params->directionDelayMs : 0U;
  393. PlsrHwSetDirLevel(axis, params->directionPositive);
  394. state->state = (state->directionDelayRemainingMs > 0U)
  395. ? PLSR_HW_STATE_DIR_SETTLING
  396. : PLSR_HW_STATE_PWM_PENDING;
  397. return PLSR_RESULT_OK;
  398. }
  399. PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz)
  400. {
  401. PLSR_HW_AXIS_STATE *state;
  402. if (axis >= PLSR_HW_AXIS_COUNT)
  403. {
  404. return PLSR_RESULT_INVALID_ARGUMENT;
  405. }
  406. state = &PlsrHwAxes[axis];
  407. state->currentFrequencyHz = frequencyHz;
  408. if (state->state == PLSR_HW_STATE_RUNNING)
  409. {
  410. if (frequencyHz > 0UL)
  411. {
  412. /* 运行中调频:预装载写入,更新事件时生效,不触碰使能位。 */
  413. PlsrHwConfigurePwm(axis, frequencyHz);
  414. }
  415. else
  416. {
  417. PlsrHwStopPwmTimer(axis);
  418. }
  419. }
  420. else if ((state->state == PLSR_HW_STATE_PWM_PENDING)
  421. && (frequencyHz > 0UL))
  422. {
  423. PlsrHwConfigurePwm(axis, frequencyHz);
  424. PlsrHwPwmBegin(axis);
  425. state->state = PLSR_HW_STATE_RUNNING;
  426. }
  427. return PLSR_RESULT_OK;
  428. }
  429. PLSR_RESULT PlsrHwStopPulse(uint8_t axis)
  430. {
  431. PLSR_HW_AXIS_STATE *state;
  432. if (axis >= PLSR_HW_AXIS_COUNT)
  433. {
  434. return PLSR_RESULT_INVALID_ARGUMENT;
  435. }
  436. state = &PlsrHwAxes[axis];
  437. if (state->state != PLSR_HW_STATE_IDLE)
  438. {
  439. PlsrHwStopPwmTimer(axis);
  440. state->state = PLSR_HW_STATE_IDLE;
  441. }
  442. return PLSR_RESULT_OK;
  443. }
  444. uint8_t PlsrHwIsPulseActive(uint8_t axis)
  445. {
  446. if (axis >= PLSR_HW_AXIS_COUNT)
  447. {
  448. return 0U;
  449. }
  450. return (PlsrHwAxes[axis].state == PLSR_HW_STATE_RUNNING) ? 1U : 0U;
  451. }
  452. PLSR_HW_STATE PlsrHwGetState(uint8_t axis)
  453. {
  454. if (axis >= PLSR_HW_AXIS_COUNT)
  455. {
  456. return PLSR_HW_STATE_IDLE;
  457. }
  458. return PlsrHwAxes[axis].state;
  459. }
  460. uint32_t PlsrHwGetTimerClockHz(uint8_t axis)
  461. {
  462. if (axis >= PLSR_HW_AXIS_COUNT)
  463. {
  464. return 0UL;
  465. }
  466. return PlsrHwAxisMap[axis].timerClockHz;
  467. }
  468. void PlsrHwTick(uint8_t axis)
  469. {
  470. PLSR_HW_AXIS_STATE *state;
  471. if (axis >= PLSR_HW_AXIS_COUNT)
  472. {
  473. return;
  474. }
  475. state = &PlsrHwAxes[axis];
  476. switch (state->state)
  477. {
  478. case PLSR_HW_STATE_DIR_SETTLING:
  479. if (state->directionDelayRemainingMs > 0U)
  480. {
  481. state->directionDelayRemainingMs--;
  482. }
  483. if (state->directionDelayRemainingMs == 0U)
  484. {
  485. state->state = PLSR_HW_STATE_PWM_PENDING;
  486. }
  487. break;
  488. case PLSR_HW_STATE_PWM_PENDING:
  489. if (state->currentFrequencyHz > 0UL)
  490. {
  491. PlsrHwConfigurePwm(axis, state->currentFrequencyHz);
  492. PlsrHwPwmBegin(axis);
  493. state->state = PLSR_HW_STATE_RUNNING;
  494. }
  495. break;
  496. default:
  497. break;
  498. }
  499. }
  500. /* 输出定时器更新中断:每周期末触发一次(=1 个脉冲)。 */
  501. void PlsrHwOnTimerUpdate(uint8_t axis)
  502. {
  503. PLSR_HW_AXIS_STATE *state;
  504. if (axis >= PLSR_HW_AXIS_COUNT)
  505. {
  506. return;
  507. }
  508. state = &PlsrHwAxes[axis];
  509. PlsrHwTimerClearUif(axis);
  510. if (state->state != PLSR_HW_STATE_RUNNING)
  511. {
  512. return;
  513. }
  514. state->emittedPulses++;
  515. if (state->emittedPulses >= state->targetPulses)
  516. {
  517. /* 更新时刻 = 周期结束:关通道即完整下降沿后停止,无额外脉冲。 */
  518. PlsrHwStopPwmTimer(axis);
  519. state->state = PLSR_HW_STATE_DONE;
  520. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  521. }
  522. }
  523. #ifdef PLSR_HOST_TEST
  524. uint32_t PlsrHwTestGetArr(uint8_t axis)
  525. {
  526. return PlsrHwTimers[axis].arr;
  527. }
  528. uint32_t PlsrHwTestGetCcr(uint8_t axis)
  529. {
  530. return PlsrHwTimers[axis].ccr1;
  531. }
  532. uint32_t PlsrHwTestGetCcmr1(uint8_t axis)
  533. {
  534. return PlsrHwTimers[axis].ccmr1;
  535. }
  536. uint32_t PlsrHwTestGetCr1(uint8_t axis)
  537. {
  538. return PlsrHwTimers[axis].cr1;
  539. }
  540. uint32_t PlsrHwTestGetPsc(uint8_t axis)
  541. {
  542. return PlsrHwTimers[axis].psc;
  543. }
  544. uint8_t PlsrHwTestGetPwmEnabled(uint8_t axis)
  545. {
  546. return ((PlsrHwTimers[axis].ccer & PLSR_HW_TIMER_CHANNEL1_BIT) != 0UL)
  547. ? 1U
  548. : 0U;
  549. }
  550. uint8_t PlsrHwTestGetDirLevel(uint8_t axis)
  551. {
  552. return PlsrHwTimers[axis].dirLevel;
  553. }
  554. void PlsrHwTestTriggerUpdate(uint8_t axis)
  555. {
  556. PlsrHwOnTimerUpdate(axis);
  557. }
  558. #endif
  559. #ifndef PLSR_HOST_TEST
  560. void TIM1_UP_TIM10_IRQHandler(void)
  561. {
  562. PlsrHwOnTimerUpdate(0U);
  563. }
  564. void TIM8_UP_TIM13_IRQHandler(void)
  565. {
  566. PlsrHwOnTimerUpdate(1U);
  567. }
  568. void TIM1_TRG_COM_TIM11_IRQHandler(void)
  569. {
  570. PlsrHwOnTimerUpdate(2U);
  571. }
  572. void TIM8_TRG_COM_TIM14_IRQHandler(void)
  573. {
  574. PlsrHwOnTimerUpdate(3U);
  575. }
  576. #endif