HPMicro:PWM双更新
PWM 定时器的比较器 CMPx,它们的影子寄存器值生效时刻可以通过MPCFGx[CMPSHDWUPT] 位设置:定时器的某一个 CMP 发生匹配后生效,用户可以通过 GCR [CMPSHDWSEL] 从比较器 0∼15 中选择一个,匹配可以是该比较器的输出比较,也可以是输入捕获。用户可以选择把选中的比较器 CMPx的值设为与 RLD 或 xRLD 相等,达到一个完整的 PWM 周期后更新影子寄存器的目的。
PWM双更新,就是在一个PWM周期内设置两个比较器来更新选定的比较器的值。如下图所示,在任意时刻修改CMP0影子寄存器以后,会在PWM计数器值到达CMP2和CMP3以后,CMP0的值才会生效。
以下是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);}#if 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的更新触发源*/#else/*CH8自己一个周期产生两个上升沿,独自触发两次*/cmp_config[3].mode = pwm_cmp_mode_output_compare;cmp_config[3].cmp = (reload >> 1) + 1;cmp_config[3].update_trigger = pwm_shadow_register_update_on_modify;cmp_config[4].mode = pwm_cmp_mode_output_compare;cmp_config[4].cmp = reload - 1;cmp_config[4].update_trigger = pwm_shadow_register_update_on_modify;pwm_output_channel_t pwm_output_ch_cfg;pwm_config_cmp(PWM, cmp_index + 2, &cmp_config[2]);pwm_config_cmp(PWM, cmp_index + 3, &cmp_config[3]);pwm_config_cmp(PWM, cmp_index + 4, &cmp_config[4]);/* 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 + 4; /* end channel */pwm_output_ch_cfg.invert_output = false;pwm_config_output_channel(PWM, 8, &pwm_output_ch_cfg);
#endif/*这里配置通道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 edge aligned waveform\n");//printf("Two waveforms will be generated, PWM P%d is the target waveform\n", PWM_OUTPUT_PIN1);//printf("whose duty cycle will be updated from 0 - 100 and back to 0; PWM P%d is a reference\n", PWM_OUTPUT_PIN2);//generate_edge_aligned_waveform();//printf("\n\n>> Generate edge aligned waveform and fault mode enable\n");//printf("Two waveforms will be generated, PWM P%d is the target waveform\n", PWM_OUTPUT_PIN1);//printf("whose duty cycle will be updated from 0 - 100 and back to 0; PWM P%d is a reference\n", PWM_OUTPUT_PIN2);//generate_edge_aligned_waveform_fault_mode();//printf("\n\n>> Generate central aligned waveform\n");//printf("Two waveforms will be generated, PWM P%d is the target waveform\n", PWM_OUTPUT_PIN1);//printf("whose duty cycle will be updated from 0 - 100 and back to 0; PWM P%d is a reference\n", PWM_OUTPUT_PIN2);//generate_central_aligned_waveform();printf("\n\n>> Generate central aligned waveform in pair\n");printf("Two waveforms will be generated in pair, PWM P%d and P%d are target\n", PWM_OUTPUT_PIN1, PWM_OUTPUT_PIN2);printf("waveforms whose duty cycle will be updated from 0 - 100 and back to 0\n");generate_central_aligned_waveform_in_pair();//printf("\n\n>> Generate edge aligned jit waveform\n");//printf("Two waveforms will be generated, PWM P%d is the target waveform\n", PWM_OUTPUT_PIN1);//printf("whose duty cycle will be updated from 0 - 100 and back to 0; PWM P%d is a reference\n", PWM_OUTPUT_PIN2);//generate_pwm_cmpjit_edge_aligned_waveform();disable_all_pwm_output();printf("test done\n");while(1);return 0;
}
测试波形如下所示: