PWM 定时器的比较器 CMPx,它们的影子寄存器值生效时刻可以通过MPCFGx[CMPSHDWUPT] 位设置:定时器的某一个 CMP 发生匹配后生效,用户可以通过 GCR [CMPSHDWSEL] 从比较器 0∼15 中选择一个,匹配可以是该比较器的输出比较,也可以是输入捕获。用户可以选择把选中的比较器 CMPx的值设为与 RLD 或 xRLD 相等,达到一个完整的 PWM 周期后更新影子寄存器的目的。
PWM双更新,就是在一个PWM周期内设置两个比较器来更新选定的比较器的值。如下图所示,在任意时刻修改CMP0影子寄存器以后,会在PWM计数器值到达CMP2和CMP3以后,CMP0的值才会生效。PWM双更新的主要作用是可以及时更新CMP0,使PWM波形及时变化,不致于等到经过一个PWM周期才使更新生效。
以下是PWM V1版本实现PWM双更新功能的示例代码:
void pwm_cmp_change(void)
{
static uint32_t timer = 0;
timer++;
if(timer % 2 == 0)
{
pwm_update_raw_cmp_edge_aligned(PWM, 0, reload * 2 / 3);
pwm_update_raw_cmp_edge_aligned(PWM, 1, reload - 1);
}
else if(timer % 2 == 1)
{
pwm_update_raw_cmp_edge_aligned(PWM, 0, reload * 1 / 3);
pwm_update_raw_cmp_edge_aligned(PWM, 1, reload - 1);
}
}
void generate_central_aligned_waveform_in_pair(void)
{
uint8_t cmp_index = 0;
uint32_t duty, duty_step;
bool increase_duty_cycle = true;
pwm_cmp_config_t cmp_config[5] = {0};
pwm_pair_config_t pwm_pair_config = {0};
pwm_output_channel_t pwm_output_ch_cfg;
pwm_stop_counter(PWM);
reset_pwm_counter();
/*
* reload and start counter
*/
pwm_set_reload(PWM, 0, reload);
pwm_set_start_count(PWM, 0, 0);
/*
* config cmp1 and cmp2
*/
cmp_config[0].mode = pwm_cmp_mode_output_compare;
cmp_config[0].cmp = reload/4;
cmp_config[0].update_trigger = pwm_shadow_register_update_on_hw_event; //pwm_shadow_register_update_on_modify pwm_shadow_register_update_on_hw_event; //pwm_shadow_register_update_on_hw_event;
cmp_config[1].mode = pwm_cmp_mode_output_compare;
cmp_config[1].cmp = reload+1;
cmp_config[1].update_trigger = pwm_shadow_register_update_on_sh_synci;
cmp_config[2].mode = pwm_cmp_mode_output_compare; // cmp2发生匹配,触发cpm0生效
cmp_config[2].cmp = reload>>1;
cmp_config[2].update_trigger = pwm_shadow_register_update_on_modify;
cmp_config[3].mode = pwm_cmp_mode_output_compare; // cmp3发生匹配,触发cpm0生效
cmp_config[3].cmp = reload - 1;
cmp_config[3].update_trigger = pwm_shadow_register_update_on_modify;
cmp_config[4].mode = pwm_cmp_mode_output_compare; // 触发产生SHRLDSYNCI上升沿
cmp_config[4].cmp = (reload>>1) + 1000;
cmp_config[4].update_trigger = pwm_shadow_register_update_on_modify;
pwm_get_default_pwm_pair_config(PWM, &pwm_pair_config);
pwm_pair_config.pwm[0].enable_output = true;
pwm_pair_config.pwm[0].dead_zone_in_half_cycle = 8000;
pwm_pair_config.pwm[0].invert_output = false;
pwm_pair_config.pwm[1].enable_output = true;
pwm_pair_config.pwm[1].dead_zone_in_half_cycle = 16000;
pwm_pair_config.pwm[1].invert_output = false;
/*
* config pwm
*/
if (status_success != pwm_setup_waveform_in_pair(PWM, PWM_OUTPUT_PIN1, &pwm_pair_config, cmp_index, cmp_config, 2)) {
printf("failed to setup waveform\n");
while(1);
}
/*CMP2,CMP3各触发一次*/
pwm_config_cmp(PWM, cmp_index + 2, &cmp_config[2]);
/* Set comparator channel to generate a trigger signal */
pwm_output_ch_cfg.cmp_start_index = cmp_index + 2; /* start channel */
pwm_output_ch_cfg.cmp_end_index = cmp_index + 2; /* end channel */
pwm_output_ch_cfg.invert_output = false;
pwm_load_cmp_shadow_on_match(PWM, cmp_index + 2, &cmp_config[2]); /*将CMP2做为 CMP0的更新触发源*/
pwm_config_cmp(PWM, cmp_index + 3, &cmp_config[3]);
/* Set comparator channel to generate a trigger signal */
pwm_output_ch_cfg.cmp_start_index = cmp_index + 3; /* start channel */
pwm_output_ch_cfg.cmp_end_index = cmp_index + 3; /* end channel */
pwm_output_ch_cfg.invert_output = false;
pwm_load_cmp_shadow_on_match(PWM, cmp_index + 3, &cmp_config[3]); /*将CMP3做为 CMP0的更新触发源*/
/*这里配置通道10连接到互联管理器,用来触发用于输出PWM的比较器1更新*/
pwm_output_ch_cfg.cmp_start_index = cmp_index + 4; /* start channel */
pwm_output_ch_cfg.cmp_end_index = cmp_index + 4; /* end channel */
pwm_output_ch_cfg.invert_output = false;
pwm_config_output_channel(PWM, 10, &pwm_output_ch_cfg);
pwm_config_cmp(PWM, cmp_index + 4, &cmp_config[4]);
trgm_output_t trgm0_io_config0 = {0};
trgm0_io_config0.invert = 0;
trgm0_io_config0.type = trgm_output_same_as_input;
trgm0_io_config0.input = HPM_TRGM0_INPUT_SRC_PWM0_CH10REF;
trgm_output_config(HPM_TRGM0, HPM_TRGM0_OUTPUT_SRC_PWM0_SHRLDSYNCI, &trgm0_io_config0);
pwm_start_counter(PWM);
pwm_issue_shadow_register_lock_event(PWM);
board_timer_create(50, pwm_cmp_change); // 50ms修改一次比较器cmp0的影子寄存器值
board_delay_ms(10000);
}
int main(void)
{
uint32_t freq;
board_init();
init_pwm_pins(PWM);
printf("pwm example\n");
freq = clock_get_frequency(PWM_CLOCK_NAME);
reload = freq / 1000 * PWM_PERIOD_IN_MS - 1;
printf("\n\n>> Test force PWM output on P%d and P%d\n", PWM_OUTPUT_PIN1, PWM_OUTPUT_PIN2);
test_pwm_force_output();
printf("\n\n>> Generate central aligned waveform in pair\n");
generate_central_aligned_waveform_in_pair();
disable_all_pwm_output();
printf("test done\n");
while(1);
return 0;
}
测试波形如下所示: