/**************************************************************************//**
 * @file     main.c
 * @version  V1.00
 * $Revision: 1 $
 * $Date: 14/07/30 10:00a $
 * @brief    Demonstrate the usage of SYS driver by changing different 
 *           HCLK setting for the system clock source. 
 *
 * @note
 * Copyright (C) 2014 Nuvoton Technology Corp. All rights reserved.
 ******************************************************************************/
#include "stdio.h"
#include "N572.h"

#define SIGNATURE       0x125ab234
#define FLAG_ADDR       0x20001FFC

void SYS_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Enable External XTL32K */
    CLK_EnableXtalRC(CLK_PWRCTL_XTL32K_EN_Msk);

    /* Enable External OSC48M(F072) || OSC24M(F065) */
	#if (__CHIP_SERIES__==__N572F065_SERIES__)
    CLK_EnableXtalRC(CLK_PWRCTL_OSC24M_EN_Msk);
	#elif (__CHIP_SERIES__==__N572F072_SERIES__)
	CLK_EnableXtalRC(CLK_PWRCTL_OSC48M_EN_Msk);
	#endif
	
	/* Set RAM wait state */
	SYS_SET_RAM_WAIT_STATE(SYS_IPRST0_RAMWS_ZERO_WAIT);
	
    /* Set flash memory wait state */
	SYS_SET_CPU_WAIT_STATE(SYS_IPRST0_CPUWS_1HCLK_WAIT);
	
	/* Procedures to configure the HCLK from internal RC */
	#if (__CHIP_SERIES__==__N572F065_SERIES__)
	CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_RC_24M,CLK_CLKDIV_HCLK(1));
	#elif (__CHIP_SERIES__==__N572F072_SERIES__)
	CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_RC_48M,CLK_CLKDIV_HCLK(1));
	#endif

    /* Update System Core Clock */
    /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
    SystemCoreClockUpdate();

	/* PLL1 power down function */
	CLK_SetPLL1Mode(PLL_PWOERDOWN_MODE);
	CLK_SetPLL2Mode(PLL_PWOERDOWN_MODE);

    /* Lock protected registers */
    SYS_LockReg();
}

/*---------------------------------------------------------------------------------------------------------*/
/*  Main Function                                                                                          */
/*---------------------------------------------------------------------------------------------------------*/
int32_t main (void)
{
    uint32_t u32RstSrt;
	uint8_t u8Tmp;
	
    /* Lock protected registers */
    if(!SYS_IsRegLocked()) // In end of main function, program issued CPU reset and write-protection will be disabled.
        SYS_LockReg();

    /* 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. If user want to write protected register, please issue SYS_UnlockReg() to unlock protected register.

    /*
        This sample code will show some function about system manager controller and clock controller:
        1. Read PDID
        2. Get and clear reset source
        3. Lock & unlock protected register.
	    4. Change system clock.
        5. Brown-Out Detector.
	    6. Reset 
    */
    printf("\n+------------------------------------------------------------------------+\n");
    printf("|                      System Driver Sample Code                         |\n");
    printf("+------------------------------------------------------------------------+\n");
	printf("CPU @ %dHz\n", SystemCoreClock );

    if ( M32(FLAG_ADDR) == SIGNATURE) 
	{
        printf("  CPU Reset success!\n");
        M32(FLAG_ADDR) = 0;
        printf("  Press any key to continue ...\n");
        getchar();
    }

    /*---------------------------------------------------------------------------------------------------------*/
    /* Misc system function test                                                                               */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Read Part Device ID */
    printf("Product ID 0x%x\n", SYS_ReadPDID() );

    /* Get reset source from last operation */
    u32RstSrt = SYS_GetResetSrc();
    printf("Reset Source 0x%x\n", u32RstSrt );

    /* Clear reset source */
    SYS_ClearResetSrc( u32RstSrt );

    /* Unlock protected registers for Clock adj and Brown-Out Detector settings */
    SYS_UnlockReg();

	printf("\nSelect HCLK Frequency(1-3), Exit and run BOD(Other Key):\n");
	printf("Key 1: Internal OSC 48000000 Hz(Only F072)\n");
	printf("Key 2: Internal OSC 24000000 Hz(Only F065)\n");
	printf("Key 3: External Xtal 32768 Hz\n");

	do
	{
		u8Tmp = getchar();
		
		switch(u8Tmp)
		{
			case '1':
				#if (__CHIP_SERIES__==__N572F072_SERIES__)
				CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_RC_48M, CLK_CLKDIV_HCLK(1));
				#endif
				break;
		
			case '2':
				#if (__CHIP_SERIES__==__N572F065_SERIES__)
				CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_RC_24M, CLK_CLKDIV_HCLK(1));
				#endif
				break;
			
			case '3':
				CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_XTL_32K, CLK_CLKDIV_HCLK(1));
				break;	
			
			default:
				u8Tmp = 0;
				break;
		}
		
		if( u8Tmp != 0 )
			printf("HCLK frequency became %d Hz\n", CLK_GetHCLKFreq());
		
	}while( u8Tmp != 0 );
	
    /*---------------------------------------------------------------------------------------------------------*/
    /* Brown-Out detector test                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/
	
	/* Enable Brown-Out detector */
	SYS_EnableBOD(SYS_BODCTL_BODVL_2_7V);
	
	/* Get voltage output */
	for( u8Tmp = 0; u8Tmp < 10 ; u8Tmp++ )
	{
		if ( SYS_GET_BOD_OUTPUT() )
			printf("Detected voltage is lower than threshold value.\n");
		else
			printf("Detected voltage is higher than threshold value.\n");	
	}	
	
	/* Disable Brown-Out detector */
	SYS_DisableBOD();
	
    /* Write a signature work to SRAM to check if it is reset by software */
    M32(FLAG_ADDR) = SIGNATURE;
    printf("\n\n  >>> Reset CPU <<<\n");

    /* Reset CPU */
    SYS_ResetCPU();
}
