/*!
 * @file    	system_apm32f10x.c
 * @brief	 	CMSIS Cortex-M3 Device Peripheral Access Layer System Source File
 *
 * @details	
 *
 * @version		V1.0.0
 * @author  	
 * @date    	2019-8-7
 *
 */

#include "apm32f10x.h"

//#define SYSTEM_CLOCK_HXT    HXT_VALUE
//#define SYSTEM_CLOCK_24MHz  (24000000)
//#define SYSTEM_CLOCK_36MHz  (36000000)
//#define SYSTEM_CLOCK_48MHz  (48000000)
//#define SYSTEM_CLOCK_56MHz  (56000000)
//#define SYSTEM_CLOCK_72MHz  (72000000)
//#define SYSTEM_CLOCK_96MHz  (96000000)

#define SYSTEM_CLOCK_72MHz  (72000000)

#if defined (APM32F10X_HD) || (defined APM32F10X_XL)
//#define DATA_IN_ExtSRAM
#endif

/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET  0x0

#ifdef SYSTEM_CLOCK_HXT
uint32_t SystemCoreClock         = SYSTEM_CLOCK_HXT;
#elif defined SYSTEM_CLOCK_24MHz
uint32_t SystemCoreClock         = SYSTEM_CLOCK_24MHz;
#elif defined SYSTEM_CLOCK_36MHz
uint32_t SystemCoreClock         = SYSTEM_CLOCK_36MHz;
#elif defined SYSTEM_CLOCK_48MHz
uint32_t SystemCoreClock         = SYSTEM_CLOCK_48MHz;
#elif defined SYSTEM_CLOCK_56MHz
uint32_t SystemCoreClock         = SYSTEM_CLOCK_56MHz;
#elif defined SYSTEM_CLOCK_72MHz
uint32_t SystemCoreClock         = SYSTEM_CLOCK_72MHz;
#else
uint32_t SystemCoreClock         = HIRC_VALUE;
#endif


static void SystemClockConfig(void);

#ifdef SYSTEM_CLOCK_HXT
static void SystemClockHXT(void);
#elif defined SYSTEM_CLOCK_24MHz
static void SystemClock24M(void);
#elif defined SYSTEM_CLOCK_36MHz
static void SystemClock36M(void);
#elif defined SYSTEM_CLOCK_48MHz
static void SystemClock48M(void);
#elif defined SYSTEM_CLOCK_56MHz
static void SystemClock56M(void);  
#elif defined SYSTEM_CLOCK_72MHz
static void SystemClock72M(void);
#elif defined SYSTEM_CLOCK_96MHz
static void SystemClock96M(void);
#endif

#ifdef DATA_IN_ExtSRAM
static void SystemExtSramInit(void); 
#endif /* DATA_IN_ExtSRAM */


/*!
 * @brief	Setup the microcontroller system	
 *			Initialize the Embedded Flash Interface, the PLL and update the SystemCoreClock variable
 *
 * @see 
 *
 * @note 	This function should be used only after reset
 */
void SystemInit (void)
{
	/** Set HIRCEN bit */
	RCM->CTRL_B.HIRCEN = BIT_SET;
	/** Reset SCSEL, AHBDIV, APB1DIV, APB2DIV, ADCDIV and COC bits */
	RCM->CFG &= (uint32_t)0xF8FF0000;
	/** Reset HXTEN, CSSEN and PLLEN bits */
	RCM->CTRL &= (uint32_t)0xFEF6FFFF;
	/** Reset HXTBYP bit */
	RCM->CTRL_B.HXTBYP = BIT_RESET;
	/** Reset PLLSEL, PLLXTDIV, PLLMF and USBDIV bits */
	RCM->CFG &= (uint32_t)0xFF80FFFF;
	/** Disable all interrupts and clear pending bits */
	RCM->INT = 0x009F0000;
    
#if defined (APM32F10X_HD) || (defined APM32F10X_XL)
#ifdef DATA_IN_ExtSRAM
    SystemExtSramInit(); 
#endif
#endif 
	SystemClockConfig();

#ifdef VECT_TAB_SRAM
  	SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
#else
  	SCB->VTOR = FMC_BASE | VECT_TAB_OFFSET;
#endif 
}

/*!
 * @brief	Update SystemCoreClock variable according to Clock Register Values		
 *			The SystemCoreClock variable contains the core clock (HCLK)
 *
 * @see 
 *
 * @note 
 */
void SystemCoreClockUpdate (void)
{
	uint32_t sysClock, pllMull, pllSource, Prescaler;
	uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};

	sysClock = RCM->CFG_B.SCS;
	
	switch(sysClock)
	{
		/** sys clock is HIRC */
		case 0:
			SystemCoreClock = HIRC_VALUE;
			break;
			
		/** sys clock is HXT */	
		case 1:
			SystemCoreClock = HXT_VALUE;
			break;

		/** sys clock is PLL */	
		case 2:
			pllMull = RCM->CFG_B.PLLMF + 2;
			pllSource = RCM->CFG_B.PLLSEL;

			/** PLL entry clock source is HXT */
			if(pllSource == BIT_SET)
			{
				SystemCoreClock = HXT_VALUE * pllMull;
				
				/** HXT clock divided by 2 */
				if(pllSource == RCM->CFG_B.PLLXTDIV)
				{
					SystemCoreClock >>= 1;
				}
			}
			/** PLL entry clock source is HIRC/2 */
			else
			{
				SystemCoreClock = (HIRC_VALUE >> 1) * pllMull;
			}
			break;		

		default:
			SystemCoreClock  = HIRC_VALUE;
			break;
	}	

	Prescaler = AHBPrescTable[RCM->CFG_B.AHBDIV];
	SystemCoreClock >>= Prescaler;
}

/*!
 * @brief	Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers	
 *
 * @see 
 *
 * @note 
 */
static void SystemClockConfig(void)
{	
#ifdef SYSTEM_CLOCK_HXT
 	SystemClockHXT();
#elif defined SYSTEM_CLOCK_24MHz
	SystemClock24M();
#elif defined SYSTEM_CLOCK_36MHz
	SystemClock36M();
#elif defined SYSTEM_CLOCK_48MHz
	SystemClock48M();
#elif defined SYSTEM_CLOCK_56MHz
	SystemClock56M();  
#elif defined SYSTEM_CLOCK_72MHz
	SystemClock72M();
#elif defined SYSTEM_CLOCK_96MHz
	SystemClock96M();
#endif
}

#ifdef DATA_IN_ExtSRAM
/*!
 * @brief	Setup the external memory controller	
 *
 * @see 
 *
 * @note 
 */
void SystemExtSramInit(void) 
{
  RCM->AHBENR = 0x00000114; 
  RCM->APB2ENR = 0x000001E0;
  
  GPIOD->CRL = 0x44BB44BB;  
  GPIOD->CRH = 0xBBBBBBBB;

  GPIOE->CRL = 0xB44444BB;  
  GPIOE->CRH = 0xBBBBBBBB;

  GPIOF->CRL = 0x44BBBBBB;  
  GPIOF->CRH = 0xBBBB4444;

  GPIOG->CRL = 0x44BBBBBB;  
  GPIOG->CRH = 0x44444B44;
   

  FSMC_Bank1->BTCR[4] = 0x00001011;
  FSMC_Bank1->BTCR[5] = 0x00000200;
}
#endif

#if defined SYSTEM_CLOCK_HXT
/*!
 * @brief	 Selects HXT as System clock source and configure HCLK, PCLK2 and PCLK1 prescalers		
 *
 * @see 
 *
 * @note 
 */
static void SystemClockHXT(void)
{
	__IO uint32_t i;
	
	RCM->CTRL_B.HXTEN= BIT_SET;

	for(i = 0; i < HXT_STARTUP_TIMEOUT; i++)
	{
		if(RCM->CTRL_B.HXTRDYF)
		{
			break;
		}
	}
	
	if(RCM->CTRL_B.HXTRDYF)
	{
		/* Enable Prefetch Buffer */
		FMC->CTRL1_B.PBEN = BIT_SET;
		/* Flash 0 wait state */
		FMC->CTRL1_B.LATENCY = 0;
		
		/* HCLK = SYSCLK */
		RCM->CFG_B.AHBDIV= 0X00;
		/* PCLK2 = HCLK */
		RCM->CFG_B.APB2DIV= 0;
		/* PCLK1 = HCLK */
		RCM->CFG_B.APB1DIV = 0;

		/* Select HXT as system clock source */
		RCM->CFG_B.SCSEL = 1; 

		/** Wait till HXT is used as system clock source */
		while(RCM->CFG_B.SCS!= 0x01);
	}
}


#elif defined SYSTEM_CLOCK_24MHz
/*!
 * @brief	Sets System clock frequency to 24MHz and configure HCLK, PCLK2 and PCLK1 prescalers			
 *
 * @see 
 *
 * @note 
 */
static void SystemClock24M(void)
{
 	__IO uint32_t i;
  
	RCM->CTRL_B.HXTEN= BIT_SET;
  
	for(i = 0; i < HXT_STARTUP_TIMEOUT; i++)
	{
		if(RCM->CTRL_B.HXTRDYF)
		{
			break;
		}
	}
	  
	if(RCM->CTRL_B.HXTRDYF)
	{
		/* Enable Prefetch Buffer */
		FMC->CTRL1_B.PBEN = BIT_SET;
		/* Flash 0 wait state */
		FMC->CTRL1_B.LATENCY = 0;

		/* HCLK = SYSCLK */
		RCM->CFG_B.AHBDIV= 0X00;
		/* PCLK2 = HCLK */
		RCM->CFG_B.APB2DIV= 0;
		/* PCLK1 = HCLK */
		RCM->CFG_B.APB1DIV = 0;

		/** PLL: (HXT / 2) * 6 */
		RCM->CFG_B.PLLSEL = 1;
		RCM->CFG_B.PLLXTDIV = 1;
		RCM->CFG_B.PLLMF = 4;
		
		/** Enable PLL */
		RCM->CTRL_B.PLLEN = 1;
		/** Wait PLL Ready */
		while(RCM->CTRL_B.PLLRDYF == BIT_RESET);

		/* Select PLL as system clock source */
		RCM->CFG_B.SCSEL = 2; 	
		/* Wait till PLL is used as system clock source */
		while(RCM->CFG_B.SCS!= 0x02);
	}
}

#elif defined SYSTEM_CLOCK_36MHz
/*!
 * @brief	Sets System clock frequency to 36MHz and configure HCLK, PCLK2 and PCLK1 prescalers			
 *
 * @see 
 *
 * @note 
 */
static void SystemClock36M(void)
{
 	__IO uint32_t i;
	  
	RCM->CTRL_B.HXTEN= BIT_SET;
  
	for(i = 0; i < HXT_STARTUP_TIMEOUT; i++)
	{
		if(RCM->CTRL_B.HXTRDYF)
		{
			break;
		}
	}
	  
	if(RCM->CTRL_B.HXTRDYF)
	{
		/* Enable Prefetch Buffer */
		FMC->CTRL1_B.PBEN = BIT_SET;
		/* Flash 1 wait state */
		FMC->CTRL1_B.LATENCY = 1;

		/* HCLK = SYSCLK */
		RCM->CFG_B.AHBDIV= 0X00;
		/* PCLK2 = HCLK */
		RCM->CFG_B.APB2DIV= 0;
		/* PCLK1 = HCLK */
		RCM->CFG_B.APB1DIV = 0;

		/** PLL: (HXT / 2) * 9 */
		RCM->CFG_B.PLLSEL = 1;
		RCM->CFG_B.PLLXTDIV = 1;
		RCM->CFG_B.PLLMF = 7;
		
		/** Enable PLL */
		RCM->CTRL_B.PLLEN = 1;
		/** Wait PLL Ready */
		while(RCM->CTRL_B.PLLRDYF == BIT_RESET);

		/* Select PLL as system clock source */
		RCM->CFG_B.SCSEL = 2; 	
		/* Wait till PLL is used as system clock source */
		while(RCM->CFG_B.SCS != 0x02);
	} 
}

#elif defined SYSTEM_CLOCK_48MHz
/*!
 * @brief	Sets System clock frequency to 46MHz and configure HCLK, PCLK2 and PCLK1 prescalers			
 *
 * @see 
 *
 * @note 
 */
static void SystemClock48M(void)
{
 	__IO uint32_t i;
	  
	RCM->CTRL_B.HXTEN= BIT_SET;
  
	for(i = 0; i < HXT_STARTUP_TIMEOUT; i++)
	{
		if(RCM->CTRL_B.HXTRDYF)
		{
			break;
		}
	}
	  
	if(RCM->CTRL_B.HXTRDYF)
	{
		/* Enable Prefetch Buffer */
		FMC->CTRL1_B.PBEN = BIT_SET;
		/* Flash 1 wait state */
		FMC->CTRL1_B.LATENCY = 1;

		/* HCLK = SYSCLK */
		RCM->CFG_B.AHBDIV= 0X00;
		/* PCLK2 = HCLK */
		RCM->CFG_B.APB2DIV= 0;
		/* PCLK1 = HCLK / 2 */
		RCM->CFG_B.APB1DIV = 4;

		/** PLL: HXT * 6 */
		RCM->CFG_B.PLLSEL = 1;
		RCM->CFG_B.PLLMF = 4;
		
		/** Enable PLL */
		RCM->CTRL_B.PLLEN = 1;
		/** Wait PLL Ready */
		while(RCM->CTRL_B.PLLRDYF == BIT_RESET);

		/* Select PLL as system clock source */
		RCM->CFG_B.SCSEL = 2; 	
		/* Wait till PLL is used as system clock source */
		while(RCM->CFG_B.SCS!= 0x02);
	}
}

#elif defined SYSTEM_CLOCK_56MHz
/*!
 * @brief	Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers			
 *
 * @see 
 *
 * @note 
 */
static void SystemClock56M(void)
{
 	__IO uint32_t i;
	  
	RCM->CTRL_B.HXTEN= BIT_SET;
  
	for(i = 0; i < HXT_STARTUP_TIMEOUT; i++)
	{
		if(RCM->CTRL_B.HXTRDYF)
		{
			break;
		}
	}
	  
	if(RCM->CTRL_B.HXTRDYF)
	{
		/* Enable Prefetch Buffer */
		FMC->CTRL1_B.PBEN = BIT_SET;
		/* Flash 2 wait state */
		FMC->CTRL1_B.LATENCY = 2;

		/* HCLK = SYSCLK */
		RCM->CFG_B.AHBDIV= 0X00;
		/* PCLK2 = HCLK */
		RCM->CFG_B.APB2DIV= 0;
		/* PCLK1 = HCLK / 2 */
		RCM->CFG_B.APB1DIV = 4;

		/** PLL: HXT * 7 */
		RCM->CFG_B.PLLSEL = 1;
		RCM->CFG_B.PLLMF = 5;
		
		/** Enable PLL */
		RCM->CTRL_B.PLLEN = 1;
		/** Wait PLL Ready */
		while(RCM->CTRL_B.PLLRDYF == BIT_RESET);

		/* Select PLL as system clock source */
		RCM->CFG_B.SCSEL = 2; 	
		/* Wait till PLL is used as system clock source */
		while(RCM->CFG_B.SCS!= 0x02);
	}
}

#elif defined SYSTEM_CLOCK_72MHz
/*!
 * @brief	Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers			
 *
 * @see 
 *
 * @note 
 */
static void SystemClock72M(void)
{
 	__IO uint32_t i;
	  
	RCM->CTRL_B.HXTEN= BIT_SET;
  
	for(i = 0; i < HXT_STARTUP_TIMEOUT; i++)
	{
		if(RCM->CTRL_B.HXTRDYF)
		{
			break;
		}
	}
	  
	if(RCM->CTRL_B.HXTRDYF)
	{
		/* Enable Prefetch Buffer */
		FMC->CTRL1_B.PBEN = BIT_SET;
		/* Flash 2 wait state */
		FMC->CTRL1_B.LATENCY = 2;

		/* HCLK = SYSCLK */
		RCM->CFG_B.AHBDIV= 0X00;
		/* PCLK2 = HCLK */
		RCM->CFG_B.APB2DIV= 0;
		/* PCLK1 = HCLK / 2 */
		RCM->CFG_B.APB1DIV = 4;

		/** PLL: HXT * 9 */
		RCM->CFG_B.PLLSEL = 1;
		RCM->CFG_B.PLLMF = 7;
		
		/** Enable PLL */
		RCM->CTRL_B.PLLEN = 1;
		/** Wait PLL Ready */
		while(RCM->CTRL_B.PLLRDYF == BIT_RESET);

		/* Select PLL as system clock source */
		RCM->CFG_B.SCSEL = 2; 	
		/* Wait till PLL is used as system clock source */
		while(RCM->CFG_B.SCS!= 0x02);
	}

}

#elif defined SYSTEM_CLOCK_96MHz
/*!
 * @brief	Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers			
 *
 * @see 
 *
 * @note 
 */
static void SystemClock96M(void)
{
 	__IO uint32_t i;
	  
	RCM->CTRL_B.HXTEN= BIT_SET;
  
	for(i = 0; i < HXT_STARTUP_TIMEOUT; i++)
	{
		if(RCM->CTRL_B.HXTRDYF)
		{
			break;
		}
	}
	  
	if(RCM->CTRL_B.HXTRDYF)
	{
		/* Enable Prefetch Buffer */
		FMC->CTRL1_B.PBEN = BIT_SET;
		/* Flash 3 wait state */
		FMC->CTRL1_B.LATENCY = 3;

		/* HCLK = SYSCLK */
		RCM->CFG_B.AHBDIV= 0X00;
		/* PCLK2 = HCLK */
		RCM->CFG_B.APB2DIV= 0;
		/* PCLK1 = HCLK / 2 */
		RCM->CFG_B.APB1DIV = 4;

		/** PLL: HXT * 12 */
		RCM->CFG_B.PLLSEL = 1;
		RCM->CFG_B.PLLMF = 10;
		
		/** Enable PLL */
		RCM->CTRL_B.PLLEN = 1;
		/** Wait PLL Ready */
		while(RCM->CTRL_B.PLLRDYF == BIT_RESET);

		/* Select PLL as system clock source */
		RCM->CFG_B.SCSEL = 2; 	
		/* Wait till PLL is used as system clock source */
		while(RCM->CFG_B.SCS!= 0x02);
	}

}
#endif

