HPMicro:6E系列芯片实现PWM双更新

因为先楫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进行测试

 使用逻辑分析仪来看输出波形:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AllenSun-1990

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值