因为先楫6E系列芯片使用PWM V2版本,在实现PWM双更新的时候,使用方法和PWM V1版本不同。这篇文章提供了参考用例,供大家参考。这里使用了PWM V2的触发输出功能和触发输入功能,将触发输出的PWM波形通过TRGM作为触发输入信号,来同步PWM的比较器1更新生效。
/*
* Copyright (c) 2021 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "board.h"
#include <stdio.h>
#include "hpm_debug_console.h"
#include "hpm_pwmv2_drv.h"
#include "hpm_trgm_drv.h"
#include "hpm_clock_drv.h"
#ifndef PWM
#define PWM BOARD_APP_PWM
#define PWM_CLOCK_NAME BOARD_APP_PWM_CLOCK_NAME
#define PWM_OUTPUT_PIN1 BOARD_APP_PWM_OUT2
#define PWM_OUTPUT_PIN2 BOARD_APP_PWM_OUT3
#define TRGM BOARD_APP_TRGM
#define TRGM_PWM_OUTPUT BOARD_APP_TRGM_PWM_OUTPUT
#endif
#ifndef TEST_LOOP
#define TEST_LOOP (200)
#endif
#define PWM_PERIOD_IN_MS (1)
uint32_t reload;
void generate_central_aligned_waveform_in_pair(void)
{
uint32_t duty, duty_step;
bool increase_duty_cycle = true;
pwmv2_disable_counter(PWM, pwm_counter_0);
pwmv2_reset_counter(PWM, pwm_counter_0);
pwmv2_shadow_register_unlock(PWM);
pwmv2_set_shadow_val(PWM, PWMV2_SHADOW_INDEX(0), reload, 0, false);
pwmv2_set_shadow_val(PWM, PWMV2_SHADOW_INDEX(1), reload, 0, false);
pwmv2_set_shadow_val(PWM, PWMV2_SHADOW_INDEX(2), reload, 0, false);
pwmv2_set_shadow_val(PWM, PWMV2_SHADOW_INDEX(16), reload >> 1, 0, false);
pwmv2_set_shadow_val(PWM, PWMV2_SHADOW_INDEX(17), reload - 1, 0, false);
pwmv2_set_shadow_val(PWM, PWMV2_SHADOW_INDEX(18), reload >> 2, 0, false);
pwmv2_counter_select_data_offset_from_shadow_value(PWM, pwm_counter_0, PWMV2_SHADOW_INDEX(0));
pwmv2_counter_burst_disable(PWM, pwm_counter_0);
pwmv2_set_reload_update_time(PWM, pwm_counter_0, pwm_reload_update_on_reload);
pwmv2_select_cmp_source(PWM, PWMV2_CMP_INDEX(0), cmp_value_from_shadow_val, PWMV2_SHADOW_INDEX(1));
pwmv2_select_cmp_source(PWM, PWMV2_CMP_INDEX(1), cmp_value_from_shadow_val, PWMV2_SHADOW_INDEX(2));
pwmv2_select_cmp_source(PWM, PWMV2_CMP_INDEX(16), cmp_value_from_shadow_val, PWMV2_SHADOW_INDEX(16)); // cmp16发生匹配,触发cpm0生效
pwmv2_select_cmp_source(PWM, PWMV2_CMP_INDEX(17), cmp_value_from_shadow_val, PWMV2_SHADOW_INDEX(17)); // cmp17发生匹配,触发cpm0生效
pwmv2_select_cmp_source(PWM, PWMV2_CMP_INDEX(18), cmp_value_from_shadow_val, PWMV2_SHADOW_INDEX(18));
pwmv2_cmp_update_trig_time(BOARD_APP_PWM, PWMV2_CMP_INDEX(0), pwm_shadow_register_update_on_rld_cmp_select0);
pwmv2_cmp_update_trig_time(BOARD_APP_PWM, PWMV2_CMP_INDEX(0), pwm_shadow_register_update_on_rld_cmp_select1);
//pwmv2_cmp_update_trig_time(BOARD_APP_PWM, PWMV2_CMP_INDEX(0), pwm_shadow_register_update_on_modify);
//pwmv2_cmp_update_trig_time(BOARD_APP_PWM, PWMV2_CMP_INDEX(1), pwm_shadow_register_update_on_modify);
pwmv2_cmp_update_trig_time(BOARD_APP_PWM, PWMV2_CMP_INDEX(1), pwm_shadow_register_update_on_trigmux); // pwm_shadow_register_update_on_trigmux
pwmv2_cmp_update_trig_time(BOARD_APP_PWM, PWMV2_CMP_INDEX(16), pwm_shadow_register_update_on_modify);
pwmv2_cmp_update_trig_time(BOARD_APP_PWM, PWMV2_CMP_INDEX(17), pwm_shadow_register_update_on_modify);
pwmv2_cmp_update_trig_time(BOARD_APP_PWM, PWMV2_CMP_INDEX(18), pwm_shadow_register_update_on_modify);
pwmv2_cmp_select_counter(PWM, PWMV2_CMP_INDEX(16), pwm_counter_0);
pwmv2_cmp_select_counter(PWM, PWMV2_CMP_INDEX(17), pwm_counter_0);
pwmv2_cmp_select_counter(PWM, PWMV2_CMP_INDEX(18), pwm_counter_0);
pwmv2_reload_select_compare_point0_index(BOARD_APP_PWM, pwm_counter_0, PWMV2_CMP_INDEX(16));
pwmv2_reload_select_compare_point1_index(BOARD_APP_PWM, pwm_counter_0, PWMV2_CMP_INDEX(17));
pwmv2_set_trigout_cmp_index(BOARD_APP_PWM, pwm_channel_2, PWMV2_CMP_INDEX(18));
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_PWM1_TRGO_0;
trgm_output_config(HPM_TRGM0, HPM_TRGM0_OUTPUT_SRC_MOT_GPIO9, &trgm0_io_config0);
trgm_enable_io_output(HPM_TRGM0, 1 << 9);
trgm_output_t trgm0_io_config1 = {0};
trgm0_io_config1.invert = 0;
trgm0_io_config1.type = trgm_output_same_as_input;
trgm0_io_config1.input = HPM_TRGM0_INPUT_SRC_PWM1_TRGO_2;
trgm_output_config(HPM_TRGM0, HPM_TRGM0_OUTPUT_SRC_PWM1_TRIG_IN3, &trgm0_io_config1);
pwmv2_select_cmp_trigmux(BOARD_APP_PWM, PWMV2_CMP_INDEX(1), pwm_channel_3);
pwmv2_set_dead_area(PWM, BOARD_APP_PWM_OUT1, 50);
pwmv2_set_dead_area(PWM, BOARD_APP_PWM_OUT2, 50);
pwmv2_shadow_register_lock(PWM);
pwmv2_disable_four_cmp(PWM, BOARD_APP_PWM_OUT1);
pwmv2_channel_enable_output(PWM, BOARD_APP_PWM_OUT1);
pwmv2_channel_enable_output(PWM, BOARD_APP_PWM_OUT2);
pwmv2_enable_pair_mode(PWM, BOARD_APP_PWM_OUT1);
pwmv2_enable_pair_mode(PWM, BOARD_APP_PWM_OUT2);
pwmv2_enable_counter(PWM, pwm_counter_0);
pwmv2_start_pwm_output(PWM, pwm_counter_0);
duty_step = reload / 100;
duty = reload / 2;
increase_duty_cycle = true;
for (uint32_t i = 0; i < 10; i++) { //TEST_LOOP
if (increase_duty_cycle) {
if ((duty + duty_step) >= reload) {
increase_duty_cycle = false;
continue;
}
duty += duty_step;
} else {
if (duty <= duty_step) {
increase_duty_cycle = true;
continue;
}
duty -= duty_step;
}
pwmv2_shadow_register_unlock(PWM);
pwmv2_set_shadow_val(PWM, PWMV2_SHADOW_INDEX(1), (reload - duty) >> 1, 0, false);
pwmv2_set_shadow_val(PWM, PWMV2_SHADOW_INDEX(2), (reload + duty) >> 1, 0, false);
pwmv2_shadow_register_lock(PWM);
board_delay_ms(100);
}
}
void pwm_force_output(void)
{
board_delay_ms(500);
pwmv2_enable_shadow_lock_feature(PWM);
pwmv2_set_force_update_time(PWM, BOARD_APP_PWM_OUT1, pwm_force_immediately);
pwmv2_set_force_update_time(PWM, BOARD_APP_PWM_OUT2, pwm_force_immediately);
pwmv2_force_update_time_by_shadow(PWM, BOARD_APP_PWM_OUT1, pwm_force_update_shadow_immediately);
pwmv2_force_update_time_by_shadow(PWM, BOARD_APP_PWM_OUT2, pwm_force_update_shadow_immediately);
pwmv2_enable_force_by_software(PWM, BOARD_APP_PWM_OUT1);
pwmv2_enable_force_by_software(PWM, BOARD_APP_PWM_OUT2);
pwmv2_enable_software_force(PWM, BOARD_APP_PWM_OUT1);
pwmv2_enable_software_force(PWM, BOARD_APP_PWM_OUT2);
pwmv2_channel_enable_output(PWM, BOARD_APP_PWM_OUT1);
pwmv2_channel_enable_output(PWM, BOARD_APP_PWM_OUT2);
pwmv2_shadow_register_unlock(PWM);
pwmv2_force_output(PWM, BOARD_APP_PWM_OUT1, pwm_force_output_1, false);
pwmv2_force_output(PWM, BOARD_APP_PWM_OUT2, pwm_force_output_1, false);
pwmv2_shadow_register_lock(PWM);
board_delay_ms(500);
pwmv2_shadow_register_unlock(PWM);
pwmv2_force_output(PWM, BOARD_APP_PWM_OUT1, pwm_force_output_0, false);
pwmv2_force_output(PWM, BOARD_APP_PWM_OUT2, pwm_force_output_0, false);
pwmv2_shadow_register_lock(PWM);
board_delay_ms(500);
pwmv2_disable_force_by_software(PWM, BOARD_APP_PWM_OUT1);
pwmv2_disable_force_by_software(PWM, BOARD_APP_PWM_OUT2);
}
void disable_all_pwm_output(void)
{
board_delay_ms(500);
pwmv2_enable_shadow_lock_feature(PWM);
pwmv2_set_force_update_time(PWM, BOARD_APP_PWM_OUT1, pwm_force_immediately);
pwmv2_set_force_update_time(PWM, BOARD_APP_PWM_OUT2, pwm_force_immediately);
pwmv2_set_force_update_time(PWM, BOARD_APP_PWM_OUT3, pwm_force_immediately);
pwmv2_set_force_update_time(PWM, BOARD_APP_PWM_OUT4, pwm_force_immediately);
pwmv2_set_force_update_time(PWM, pwm_channel_5, pwm_force_immediately);
pwmv2_force_update_time_by_shadow(PWM, BOARD_APP_PWM_OUT1, pwm_force_update_shadow_immediately);
pwmv2_force_update_time_by_shadow(PWM, BOARD_APP_PWM_OUT2, pwm_force_update_shadow_immediately);
pwmv2_force_update_time_by_shadow(PWM, BOARD_APP_PWM_OUT3, pwm_force_update_shadow_immediately);
pwmv2_force_update_time_by_shadow(PWM, BOARD_APP_PWM_OUT4, pwm_force_update_shadow_immediately);
pwmv2_force_update_time_by_shadow(PWM, pwm_channel_5, pwm_force_update_shadow_immediately);
pwmv2_channel_enable_output(PWM, BOARD_APP_PWM_OUT1);
pwmv2_channel_enable_output(PWM, BOARD_APP_PWM_OUT2);
pwmv2_channel_enable_output(PWM, BOARD_APP_PWM_OUT3);
pwmv2_channel_enable_output(PWM, BOARD_APP_PWM_OUT4);
pwmv2_channel_enable_output(PWM, pwm_channel_5);
pwmv2_enable_force_by_software(PWM, BOARD_APP_PWM_OUT1);
pwmv2_enable_force_by_software(PWM, BOARD_APP_PWM_OUT2);
pwmv2_enable_force_by_software(PWM, BOARD_APP_PWM_OUT3);
pwmv2_enable_force_by_software(PWM, BOARD_APP_PWM_OUT4);
pwmv2_enable_force_by_software(PWM, pwm_channel_5);
pwmv2_enable_software_force(PWM, BOARD_APP_PWM_OUT1);
pwmv2_enable_software_force(PWM, BOARD_APP_PWM_OUT2);
pwmv2_enable_software_force(PWM, BOARD_APP_PWM_OUT3);
pwmv2_enable_software_force(PWM, BOARD_APP_PWM_OUT4);
pwmv2_enable_software_force(PWM, pwm_channel_5);
pwmv2_shadow_register_unlock(PWM);
pwmv2_force_output(PWM, BOARD_APP_PWM_OUT1, pwm_force_output_0, false);
pwmv2_force_output(PWM, BOARD_APP_PWM_OUT2, pwm_force_output_0, false);
pwmv2_force_output(PWM, BOARD_APP_PWM_OUT3, pwm_force_output_0, false);
pwmv2_force_output(PWM, BOARD_APP_PWM_OUT4, pwm_force_output_0, false);
pwmv2_force_output(PWM, pwm_channel_5, pwm_force_output_0, false);
pwmv2_shadow_register_lock(PWM);
}
void pwm_fault_async(void)
{
pwmv2_async_fault_source_config_t fault_cfg;
fault_cfg.async_signal_from_pad_index = BOARD_APP_PWM_FAULT_PIN;
fault_cfg.fault_async_pad_level = pad_fault_active_high;
pwmv2_config_async_fault_source(PWM, BOARD_APP_PWM_OUT1, &fault_cfg);
pwmv2_config_async_fault_source(PWM, BOARD_APP_PWM_OUT2, &fault_cfg);
pwmv2_set_fault_mode(PWM, BOARD_APP_PWM_OUT1, pwm_fault_output_0);
pwmv2_set_fault_mode(PWM, BOARD_APP_PWM_OUT2, pwm_fault_output_0);
pwmv2_enable_fault_from_pad(PWM, BOARD_APP_PWM_OUT1);
pwmv2_enable_fault_from_pad(PWM, BOARD_APP_PWM_OUT2);
}
int main(void)
{
uint32_t freq;
board_init();
init_pwm_pins(PWM);
init_pwm_fault_pins();
printf("pwm example\n");
freq = clock_get_frequency(PWM_CLOCK_NAME);
reload = freq / 1000 * PWM_PERIOD_IN_MS - 1;
pwm_fault_async();
printf("\n\n>> Test force PWM output on P%d and P%d\n", PWM_OUTPUT_PIN1, PWM_OUTPUT_PIN2);
pwm_force_output();
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();
disable_all_pwm_output();
printf("test done\n");
while (1) {
;
}
return 0;
}
可以使用6E00 EVK进行测试
使用逻辑分析仪来看输出波形: