Output - Timer Trigger GDMA

This example introduces how to use a timer to trigger GDMA for controlling the GPIO output level.

Users can modify pin information through different macro configurations. For specific macro configurations, refer to Configurations.

Requirements

For hardware requirements, please refer to the Requirements.

Configurations

  1. The following macros can be configured to modify GPIO pin definitions.

    #define PIN_OUT              ADC_2
    
  2. The following macros can be configured to modify the period of GPIO level changes.

    #define DMA_TIMER_INTERVAL       (1000)
    
  1. The entry function is as follows, call this function in main() to run this sample code. For more details, please refer to the Initialization.

    dma_tim_demo();
    

Building and Downloading

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

Experimental Verification

  1. Use a logic analyzer to capture the waveform of P0_2.

  2. Press the Reset button on the EVB.

  3. After initialization is complete, P0_2 will output a waveform and the output waveform results of single-block or multi-block are as described below.

../../../_images/GPIO_DMA_Result_Diagram.png

GPIO Timer Trigger GDMA Output Expected Result Diagram

Code Overview

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

Source Code Directory

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

  • For project directory, please refer to Source Code Directory.

  • Source code directory: sdk\sample\io_demo\gdma\multiblock_tim_gpio\dma_tim_demo.c.

Initialization

The initialization flow for peripherals can refer to Initialization Flow.

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

    static void board_dma_tim_init(void)
    {
        Pad_Config(PIN_OUT, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_HIGH);
    
        Pinmux_Config(PIN_OUT, DWGPIO);
    }
    
  2. Call hw_timer_create_dma_mode() to create a hardware timer in GDMA mode.

  3. Call RCC_PeriphClockCmd() to enable the GPIO clock.

  4. Initialize the GPIO peripheral.

    1. Define the GPIO_InitTypeDef type GPIO_InitStruct, and call GPIO_StructInit() to pre-fill GPIO_InitStruct with default values.

    2. Modify the GPIO_InitStruct parameters as needed. The initialization parameter configurations for GPIO are shown in the table below. Call GPIO_Init() to initialize the GPIO peripheral.

GPIO Initialization Parameters

GPIO Hardware Parameters

Setting in the GPIO_InitStruct

GPIO

GPIO Pin

GPIO_InitTypeDef::GPIO_PinBit

GPIO_PIN_OUT

GPIO Direction

GPIO_InitTypeDef::GPIO_Mode

GPIO_Mode_OUT

GPIO Interrupt

GPIO_InitTypeDef::GPIO_ITCmd

DISABLE

GPIO Control Mode

GPIO_InitTypeDef::GPIO_ControlMode

GPIO_HARDWARE_MODE

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

  2. Call GDMA_channel_request to request a free GDMA channel and register the GDMA interrupt handler.

  3. Initialize the GDMA peripheral:

    1. Define a 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 parameters for the GDMA channel are configured as shown in the table below.

    GDMA Initialization Parameters

    GDMA Hardware Parameters

    Setting in the GDMA_InitStruct

    GDMA

    Channel Num

    GDMA_InitTypeDef::GDMA_ChannelNum

    TIM_DMA_CHANNEL_NUM

    Transfer Direction

    GDMA_InitTypeDef::GDMA_DIR

    GDMA_DIR_MemoryToPeripheral

    Buffer Size

    GDMA_InitTypeDef::GDMA_BufferSize

    10

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

    Source Address

    GDMA_InitTypeDef::GDMA_SourceAddr

    gpio_control_pattern

    Destination Address

    GDMA_InitTypeDef::GDMA_DestinationAddr

    GPIOA_DMA_PORT_ADDR

    Destination handshake

    GDMA_InitTypeDef::GDMA_DestHandshake

    hw_timer_get_dma_handshake()

    Multi-block Enable

    GDMA_InitTypeDef::GDMA_Multi_Block_En

    0

    Multi-block Mode

    GDMA_InitTypeDef::GDMA_Multi_Block_Mode

    LLI_TRANSFER

    Multi-block Struct

    GDMA_InitTypeDef::GDMA_Multi_Block_Struct

    GDMA_LLIStruct

    1. Configure the information of the LLI structure.

      1. Configure GDMA_LLIDef::SAR as the source address for each block transfer, and configure GDMA_LLIDef::DAR as the destination address for each block transfer.

      2. Configure GDMA_LLIDef::LLP as a pointer to the LLI structure corresponding to the next block, to link the next transfer unit in multi-block transfers.

      3. Configure GDMA_LLIDef::CTL_LOW with the basic information of the GDMA transfer; refer to the sample for specific configuration.

      4. Configure GDMA_LLIDef::CTL_HIGH with the amount of data transferred for each block, with its value being GDMA_InitTypeDef::GDMA_BufferSize.

      for (int i = 0; i < 6; i++)
      {
          if (i == 5)
          {
              //GDMA_LLIStruct[i].LLP=0;
              GDMA_LLIStruct[i].SAR = (uint32_t)(&(gpio_control_pattern_1[i]));
              GDMA_LLIStruct[i].DAR = (uint32_t)(GPIOA_DMA_PORT_ADDR);
              GDMA_LLIStruct[i].LLP = 0;  // link back to beginning
              /* configure low 32 bit of CTL register */
              GDMA_LLIStruct[i].CTL_LOW = BIT(0)
                                          | (GDMA_InitStruct.GDMA_DestinationDataSize << 1)
                                          | (GDMA_InitStruct.GDMA_SourceDataSize << 4)
                                          | (GDMA_InitStruct.GDMA_DestinationInc << 7)
                                          | (GDMA_InitStruct.GDMA_SourceInc << 9)
                                          | (GDMA_InitStruct.GDMA_DestinationMsize << 11)
                                          | (GDMA_InitStruct.GDMA_SourceMsize << 14)
                                          | (GDMA_InitStruct.GDMA_DIR << 20);
              /* configure high 32 bit of CTL register */
              GDMA_LLIStruct[i].CTL_HIGH = GDMA_InitStruct.GDMA_BufferSize;
          }
          else
          {
              GDMA_LLIStruct[i].SAR = (uint32_t)(&(gpio_control_pattern_1[i]));
              GDMA_LLIStruct[i].DAR = (uint32_t)(GPIOA_DMA_PORT_ADDR);
              GDMA_LLIStruct[i].LLP = (uint32_t)&GDMA_LLIStruct[i + 1];
              /* configure low 32 bit of CTL register */
              GDMA_LLIStruct[i].CTL_LOW = BIT(0)
                                          | (GDMA_InitStruct.GDMA_DestinationDataSize << 1)
                                          | (GDMA_InitStruct.GDMA_SourceDataSize << 4)
                                          | (GDMA_InitStruct.GDMA_DestinationInc << 7)
                                          | (GDMA_InitStruct.GDMA_SourceInc << 9)
                                          | (GDMA_InitStruct.GDMA_DestinationMsize << 11)
                                          | (GDMA_InitStruct.GDMA_SourceMsize << 14)
                                          | (GDMA_InitStruct.GDMA_DIR << 20)
                                          | BIT(28) | BIT(27);
              /* configure high 32 bit of CTL register */
              GDMA_LLIStruct[i].CTL_HIGH = GDMA_InitStruct.GDMA_BufferSize;
          }
      }
      
    2. Call GDMA_Init() to initialize the GDMA peripheral.

    3. Configure the GDMA total transfer completion interrupt: GDMA_INT_Transfer and NVIC. For NVIC-related configuration, refer to Interrupt Configuration.

  4. Call GDMA_Cmd() to enable GDMA channel for transmission.

Functional Implementation

  1. The array gpio_control_pattern is used to control the GPIO levels, where 1 represents a high output level, and 0 represents a low output level.

  2. Call hw_timer_start() to start timer. Every time the timer expires twice, the GPIO level will change according to the current GDMA transfer data.

  3. When the GDMA transfer ends, the tim_dma_handler will be called.