/**************************************************************************//**
 * @file     fmc.c
 * @version  V1.00
 * $Revision: 1 $
 * $Date: 14/07/15 2:52p $
 * @brief    N572 FMC driver source file
 *
 * @note
 * Copyright (C) 2014 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/

//* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include "N572.h"


/** @addtogroup N572_Device_Driver N572 Device Driver
  @{
*/

/** @addtogroup N572_FMC_Driver FMC Driver
  @{
*/

/** @addtogroup N572_FMC_EXPORTED_FUNCTIONS FMC Exported Functions
  @{
*/

/**
  * @brief    Enable Erase/Write of ISP function
  * @retval   None
  */
void FMC_EnableWrite (void)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	FMC->ISPCTL &= ~FMC_ISPCTL_EWEN_Msk;
	SYS_Lock(u8Lock);
}

/**
  * @brief    Disable Erase/Write of ISP function
  * @retval   None
  */
void FMC_DisableWrite (void)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	FMC->ISPCTL |= FMC_ISPCTL_EWEN_Msk;
	SYS_Lock(u8Lock);
}

/**
  * @brief    Enable FMC ISP function
  */
void FMC_Open(void)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	FMC->ISPCTL |=  (FMC_ISPCTL_ISPEN_Msk | FMC_ISPCTL_EWEN_Msk);
	SYS_Lock(u8Lock);
}

/**
  * @brief    Disable all FMC functions
  */
void FMC_Close(void)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
    FMC->ISPCTL &= ~FMC_ISPCTL_ISPEN_Msk;
	SYS_Lock(u8Lock);
}

/**
  * @brief    Set falsh page erase time
  * @param    u32PageEraseTime:   Flash page erase time
  *         - \ref FMC_PAGE_ERASE_00_75MS
  *         - \ref FMC_PAGE_ERASE_01_00MS
  *         - \ref FMC_PAGE_ERASE_01_50MS
  *         - \ref FMC_PAGE_ERASE_02_00MS
  *         - \ref FMC_PAGE_ERASE_02_50MS
  *         - \ref FMC_PAGE_ERASE_03_00MS
  *         - \ref FMC_PAGE_ERASE_04_00MS
  *         - \ref FMC_PAGE_ERASE_05_00MS
  * @retval   None
  */
void FMC_SetPageEraseTime(uint32_t u32PageEraseTime)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	FMC->ISPCTL |= u32PageEraseTime;
	SYS_Lock(u8Lock);
}

/**
  * @brief    Set falsh program time
  * @param    u32ProgramTime:   Flash program time
  *         - \ref FMC_PROGRAM_TIME_10_US
  *         - \ref FMC_PROGRAM_TIME_15_US
  *         - \ref FMC_PROGRAM_TIME_20_US
  *         - \ref FMC_PROGRAM_TIME_25_US
  *         - \ref FMC_PROGRAM_TIME_30_US
  *         - \ref FMC_PROGRAM_TIME_35_US
  *         - \ref FMC_PROGRAM_TIME_40_US
  *         - \ref FMC_PROGRAM_TIME_45_US
  * @retval   None
  */
void FMC_SetProgramTime(uint32_t u32ProgramTime)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	FMC->ISPCTL |= u32ProgramTime;
	SYS_Lock(u8Lock);
}

/**
  * @brief    Erase a page. The page size is 512 bytes.
  * @param    u32PageAddr   Flash page address. Must be a 512-byte aligned address.
  * @retval   0    Success
  * @retval   -1   Erase failed
  */
int32_t FMC_Erase(uint32_t u32PageAddr)
{
	int8_t i8Flag = 0;
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
    FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
    FMC->ISPADDR = u32PageAddr;
		
    // Don't allow NVIC to interrupt a FMC write operation.
    __disable_irq();
    // Trigger ISP command
    FMC->ISPTRG = (FMC->ISPTRG & (~FMC_ISPTRG_ISPGO_Msk)) | FMC_ISPTRG_ISPGO_Msk;
    // Flush M0 pipeline.
    __ISB();
    __enable_irq();
	
	if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
	{
		FMC->ISPCTL = (FMC->ISPCTL & (~FMC_ISPCTL_ISPFF_Msk)) | FMC_ISPCTL_ISPFF_Msk;
		i8Flag = -1;
	}
	SYS_Lock(u8Lock);
    return i8Flag;
}

/**
  * @brief    Writes a word data to specified flash address.
  * @param    u32Addr   Destination address
  * @param    u32Data   Word data to be written
  */
void FMC_Write(uint32_t u32Addr, uint32_t u32Data)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
    FMC->ISPCMD = FMC_ISPCMD_WRITE;
    FMC->ISPADDR = u32Addr;
    FMC->ISPDAT = u32Data;
	
    // Don't allow NVIC to interrupt a FMC write operation.
    __disable_irq();
    // Trigger ISP command
    FMC->ISPTRG = (FMC->ISPTRG & (~FMC_ISPTRG_ISPGO_Msk)) | FMC_ISPTRG_ISPGO_Msk;
    // Flush M0 pipeline.
    __ISB();
    __enable_irq();
	SYS_Lock(u8Lock);
}

/**
  * @brief    Write User Configuration
  * @param    u32Config   The word to store data
  * @retval   0    Success
  * @retval   -1   Failed
  */
int32_t FMC_WriteConfig(uint32_t *u32Config)
{
    FMC_Erase(FMC_CONFIG_BASE);

    FMC_Write(FMC_CONFIG_BASE, *u32Config);
    if(FMC_Read(FMC_CONFIG_BASE) != *u32Config)
		return -1;
	else
		return 0;
}

/**
  * @brief    Read a word from specified flash address.
  * @param    u32Addr   Flash word address. Must be a word aligned address.
  * @retval   The word data stored in the flash address "u32Addr".
  */
uint32_t FMC_Read(uint32_t u32Addr)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	
    FMC->ISPCMD = FMC_ISPCMD_READ;
    FMC->ISPADDR = u32Addr;
	
    // Trigger ISP command
    FMC->ISPTRG = (FMC->ISPTRG & (~FMC_ISPTRG_ISPGO_Msk)) | FMC_ISPTRG_ISPGO_Msk;
    // Flush M0 pipeline.
    __ISB();

	SYS_Lock(u8Lock);
    return FMC->ISPDAT;
}

/**
  * @brief    Read company ID.
  * @retval   The company ID.
  */
uint32_t FMC_ReadCID(void)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	
    FMC->ISPCMD = FMC_ISPCMD_READ_CID;
    FMC->ISPADDR = 0x0;
	
    // Trigger ISP command
    FMC->ISPTRG = (FMC->ISPTRG & (~FMC_ISPTRG_ISPGO_Msk)) | FMC_ISPTRG_ISPGO_Msk;
    // Flush M0 pipeline.
    __ISB();

	SYS_Lock(u8Lock);
	return FMC->ISPDAT;
}

/**
  * @brief    Read device ID.
  * @retval   The device ID.
  */
uint32_t FMC_ReadDID(void)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	
    FMC->ISPCMD = FMC_ISPCMD_READ_DID;
    FMC->ISPADDR = 0;
	
    // Trigger ISP command
    FMC->ISPTRG = (FMC->ISPTRG & (~FMC_ISPTRG_ISPGO_Msk)) | FMC_ISPTRG_ISPGO_Msk;
    // Flush M0 pipeline.
    __ISB();

	SYS_Lock(u8Lock);
	return FMC->ISPDAT;
}

/**
  * @brief    Read the User Configuration words.
  * @param    u32Config: The word to store data.
  * @retval   None
  */
void FMC_ReadConfig(uint32_t *u32Config)
{
    *u32Config = FMC_Read(FMC_CONFIG_BASE);
}

/**
  * @brief    Enable User Config update.
  * @retval   None
  */
void FMC_EnableCfgUpdate(void)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	FMC->ISPCTL |=  FMC_ISPCTL_CFGUEN_Msk;
	SYS_Lock(u8Lock);
}

/**
  * @brief    Disable User Config update.
  * @retval   None
  */
void FMC_DisableCfgUpdate(void)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	FMC->ISPCTL &= ~FMC_ISPCTL_CFGUEN_Msk;
	SYS_Lock(u8Lock);
}

/*@}*/ /* end of group N572_FMC_EXPORTED_FUNCTIONS */

/*@}*/ /* end of group N572_FMC_Driver */

/*@}*/ /* end of group N572_Device_Driver */

/*** (C) COPYRIGHT 2014 Nuvoton Technology Corp. ***/


