text: /**************************************************************************//**
   * @file     main.c
   * @version  V3.00
   * @brief
   *           Use PDMA0 channel 4 to transfer data from memory to memory by scatter-gather mode.
   *
   * @copyright SPDX-License-Identifier: Apache-2.0
   * @copyright Copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
   ******************************************************************************/
  #include <stdio.h>
  #include "NuMicro.h"
  
  /*---------------------------------------------------------------------------------------------------------*/
  /* Macro, type and constant definitions                                                                    */
  /*---------------------------------------------------------------------------------------------------------*/
  #define PDMA_TEST_LENGTH 64
  
  #ifdef __CCARM__
  extern uint32_t Image$$RW$$Base;
  #endif
  
  __attribute__((aligned)) static uint8_t au8SrcArray[256];
  __attribute__((aligned)) static uint8_t au8DestArray0[256];
  __attribute__((aligned)) static uint8_t au8DestArray1[256];
  
  typedef struct dma_desc_t
  {
      uint32_t u32Ctl;
      uint32_t u32Src;
      uint32_t u32Dest;
      uint32_t u32Offset;
  } DMA_DESC_T;
  
  static DMA_DESC_T DMA_DESC[2]; /* Descriptor table */
  
  
  void PDMA0_IRQHandler(void);
  void SYS_Init(void);
  void UART0_Init(void);
  
  /**
   * @brief       DMA IRQ
   *
   * @param       None
   *
   * @return      None
   *
   * @details     The DMA default IRQ, declared in startup_m460.s.
   */
  void PDMA0_IRQHandler(void)
  {
  
  }
  
  void SYS_Init(void)
  {
  
      /*---------------------------------------------------------------------------------------------------------*/
      /* Init System Clock                                                                                       */
      /*---------------------------------------------------------------------------------------------------------*/
  
      /* Enable HIRC clock */
      CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);
  
      /* Wait for HIRC clock ready */
      CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);
  
      /* Set PCLK0 and PCLK1 to HCLK/2 */
      CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2);
  
      /* Set core clock to 200MHz */
      CLK_SetCoreClock(200000000);
  
      /* Enable all GPIO clock */
      CLK->AHBCLK0 |= CLK_AHBCLK0_GPACKEN_Msk | CLK_AHBCLK0_GPBCKEN_Msk | CLK_AHBCLK0_GPCCKEN_Msk | CLK_AHBCLK0_GPDCKEN_Msk |
                      CLK_AHBCLK0_GPECKEN_Msk | CLK_AHBCLK0_GPFCKEN_Msk | CLK_AHBCLK0_GPGCKEN_Msk | CLK_AHBCLK0_GPHCKEN_Msk;
      CLK->AHBCLK1 |= CLK_AHBCLK1_GPICKEN_Msk | CLK_AHBCLK1_GPJCKEN_Msk;
  
      /* Enable UART0 module clock */
      CLK_EnableModuleClock(UART0_MODULE);
  
      /* Select UART0 module clock source as HIRC and UART0 module clock divider as 1 */
      CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
  
      /* Enable PDMA0 clock source */
      CLK_EnableModuleClock(PDMA0_MODULE);
  
      /*---------------------------------------------------------------------------------------------------------*/
      /* Init I/O Multi-function                                                                                 */
      /*---------------------------------------------------------------------------------------------------------*/
  
      /* Set multi-function pins for UART0 RXD and TXD */
      SET_UART0_RXD_PB12();
      SET_UART0_TXD_PB13();
  
  }
  
  void UART0_Init(void)
  {
      /*---------------------------------------------------------------------------------------------------------*/
      /* Init UART                                                                                               */
      /*---------------------------------------------------------------------------------------------------------*/
  
      /* Configure UART0 and set UART0 baud rate */
      UART_Open(UART0, 115200);
  }
  
  /*---------------------------------------------------------------------------------------------------------*/
  /* MAIN function                                                                                           */
  /*---------------------------------------------------------------------------------------------------------*/
  int main(void)
  {
      uint32_t u32Src, u32Dst0, u32Dst1, u32TimeOutCnt;
  
      /* Unlock protected registers */
      SYS_UnlockReg();
  
      /* Init System, IP clock and multi-function I/O */
      SYS_Init();
  
      /* Lock protected registers */
      /* If user want to write protected register, please issue SYS_UnlockReg() to unlock protected register. */
      SYS_LockReg();
  
      /* Init UART for printf */
      UART0_Init();
  
      printf("\n\nCPU @ %dHz\n", SystemCoreClock);
      printf("+-----------------------------------------------------------------------+ \n");
      printf("|       PDMA Memory to Memory Driver Sample Code (Scatter-gather)       | \n");
      printf("+-----------------------------------------------------------------------+ \n");
  
      u32Src = (uint32_t)au8SrcArray;
      u32Dst0 = (uint32_t)au8DestArray0;
      u32Dst1 = (uint32_t)au8DestArray1;
  
      /* This sample will transfer data by finished two descriptor table in sequence.(descriptor table 1 -> descriptor table 2) */
  
      /*----------------------------------------------------------------------------------
        PDMA transfer configuration:
  
          Channel = 4
          Operation mode = scatter-gather mode
          First scatter-gather descriptor table = DMA_DESC[0]
          Request source = PDMA_MEM(memory to memory)
  
          Transmission flow:
             ------------------------      -----------------------
            |                        |    |                       |
            |  DMA_DESC[0]           | -> |  DMA_DESC[1]          | -> transfer done
            |  (Descriptor table 1)  |    |  (Descriptor table 2) |
            |                        |    |                       |
             ------------------------      -----------------------
  
      ----------------------------------------------------------------------------------*/
  
      /* Open Channel 4 */
      PDMA_Open(PDMA0, 1 << 4);
      /* Enable Scatter Gather mode, assign the first scatter-gather descriptor table is table 1,
         and set transfer mode as memory to memory */
      PDMA_SetTransferMode(PDMA0, 4, PDMA_MEM, 1, (uint32_t)&DMA_DESC[0]);
  
      /* Set SRAM R/W base of Scatter-Gather mode */
  #ifdef __CCARM__
      PDMA0->SCATBA = (uint32_t)&Image$$RW$$Base;
  #endif
  
      /*------------------------------------------------------------------------------------------------------
  
                           au8SrcArray                         au8DestArray0
                           ---------------------------   -->   ---------------------------
                         /| [0]  | [1]  |  [2] |  [3] |       | [0]  | [1]  |  [2] |  [3] |\
                          |      |      |      |      |       |      |      |      |      |
         PDMA_TEST_LENGTH |            ...            |       |            ...            | PDMA_TEST_LENGTH
                          |      |      |      |      |       |      |      |      |      |
                         \| [60] | [61] | [62] | [63] |       | [60] | [61] | [62] | [63] |/
                           ---------------------------         ---------------------------
                           \                         /         \                         /
                                 32bits(one word)                     32bits(one word)
  
        Descriptor table 1 configuration:
  
          Operation mode = scatter-gather mode
          Next descriptor table = DMA_DESC[1](Descriptor table 2)
          transfer done and table empty interrupt = disable
  
          Transfer count = PDMA_TEST_LENGTH
          Transfer width = 32 bits(one word)
          Source address = au8SrcArray
          Source address increment size = 32 bits(one word)
          Destination address = au8DestArray0
          Destination address increment size = 32 bits(one word)
          Transfer type = burst transfer
  
          Total transfer length = PDMA_TEST_LENGTH * 32 bits
      ------------------------------------------------------------------------------------------------------*/
      DMA_DESC[0].u32Ctl =
          ((PDMA_TEST_LENGTH - 1) << PDMA_DSCT_CTL_TXCNT_Pos) | /* Transfer count is PDMA_TEST_LENGTH */ \
          PDMA_WIDTH_32 |   /* Transfer width is 32 bits(one word) */ \
          PDMA_SAR_INC |    /* Source increment size is 32 bits(one word) */ \
          PDMA_DAR_INC |    /* Destination increment size is 32 bits(one word) */ \
          PDMA_REQ_BURST |  /* Transfer type is burst transfer type */ \
          PDMA_BURST_128 |  /* Burst size is 128. No effect in single transfer type */ \
          PDMA_TBINTDIS_DISABLE |   /* Disable transfer done and table empty interrupt */ \
          PDMA_OP_SCATTER;  /* Operation mode is scatter-gather mode */
  
      /* Configure source address */
      DMA_DESC[0].u32Src = u32Src;
      /* Configure destination address */
      DMA_DESC[0].u32Dest = u32Dst0;
      /* Configure next descriptor table address */
      DMA_DESC[0].u32Offset = (uint32_t)&DMA_DESC[1] - (PDMA0->SCATBA); /* next descriptor table is table 2 */
  
  
      /*------------------------------------------------------------------------------------------------------
  
                           au8DestArray0                       au8DestArray1
                           ---------------------------   -->   ---------------------------
                         /| [0]  | [1]  |  [2] |  [3] |       | [0]  | [1]  |  [2] |  [3] |\
                          |      |      |      |      |       |      |      |      |      |
         PDMA_TEST_LENGTH |            ...            |       |            ...            | PDMA_TEST_LENGTH
                          |      |      |      |      |       |      |      |      |      |
                         \| [60] | [61] | [62] | [63] |       | [60] | [61] | [62] | [63] |/
                           ---------------------------         ---------------------------
                           \                         /         \                         /
                                 32bits(one word)                     32bits(one word)
  
        Descriptor table 2 configuration:
  
          Operation mode = basic mode
          transfer done and table empty interrupt = enable
  
          Transfer count = PDMA_TEST_LENGTH
          Transfer width = 32 bits(one word)
          Source address = au8DestArray0
          Source address increment size = 32 bits(one word)
          Destination address = au8DestArray1
          Destination address increment size = 32 bits(one word)
          Transfer type = burst transfer
  
          Total transfer length = PDMA_TEST_LENGTH * 32 bits
      ------------------------------------------------------------------------------------------------------*/
      DMA_DESC[1].u32Ctl =
          ((PDMA_TEST_LENGTH - 1) << PDMA_DSCT_CTL_TXCNT_Pos) | /* Transfer count is PDMA_TEST_LENGTH */ \
          PDMA_WIDTH_32 |   /* Transfer width is 32 bits(one word) */ \
          PDMA_SAR_INC |    /* Source increment size is 32 bits(one word) */ \
          PDMA_DAR_INC |    /* Destination increment size is 32 bits(one word) */ \
          PDMA_REQ_BURST |  /* Transfer type is burst transfer type */ \
          PDMA_BURST_128 |  /* Burst size is 128. No effect in single transfer type */ \
          PDMA_OP_BASIC;    /* Operation mode is basic mode */
  
      DMA_DESC[1].u32Src = u32Dst0;
      DMA_DESC[1].u32Dest = u32Dst1;
      DMA_DESC[1].u32Offset = 0; /* No next operation table. No effect in basic mode */
  
  
      /* Generate a software request to trigger transfer with PDMA channel 4 */
      PDMA_Trigger(PDMA0, 4);
  
      /* Waiting for transfer done */
      u32TimeOutCnt = SystemCoreClock; /* 1 second time-out */
      while(PDMA_IS_CH_BUSY(PDMA0, 4))
      {
          if(--u32TimeOutCnt == 0)
          {
              printf("Wait for PDMA transfer done time-out!\n");
              break;
          }
      }
  
      printf("test done...\n");
  
      /* Close Channel 4 */
      PDMA_Close(PDMA0);
  
      while(1);
  }
  