|
|
@@ -56,6 +56,14 @@ static volatile uint8_t s_req_pending; |
|
|
*/ |
|
|
*/ |
|
|
static uint8_t s_regs_prepared; |
|
|
static uint8_t s_regs_prepared; |
|
|
static volatile uint8_t s_seg_end_fall_armed; /* 1=末拍 CC1 下降沿后强制拉低 */ |
|
|
static volatile uint8_t s_seg_end_fall_armed; /* 1=末拍 CC1 下降沿后强制拉低 */ |
|
|
|
|
|
/* |
|
|
|
|
|
* 冷启动首拍保护:Commit 后第一次 SetFreqIsr 必须先钉住工作 ARR=起跳频, |
|
|
|
|
|
* 再把下一拍写入影子。否则 ARPE 未生效时 ISR 会直接改写工作寄存器, |
|
|
|
|
|
* 示波器上首周期频率变成「第 2 个脉冲」的频率(起跳越高越明显)。 |
|
|
|
|
|
*/ |
|
|
|
|
|
static volatile uint8_t s_protect_start_period; |
|
|
|
|
|
static uint32_t s_protect_arr; |
|
|
|
|
|
static uint32_t s_protect_ccr; |
|
|
|
|
|
|
|
|
/*============================================================================*/ |
|
|
/*============================================================================*/ |
|
|
/* 路选择 / 时钟 / GPIO */ |
|
|
/* 路选择 / 时钟 / GPIO */ |
|
|
@@ -271,6 +279,9 @@ void PlsrPulseDriverInit(void) |
|
|
s_locked_psc = 0U; |
|
|
s_locked_psc = 0U; |
|
|
s_req_pending = 0U; |
|
|
s_req_pending = 0U; |
|
|
s_req_freq = 0U; |
|
|
s_req_freq = 0U; |
|
|
|
|
|
s_protect_start_period = 0U; |
|
|
|
|
|
s_protect_arr = 0U; |
|
|
|
|
|
s_protect_ccr = 0U; |
|
|
s_active_htim = &htim10; |
|
|
s_active_htim = &htim10; |
|
|
PlsrPulseDriverDirGpioInit(); |
|
|
PlsrPulseDriverDirGpioInit(); |
|
|
/* 三路都 Init + 空闲拉低,计数器关闭;出脉冲时只 Start 选中那路 */ |
|
|
/* 三路都 Init + 空闲拉低,计数器关闭;出脉冲时只 Start 选中那路 */ |
|
|
@@ -583,22 +594,26 @@ static void PlsrPulseDriverLoadRegs(uint32_t freq_hz) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* @brief 开沿:先 Forced Active 出首上升沿,再切 PWM1 连续发脉冲 |
|
|
|
|
|
|
|
|
* @brief 开沿:直写工作 ARR 后立刻打开预装载并同步影子,再使能计数 |
|
|
* |
|
|
* |
|
|
* @note WAIT/换向后若首拍 CCR 工作值为 0,PWM1 会整拍低电平,示波器上就是 |
|
|
|
|
|
* 「延时 + 本段第一脉冲周期」。Forced Active 与 CNT/CCR 无关,首沿必须出现。 |
|
|
|
|
|
* Commit 内不再 UG,避免预装载影子把 CCR 又打回旧值/0。 |
|
|
|
|
|
|
|
|
* @note 必须先 ARPE+影子=起跳频,再 ENABLE。若先开表再开 ARPE, |
|
|
|
|
|
* 高频下首拍 UPDATE 的 ISR 可能在 ARPE 仍关时改 ARR,工作寄存器 |
|
|
|
|
|
* 被直接写成 f(1),示波器上首周期就像「x=2」而不是起跳频。 |
|
|
|
|
|
* CNT=ARR:下一节拍产生 UPDATE,建立 PWM1 首上升沿并进入脉冲计数。 |
|
|
*/ |
|
|
*/ |
|
|
static void PlsrPulseDriverCommitOutput(void) |
|
|
static void PlsrPulseDriverCommitOutput(void) |
|
|
{ |
|
|
{ |
|
|
TIM_HandleTypeDef *htim = s_active_htim; |
|
|
TIM_HandleTypeDef *htim = s_active_htim; |
|
|
uint32_t ccmr; |
|
|
uint32_t ccmr; |
|
|
|
|
|
uint32_t ccr; |
|
|
|
|
|
|
|
|
if ((htim == (TIM_HandleTypeDef *)0) || (htim->Instance == (TIM_TypeDef *)0)) |
|
|
if ((htim == (TIM_HandleTypeDef *)0) || (htim->Instance == (TIM_TypeDef *)0)) |
|
|
{ |
|
|
{ |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ccr = (s_last_ccr < 1U) ? 1U : s_last_ccr; |
|
|
|
|
|
|
|
|
__HAL_TIM_DISABLE(htim); |
|
|
__HAL_TIM_DISABLE(htim); |
|
|
__HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); |
|
|
__HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); |
|
|
|
|
|
|
|
|
@@ -606,32 +621,33 @@ static void PlsrPulseDriverCommitOutput(void) |
|
|
htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); |
|
|
htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); |
|
|
htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); |
|
|
htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); |
|
|
htim->Instance->ARR = s_last_arr; |
|
|
htim->Instance->ARR = s_last_arr; |
|
|
htim->Instance->CCR1 = (s_last_ccr < 1U) ? 1U : s_last_ccr; |
|
|
|
|
|
htim->Instance->CNT = 0U; |
|
|
|
|
|
|
|
|
htim->Instance->CCR1 = ccr; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* 唯一的脉冲启动入口。通道必须在 CEN 前使能;TIM10/11/13 在 |
|
|
|
|
|
* 运行中由 CC1E=0 -> 1 不保证重新建立当前 PWM1 电平,会保持无输出。 |
|
|
|
|
|
* CNT 从 ARR 开始,下一计数节拍产生真实 UPDATE:该 UPDATE 同时建立 |
|
|
|
|
|
* PWM1 首上升沿并进入现有脉冲 ISR 计数,边沿与 s_done 保持一一对应。 |
|
|
|
|
|
*/ |
|
|
|
|
|
ccmr = htim->Instance->CCMR1; |
|
|
ccmr = htim->Instance->CCMR1; |
|
|
ccmr &= (uint32_t)(~TIM_CCMR1_OC1M); |
|
|
ccmr &= (uint32_t)(~TIM_CCMR1_OC1M); |
|
|
ccmr |= TIM_OCMODE_PWM1; |
|
|
ccmr |= TIM_OCMODE_PWM1; |
|
|
htim->Instance->CCMR1 = ccmr; |
|
|
htim->Instance->CCMR1 = ccmr; |
|
|
htim->Instance->CCER |= TIM_CCER_CC1E; |
|
|
htim->Instance->CCER |= TIM_CCER_CC1E; |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* 先打开预装载并把影子钉成同一频率,再 ENABLE。 |
|
|
|
|
|
* 否则首拍 ISR 的 SetFreqIsr 可能落在 ARPE=0 窗口,直接改写工作 ARR。 |
|
|
|
|
|
*/ |
|
|
|
|
|
htim->Instance->CR1 |= TIM_CR1_ARPE; |
|
|
|
|
|
htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; |
|
|
|
|
|
htim->Instance->ARR = s_last_arr; |
|
|
|
|
|
htim->Instance->CCR1 = ccr; |
|
|
|
|
|
|
|
|
htim->Instance->CNT = s_last_arr; |
|
|
htim->Instance->CNT = s_last_arr; |
|
|
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); |
|
|
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); |
|
|
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); |
|
|
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); |
|
|
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE); |
|
|
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE); |
|
|
__HAL_TIM_ENABLE(htim); |
|
|
__HAL_TIM_ENABLE(htim); |
|
|
|
|
|
|
|
|
/* 运行期改频仍走预装载 */ |
|
|
|
|
|
htim->Instance->CR1 |= TIM_CR1_ARPE; |
|
|
|
|
|
htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; |
|
|
|
|
|
htim->Instance->ARR = s_last_arr; |
|
|
|
|
|
htim->Instance->CCR1 = (s_last_ccr < 1U) ? 1U : s_last_ccr; |
|
|
|
|
|
|
|
|
/* 记录起跳工作寄存器,供首拍 ISR 保护当前周期 */ |
|
|
|
|
|
s_protect_arr = s_last_arr; |
|
|
|
|
|
s_protect_ccr = ccr; |
|
|
|
|
|
s_protect_start_period = 1U; |
|
|
|
|
|
|
|
|
s_regs_prepared = 0U; |
|
|
s_regs_prepared = 0U; |
|
|
} |
|
|
} |
|
|
@@ -737,23 +753,53 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) |
|
|
uint32_t clk_hz; |
|
|
uint32_t clk_hz; |
|
|
TIM_HandleTypeDef *htim; |
|
|
TIM_HandleTypeDef *htim; |
|
|
|
|
|
|
|
|
/* 匀速热路径:频率未变 → 不算量化、不写寄存器 */ |
|
|
|
|
|
if (freq_hz == s_last_freq) |
|
|
|
|
|
|
|
|
htim = s_active_htim; |
|
|
|
|
|
if (htim == (TIM_HandleTypeDef *)0) |
|
|
{ |
|
|
{ |
|
|
|
|
|
if (freq_hz == 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
s_req_freq = 0U; |
|
|
|
|
|
s_req_pending = 1U; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
s_req_freq = freq_hz; |
|
|
|
|
|
s_req_pending = 1U; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (freq_hz == 0U) |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* 冷启动首拍:无论下一频是否变化,先把工作 ARR 钉回起跳频,再开预装载。 |
|
|
|
|
|
* 必须在「freq==last 早退」之前做,否则首拍保护标志清不掉。 |
|
|
|
|
|
*/ |
|
|
|
|
|
if (s_protect_start_period != 0U) |
|
|
|
|
|
{ |
|
|
|
|
|
s_protect_start_period = 0U; |
|
|
|
|
|
htim->Instance->CR1 &= (uint32_t)(~TIM_CR1_ARPE); |
|
|
|
|
|
htim->Instance->CCMR1 &= (uint32_t)(~TIM_CCMR1_OC1PE); |
|
|
|
|
|
htim->Instance->ARR = s_protect_arr; |
|
|
|
|
|
htim->Instance->CCR1 = (s_protect_ccr < 1U) ? 1U : s_protect_ccr; |
|
|
|
|
|
htim->Instance->CR1 |= TIM_CR1_ARPE; |
|
|
|
|
|
htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; |
|
|
|
|
|
/* 影子也先钉成起跳,下面再写入真正的下一拍频率 */ |
|
|
|
|
|
htim->Instance->ARR = s_protect_arr; |
|
|
|
|
|
htim->Instance->CCR1 = (s_protect_ccr < 1U) ? 1U : s_protect_ccr; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
/* 常规路径:确保预装载开启,禁止直写工作寄存器 */ |
|
|
|
|
|
htim->Instance->CR1 |= TIM_CR1_ARPE; |
|
|
|
|
|
htim->Instance->CCMR1 |= TIM_CCMR1_OC1PE; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 匀速热路径:频率未变 → 不算量化、不写寄存器 */ |
|
|
|
|
|
if (freq_hz == s_last_freq) |
|
|
{ |
|
|
{ |
|
|
s_req_freq = 0U; |
|
|
|
|
|
s_req_pending = 1U; |
|
|
|
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
htim = s_active_htim; |
|
|
|
|
|
if (htim == (TIM_HandleTypeDef *)0) |
|
|
|
|
|
|
|
|
if (freq_hz == 0U) |
|
|
{ |
|
|
{ |
|
|
s_req_freq = freq_hz; |
|
|
|
|
|
|
|
|
s_req_freq = 0U; |
|
|
s_req_pending = 1U; |
|
|
s_req_pending = 1U; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
@@ -783,12 +829,19 @@ void PlsrPulseDriverSetFreqIsr(uint32_t freq_hz) |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (ccr < 1U) |
|
|
|
|
|
{ |
|
|
|
|
|
ccr = 1U; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 此时 ARPE 已开:只改影子,下一 UPDATE 才切换,当前起跳周期不受影响 */ |
|
|
__HAL_TIM_SET_AUTORELOAD(htim, arr); |
|
|
__HAL_TIM_SET_AUTORELOAD(htim, arr); |
|
|
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); |
|
|
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr); |
|
|
|
|
|
|
|
|
s_last_freq = freq_hz; |
|
|
s_last_freq = freq_hz; |
|
|
s_last_psc = psc; |
|
|
s_last_psc = psc; |
|
|
s_last_arr = arr; |
|
|
s_last_arr = arr; |
|
|
|
|
|
s_last_ccr = ccr; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** @brief 丢弃挂起(见 plsr_pulse_driver.h) */ |
|
|
/** @brief 丢弃挂起(见 plsr_pulse_driver.h) */ |
|
|
@@ -797,6 +850,12 @@ void PlsrPulseDriverClearPending(void) |
|
|
s_req_pending = 0U; |
|
|
s_req_pending = 0U; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** @brief 取消冷启动首拍保护(见 plsr_pulse_driver.h) */ |
|
|
|
|
|
void PlsrPulseDriverClearStartPeriodProtect(void) |
|
|
|
|
|
{ |
|
|
|
|
|
s_protect_start_period = 0U; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** @brief 消费挂起改频(见 plsr_pulse_driver.h) */ |
|
|
/** @brief 消费挂起改频(见 plsr_pulse_driver.h) */ |
|
|
void PlsrPulseDriverApplyPending(void) |
|
|
void PlsrPulseDriverApplyPending(void) |
|
|
{ |
|
|
{ |
|
|
@@ -827,6 +886,7 @@ void PlsrPulseDriverStop(void) |
|
|
{ |
|
|
{ |
|
|
s_req_pending = 0U; |
|
|
s_req_pending = 0U; |
|
|
s_regs_prepared = 0U; |
|
|
s_regs_prepared = 0U; |
|
|
|
|
|
s_protect_start_period = 0U; |
|
|
PlsrPulseDriverStopHtim(&htim10); |
|
|
PlsrPulseDriverStopHtim(&htim10); |
|
|
PlsrPulseDriverStopHtim(&htim11); |
|
|
PlsrPulseDriverStopHtim(&htim11); |
|
|
PlsrPulseDriverStopHtim(&htim13); |
|
|
PlsrPulseDriverStopHtim(&htim13); |
|
|
|