text: /***************************************************************************//**
   * @file     main.c
   * @brief
   *           Demonstrate how to upgrade firmware between USB device and PC through USB DFU (Device Firmware Upgrade) class.
   *           A Windows tool is also included in this sample code to connect with USB device.
   *
   * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
   ******************************************************************************/
  #include <stdio.h>
  #include "NUC100Series.h"
  #include "fmc_user.h"
  #include "dfu_transfer.h"
  
  #define PLLCON_SETTING          CLK_PLLCON_48MHz_HXT
  #define PLL_CLOCK               48000000
  
  #define V6M_AIRCR_VECTKEY_DATA    0x05FA0000UL
  #define V6M_AIRCR_SYSRESETREQ     0x00000004UL
  
  #define DetectPin   PD0
  
  uint32_t g_apromSize;
  
  uint32_t GetApromSize()
  {
      //the smallest of APROM size is 2K
      uint32_t size = 0x800, data;
      int result;
  
      do
      {
          result = FMC_Read_User(size, &data);
  
          if(result < 0)
          {
              return size;
          }
          else
          {
              size *= 2;
          }
      }
      while(1);
  }
  
  void SYS_Init(void)
  {
      /*---------------------------------------------------------------------------------------------------------*/
      /* Init System Clock                                                                                       */
      /*---------------------------------------------------------------------------------------------------------*/
  
      /* Enable Internal RC 22.1184MHz clock */
      CLK->PWRCON |= CLK_PWRCON_OSC22M_EN_Msk;
  
      /* Waiting for Internal RC clock ready */
      while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_OSC22M_STB_Msk));
  
      /* Enable external XTAL 12 MHz clock */
      CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk;
  
      /* Waiting for external XTAL clock ready */
      while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_XTL12M_STB_Msk));
  
      /* Select HCLK clock source as HIRC and HCLK clock divider as 1 */
      CLK->CLKSEL0 = (CLK->CLKSEL0 & (~CLK_CLKSEL0_HCLK_S_Msk)) | CLK_CLKSEL0_HCLK_S_HIRC;
      CLK->CLKDIV = (CLK->CLKDIV & (~CLK_CLKDIV_HCLK_N_Msk)) | CLK_CLKDIV_HCLK(1);
  
      /* Set core clock as PLL_CLOCK from PLL */
      CLK->PLLCON = PLLCON_SETTING;
  
      while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_PLL_STB_Msk));
  
      CLK->CLKDIV = (CLK->CLKDIV & (~CLK_CLKDIV_HCLK_N_Msk)) | CLK_CLKDIV_HCLK(1);
      CLK->CLKSEL0 = (CLK->CLKSEL0 & (~CLK_CLKSEL0_HCLK_S_Msk)) | CLK_CLKSEL0_HCLK_S_PLL;
  
      /* Update System Core Clock */
      PllClock        = PLL_CLOCK;            // PLL
      SystemCoreClock = PLL_CLOCK / 1;        // HCLK
      CyclesPerUs     = PLL_CLOCK / 1000000;  // For CLK_SysTickDelay()
  
      /* Enable module clock */
      CLK->APBCLK |= CLK_APBCLK_USBD_EN_Msk;
      CLK->CLKDIV = (CLK->CLKDIV & (~CLK_CLKDIV_USB_N_Msk)) | CLK_CLKDIV_USB(1);
  }
  
  void USBD_IRQHandler(void);
  /*---------------------------------------------------------------------------------------------------------*/
  /*  Main Function                                                                                          */
  /*---------------------------------------------------------------------------------------------------------*/
  int32_t main(void)
  {
      /* Unlock write-protected registers */
      SYS_UnlockReg();
  
      /* Init system and multi-funcition I/O */
      SYS_Init();
  
      CLK->AHBCLK |= CLK_AHBCLK_ISP_EN_Msk;
      FMC->ISPCON |= FMC_ISPCON_ISPEN_Msk | FMC_ISPCON_APUEN_Msk | FMC_ISPCON_ISPFF_Msk;
      g_apromSize = GetApromSize();
  
      /* Open USB controller */
      USBD_Open(&gsInfo, DFU_ClassRequest, NULL);
  
      /*Init Endpoint configuration for DFU */
      DFU_Init();
  
      /* Start USB device */
      USBD_Start();
  
      /* polling USBD interrupt flag */
      while(DetectPin == 0)
      {
          USBD_IRQHandler();
      }
  
      SYS->RSTSRC = (SYS_RSTSRC_RSTS_POR_Msk | SYS_RSTSRC_RSTS_RESET_Msk);//clear bit
      FMC->ISPCON &=  ~(FMC_ISPCON_ISPEN_Msk | FMC_ISPCON_BS_Msk);
      SCB->AIRCR = (V6M_AIRCR_VECTKEY_DATA | V6M_AIRCR_SYSRESETREQ);
  
      /* Trap the CPU */
      while(1);
  }
  
  /*** (C) COPYRIGHT 2019 Nuvoton Technology Corp. ***/
  