/**
 *******************************************************************************
 *
 * @file        API_Flash.c
 *
 * @brief       Application for serial flash 
 *
 * @par         Project
 *              MG32
 * @version     V1.01
 * @date        2021/06/01
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2018 Megawin Technology Co., Ltd.
 *              All rights reserved.
 *
 *******************************************************************************
 * @par         Disclaimer 
 * The Demo software is provided "AS IS" without any warranty, either 
 * expressed or implied, including, but not limited to, the implied warranties 
 * of merchantability and fitness for a particular purpose. The author will 
 * not be liable for any special, incidental, consequential or indirect 
 * damages due to loss of data or any other reason. 
 * These statements agree with the world wide and local dictated laws about 
 * authorship and violence against these laws. 
 *******************************************************************************
 *******************************************************************************
 */


/* Includes ------------------------------------------------------------------*/
#include "API_Flash.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/


/**
 * @name	Flash 
 *   		
 */ 
///@{
/**
 *******************************************************************************
 * @brief  	    Flash Init
 * @details  
 * @param[in]   None
 * @return	    None 
 * @note
 * @par         Example
 * @code
    API_Flash_Init ();
 * @endcode
 *******************************************************************************
 */
void API_Flash_Init (void)
{
 
    /*=== 2. Default Initial SPI ===*/
    SPI_DeInit(SPI0);
    
    /*=== 3. Configure clock divider ===*/                      // SPI clock = 1MHz
    SPI_Clock_Select(SPI0, SPI_CK_SPIx_PR);                     // CK_SPIx = CK_SPIx_PR
    SPI_PreDivider_Select(SPI0, SPI_PDIV_1);                    // PDIV outpu = CK_SPIx /2
    SPI_Prescaler_Select(SPI0, SPI_PSC_2);                      // Prescaler outpu = PDIV outpu /3
    SPI_Divider_Select(SPI0, SPI_DIV_2);                        // DIV outpu = PDIV outpu /2
    
    /*=== 4. Configure SPI data line, mode and data size... ===*/
    SPI_DataLine_Select(SPI0, SPI_Standard);                    // SPI data line standard SPI
    SPI_ModeAndNss_Select(SPI0, SPI_Master);             // Master with NSS
    SPI_ClockPhase_Select(SPI0, SPI_LeadingEdge);               // CPHA = 0
    SPI_ClockPolarity_Select(SPI0, SPI_Low);                    // CPOL = 0
    SPI_FirstBit_Select(SPI0, SPI_MSB);                         // MSB first
    SPI_DataSize_Select(SPI0, SPI_8bits);                       // Data size 8bits
    
    /*=== 6. Enable SPI ===*/
    SPI_Cmd(SPI0, ENABLE);                                              // Enable SPI

}
///@} 


/**
 * @name	Flash Erase
 *   		
 */ 
///@{
/**
 *******************************************************************************
 * @brief  	    Flash erase
 * @details  
 * @param[in]   Address: start address.
 * 	@arg\b		    0x00000000 ~ 0xFFFFFFFF.
 * @param[in]   Length: erase space
 * 	@arg\b	        0x00000001 ~ 0xFFFFFFFF.
 * @return	    	
 * @note        Erase minimum block 64K bytes
 *              Maxmum start address is depending on the flash size.
 * @par         Example
 * @code
    API_Flash_Erase (0x00000000, 0x00010000);
 * @endcode
 *******************************************************************************
 */
void API_Flash_Erase (uint32_t Address, uint32_t Length)
{
    uint32_t AddressIndex;
    uint16_t EraseTheBlockTotalNumber;
    uint16_t CNT;
    
    
    AddressIndex = Address;
    
    /* calculate erase the block total number */
    EraseTheBlockTotalNumber = (uint16_t)(Length >> 16);
    if((Length & 0x0000FFFF) != 0)
        EraseTheBlockTotalNumber++;

    
    for(CNT=0; CNT<EraseTheBlockTotalNumber; CNT++)
    {
        MID_Flash_Write_Enable();
        
        // Calculate erase start address
        AddressIndex += (((uint32_t) CNT) << 16); 
        
        /* Block erase 64KB */
        nCS = 0;
        SPI_SetTxData(SPI0, SPI_1Byte, 0xD8);
        while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TXF flag
        SPI_ClearFlag(SPI0, (SPI_TCF | SPI_TXF | SPI_RXF));                 // Clear TXF and RXF
        
        SPI_DataSize_Select(SPI0, SPI_24bits);
        SPI_SetTxData(SPI0, SPI_3Byte, AddressIndex);
        while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TXF flag
        SPI_ClearFlag(SPI0, (SPI_TCF | SPI_TXF | SPI_RXF));                 // Clear TXF and RXF
        SPI_DataSize_Select(SPI0, SPI_8bits);
        nCS = 1;
        
        MID_Flash_Check_Busy();
    }
}
///@} 


/**
 * @name	Flash program
 *   		
 */ 
///@{
/**
 *******************************************************************************
 * @brief  	    flash multi-bytes write
 * @details  
 * @param[in]   Address: start address.
 * 	@arg\b		    0x00000000 ~ 0xFFFFFFFF.
 * @param[in]   DataSource: transfer data source address
 * 	@arg\b	
 * @param[in]   Length: write total length
 * 	@arg\b	        0x00000001 ~ 0xFFFFFFFF.
 * @return	    	
 * @note        Maxmum length and start address is depending on the flash size.
 * @par         Example
 * @code
    API_Flash_MultiBytesWrite (0x00010000, &source, 0x10000);
 * @endcode
 *******************************************************************************
 */
void API_Flash_MultiBytesWrite (uint32_t Address, uint8_t *DataSource, uint32_t Length)
{
    uint32_t AddressIndex;      // Page age start address
    uint16_t ProgramLoop;       // Program the block total number 
    uint16_t LoopCnt;           // Program loop counter
    uint16_t PageProgramLength; // Each page program length
    uint32_t NeedProgramLength; // Not program total number
    uint8_t *PageDataSource;    // Each page program data source address
    
    
    // Init value 
    AddressIndex = Address;
    PageDataSource = DataSource;
    NeedProgramLength = Length;
    
    /* calculate program the block total number */
    ProgramLoop = (uint16_t)(Length >> 8);
    if((Length & 0x000000FF) != 0)
        ProgramLoop++;
    
    for(LoopCnt=0; LoopCnt<ProgramLoop; LoopCnt++)
    {
        // Calculate page program length
        if((NeedProgramLength & 0xFFFFFF00) == 0)
        {
            PageProgramLength = (uint16_t)(NeedProgramLength & 0x000000FF);
        }
        else    
        {
            PageProgramLength = 0x100;
        }

        // Page program
        MID_Flash_Page_Program(AddressIndex, PageDataSource, PageProgramLength);
        
        // Addres addressIndex
        AddressIndex += 0x100;
        PageDataSource += 0x100;
    }
}


/**
 *******************************************************************************
 * @brief  	    SPIx flash 1 byte write
 * @details  
 * @param[in]   Address: address.
 * 	@arg\b		    0x00000000 ~ 0xFFFFFFFF.
 * @param[in]   Dat: write data
 * 	@arg\b	        0x00 ~ 0xFF
 * @return	    	
 * @note
 * @par         Example
 * @code
    API_Flash_1ByteWrite (0x00010000, 0x5A);
 * @endcode
 *******************************************************************************
 */
void API_Flash_1ByteWrite (uint32_t Address, uint8_t Dat)
{
    MID_Flash_Page_Program(Address, &Dat, 1);
}
///@} 


/**
 * @name	Flash read
 *   		
 */ 
///@{
/**
 *******************************************************************************
 * @brief  	    SPIx flash multi-bytes write
 * @details  
 * @param[in]   Address: read start address.
 * 	@arg\b		    0x00000000 ~ 0xFFFFFFFF.
 * @param[in]   BufferAddreass: buffer address.
 * 	@arg\b	
 * @param[in]   Length: read total length
 * 	@arg\b	        0x00000001 ~ 0xFFFFFFFF.
 * @return	    	
 * @note        Maxmum start address is depending on the flash size.
 * @par         Example
 * @code
    API_Flash_MultiBytesRead (0x00010000, &source, 0x10000);
 * @endcode
 *******************************************************************************
 */
void API_Flash_MultiBytesRead (uint32_t Address, uint8_t *BufferAddreass, uint32_t Length)
{
	uint32_t i;
    uint8_t  *ReadBuffer;
    
    
    ReadBuffer = BufferAddreass;
	nCS = 0;
    /* Write command */
	SPI_SetTxData(SPI0, SPI_1Byte, 0x03);
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TXF flag
    SPI_ClearFlag(SPI0, (SPI_TCF | SPI_TXF | SPI_RXF));                 // Clear TXF and RXF
	
    /* Write address */
	SPI_DataSize_Select(SPI0, SPI_24bits);
	SPI_SetTxData(SPI0, SPI_3Byte, Address);
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TXF flag
    SPI_ClearFlag(SPI0, (SPI_ALLF));                                    // Clear TXF and RXF
    SPI_ClearRxData(SPI0);                                              // Clear RX shadow and RDAT
	SPI_DataSize_Select(SPI0, SPI_8bits);
    
    /* Read data */
	for(i = 0; i < Length; i++)
	{
		SPI_SetTxData(SPI0, SPI_1Byte, Dummy_Data);
		while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    
		SPI_ClearFlag(SPI0, SPI_TCF | SPI_TXF | SPI_RXF);                   
        *ReadBuffer = SPI_GetRxData(SPI0);                              // Store data to buffer
        ReadBuffer ++;
	}
	nCS = 1;
}


/**
 *******************************************************************************
 * @brief  	    SPIx flash 1 byte read
 * @details  
 * @param[in]   Address: address. 
 * 	@arg\b		    0x00000000 ~ 0xFFFFFFFF
 * @return	    Flash data
 * @note        Maxmum start address is depending on the flash size.
 * @par         Example
 * @code
    API_Flash_1ByteRead (0x00010000);
 * @endcode
 *******************************************************************************
 */
uint8_t API_Flash_1ByteRead (uint32_t Address)
{ 
	nCS = 0;
    
    /* Write command */
	SPI_SetTxData(SPI0, SPI_1Byte, 0x03);
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TXF flag
    SPI_ClearFlag(SPI0, (SPI_TCF | SPI_TXF | SPI_RXF));                 // Clear TXF and RXF
	
    /* Write address */
	SPI_DataSize_Select(SPI0, SPI_24bits);
	SPI_SetTxData(SPI0, SPI_3Byte, Address);
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TXF flag
    SPI_ClearFlag(SPI0, (SPI_ALLF));                                    // Clear TXF and RXF
	SPI_DataSize_Select(SPI0, SPI_8bits);
    
    /* Read data */
    SPI_SetTxData(SPI0, SPI_1Byte, Dummy_Data);
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TCF flag
    SPI_ClearFlag(SPI0, SPI_TCF | SPI_TXF | SPI_RXF);                   // Clear TCF

	nCS = 1;

    return  (uint8_t)SPI_GetRxData(SPI0);
}
///@} 



