PWM+GDMA

This example implements the output of a PWM waveform with variable duty cycles by using the PWM and GDMA functions of ENHTIM.

The user can specify the duty cycle data as needed. The GDMA will transfer the data into the CCR FIFO of the ENHTIM (ENHTIM_CCR_FIFO_ENTRY) to generate the desired PWM waveform.

Users can modify pin information, PWM output frequency, etc., through different macro configurations. For specific macro configurations, see Configurations.

Requirements

For requirements, please refer to the Requirements.

Wiring

Connect P0_0 (PWM_P) and P0_1 (PWM_N) to a logic analyzer.

Configurations

  1. The following macro can be configured to modify the output pin of the PWM wave.

    #define PWM_OUT_P_PIN                     P0_0
    #define PWM_OUT_N_PIN                     P0_1
    
  2. The frequency of PWM can be modified by configuring the following macro.

    #define PWM_MAXCNT                        100                   /*< Setting this macro to 100 means the PWM period is 100 * 25 ns. */
    
  3. The following array can be configured to modify the PWM duty cycle value.

    static uint32_t ccr_fifo_buf[] = {0x0A, 0x14, 0x1E, 0x32};      /*< Setting the array values to modify the duty cycle. The PWM Compare values are 10 * 25 ns, 20 * 25 ns, 30 * 25 ns, and 50 * 25 ns. */
    

Building and Downloading

For building and downloading, please refer to the Building and Downloading.

Experimental Verification

  1. After the EVB starts, observe the PWM waveform with an output period of 2.5 us and duty cycles of 90%, 80%, 70%, 50% respectively using a logic analyzer on the P0_0 and P0_1 pins.

Here should be the picture of the PWM waveform outputted by enhtim

PWM Output Waveform

Code Overview

This section mainly introduces the code and process description for initialization and corresponding function implementation in the example.

Source Code Directory

The directory for project file and source code are as follows:

  • Project directory: sdk\samples\peripheral\enhtimer\pwm+gdma\proj

  • Source code directory: sdk\samples\peripheral\enhtimer\pwm+gdma\src

Initialization

The initialization flow for peripherals can refer to Initialization Flow in General Introduction.

  1. Call Pad_Config() and Pinmux_Config() to configure the PAD and PINMUX of the corresponding pins.

    void board_enhance_pwm_init(void)
    {
        Pad_Config(PWM_OUT_P_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_LOW);
        Pad_Config(PWM_OUT_N_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_LOW);
    
        Pinmux_Config(PWM_OUT_P_PIN, PWM_PINMUX_OUT_P);
        Pinmux_Config(PWM_OUT_N_PIN, PWM_PINMUX_OUT_N);
    }
    
  2. Call RCC_PeriphClockCmd() to enable the GDMA clock.

  3. Initialize the GDMA peripheral:

    1. Define the GDMA_InitTypeDef type GDMA_InitStruct, and call GDMA_StructInit() to pre-fill GDMA_InitStruct with default values.

    2. Modify the GDMA_InitStruct parameters as needed. The initialization parameter configurations for GDMA are shown in the table below. Call GDMA_Init() to initialize the GDMA peripheral.

GDMA Initialization Parameters

GDMA Hardware Parameters

Setting in the GDMA_InitStruct

GDMA

Channel Num

GDMA_InitTypeDef::GDMA_ChannelNum

GDMA_CH_NUM0

Source Data Size

GDMA_InitTypeDef::GDMA_SourceDataSize

GDMA_DataSize_Word

Destination Data Size

GDMA_InitTypeDef::GDMA_DestinationDataSize

GDMA_DataSize_Word

Source Burst Transaction Length

GDMA_InitTypeDef::GDMA_SourceMsize

GDMA_Msize_1

Destination Burst Transaction Length

GDMA_InitTypeDef::GDMA_DestinationMsize

GDMA_Msize_1

Destination Handshake

GDMA_InitTypeDef::GDMA_DestHandshake

GDMA_Handshake_ENH_TIM0

Transfer Direction

GDMA_InitTypeDef::GDMA_DIR

GDMA_DIR_MemoryToPeripheral

Source Address Increment or Decrement

GDMA_InitTypeDef::GDMA_SourceInc

DMA_SourceInc_Inc

Destination Address Increment or Decrement

GDMA_InitTypeDef::GDMA_DestinationInc

DMA_DestinationInc_Fix

Source Address

GDMA_InitTypeDef::GDMA_SourceAddr

(uint32_t)ccr_fifo_buf

Buffer Size

GDMA_InitTypeDef::GDMA_BufferSize

4

Destination Address

GDMA_InitTypeDef::GDMA_DestinationAddr

& (Enhance_Timer->ENHTIM_CCR_FIFO_ENTRY)

Secure function enable

GDMA_InitTypeDef::GDMA_Secure_En

ENABLE

  1. Call RCC_PeriphClockCmd() to enable the ENHTIM clock.

  2. Initialize the ENHTIM peripheral:

    1. Define the ENHTIM_InitTypeDef type ENHTIM_InitStruct, and call ENHTIM_StructInit() to pre-fill ENHTIM_InitStruct with default values.

    2. Modify the ENHTIM_InitStruct parameters as needed. The initialization parameter configurations for ENHTIM are shown in the table below. Call ENHTIM_Init() to initialize the ENHTIM peripheral.

ENHTIM Initialization Parameters

ENHTIM Hardware Parameters

Setting in the ENHTIM_InitStruct

ENHTIM

Counter mode

ENHTIM_InitTypeDef::ENHTIM_Mode

ENHTIM_MODE_PWM_AUTO

PWM mode

ENHTIM_InitTypeDef::ENHTIM_PWMOutputEn

ENABLE

Toggle output polarity

ENHTIM_InitTypeDef::ENHTIM_PWMStartPolarity

ENHTIM_PWM_START_WITH_HIGH

Count value

ENHTIM_InitTypeDef::ENHTIM_MaxCount

PWM_MAXCNT

PWM deadzone clock source

ENHTIM_InitTypeDef::ENHTIM_PWMDeadZoneClockSource

ENHTIM_PWM_DZCLKSRCE_32K

PWM deadzone function enable

ENHTIM_InitTypeDef::ENHTIM_PWMDeadZoneEn

ENABLE

PWM P stop state

ENHTIM_InitTypeDef::ENHTIM_PWMStopStateP

ENHTIM_PWM_STOP_AT_HIGH

PWM N stop state

ENHTIM_InitTypeDef::ENHTIM_PWMStopStateN

ENHTIM_PWM_STOP_AT_LOW

Size of deadzone time

ENHTIM_InitTypeDef::ENHTIM_DeadZoneSize

0x0

GDMA function enable

ENHTIM_InitTypeDef::ENHTIM_DmaEn

ENABLE

GDMA target

ENHTIM_InitTypeDef::ENHTIM_DmaTragget

ENHTIM_DMA_CCR_FIFO

  1. Call GDMA_Cmd() to enable the GDMA peripheral and call ENHTIM_Cmd() to enable the ENHTIM peripheral.

Functional Implementation

To better illustrate which parameters users can modify to achieve the desired waveform, the following example demonstrates how to obtain the waveform shown in the figure below:

Here should be pwm duty cycle variation flow

PWM with variable duty cycle

  1. Determine the PWM Period: You can calculate it using the following formula: PWM_Period = Clock_Period * PWM_MAXCNT. Here, Clock_Period is 25 ns (based on a 40 MHz clock source). As illustrated, if a PWM waveform with a period of 100 us is desired, set the PWM_MAXCNT macro definition to 4000 in the Configuration Options.

  2. Determine the Duty Cycle: Organize the data to be entered into the CCR FIFO according to needs to set the duty cycle. For example, to generate a PWM waveform with a 100 µs period and duty cycles of 100%, 80%, 60%, 50%, 30%, 20%, 10%, and 0%, set the GDMA_InitTypeDef::GDMA_BufferSize to 8. Below is the ccr_fifo_buf data. For an 80% duty cycle, ccr_fifo_buf[1] should be set to 800. The calculation for the high-level duty cycle is: ((PWM_MAXCNT - CCR) / PWM_MAXCNT) = ((4000 - 800) / 4000) = 80%.

    static uint32_t ccr_fifo_buf[8] = {0, 800, 1600, 2000, 2800, 3200, 3600, 4000};
    

See Also

Please refer to the relevant API Reference: