PWM

This example demonstrates the use of the TIM peripheral to output PWM waveforms, and it can achieve the following functions:

  • Using TIM2 to output PWM with a period of 1s and a duty cycle of 50%, with P0_1 as the PWM output.

  • Implementing complementary PWM output with P0_2 as PWM_P output and P2_2 as PWM_N output. When the dead zone is set, PWM_P and PWM_N will be delayed by one dead zone duration when outputting high levels. The macro PWM_DEAD_ZONE_CLOCK_SOURCE_5M can be configured to switch the dead zone clock source to 5M.

  • Implementing PWM complementary Bypass function with P0_2 as PWM_P output and P2_2 as PWM_N output. When the Bypass function is set by configuring the macro PWM_DEAD_ZONE_BYPASS, PWM_P and PWM_N output waveforms are completely complementary, with no dead zone generated.

  • The macro PWM_COMPL_OUTPUT_EM_STOP_TEST can be configured to implement the PWM output emergency stop function.

Requirements

The sample supports the following development kits:

Development Kits

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

For more requirements, please refer to Quick Start.

Wiring

Connect P0_1 (PWM output), P0_2 (PWM_P), and P2_2 (PWM_N) to the logic analyzer to observe the waveform.

Configurations

The configurable macros for this example are as follows:

  1. PWM_DEAD_ZONE_CLOCK_SOURCE_5M : Configuring this macro adjusts the clock source of the PWM complementary waveform output dead zone to 5M.

  2. PWM_DEAD_ZONE_BYPASS : Configuring this macro adjusts the output PWM complementary waveform to be fully complementary, with no dead zone.

  3. PWM_COMPL_OUTPUT_EM_STOP_TEST : Configuring this macro implements the emergency stop function for PWM output.

Building and Downloading

This sample can be found in the SDK folder:

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

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

Please follow these steps to build and run the example:

  1. Open sample project file.

  2. To build the target, follow the steps listed on the Generating App Image in Quick Start.

  3. After a successful compilation, the app bin app_MP_xxx.bin will be generated in the directory mdk\bin or gcc\bin.

  4. To download app bin into EVB board, follow the steps listed on the MP Tool Download in Quick Start.

  5. Press reset button on EVB board and it will start running.

Experimental Verification

  1. Using a logic analyzer, you can observe that P0_1 outputs a PWM wave with a period of 1 second and a duty cycle of 50%. P0_2, as PWM_P, outputs a waveform that is delayed by the deadzone time at the rising edge relative to P0_1. P2_2 outputs a PWM wave as PWM_N, which is out of phase with P0_2.

Here should be the image of the PWM output

PWM Output Waveform

  1. Zooming in on the waveform above, when the macro PWM_DEAD_ZONE_CLOCK_SOURCE_5M is not enabled, the dead zone length is 5ms. When the macro PWM_DEAD_ZONE_CLOCK_SOURCE_5M is enabled, the dead zone length becomes 4us.

Here should be the image of the PWM dead zone output

PWM Dead Zone Waveform

  1. When the macro PWM_DEAD_ZONE_BYPASS is enabled, the complementary PWM waveform output shows no dead zone, resulting in a completely complementary waveform.

Here should be the image of the PWM output

PWM Bypass Output Waveform

  1. When the macro PWM_COMPL_OUTPUT_EM_STOP_TEST is enabled, the complementary PWM waveform output periodically pauses, indicating an emergency stop.

Here should be the image of the PWM output

PWM Emergency Stop Output Waveform

Code Overview

This chapter will be introduced according to the following several parts:

  1. Source Code Directory.

  2. Peripheral initialization will be introduced in chapter Initialization.

  3. Functional implementation after initialization will be introduced in chapter Function Implementation.

Source Code Directory

  • Project directory: sdk\board\evb\io_sample\TIM\PWM

  • Source code directory: sdk\src\sample\io_sample\TIM\PWM

Source files are currently categorized into several groups as below.

└── 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

Initialization

When the EVB resets, the main function is executed, following this process:

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

    ...
}

In pwm_demo, it includes PAD/PINMUX settings and TIM peripheral initialization.

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

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

board_pwm_init is the PAD/PINMUX settings, including the following steps:

  1. Configure PAD: set pin, PINMUX mode, PowerOn, internal pull-none, output high.

  2. Configure PINMUX: configure the pin for TIM_PWM2, PWM2_P, and PWM2_N functions respectively.

#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 is the initialization for the TIM peripheral, including the following steps:

  1. Enable the RCC clock.

  2. Configure TIM to a user-defined mode.

  3. Enable the PWM output function of TIM, configure the output period and duty cycle.

  4. Configure the PWM emergency stop function, complementary pin output levels.

  5. Enable the PWM dead zone function, set the size of the dead zone.

  6. If the macro PWM_DEAD_ZONE_CLOCK_SOURCE_5M is enabled, execute RCC_ClockSrc5MCmd() to enable the 5M clock, and execute TIM_PWMChangeDZClockSrc() to switch the clock source of the dead zone.

  7. If the macro PWM_DEAD_ZONE_BYPASS is enabled, execute TIM_PWMDZBypassCmd() to enable the bypass function.

  8. Enable TIM2 and start outputting the PWM waveform.

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
}

Functional Implementation

After the initialization phase is completed, the PWM output waveform can be observed in the logic analyzer.

If the macro PWM_COMPL_OUTPUT_EM_STOP_TEST is enabled, the function TIM_PWMComplOutputEMCmd() will be executed within the main function, repeatedly enabling and disabling the PWM output emergency stop function.

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
    }
}