#include "plsr_hal_f407.h" #include "plsr_address_map.h" #include "plsr_core.h" #include "plsr_job.h" #include #ifndef PLSR_HOST_TEST #include "stm32f4xx.h" #include "stm32f4xx_hal.h" #endif #define PLSR_HW_TIMER_CHANNEL1_BIT (0x0001U) #define PLSR_HW_TIMER_UPDATE_BIT (0x0001U) #define PLSR_HW_OUTPUT_POINT_COUNT (21U) typedef struct { uint32_t timerClockHz; uint8_t directionPoint; /* 0xFF = 无 */ #ifndef PLSR_HOST_TEST TIM_TypeDef *timer; GPIO_TypeDef *gpioPort; uint16_t gpioPin; uint8_t afMode; IRQn_Type irq; #endif } PLSR_HW_AXIS_MAP; #ifndef PLSR_HOST_TEST /* 输出点(Y 点号)→ GPIO 引脚:XDM-60T4-E 原理图。 * 点号 8/9/18/19 不存在(资源层掩码 0x0013FCFF 已约束)。 */ typedef struct { GPIO_TypeDef *port; uint16_t pin; } PLSR_HW_OUTPUT_PIN; static const PLSR_HW_OUTPUT_PIN PlsrHwOutputPins[PLSR_HW_OUTPUT_POINT_COUNT] = { {GPIOF, GPIO_PIN_6}, /* Y0 */ {GPIOF, GPIO_PIN_8}, /* Y1 */ {GPIOF, GPIO_PIN_7}, /* Y2 */ {GPIOF, GPIO_PIN_9}, /* Y3 */ {GPIOI, GPIO_PIN_8}, /* Y4 */ {GPIOE, GPIO_PIN_6}, /* Y5 */ {GPIOE, GPIO_PIN_5}, /* Y6 */ {GPIOE, GPIO_PIN_4}, /* Y7 */ {NULL, 0U}, /* Y8 */ {NULL, 0U}, /* Y9 */ {GPIOG, GPIO_PIN_7}, /* Y10 */ {GPIOG, GPIO_PIN_6}, /* Y11 */ {GPIOH, GPIO_PIN_9}, /* Y12 */ {GPIOH, GPIO_PIN_8}, /* Y13 */ {GPIOH, GPIO_PIN_7}, /* Y14 */ {GPIOH, GPIO_PIN_6}, /* Y15 */ {GPIOF, GPIO_PIN_11}, /* Y16 */ {GPIOB, GPIO_PIN_0}, /* Y17 */ {NULL, 0U}, /* Y18 */ {NULL, 0U}, /* Y19 */ {GPIOH, GPIO_PIN_5} /* Y20 */ }; #endif /* Q0~Q3 定时器:XDM-60T4-E。 * PF6=TIM10_CH1(AF3)、PF7=TIM11_CH1(AF3)、PF8=TIM13_CH1(AF9)、PF9=TIM14_CH1(AF9)。 * 定时器时钟由 RCC 实际配置计算(APB2 分频≠1 时定时器时钟×2)。 */ static const PLSR_HW_AXIS_MAP PlsrHwAxisMap[PLSR_HW_AXIS_COUNT] = { #ifndef PLSR_HOST_TEST {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM10, GPIOF, GPIO_PIN_6, 3U, TIM1_UP_TIM10_IRQn}, {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM13, GPIOF, GPIO_PIN_8, 9U, TIM8_UP_TIM13_IRQn}, {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM11, GPIOF, GPIO_PIN_7, 3U, TIM1_TRG_COM_TIM11_IRQn}, {168000000UL, PLSR_HW_DIR_POINT_NONE, TIM14, GPIOF, GPIO_PIN_9, 9U, TIM8_TRG_COM_TIM14_IRQn} #else {168000000UL, PLSR_HW_DIR_POINT_NONE}, {168000000UL, PLSR_HW_DIR_POINT_NONE}, {168000000UL, PLSR_HW_DIR_POINT_NONE}, {168000000UL, PLSR_HW_DIR_POINT_NONE} #endif }; /* host 测试:模拟定时器寄存器。 */ #ifdef PLSR_HOST_TEST typedef struct { uint32_t cr1; uint32_t dier; uint32_t sr; uint32_t psc; uint32_t arr; uint32_t ccr1; uint32_t ccer; uint8_t dirLevel; } PLSR_HW_TIMER_REGS; static PLSR_HW_TIMER_REGS PlsrHwTimers[PLSR_HW_AXIS_COUNT]; #endif typedef struct { PLSR_HW_STATE state; uint32_t currentFrequencyHz; int64_t targetPulses; int64_t emittedPulses; uint16_t directionDelayRemainingMs; uint8_t directionPoint; uint8_t directionPositive; } PLSR_HW_AXIS_STATE; static PLSR_HW_AXIS_STATE PlsrHwAxes[PLSR_HW_AXIS_COUNT]; /* ---- 定时器寄存器访问抽象(host 模拟 / 生产真实) ---- */ static void PlsrHwTimerSetArr(uint8_t axis, uint32_t value) { #ifdef PLSR_HOST_TEST PlsrHwTimers[axis].arr = value; #else PlsrHwAxisMap[axis].timer->ARR = value; #endif } static void PlsrHwTimerSetPsc(uint8_t axis, uint32_t value) { #ifdef PLSR_HOST_TEST PlsrHwTimers[axis].psc = value; #else PlsrHwAxisMap[axis].timer->PSC = value; #endif } static void PlsrHwTimerSetCcr(uint8_t axis, uint32_t value) { #ifdef PLSR_HOST_TEST PlsrHwTimers[axis].ccr1 = value; #else PlsrHwAxisMap[axis].timer->CCR1 = value; #endif } static void PlsrHwTimerSetCen(uint8_t axis, uint32_t value) { #ifdef PLSR_HOST_TEST PlsrHwTimers[axis].cr1 = (PlsrHwTimers[axis].cr1 & ~0x0001UL) | value; #else if (value != 0UL) { PlsrHwAxisMap[axis].timer->CR1 |= TIM_CR1_CEN; } else { PlsrHwAxisMap[axis].timer->CR1 &= ~TIM_CR1_CEN; } #endif } static void PlsrHwTimerSetCc1e(uint8_t axis, uint32_t value) { #ifdef PLSR_HOST_TEST PlsrHwTimers[axis].ccer = (PlsrHwTimers[axis].ccer & ~0x0001UL) | value; #else if (value != 0UL) { PlsrHwAxisMap[axis].timer->CCER |= TIM_CCER_CC1E; } else { PlsrHwAxisMap[axis].timer->CCER &= ~TIM_CCER_CC1E; } #endif } static void PlsrHwTimerSetUie(uint8_t axis, uint32_t value) { #ifdef PLSR_HOST_TEST PlsrHwTimers[axis].dier = (PlsrHwTimers[axis].dier & ~0x0001UL) | value; #else if (value != 0UL) { PlsrHwAxisMap[axis].timer->DIER |= TIM_DIER_UIE; } else { PlsrHwAxisMap[axis].timer->DIER &= ~TIM_DIER_UIE; } #endif } static void PlsrHwTimerClearUif(uint8_t axis) { #ifdef PLSR_HOST_TEST PlsrHwTimers[axis].sr &= ~PLSR_HW_TIMER_UPDATE_BIT; #else PlsrHwAxisMap[axis].timer->SR &= ~TIM_SR_UIF; #endif } /* ---- DIR 输出 ---- */ static void PlsrHwSetDirLevel(uint8_t axis, uint8_t positive) { PLSR_HW_AXIS_STATE *state = &PlsrHwAxes[axis]; state->directionPositive = (positive != 0U) ? 1U : 0U; if (state->directionPoint == PLSR_HW_DIR_POINT_NONE) { return; } #ifdef PLSR_HOST_TEST PlsrHwTimers[axis].dirLevel = (positive != 0U) ? 1U : 0U; #else if (state->directionPoint < PLSR_HW_OUTPUT_POINT_COUNT) { const PLSR_HW_OUTPUT_PIN *pin = &PlsrHwOutputPins[state->directionPoint]; if (pin->port != NULL) { HAL_GPIO_WritePin(pin->port, pin->pin, (positive != 0U) ? GPIO_PIN_SET : GPIO_PIN_RESET); } } #endif } /* ---- PWM 启停 ---- */ static void PlsrHwStartPwmTimer(uint8_t axis, uint32_t frequencyHz) { uint16_t psc; uint16_t arr; if (PlsrCalculateTimerDivider(PlsrHwAxisMap[axis].timerClockHz, frequencyHz, &psc, &arr) != PLSR_RESULT_OK) { return; } PlsrHwTimerSetPsc(axis, psc); PlsrHwTimerSetArr(axis, arr); PlsrHwTimerSetCcr(axis, (uint32_t)arr / 2UL); /* 50% 占空比 */ PlsrHwTimerSetUie(axis, 1UL); PlsrHwTimerSetCc1e(axis, 1UL); PlsrHwTimerSetCen(axis, 1UL); } static void PlsrHwStopPwmTimer(uint8_t axis) { PlsrHwTimerSetCc1e(axis, 0UL); PlsrHwTimerSetUie(axis, 0UL); PlsrHwTimerSetCen(axis, 0UL); } uint8_t PlsrHwResolveDirectionPoint(uint8_t pointNumber) { /* 与资源层一致的合法输出点掩码(Q0~Q7、Q10~Q17、Q20)。 */ const uint32_t validOutputMask = 0x0013FCFFUL; if (pointNumber >= PLSR_HW_OUTPUT_POINT_COUNT) { return 0U; } if ((validOutputMask & (1UL << pointNumber)) == 0UL) { return 0U; } #ifndef PLSR_HOST_TEST if (PlsrHwOutputPins[pointNumber].port == NULL) { return 0U; } #endif return 1U; } PLSR_RESULT PlsrHwInit(void) { uint8_t axis; (void)memset(PlsrHwAxes, 0, sizeof(PlsrHwAxes)); for (axis = 0U; axis < PLSR_HW_AXIS_COUNT; axis++) { PlsrHwAxes[axis].state = PLSR_HW_STATE_IDLE; PlsrHwAxes[axis].directionPoint = PLSR_HW_DIR_POINT_NONE; #ifdef PLSR_HOST_TEST (void)memset(&PlsrHwTimers[axis], 0, sizeof(PlsrHwTimers[axis])); #else PlsrHwTimerSetCc1e(axis, 0UL); PlsrHwTimerSetUie(axis, 0UL); PlsrHwTimerSetCen(axis, 0UL); #endif } #ifndef PLSR_HOST_TEST { GPIO_InitTypeDef gpio; uint8_t point; /* 1. 输出点 GPIO 时钟。 */ __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOI_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /* 2. 全部输出点上电安全电平(推挽输出、低)。 */ gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; for (point = 0U; point < PLSR_HW_OUTPUT_POINT_COUNT; point++) { if (PlsrHwOutputPins[point].port != NULL) { gpio.Pin = PlsrHwOutputPins[point].pin; HAL_GPIO_WritePin(PlsrHwOutputPins[point].port, PlsrHwOutputPins[point].pin, GPIO_PIN_RESET); HAL_GPIO_Init(PlsrHwOutputPins[point].port, &gpio); } } /* 3. 定时器时钟。 */ __HAL_RCC_TIM10_CLK_ENABLE(); __HAL_RCC_TIM11_CLK_ENABLE(); __HAL_RCC_TIM13_CLK_ENABLE(); __HAL_RCC_TIM14_CLK_ENABLE(); /* 4. 脉冲点切定时器复用(PF6/7=AF3、PF8/9=AF9)。 * 定时器通道尚未使能(CC1E=0),输出为无效电平(低),无毛刺。 */ gpio.Mode = GPIO_MODE_AF_PP; gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7; gpio.Alternate = 3U; HAL_GPIO_Init(GPIOF, &gpio); gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9; gpio.Alternate = 9U; HAL_GPIO_Init(GPIOF, &gpio); /* 5. 更新中断 NVIC:高速计数/尾脉冲层(P3b 统一规划优先级表)。 */ HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 1U, 0U); HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn); HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 1U, 0U); HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn); HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 1U, 0U); HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn); HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 1U, 0U); HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn); } #endif return PLSR_RESULT_OK; } PLSR_RESULT PlsrHwStartPulse(uint8_t axis, const PLSR_HW_START_PARAMS *params) { PLSR_HW_AXIS_STATE *state; if ((axis >= PLSR_HW_AXIS_COUNT) || (params == NULL)) { return PLSR_RESULT_INVALID_ARGUMENT; } if (params->targetPulses <= 0) { return PLSR_RESULT_INVALID_ARGUMENT; } state = &PlsrHwAxes[axis]; if (state->state == PLSR_HW_STATE_RUNNING) { return PLSR_RESULT_BUSY; } state->targetPulses = params->targetPulses; state->emittedPulses = 0; state->currentFrequencyHz = params->frequencyHz; state->directionPoint = params->directionPoint; state->directionDelayRemainingMs = params->directionDelayMs; PlsrHwSetDirLevel(axis, params->directionPositive); state->state = (params->directionDelayMs > 0U) ? PLSR_HW_STATE_DIR_SETTLING : PLSR_HW_STATE_PWM_PENDING; return PLSR_RESULT_OK; } PLSR_RESULT PlsrHwSetFrequency(uint8_t axis, uint32_t frequencyHz) { PLSR_HW_AXIS_STATE *state; if (axis >= PLSR_HW_AXIS_COUNT) { return PLSR_RESULT_INVALID_ARGUMENT; } state = &PlsrHwAxes[axis]; state->currentFrequencyHz = frequencyHz; if (state->state == PLSR_HW_STATE_RUNNING) { if (frequencyHz > 0UL) { PlsrHwStartPwmTimer(axis, frequencyHz); } else { PlsrHwStopPwmTimer(axis); } } else if ((state->state == PLSR_HW_STATE_PWM_PENDING) && (frequencyHz > 0UL)) { PlsrHwStartPwmTimer(axis, frequencyHz); state->state = PLSR_HW_STATE_RUNNING; } return PLSR_RESULT_OK; } PLSR_RESULT PlsrHwStopPulse(uint8_t axis) { PLSR_HW_AXIS_STATE *state; if (axis >= PLSR_HW_AXIS_COUNT) { return PLSR_RESULT_INVALID_ARGUMENT; } state = &PlsrHwAxes[axis]; if (state->state != PLSR_HW_STATE_IDLE) { PlsrHwStopPwmTimer(axis); state->state = PLSR_HW_STATE_IDLE; } return PLSR_RESULT_OK; } uint8_t PlsrHwIsPulseActive(uint8_t axis) { if (axis >= PLSR_HW_AXIS_COUNT) { return 0U; } return (PlsrHwAxes[axis].state == PLSR_HW_STATE_RUNNING) ? 1U : 0U; } PLSR_HW_STATE PlsrHwGetState(uint8_t axis) { if (axis >= PLSR_HW_AXIS_COUNT) { return PLSR_HW_STATE_IDLE; } return PlsrHwAxes[axis].state; } uint32_t PlsrHwGetTimerClockHz(uint8_t axis) { if (axis >= PLSR_HW_AXIS_COUNT) { return 0UL; } return PlsrHwAxisMap[axis].timerClockHz; } void PlsrHwTick(uint8_t axis) { PLSR_HW_AXIS_STATE *state; if (axis >= PLSR_HW_AXIS_COUNT) { return; } state = &PlsrHwAxes[axis]; switch (state->state) { case PLSR_HW_STATE_DIR_SETTLING: if (state->directionDelayRemainingMs > 0U) { state->directionDelayRemainingMs--; } if (state->directionDelayRemainingMs == 0U) { state->state = PLSR_HW_STATE_PWM_PENDING; } break; case PLSR_HW_STATE_PWM_PENDING: if (state->currentFrequencyHz > 0UL) { PlsrHwStartPwmTimer(axis, state->currentFrequencyHz); state->state = PLSR_HW_STATE_RUNNING; } break; default: break; } } /* 输出定时器更新中断:每周期末触发一次(=1 个脉冲)。 */ void PlsrHwOnTimerUpdate(uint8_t axis) { PLSR_HW_AXIS_STATE *state; if (axis >= PLSR_HW_AXIS_COUNT) { return; } state = &PlsrHwAxes[axis]; PlsrHwTimerClearUif(axis); if (state->state != PLSR_HW_STATE_RUNNING) { return; } state->emittedPulses++; if (state->emittedPulses >= state->targetPulses) { /* 更新时刻 = 周期结束:关通道即完整下降沿后停止,无额外脉冲。 */ PlsrHwStopPwmTimer(axis); state->state = PLSR_HW_STATE_DONE; (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE); } } #ifdef PLSR_HOST_TEST uint32_t PlsrHwTestGetArr(uint8_t axis) { return PlsrHwTimers[axis].arr; } uint32_t PlsrHwTestGetCcr(uint8_t axis) { return PlsrHwTimers[axis].ccr1; } uint32_t PlsrHwTestGetPsc(uint8_t axis) { return PlsrHwTimers[axis].psc; } uint8_t PlsrHwTestGetPwmEnabled(uint8_t axis) { return ((PlsrHwTimers[axis].ccer & PLSR_HW_TIMER_CHANNEL1_BIT) != 0UL) ? 1U : 0U; } uint8_t PlsrHwTestGetDirLevel(uint8_t axis) { return PlsrHwTimers[axis].dirLevel; } void PlsrHwTestTriggerUpdate(uint8_t axis) { PlsrHwOnTimerUpdate(axis); } #endif #ifndef PLSR_HOST_TEST void TIM1_UP_TIM10_IRQHandler(void) { PlsrHwOnTimerUpdate(0U); } void TIM8_UP_TIM13_IRQHandler(void) { PlsrHwOnTimerUpdate(1U); } void TIM1_TRG_COM_TIM11_IRQHandler(void) { PlsrHwOnTimerUpdate(2U); } void TIM8_TRG_COM_TIM14_IRQHandler(void) { PlsrHwOnTimerUpdate(3U); } #endif