PWM

该示例演示使用 TIM 外设实现输出 PWM 波形的功能,该示例可实现以下功能:

  • 使用 TIM2,实现输出周期为 1s、占空比为 50% 的 PWM 功能,使用 P0_1 作为 PWM 输出。

  • 实现 PWM 互补输出功能,使用 P0_2 作为 PWM_P 输出,使用 P2_2 作为 PWM_N 输出。当设置死区后,PWM_P 和 PWM_N 在输出高电平时会比 PWM 延迟一个死区时长。可配置宏 PWM_DEAD_ZONE_CLOCK_SOURCE_5M ,将死区时钟源切换至 5M。

  • 实现 PWM 互补 Bypass 功能,使用 P0_2 作为 PWM_P 输出,使用 P2_2 作为 PWM_N 输出。当通过配置宏 PWM_DEAD_ZONE_BYPASS 设置 Bypass 功能后,PWM_P 和 PWM_N 输出波形完全互补,此时无死区产生。

  • 可以通过配置宏 PWM_COMPL_OUTPUT_EM_STOP_TEST 实现 PWM 输出急停功能。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

更多信息请参考 快速入门

硬件连线

连接 P0_1(PWM 输出),P0_2(PWM_P)和 P2_2(PWM_N)至逻辑分析仪观察波形。

配置选项

该示例可配置的宏如下:

  1. PWM_DEAD_ZONE_CLOCK_SOURCE_5M :配置该宏可将 PWM 互补波形的输出死区时钟源调整至 5M。

  2. PWM_DEAD_ZONE_BYPASS :配置该宏可调整输出的 PWM 互补波形为完全互补,无死区产生。

  3. PWM_COMPL_OUTPUT_EM_STOP_TEST :配置该宏可实现输出 PWM 急停功能。

编译和下载

该示例的工程路径如下:

Project file: board\evb\io_sample\TIM\PWM\mdk

Project file: board\evb\io_sample\TIM\PWM\gcc

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 快速入门编译 APP Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bingcc\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 快速入门MP Tool 给出的步骤将 app bin 烧录至 EVB 内。

  5. 按下 reset 按键,开始运行。

测试验证

  1. 通过逻辑分析仪可以看到 P0_1 输出周期为 1s、占空比为 50% 的 PWM 波,P0_2 作为 PWM_P 输出相对于 P0_1 在上升沿延迟死区时间的波形,P2_2 作为 PWM_N 输出与 P0_2 反相的 PWM 波。

这里应该是输出pwm的图片

PWM 的输出波形

  1. 放大上述波形,当未开启宏 PWM_DEAD_ZONE_CLOCK_SOURCE_5M 时,死区长度为 5 ms。当开启宏 PWM_DEAD_ZONE_CLOCK_SOURCE_5M 后,死区长度变为 4 us。

这里应该是输出pwm死区的图片

PWM 死区波形

  1. 当开启宏 PWM_DEAD_ZONE_BYPASS 时,可看到输出的互补 PWM 波形为完全互补,没有死区产生。

这里应该是输出pwm的图片

PWM Bypass 输出波形

  1. 当开启宏 PWM_COMPL_OUTPUT_EM_STOP_TEST 时,可以在输出 PWM 互补波形内看到每隔一段时间就会暂停 PWM 的互补输出。

这里应该是输出pwm的图片

PWM 急停输出波形

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  • 工程路径: sdk\board\evb\io_sample\TIM\PWM

  • 源码路径: sdk\src\sample\io_sample\TIM\PWM

该工程的工程文件代码结构如下:

└── Project: pwm
    └── secure_only_app
        └── include
            ├── app_define.h
            └── rom_uuid.h
        ├── cmsis                    includes CMSIS header files and startup files
            ├── overlay_mgr.c
            ├── system_rtl876x.c
            └── startup_rtl876x.s
        ├── lib                      includes all binary symbol files that user application is built on
            ├── rtl8752h_sdk.lib
            ├── gap_utils.lib
            └── ROM.lib
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl876x_rcc.c
            ├── rtl876x_pinmux.c
            ├── rtl876x_nvic.c
            └── rtl876x_tim.c
        ├── profile
        └── app                      includes the ble_peripheral user application implementation
            └── main.c

初始化

当 EVB 复位启动时,执行 main 函数,执行以下流程:

int main(void)
{
    extern uint32_t random_seed_value;
    srand(random_seed_value);
    pwm_demo();

    ...
}

pwm_demo 中,包含 PAD/PINMUX 设置和 TIM 外设的初始化。

void pwm_demo(void)
{
    /* Configure PAD and pinmux firstly! */
    board_pwm_init();

    /* Initialize TIM peripheral */
    driver_pwm_init();
}

board_pwm_init 为 PAD/PINMUX 设置,包含如下流程:

  1. 配置 PAD:设置引脚,PINMUX 模式,PowerOn,无内部上拉,输出高。

  2. 配置 PINMUX:分别配置引脚为 TIM_PWM2,PWM2_P 和 PWM2_N 功能。

#define PWM_OUT_PIN_PINMUX      TIM_PWM2
#define PWM_OUT_P_PIN_PINMUX    PWM2_P
#define PWM_OUT_N_PIN_PINMUX    PWM2_N

void board_pwm_init(void)
{
    Pad_Config(PWM_OUT_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_HIGH);
    Pad_Config(PWM_OUT_P_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_HIGH);
    Pad_Config(PWM_OUT_N_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_HIGH);
    Pinmux_Config(PWM_OUT_PIN, PWM_OUT_PIN_PINMUX);
    Pinmux_Config(PWM_OUT_P_PIN, PWM_OUT_P_PIN_PINMUX);
    Pinmux_Config(PWM_OUT_N_PIN, PWM_OUT_N_PIN_PINMUX);
}

driver_pwm_init 为 TIM 外设的初始化,包含如下流程:

  1. 使能 RCC 时钟。

  2. 配置 TIM 为用户自定义模式。

  3. 打开 TIM 的 PWM 输出功能,配置输出周期及占空比。

  4. 配置 PWM 急停功能时,互补引脚输出电平。

  5. 使能 PWM 死区功能,设置死区大小。

  6. 若开启宏 PWM_DEAD_ZONE_CLOCK_SOURCE_5M,执行 RCC_ClockSrc5MCmd() 开启 5M 时钟,执行 TIM_PWMChangeDZClockSrc() 切换死区的时钟源。

  7. 若开启宏 PWM_DEAD_ZONE_BYPASS,执行 TIM_PWMDZBypassCmd() 开启 bypass 功能。

  8. 使能 TIM2,开始输出 PWM 波形。

void driver_pwm_init(void)
{
    RCC_PeriphClockCmd(APBPeriph_TIMER, APBPeriph_TIMER_CLOCK, ENABLE);
#if PWM_DEAD_ZONE_CLOCK_SOURCE_5M
    RCC_ClockSrc5MCmd();
#endif

    TIM_TimeBaseInitTypeDef TIM_InitStruct;

    TIM_StructInit(&TIM_InitStruct);
    TIM_InitStruct.TIM_Mode             = TIM_Mode_UserDefine;
    TIM_InitStruct.TIM_PWM_En           = PWM_ENABLE;
    TIM_InitStruct.TIM_PWM_High_Count   = PWM_HIGH_COUNT;
    TIM_InitStruct.TIM_PWM_Low_Count    = PWM_LOW_COUNT;
    TIM_InitStruct.PWM_Stop_State_P     = PWM_STOP_AT_HIGH;
    TIM_InitStruct.PWM_Stop_State_N     = PWM_STOP_AT_LOW;
    TIM_InitStruct.PWMDeadZone_En       = DEADZONE_ENABLE;  //enable to use pwn p/n output
    TIM_InitStruct.PWM_Deazone_Size     = PWM_DEAD_ZONE_SIZE;
    TIM_TimeBaseInit(TIM2, &TIM_InitStruct);

#if PWM_DEAD_ZONE_CLOCK_SOURCE_5M
    TIM_PWMChangeDZClockSrc((PWM_TypeDef *)(&TIMER_PWM2_CR), ENABLE);
#endif

    TIM_Cmd(TIM2, ENABLE);

#if PWM_DEAD_ZONE_BYPASS
    TIM_PWMDZBypassCmd((PWM_TypeDef *)(&TIMER_PWM2_CR), ENABLE);
#endif
}

功能实现

初始化阶段完成后,可在逻辑分析仪内观察到 PWM 输出波形。

若开启宏 PWM_COMPL_OUTPUT_EM_STOP_TEST,在主函数内,执行 TIM_PWMComplOutputEMCmd(),循环开启和关闭 PWM 输出急停功能。

int main(void)
{
    ...

    while (1)
    {
#if PWM_COMPL_OUTPUT_EM_STOP_TEST
        platform_delay_ms(2000);
        //PWM complementary output emergency stop.
        TIM_PWMComplOutputEMCmd(PWM2, ENABLE);
        platform_delay_ms(2000);
        //Resume PWM complementary output.
        TIM_PWMComplOutputEMCmd(PWM2, DISABLE);
#else

#endif
    }
}