/**
 *******************************************************************************
 * @file        MG32_SPI_MID.c
 *
 * @brief       The SPI middle code c file
 *
 * @par         Project
 *              MG32
 * @version     V1.00
 * @date        2018/02/21
 * @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.
 *******************************************************************************
 *******************************************************************************
 */

#include "MG32_SPI_MID.h"

/*** Global Variables ***/
uint32_t Flash_ID = 0;
   
/**
 *******************************************************************************
 * @brief  	    SPIx set transfer interface and direction
 * @details  
 * @param[in]   SPIx:
 * 	@arg\b			SPI0.
 * @param[in]   SPI_NSSIS:
 * 	@arg\b		    MID_SPI_StanardSpi.
 * 	@arg\b		    MDI_SPI_1lineDataOut.
 * 	@arg\b		    MDI_SPI_1lineDataIn.
 * 	@arg\b		    MDI_SPI_2linesSeparateDataOut
 * 	@arg\b		    MDI_SPI_2linesSeparateDataIn.
 * 	@arg\b		    MDI_SPI_2linesCopyDataOut
 * 	@arg\b		    MDI_SPI_2linesCopyDataIn
 * 	@arg\b		    MDI_SPI_4linesSeparateDataOut
 * 	@arg\b		    MDI_SPI_4linesSeparateDataIn.
 * 	@arg\b		    MDI_SPI_4linesCopyDataOut
 * 	@arg\b		    MDI_SPI_4linesCopyDataIn
 * 	@arg\b		    MDI_SPI_4linesDuplicateDataOut
 * 	@arg\b		    MDI_SPI_8linesDataOut
 * 	@arg\b		    MDI_SPI_8linesDataIn
 * @return	    	
 * @note
 * @par         Example
 * @code
    MID_SPI_SetTrasferInterfaceAndDirection(SPI0, MID_SPI_StanardSpi);
 * @endcode
 *******************************************************************************
 */ void MID_SPI_SetTransferInterfaceAndDirection (SPI_Struct* SPIx, uint8_t DatControl)
{
    uint8_t Reg;


    Reg = SPIx->CR2.B[0] & ~SPI_CR2_TX_DIS_mask_b0;
    Reg |= DatControl;
    SPIx->CR2.B[0] = Reg;
}    


/**
 * @name	Flash state and configure
 *   		
 */ 
///@{
/**
 *******************************************************************************
 * @brief  	    Flash read ID
 * @details  
 * @param[in]   None
 * @return	    ID data
 * @note
 * @par         Example
 * @code
    MID_Flash_Read_ID ();
 * @endcode
 *******************************************************************************
 */
uint32_t MID_Flash_Read_ID (void)
{
    uint32_t RDAT;
    
    nCS = 0;
    SPI_SetTxData(SPI0, SPI_1Byte, 0x9F);                               // Send 1 byte and received 1 byte the same time
	while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_Normal);
	SPI_ClearRxData(SPI0);                                              // Clear RDAT all buffer
    SPI_ClearFlag(SPI0, SPI_TCF);
	SPI_DataSize_Select(SPI0, SPI_24bits);
    SPI_SetTxData(SPI0, SPI_3Byte, Dummy_Data);                         // Received 1 byte and send 1 byte the same time
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TCF flag
    SPI_ClearFlag(SPI0, SPI_TCF | SPI_TXF | SPI_RXF);                   // Clear TCF
    RDAT = SPI_GetRxData(SPI0);                                     // Store flash ID to global
	SPI_DataSize_Select(SPI0, SPI_8bits);
	nCS = 1;
    
    return RDAT;
}


/**
 *******************************************************************************
 * @brief  	    Flash write eanble
 * @details  
 * @param[in]   None   
 * @return	    None
 * @note
 * @par         Example
 * @code
    API_Flash_Write_Enable ();
 * @endcode
 *******************************************************************************
 */
void MID_Flash_Write_Enable(void)
{
	uint32_t RDAT;
	
    
  Re_Flash_Write_Enable:
    /* Write enable */
	nCS = 0;
	SPI_SetTxData(SPI0, SPI_1Byte, 0x06);
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TXF flag
    SPI_ClearFlag(SPI0, (SPI_TCF | SPI_TXF | SPI_RXF));                 // Clear TXF and RXF
	nCS = 1;

    /* Read status register */
	nCS = 0;
	SPI_SetTxData(SPI0, SPI_1Byte, 0x05);			//RDSR
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TCF flag
    SPI_ClearFlag(SPI0, SPI_TCF | SPI_TXF | SPI_RXF);                   // Clear TCF
    SPI_ClearRxData(SPI0);
    
	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
	RDAT = SPI_GetRxData(SPI0);                                         // Get received data
	nCS = 1;
	
    /* Check WEL == 1 */
	if((RDAT & 0x02) == 0x00)
		goto Re_Flash_Write_Enable;
}


/**
 *******************************************************************************
 * @brief  	    Flash check busy
 * @details  
 * @param[in]   None   
 * @return	    None
 * @note
 * @par         Example
 * @code
    API_Flash_Check_Busy ();
 * @endcode
 *******************************************************************************
 */
void MID_Flash_Check_Busy(void)
{
	uint8_t RDAT;
    
    
    /* Read status register */
	nCS = 0;
	SPI_SetTxData(SPI0, SPI_1Byte, 0x05);			//RDSR
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TCF flag
    SPI_ClearFlag(SPI0, SPI_TCF | SPI_TXF | SPI_RXF);                   // Clear TCF
    SPI_ClearRxData(SPI0);
    
    /* Check erase or write complete */
  Re_Flash_Check_Busy:
    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
    RDAT = SPI_GetRxData(SPI0);                                         // Get received data
	
	if((RDAT & 0x01) == 0x01)			//WIP, write in progress
		goto Re_Flash_Check_Busy;
    
//    /* Check write enable latch = 0 */
//	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
//    RDAT = SPI_GetRxData(SPI0);                                         // Get received data
//    
//    if((RDAT & 0x02) == 0x02)

	nCS = 1;
}
///@} 


/**
 *******************************************************************************
 * @brief  	    Flash Page Program
 * @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	        0 ~ 256.
 * @return	    	
 * @note        Maxmum length is depending on the flash size.
 *              program length maximum is 256 byte.
 * @par         Example
 * @code
    API_Flash_Page_Program (0x00010000, &source, 0x100);
 * @endcode
 *******************************************************************************
 */
void MID_Flash_Page_Program(uint32_t Addr, uint8_t *DataSource, uint16_t Length)
{
	uint16_t i;
    uint8_t *AddrIndex;
    
    
    AddrIndex = DataSource;

    MID_Flash_Write_Enable();
    
	nCS = 0;
	SPI_SetTxData(SPI0, SPI_1Byte, 0x02);                               // Write command 
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    
    SPI_ClearFlag(SPI0, (SPI_TCF | SPI_TXF | SPI_RXF));                 
	
	SPI_DataSize_Select(SPI0, SPI_24bits);                              // Write address
	SPI_SetTxData(SPI0, SPI_3Byte, Addr);
    while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);
    SPI_ClearFlag(SPI0, (SPI_TCF | SPI_TXF | SPI_RXF));
	SPI_DataSize_Select(SPI0, SPI_8bits);
	
	for(i=0; i<Length; i++)                                             // Write Data
	{
		SPI_SetTxData(SPI0, SPI_1Byte, *AddrIndex);
        AddrIndex++;
		while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);
		SPI_ClearFlag(SPI0, (SPI_TCF | SPI_TXF | SPI_RXF));             // Clear TXF and RXF
	}
	
	nCS = 1;
   
	MID_Flash_Check_Busy();                                             // Wait program complete
}


