使用PE5,根据数据手册说明,可以重映射为TIMER8_CH0。

代码实现:
#define PWM_TIMER TIMER8
#define PWM_TIMER_RCU RCU_TIMER8
#define PWM_GPIO_RCU RCU_GPIOE
#define PWM_GPIO_PORT GPIOE
#define PWM_GPIO_PIN GPIO_PIN_5
#define PWM_CHANNEL TIMER_CH_0
#define PWM_DUTY_MAX 10000U // 10000 = 100.00%
#define PWM_MAX_COUNTS 65535U // ARR+1, 留出 CCR=65535 支持 100%
static uint16_t s_pwm_arr;
static uint16_t s_pwm_duty_10000;
static uint8_t s_pwm_output_enabled = 0U;
static uint32_t timer8_clock_get(void)
{
uint32_t pclk2 = rcu_clock_freq_get(CK_APB2);
if ((RCU_CFG0 & RCU_CFG0_APB2PSC) == RCU_APB2_CKAHB_DIV1)
{
return pclk2;
}
else
{
return pclk2 * 2U;
}
}
static void pwm_calc_millihz(uint64_t freq_millihz, uint16_t *psc, uint16_t *arr)
{
uint32_t timer_clk;
uint64_t total_counts_64;
uint32_t total_counts;
uint32_t psc_div;
uint32_t arr_counts;
timer_clk = timer8_clock_get();
total_counts_64 = ((uint64_t)timer_clk * 1000ULL + freq_millihz / 2ULL) / freq_millihz;
if (total_counts_64 < 2ULL)
{
total_counts_64 = 2ULL;
}
if (total_counts_64 > (65536ULL * 65535ULL))
{
total_counts_64 = 65536ULL * 65535ULL;
}
total_counts = (uint32_t)total_counts_64;
psc_div = (total_counts + 65535U - 1U) / 65535U;
if (psc_div < 1U)
{
psc_div = 1U;
}
if (psc_div > 65536U)
{
psc_div = 65536U;
}
arr_counts = (total_counts + psc_div / 2U) / psc_div;
if (arr_counts < 2U)
{
arr_counts = 2U;
}
if (arr_counts > 65535U)
{
arr_counts = 65535U;
}
*psc = (uint16_t)(psc_div - 1U);
*arr = (uint16_t)(arr_counts - 1U);
}
static uint16_t pwm_duty_to_ccr(uint16_t arr, uint16_t duty_10000)
{
uint32_t counts = (uint32_t)arr + 1U;
if (duty_10000 > PWM_DUTY_MAX)
{
duty_10000 = PWM_DUTY_MAX;
}
return (uint16_t)(((uint64_t)counts * duty_10000) / PWM_DUTY_MAX);
}
void pe5_pwm_set_millihz(uint64_t freq_millihz, uint16_t duty_10000)
{
uint16_t psc;
uint16_t arr;
uint16_t ccr;
if (duty_10000 > PWM_DUTY_MAX)
{
duty_10000 = PWM_DUTY_MAX;
}
pwm_calc_millihz(freq_millihz, &psc, &arr);
ccr = pwm_duty_to_ccr(arr, duty_10000);
s_pwm_arr = arr;
s_pwm_duty_10000 = duty_10000;
timer_prescaler_config(PWM_TIMER, psc, TIMER_PSC_RELOAD_UPDATE);
timer_autoreload_value_config(PWM_TIMER, arr);
timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL, ccr);
// 立即装载 PSC/ARR/CCR 的影子寄存器
timer_event_software_generate(PWM_TIMER, TIMER_EVENT_SRC_UPG);
}
void pe5_pwm_set_duty(uint16_t duty_10000)
{
if (duty_10000 > PWM_DUTY_MAX)
{
duty_10000 = PWM_DUTY_MAX;
}
s_pwm_duty_10000 = duty_10000;
timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL, pwm_duty_to_ccr(s_pwm_arr, duty_10000));
timer_event_software_generate(PWM_TIMER, TIMER_EVENT_SRC_UPG);
}
void pe5_on(void)
{
uint16_t ccr = pwm_duty_to_ccr(s_pwm_arr, s_pwm_duty_10000);
s_pwm_output_enabled = 1U;
timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL, ccr);
timer_channel_output_state_config(PWM_TIMER, PWM_CHANNEL, TIMER_CCX_ENABLE);
timer_primary_output_config(PWM_TIMER, ENABLE);
timer_enable(PWM_TIMER);
timer_event_software_generate(PWM_TIMER, TIMER_EVENT_SRC_UPG);
}
void pe5_off(void)
{
s_pwm_output_enabled = 0U;
// PWM0 + high polarity 下,CCR=0 等效为 0% 占空比,PE5 保持低电平
timer_channel_output_pulse_value_config(PWM_TIMER, PWM_CHANNEL, 0U);
timer_event_software_generate(PWM_TIMER, TIMER_EVENT_SRC_UPG);
}
void pe5_pwm_init(uint64_t freq_millihz, uint16_t duty_10000)
{
static uint8_t once_flag = 0;
if (once_flag)
{
return;
}
timer_parameter_struct timer_initpara;
timer_oc_parameter_struct oc_initpara;
rcu_periph_clock_enable(PWM_GPIO_RCU);
rcu_periph_clock_enable(RCU_AF);
rcu_periph_clock_enable(PWM_TIMER_RCU);
gpio_pin_remap_config(GPIO_TIMER8_REMAP, ENABLE);
gpio_init(PWM_GPIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, PWM_GPIO_PIN);
timer_deinit(PWM_TIMER);
timer_struct_para_init(&timer_initpara);
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0U;
timer_init(PWM_TIMER, &timer_initpara);
timer_channel_output_struct_para_init(&oc_initpara);
oc_initpara.outputstate = TIMER_CCX_ENABLE;
oc_initpara.outputnstate = TIMER_CCXN_DISABLE;
oc_initpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
oc_initpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
oc_initpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
oc_initpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(PWM_TIMER, PWM_CHANNEL, &oc_initpara);
timer_channel_output_mode_config(PWM_TIMER, PWM_CHANNEL, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(PWM_TIMER, PWM_CHANNEL, TIMER_OC_SHADOW_ENABLE);
timer_auto_reload_shadow_enable(PWM_TIMER);
pe5_pwm_set_millihz(freq_millihz, duty_10000);
timer_primary_output_config(PWM_TIMER, ENABLE);
timer_enable(PWM_TIMER);
}