text: /**************************************************************************//**
   * @file     main.c
   * @brief    ISP tool main function
   * @version  2.0.0
   *
   * Copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
   ******************************************************************************/
  #include <stdio.h>
  #include <string.h>
  #include "targetdev.h"
  #include "spi_transfer.h"
  
  #define PLLCON_SETTING  CLK_PLLCON_72MHz_HIRC
  #define PLL_CLOCK       71884880
  
  uint32_t TIMER_Open(TIMER_T *timer, uint32_t u32Mode, uint32_t u32Freq)
  {
      uint32_t u32Clk = __HIRC; // TIMER_GetModuleClock(timer);
      uint32_t u32Cmpr = 0UL, u32Prescale = 0UL;
  
      /* Fastest possible timer working freq is (u32Clk / 2). While cmpr = 2, prescaler = 0. */
      if(u32Freq > (u32Clk / 2UL))
      {
          u32Cmpr = 2UL;
      }
      else
      {
          u32Cmpr = u32Clk / u32Freq;
          u32Prescale = (u32Cmpr >> 24);  /* for 24 bits CMPDAT */
  
          if(u32Prescale > 0UL)
          {
              u32Cmpr = u32Cmpr / (u32Prescale + 1UL);
          }
      }
  
      timer->TCSR = u32Mode | u32Prescale;
      timer->TCMPR = u32Cmpr;
      return (u32Clk / (u32Cmpr * (u32Prescale + 1UL)));
  }
  
  void TIMER3_Init(void)
  {
      /* Enable IP clock */
      CLK->APBCLK |= CLK_APBCLK_TMR3_EN_Msk;
      /* Select IP clock source */
      CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_TMR3_S_Msk)) | CLK_CLKSEL1_TMR3_S_HIRC;
      // Set timer frequency to 3HZ
      TIMER_Open(TIMER3, TIMER_PERIODIC_MODE, 3);
      // Enable timer interrupt
      TIMER_EnableInt(TIMER3);
      // Start Timer 3
      TIMER_Start(TIMER3);
  }
  
  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));
  
      /* Switch HCLK clock source to Internal RC and HCLK source divide 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 PLL to power down mode and PLL_STB bit in CLKSTATUS register will be cleared by hardware */
      CLK->PLLCON |= CLK_PLLCON_PD_Msk;
  
      /* System optimization when CPU runs at 72MHz */
      FMC->FATCON |= 0x50;
  
      /* Set core clock as PLL_CLOCK from PLL */
      CLK->PLLCON = PLLCON_SETTING;
  
      while(!(CLK->CLKSTATUS & CLK_CLKSTATUS_PLL_STB_Msk));
  
      CLK->CLKSEL0 = (CLK->CLKSEL0 & (~CLK_CLKSEL0_HCLK_S_Msk)) | CLK_CLKSEL0_HCLK_S_PLL;
      CLK->CLKDIV = (CLK->CLKDIV & (~CLK_CLKDIV_HCLK_N_Msk)) | CLK_CLKDIV_HCLK(1);
  
      /* Update System Core Clock */
      PllClock        = PLL_CLOCK;            // PLL
      SystemCoreClock = PLL_CLOCK / 1;        // HCLK
      CyclesPerUs     = PLL_CLOCK / 1000000;  // For SYS_SysTickDelay()
  
      /* Select HCLK as the clock source of SPI1 */
      CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI1_S_Msk)) | CLK_CLKSEL1_SPI1_S_HCLK;
      /* Enable SPI1 peripheral clock */
      CLK->APBCLK |= CLK_APBCLK_SPI1_EN_Msk;
  
      /*---------------------------------------------------------------------------------------------------------*/
      /* Init I/O Multi-function                                                                                 */
      /*---------------------------------------------------------------------------------------------------------*/
      /* Setup SPI1 multi-function pins */
      SYS->GPC_MFP &= ~(SYS_GPC_MFP_PC8_Msk | SYS_GPC_MFP_PC9_Msk | SYS_GPC_MFP_PC10_Msk | SYS_GPC_MFP_PC11_Msk);
      SYS->GPC_MFP |= SYS_GPC_MFP_PC8_SPI1_SS0 | SYS_GPC_MFP_PC9_SPI1_CLK | SYS_GPC_MFP_PC10_SPI1_MISO0 | SYS_GPC_MFP_PC11_SPI1_MOSI0;
      SYS->ALT_MFP &= ~(SYS_ALT_MFP_PC8_Msk);
      SYS->ALT_MFP |= SYS_ALT_MFP_PC8_SPI1_SS0;
  }
  
  /*---------------------------------------------------------------------------------------------------------*/
  /*  Main Function                                                                                          */
  /*---------------------------------------------------------------------------------------------------------*/
  int32_t main(void)
  {
      uint32_t cmd_buff[16];
  
      /* Unlock protected registers */
      SYS_UnlockReg();
      /* Init System, peripheral clock and multi-function I/O */
      SYS_Init();
      SPI_Init();
      GPIO_Init();
      TIMER3_Init();
  
      CLK->AHBCLK |= CLK_AHBCLK_ISP_EN_Msk;
      FMC->ISPCON |= (FMC_ISPCON_ISPEN_Msk | FMC_ISPCON_APUEN_Msk);
  
      /* Get APROM size, data flash size and address */
      g_apromSize = GetApromSize();
      GetDataFlashInfo(&g_dataFlashAddr, &g_dataFlashSize);
  
      while(1)
      {
          if(bSpiDataReady == 1)
          {
              goto _ISP;
          }
  
          if(TIMER3->TISR & TIMER_TISR_TIF_Msk)
          {
              goto _APROM;
          }
      }
  
  _ISP:
      while(1)
      {
          if(bSpiDataReady == 1)
          {
              memcpy(cmd_buff, spi_rcvbuf, 64);
              bSpiDataReady = 0;
              ParseCmd((unsigned char *)cmd_buff, 64);
          }
      }
  
  _APROM:
      SYS->RSTSRC = (SYS_RSTSRC_RSTS_POR_Msk | SYS_RSTSRC_RSTS_RESET_Msk);
      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. ***/
  