text: /**************************************************************************//**
   * @file     main.c
   * @version  V3.00
   * @brief    Use PDMA channel 2 to transfer data from memory to memory.
   *
   * SPDX-License-Identifier: Apache-2.0
   * @copyright (C) 2016 Nuvoton Technology Corp. All rights reserved.
   ******************************************************************************/
  #include <stdio.h>
  #include "NuMicro.h"
  
  /*---------------------------------------------------------------------------------------------------------*/
  /* Macro, type and constant definitions                                                                    */
  /*---------------------------------------------------------------------------------------------------------*/
  
  #define PLLCTL_SETTING  CLK_PLLCTL_96MHz_HIRC_DIV2
  #define PLL_CLOCK       96000000
  
  
  /*---------------------------------------------------------------------------------------------------------*/
  /* Global variables                                                                                        */
  /*---------------------------------------------------------------------------------------------------------*/
  #ifdef __ICCARM__
  #pragma data_alignment=4
  uint8_t au8SrcArray[256];
  uint8_t au8DestArray[256];
  #else
  __attribute__((aligned(4))) uint8_t au8SrcArray[256];
  __attribute__((aligned(4))) uint8_t au8DestArray[256];
  #endif
  
  uint32_t PDMA_TEST_LENGTH = 64;
  uint32_t volatile g_u32IsTestOver = 0;
  
  /**
   * @brief       DMA IRQ
   *
   * @param       None
   *
   * @return      None
   *
   * @details     The DMA default IRQ, declared in startup_NUC121.s.
   */
  void PDMA_IRQHandler(void)
  {
      uint32_t u32Status = PDMA_GET_INT_STATUS();
  
      if (u32Status & PDMA_INTSTS_ABTIF_Msk)   /* abort */
      {
          /* Check if channel 2 has abort error */
          if (PDMA_GET_ABORT_STS() & PDMA_ABTSTS_ABTIF2_Msk)
              g_u32IsTestOver = 2;
  
          /* Clear abort flag of channel 2 */
          PDMA_CLR_ABORT_FLAG(PDMA_ABTSTS_ABTIF2_Msk);
      }
      else if (u32Status & PDMA_INTSTS_TDIF_Msk)     /* done */
      {
          /* Check transmission of channel 2 has been transfer done */
          if (PDMA_GET_TD_STS() & PDMA_TDSTS_TDIF2_Msk)
              g_u32IsTestOver = 1;
  
          /* Clear transfer done flag of channel 2 */
          PDMA_CLR_TD_FLAG(PDMA_TDSTS_TDIF2_Msk);
      }
      else
          printf("unknown interrupt !!\n");
  }
  
  void SYS_Init(void)
  {
      /*---------------------------------------------------------------------------------------------------------*/
      /* Init System Clock                                                                                       */
      /*---------------------------------------------------------------------------------------------------------*/
  
      /* Enable HIRC clock (Internal RC 48MHz) */
      CLK->PWRCTL |= CLK_PWRCTL_HIRCEN_Msk;
  
      /* Waiting for HIRC clock ready */
      while (!(CLK->STATUS & CLK_STATUS_HIRCSTB_Msk));
  
      /* Select HCLK clock source as HIRC and and HCLK clock divider as 1 */
      CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_HCLKSEL_Msk) | CLK_CLKSEL0_HCLKSEL_HIRC;
      CLK->CLKDIV0 = (CLK->CLKDIV0 & ~CLK_CLKDIV0_HCLKDIV_Msk) | CLK_CLKDIV0_HCLK(1);
  
      /* Update System Core Clock if core clock is from HIRC*/
      PllClock        = 0;                 // PLL
      SystemCoreClock = __HIRC / 1;        // HCLK
      CyclesPerUs     = __HIRC / 1000000;  // For CLK_SysTickDelay()
  
      /* Enable UART module clock */
      CLK->APBCLK0 |= CLK_APBCLK0_UART0CKEN_Msk;
  
      /* Select UART module clock source as HIRC_DIV2 and UART module clock divider as 1 */
      CLK->CLKSEL1 &= ~CLK_CLKSEL1_UARTSEL_Msk;
      CLK->CLKSEL1 |= CLK_CLKSEL1_UARTSEL_HIRC_DIV2;
  
      /* IP clock source */
      CLK->AHBCLK |= CLK_AHBCLK_PDMACKEN_Msk;
  
  
      /*---------------------------------------------------------------------------------------------------------*/
      /* Init I/O Multi-function                                                                                 */
      /*---------------------------------------------------------------------------------------------------------*/
      /* Set PB multi-function pins for UART0 RXD and TXD */
      SYS->GPB_MFPL &= ~(SYS_GPB_MFPL_PB0MFP_Msk | SYS_GPB_MFPL_PB1MFP_Msk);
      SYS->GPB_MFPL = SYS_GPB_MFPL_PB0MFP_UART0_RXD | SYS_GPB_MFPL_PB1MFP_UART0_TXD;
  }
  
  void UART0_Init()
  {
      /*---------------------------------------------------------------------------------------------------------*/
      /* Init UART                                                                                               */
      /*---------------------------------------------------------------------------------------------------------*/
      /* Reset UART IP */
      SYS->IPRST1 |=  SYS_IPRST1_UART0RST_Msk;
      SYS->IPRST1 &= ~SYS_IPRST1_UART0RST_Msk;
  
      /* Configure UART0 and set UART0 baud rate */
      UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(__HIRC_DIV2, 115200);
      UART0->LINE = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1;
  }
  
  
  /*---------------------------------------------------------------------------------------------------------*/
  /*  Main Function                                                                                          */
  /*---------------------------------------------------------------------------------------------------------*/
  int main(void)
  {
      /* Unlock protected registers */
      SYS_UnlockReg();
  
      /* Init System, IP clock and multi-function I/O */
      SYS_Init(); //In the end of SYS_Init() will issue SYS_LockReg() to lock protected register.
  
      /* 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          | \n");
      printf("+------------------------------------------------------+ \n");
  
      /*------------------------------------------------------------------------------------------------------
  
                           au8SrcArray                         au8DestArray
                           ---------------------------   -->   ---------------------------
                         /| [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)
  
        PDMA transfer configuration:
  
          Channel = 2
          Operation mode = basic mode
          Request source = PDMA_MEM(memory to memory)
          transfer done and table empty interrupt = enable
  
          Transfer count = PDMA_TEST_LENGTH
          Transfer width = 32 bits(one word)
          Source address = au8SrcArray
          Source address increment size = 32 bits(one word)
          Destination address = au8DestArray
          Destination address increment size = 32 bits(one word)
          Transfer type = burst transfer
  
          Total transfer length = PDMA_TEST_LENGTH * 32 bits
      ------------------------------------------------------------------------------------------------------*/
  
      /* Open Channel 2 */
      PDMA->CHCTL |= (1 << 2);
  
      /* Transfer configuration of Channel 2 */
      PDMA->DSCT[2].CTL = ((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_4 |   /* Burst size is 4. No effect in single transfer type */ \
                          PDMA_OP_BASIC;   /* Operation mode is basic mode */
  
      /* Configure source address */
      PDMA->DSCT[2].SA = (uint32_t)au8SrcArray;
  
      /* Configure destination address */
      PDMA->DSCT[2].DA = (uint32_t)au8DestArray;
  
      /* Configure PDMA channel 2 as memory to memory transfer */
      PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & ~PDMA_REQSEL0_3_REQSRC2_Msk) | (PDMA_MEM << PDMA_REQSEL0_3_REQSRC2_Pos);
  
      /* Enable interrupt */
      PDMA->INTEN |= (1 << 2);
  
      /* Enable NVIC for PDMA */
      NVIC_EnableIRQ(PDMA_IRQn);
  
      g_u32IsTestOver = 0;
  
      /* Generate a software request to trigger transfer with PDMA channel 2  */
      PDMA->SWREQ = (1 << 2);
  
      /* Waiting for transfer done */
      while (g_u32IsTestOver == 0);
  
      /* Check transfer result */
      if (g_u32IsTestOver == 1)
          printf("test done...\n");
      else if (g_u32IsTestOver == 2)
          printf("target abort...\n");
  
      /* Close channel 2 */
      PDMA->CHCTL = 0;
  
      while (1);
  }
  