[MCU] 先楫官方工程师干货:快速熟悉HPM6750的PWM和HPM_SDK Driver API的使用方法(点灯)

谍纸天眼   2022-11-4 11:07 楼主

1 简介

本文主要介绍基于HPM6750 EVK Mini板驱动点亮LED三色灯,从而让用户能快速熟悉先楫MCU PWM定时器原理和HPM_SDK Driver API的使用方法。

本文档中有关HPM6750 EVK mini板的使用说明可以参考位于SDK软件包中\Doc目录下的HPM6750EVKMINI_UG.pdf

本文档中有关HPM6750 EVK mini 硬件原理图,请查阅HPM6750EVKMINI硬件设计资料\原理图\HPM6750EVKMINI Rev.B.pdf。

本文档中有关HPM6750 MCU datasheet,请查阅HPM6750_DS.pdf;有关HPM6750 MCU user manual请查阅HPM6750_UM.pdf

本文将基于HPM SDK中pwm driver api接口抽象封装针对LED灯的adapte接口,并通过adapte接口实现LED三色灯的开关和呼吸效果。

 

2 环境准备

2.1 PWM定时器原理

查阅HPM6750 MCU user manual文档中章节:电机系统->45 PWM定时器PWM内容。

 

640?wx_fmt=png

PWM的框图

 

大致介绍:

l 先楫PWM定时器由4个模块组成:定时器时间基准模块、比较器模块、输出通道模块、PWM输出控制模块。

l 定时器时间基准模块决定PWM定时器运行的时间和周期。通过读写计数器、起始寄存器、重载寄存器、计数器使能来设置定时器时间基准模块。

l PWM生成通过定时器时间基准模块配合比较器以及输出通道来生成输出参考信号。一个输出通道可匹配多个比较器(注意:匹配多个比较器必须连续),当计数器的值等于比较器的值时,产生匹配事件逻辑1,当计数器到达重载数值时,产生重载事件逻辑0。如果比较器的值和重载值相同,则会保持逻辑1产生100%占空比输出,如果比较器的值>重载值,则会保持逻辑0产生0%占空比输出。

l 输出通道输出的参考信号经过PWM输出控制模块处理互补控制、死区插入、取反控制、强制输出、故障保护后,形成输出信号到IO口。如果不对输出控制模块操作则透传输出通道参考信号。由于LED RGB三色灯使用不到以上,本文档不介绍PWM输出控制模块。

l 针对LED 简单的PWM波形,只需要一个比较器即可实现。波形实现如图:

 

640?wx_fmt=png

波形实现如图

 

PWM频率:总线时钟频率/重载值。

占空比:比较器值/总步长 * 100。

 

2.2 PWM Driver API梳理

查阅HPM SDK软件API手册中PWM driver APIs章节。

640?wx_fmt=png

 

针对LED 简单波形使用到的接口有:

//重载值设置pwm_set_reload
//计数器起始值设置pwm_set_start_count
//比较器配置pwm_config_cmp
//PWM波形设置(输出通道和比较器匹配设置)pwm_setup_waveform
//加载比较器影子寄存器匹配设置

pwm_load_cmp_shadow_on_match
//计时器使能计数pwm_start_counter
//计数器禁止计数pwm_stop_counter
//更新比较器边沿触发值(调整占空比)pwm_update_raw_cmp_edge_aligned
//使能PWM通道输出pwm_enable_output

//禁止PWM通道输出pwm_disable_output

 

2.3 确认LED 硬件PIN脚

查阅HPM6750 EVK mini 硬件原理图,确认LED三色灯三路PWM通道和管脚,分别为:

 

RED:     PWM0.P7 —— PB20

GREEN:  PWM1.P1 —— PB18

BLUE:    PWM1.P0 —— PB19

 

640?wx_fmt=png
640?wx_fmt=png

3 接口封装

 

3.1 PWM初始化

pwm_port_handle_t hpm_pwm_init(PWM_Type* pwm_id, uint32_t pwm_out, uint32_t pwm_cmp, bool init_zero, clock_name_t clock_name)
{
    led_pwm_t *handle = malloc(sizeof(led_pwm_t));
    if(NULL == handle)
        return NULL;
    memset(handle, 0, sizeof(led_pwm_t));
    handle->pwm = pwm_id;
    handle->reload = 0;
    handle->step = 0;
    handle->pwm_irq = 0;
    handle->pwm_cmp = pwm_cmp;
    handle->pwm_ch = pwm_out;
    handle->pwm_cmp_initial_zero = init_zero;
    handle->bus_freq = clock_get_frequency(clock_name);
    return (pwm_port_handle_t)handle;
}


    handle->pwm_irq = 0;
    handle->pwm_cmp = pwm_cmp;
    handle->pwm_ch = pwm_out;
    handle->pwm_cmp_initial_zero = init_zero;
    handle->bus_freq = clock_get_frequency(clock_name);
    return (pwm_port_handle_t)handle;

 

 

3.2 PWM释放

void hpm_pwm_deinit(pwm_port_handle_t pwm_handle)
{
    led_pwm_t *handle = (led_pwm_t *)pwm_handle;
    if(NULL == handle)
        return;
    pwm_disable_output(handle->pwm, handle->pwm_ch);
    free(handle);
    handle = NULL;
    return;

3.3 PWM运行


#define PWM_DUTY_STEP_COUNT (100U)
/*duty: 0~100%, freq: 100~200000000*/
int hpm_pwm_start(pwm_port_handle_t pwm_handle, uint32_t duty, uint32_t freq)
{
    led_pwm_t *handle = (led_pwm_t *)pwm_handle;
    uint32_t reload, now_cmp;
    pwm_cmp_config_t cmp_config = {0};
    pwm_config_t pwm_config = {0};
    if(NULL == handle)
    {
        return -1;
    }
    if(freq > handle->bus_freq)
    {
        return -2;
    }
    reload = handle->bus_freq / freq - 1; //start 0 index
    if(reload == 0)
        return -2;
    if(reload != handle->reload || handle->reload == 0)
    {
        handle->reload = reload;
        pwm_stop_counter(handle->pwm);
        pwm_get_default_pwm_config(handle->pwm, &pwm_config);
        pwm_get_default_cmp_config(handle->pwm, &cmp_config);
        pwm_config.enable_output = false;
        pwm_config.dead_zone_in_half_cycle = 0;
        pwm_config.invert_output = false;
        /*
        * reload and start counter
        */
        pwm_set_reload(handle->pwm, 0, handle->reload);
        pwm_set_start_count(handle->pwm, 0, 0);
        cmp_config.mode = pwm_cmp_mode_output_compare;
        cmp_config.cmp = handle->pwm_cmp_initial_zero ? 0 : handle->reload + 1;
        cmp_config.update_trigger = pwm_shadow_register_update_on_modify;
        /* config initial compare value which should take affect immediately */
        pwm_config_cmp(handle->pwm, handle->pwm_cmp, &cmp_config);
        /*
        * config pwm as output driven by cmp
        */
        if (status_success != pwm_setup_waveform(handle->pwm, handle->pwm_ch, &pwm_config, handle->pwm_cmp, &cmp_config, 1)) {
            printf("failed to setup waveform\n");
            return -3;
        }
        pwm_load_cmp_shadow_on_match(handle->pwm, handle->pwm_cmp, &cmp_config);
        handle->step = (handle->reload + 1)/PWM_DUTY_STEP_COUNT;
        pwm_update_raw_cmp_edge_aligned(handle->pwm, handle->pwm_cmp, handle->pwm_cmp_initial_zero ? 0 : handle->reload + 1);
        pwm_start_counter(handle->pwm);
    }
    if(duty == 100)
    {
        now_cmp = handle->reload + 1;
    }
    else
    {
        now_cmp = handle->step * PWM_DUTY_STEP_COUNT/100 * duty;
    }
    pwm_update_raw_cmp_edge_aligned(handle->pwm, handle->pwm_cmp, now_cmp);
    pwm_enable_output(handle->pwm, handle->pwm_ch);
    return 0;

3.4 PWM停止

nt hpm_pwm_stop(pwm_port_handle_t pwm_handle)
{
    led_pwm_t *handle = (led_pwm_t *)pwm_handle;
    if(NULL == handle)
        return -1;
    pwm_disable_output(handle->pwm, handle->pwm_ch);
    return 0;

 

4 功能实现

4.1 呼吸灯功能

#define LED_PWM_FREQ  200000 //200khz


int sample_breath_lamp(pwm_port_handle_t handle)
{
    if(NULL == handle)
    {
        printf("handle is null\n");
        return -1;
    }
    for(uint32_t i = 0; i <= 100; i++)
    {
        hpm_pwm_start(handle, i, LED_PWM_FREQ);
        board_delay_ms(10);
    }
    for(uint32_t i = 100; i > 0; i--)
    {
        hpm_pwm_start(handle, i, LED_PWM_FREQ);
        board_delay_ms(10);
    }
    hpm_pwm_stop(handle);
    return 0;
}

4.2 LED点亮呼吸

 

  board_init();
    board_init_rgb_pwm_pins();
    printf("rgb led example\n");
    pwm_port_handle_t red_handle = hpm_pwm_init(RED_PWM, RED_PWM_OUT, RED_PWM_CMP, RED_PWM_CMP_INITIAL_ZERO, RED_PWM_CLOCK_NAME);
    if(red_handle == NULL)
    {
        printf("red pwm init fail!\n");
        while(1);
    }
    pwm_port_handle_t green_handle = hpm_pwm_init(GREEN_PWM, GREEN_PWM_OUT, GREEN_PWM_CMP, GREEN_PWM_CMP_INITIAL_ZERO, GREEN_PWM_CLOCK_NAME);
    if(green_handle == NULL)
    {
        printf("green pwm init fail!\n");
        while(1);
    }
    pwm_port_handle_t blue_handle = hpm_pwm_init(BLUE_PWM, BLUE_PWM_OUT, BLUE_PWM_CMP, BLUE_PWM_CMP_INITIAL_ZERO, BLUE_PWM_CLOCK_NAME);
    if(blue_handle == NULL)
    {
        printf("blue pwm init fail!\n");
        while(1);
    }
    //on led and off led
    hpm_pwm_start(red_handle, 100, LED_PWM_FREQ);
    board_delay_ms(1000);
    hpm_pwm_start(red_handle, 0, LED_PWM_FREQ);
    board_delay_ms(1000);
    hpm_pwm_start(green_handle, 100, LED_PWM_FREQ);
    board_delay_ms(1000);
    hpm_pwm_start(green_handle, 0, LED_PWM_FREQ);
    board_delay_ms(1000);
    hpm_pwm_start(blue_handle, 100, LED_PWM_FREQ);
    board_delay_ms(1000);
    hpm_pwm_start(blue_handle, 0, LED_PWM_FREQ);
    board_delay_ms(1000);
    while(1)
    {
        printf("now red breath...\n");
        sample_breath_lamp(red_handle);
        printf("now green breath...\n");
        sample_breath_lamp(green_handle);
        printf("now bule breath...\n");
        sample_breath_lamp(blue_handle);
    }
    hpm_pwm_deinit(red_handle);
    hpm_pwm_deinit(green_handle);
    hpm_pwm_deinit(blue_handle);
    return 0;
}


 

5 功能测试

 

5.1 生成rgb_led工程

 

工程路径在HPM_SDK 文件夹:“hpm_sdk\samples\rgb_led

 

640?wx_fmt=png

 

根据SDK 开发指南文档《HPM6750EVKMINI_UG》中的工程生成步骤,在rgb_led目录下来生成segger embedded studio的工程文件。

 

640?wx_fmt=png

 

通过双击工程文件multcore_core0.emProject可以直接进入SES(segger embedded studio) 。

 

640?wx_fmt=png

 

双击“multcore_core0.emProject”打开该工程,如下图。

 

640?wx_fmt=png

 

5.2 运行rgb_led

 

运行rgb_led例程,可以查看到Mini板三色点亮熄灭以及循环呼吸效果。

 

640?wx_fmt=png
640?wx_fmt=png

 

5.3 PWM波形查看

 

通过示波器查看rgb pwm波形,确认频率和占空比是否正确。

 

A. 200KHz,50%占空比

实测:一个周期5us,波峰2.495us。

640?wx_fmt=png
640?wx_fmt=png

 

B. 200KHz, 20%占空比

实测:一个周期5us,波峰:994.7ns,验证通过。

640?wx_fmt=png
640?wx_fmt=png

 

C. 100KHz, 50%占空比

实测:一个周期10us,波峰4.995us,验证通过。

640?wx_fmt=png
640?wx_fmt=png

 

D. 100KHz, 10%占空比

实测:一个周期10us,波峰994.8ns,验证通过。

640?wx_fmt=png
640?wx_fmt=png
 

 

回复评论 (2)

非常专业的测试呀,无论从代码书写,仪器,那是相当的专业,感觉大佬分享!
点赞  2022-11-4 11:34

挺好的,SDK还是很好用的,这个系列应该出一个文档,提供给使用者

点赞  2022-11-5 22:43
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复