

/**
 ******************************************************************************
 *
 * @file        BSP_Flash.c
 * @brief       Use SPI module to control FLASH (MX25R6435F).
 *
 * @par         Project
 *              MG32
 * @version     V1.01
 * @date        2022/08/01
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 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 "BSP_SPIFlash.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define FLASH_SPI    SPI0

#define __BSP_SPI_CLEARFLAG(__FLAG__)     FLASH_SPI->STA.W = (__FLAG__)


/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
FlashCTR_TypeDef  Flash0;

/* Private function prototypes -----------------------------------------------*/
static uint8_t BSP_Flash_OutputData(void);
static void BSP_Flash_WriteFlash_Cmd (FunctionalState WREN);


/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/


/**
 *******************************************************************************
 * @brief	   SPI interface initial for Flash.
 * @details     
 * @return      
 * @exception   
 * @note                        
 *******************************************************************************
 */
void BSP_Flash_Init(void)
{
    /*GPIO Initial*/
    BSP_GPIO_PinConfig( FLASH_CEN_IOM, Data_DIR_OUT_PP , FLASH_CEN_AFS);
    BSP_GPIO_PinConfig( FLASH_SCK_IOM, Data_DIR_OUT_PP , FLASH_SCK_AFS);
    BSP_GPIO_PinConfig( FLASH_D0_IOM , Data_DIR_OUT_PP , FLASH_D0_AFS);
    BSP_GPIO_PinConfig( FLASH_D1_IOM , Data_DIR_IN_NoRU, FLASH_D1_AFS);
    
    FLASH_CEN = FLASH_CEN_NOACTIVE;
    
    /*SPI Initial*/
    
    SPI_DeInit(FLASH_SPI);                                       // SPI Register to Default value.
    
    SPI_Clock_Select(FLASH_SPI, SPI_CK_SPIx_PR);                 // SPI clock source is SPI_PR 
    SPI_PreDivider_Select(FLASH_SPI, SPI_PDIV_1);                // SPI PDIV /1
    SPI_Prescaler_Select(FLASH_SPI, SPI_PSC_1);                  // SPI PSC /1
    SPI_Divider_Select(FLASH_SPI, SPI_DIV_8);                    // SPI DIV /8
    
    //Mode
    SPI_ModeAndNss_Select(FLASH_SPI, SPI_Master);                // SPI master mode without NSS
    SPI_DataLine_Select(FLASH_SPI, SPI_Standard);                // Srandard SPI
    SPI_ClockPhase_Select(FLASH_SPI, SPI_LeadingEdge);           // Leading edge   ( CPHA = 0)
    SPI_ClockPolarity_Select(FLASH_SPI, SPI_Low);                // Clock idle low ( CPOL = 0)
    
    //Character format.
    FLASH_SPI->CR0.MBIT.LSB_EN = SPI_MSB;                        // First bit MSB      
    FLASH_SPI->CR2.MBIT.DSIZE  = SPI_8bits;                      // Data size 8bit                   
   
    //Enable SPI
    SPI_Cmd(FLASH_SPI, ENABLE);   
    
    /*Parameter Initial*/ 
    Flash0.Status       = Flash_Idle;
    Flash0.Flash_RDID   = 0x00000000;
    Flash0.BLen         = 0;
    Flash0.DataCnt      = 0;
    Flash0.Total_Length = 0;
    Flash0.DMA_MaxSize  = DMA_MAX_SIZE;
 
}
/**
 *******************************************************************************
 * @brief      Input data to Flash (SPI write data) 
 * @details     
 * @param[in]  DataLen: Data size
 *  @arg\b          0, 1 byte 
 *  @arg\b          1, 2 bytes 
 *  @arg\b          2, 3 bytes 
 *  @arg\b          3, 4 bytes 
 * @param[in]  FlashData: Send data
 * @return  
 * @exception  No
 * @note 
 *******************************************************************************
 */
void BPS_Flash_InputData(uint8_t DataLen , uint32_t FlashData)
{
    SPI_SetTxData(FLASH_SPI, (Byte_Enum) (DataLen - 1), FlashData);
    while((SPI0->STA.W & SPI_INT_TC) != SPI_INT_TC);
    __BSP_SPI_CLEARFLAG(SPI_ALLF);
    SPI_ClearRxData(FLASH_SPI);
}
/**
 *******************************************************************************
 * @brief       Read the flash manufacturer ID and memory type + memory density.
 * @details     
 * @return      Flash RDID    
 * @exception   No
 * @note
 *******************************************************************************
 */ 
void BSP_Flash_CheckFlashRDID (void)
{
    ctype RDAT;
    

    Flash0.Status = Flash_CheckID;

    FLASH_CEN = FLASH_CEN_ACTIVE;     
    
    BPS_Flash_InputData(1,FLASH_READ_IDENTIFICATION);
    RDAT.B[0] = BSP_Flash_OutputData();
    RDAT.B[1] = BSP_Flash_OutputData();
    RDAT.B[2] = BSP_Flash_OutputData();
    RDAT.B[3] = 0;
    
    FLASH_CEN = FLASH_CEN_NOACTIVE;
    
    Flash0.Flash_RDID = RDAT.W;
    
    if( Flash0.Flash_RDID != FLASH_RDID)
    {
        Flash0.Status = Flash_Fail;
        return;    
    }
    
    Flash0.Status = Flash_Idle;
    
}
/**
 *******************************************************************************
 * @brief   Read Configuration Register  
 * @details     
 * @return  
 *   @arg\b 1. Byte0 = Configuration register-1
 *   @arg\b 2. Byte1 = Configuration register-2  
 * @exception   No
 * @note
 *******************************************************************************
 */ 
uint16_t BSP_Flash_ReadFlashRDCR (void)
{
    ctype RDAT;
    
    FLASH_CEN = FLASH_CEN_ACTIVE;
    
    BPS_Flash_InputData(1,FLASH_READ_CONFIGURATION);
    RDAT.B[0] = BSP_Flash_OutputData();
    RDAT.B[1] = BSP_Flash_OutputData();
    
    FLASH_CEN = FLASH_CEN_NOACTIVE;
    
    return(RDAT.H[0]);
}
/**
 *******************************************************************************
 * @brief       Flash erase
 * @details  
 * @param[in]   EraseType: Erase type
 *  @arg\b          FLASH_ERASE_SECTOR  : Flash sector erase ( sector unit is 4K byte)
 *  @arg\b          FLASH_ERASE_BLOCK32K: Flash erase unit is 32K bytes.
 *  @arg\b          FLASH_ERASE_BLOCK64K: Flash erase uint is 64K bytes.
 *  @arg\b          FLASH_ERASE_CHIP    : Flash All erase.
 * @param[in]   Page_Num : Set Erase size.
 *  @arg\b          if EraseType = FLASH_ERASE_SECTOR   & Page_Num = 0 , erase address range is 0x000000 ~ 0x000FFF.
 *  @arg\b          if EraseType = FLASH_ERASE_BLOCK32K & Page_Num = 0 , erase address range is 0x000000 ~ 0x007FFF.
 *  @arg\b          if EraseType = FLASH_ERASE_BLOCK64K & Page_Num = 0 , erase address range is 0x000000 ~ 0x00FFFF.
 *  @arg\b          if EraseType = FLASH_ERASE_CHIP     , the Page_Num value is don't care. 
 * @return      
 * @note        No
 * @par         Example
 * @code
    API_Flash_Erase (FLASH_ERASE_SECTOR, 1);    // Erase address is 0x1000 ~ 0x1FFF
 * @endcode
 *******************************************************************************
 */
void BSP_Flash_EraseFlash(Flash_ERASE_TypeDef EraseType , uint32_t Page_Num)
{
    ctype AddressIndex;

    Flash0.Status = Flash_Erase;
    
    switch(EraseType)
    {
        case FLASH_ERASE_CHIP:
                                  break;
        case FLASH_ERASE_BLOCK64K:
                                  AddressIndex.W = 0x10000 * Page_Num;
                                  break; 
        
        case FLASH_ERASE_BLOCK32K:
                                  AddressIndex.W = 0x8000  * Page_Num;
                                  break;
        
        case FLASH_ERASE_SECTOR:
                                  AddressIndex.W = 0x1000  * Page_Num;
                                  break;    
    }
    
    if(AddressIndex.W > FLASH_MAXSIZE)
    {
        return;
    }

    BSP_Flash_WriteFlash_Cmd(ENABLE);
    
    
    FLASH_CEN = FLASH_CEN_ACTIVE;
    
    BPS_Flash_InputData(1,EraseType);
    
    if(EraseType!=FLASH_ERASE_CHIP)
    {
        BPS_Flash_InputData(1,AddressIndex.B[2]);
        BPS_Flash_InputData(1,AddressIndex.B[1]);
        BPS_Flash_InputData(1,AddressIndex.B[0]);
    }

    FLASH_CEN = FLASH_CEN_NOACTIVE;
    
}
/**
 *******************************************************************************
 * @brief    Check Flash program or erase whether complete or not.  
 * @details     
 * @return  
 * @exception   No
 * @note
 *******************************************************************************
 */ 
uint8_t BSP_Flash_CheckFlashBusy (void)
{
    uint8_t RDAT;
    
    //============================================
    /* Read status register */
    FLASH_CEN = FLASH_CEN_ACTIVE;
    
    
    BPS_Flash_InputData(1,FLASH_READ_STATUS);

    //===========================================
    /* Check erase or write complete */
    /* Get State */
    RDAT = BSP_Flash_OutputData();
    
    FLASH_CEN = FLASH_CEN_NOACTIVE;
    
    return( (RDAT & 0x01));
    
}
/**
 *******************************************************************************
 * @brief       To read Flash output data (SPI read data) 
 * @details     SPI read 1 byte data
 * @return      SPI get data 
 * @exception   No
 * @note
 *******************************************************************************
 */
static uint8_t BSP_Flash_OutputData(void)
{
    SPI_SetTxData(FLASH_SPI, SPI_1Byte, FLASH_DUMMY_DATA);
    while((SPI0->STA.W & SPI_INT_RX) != SPI_INT_RX);
    return((uint8_t)SPI_GetRxData(FLASH_SPI));
}
/**
 *******************************************************************************
 * @brief       Control Flash WREN(write enable)
 * @details     
 * @param[in]   WREN: Flash write control
 *  @arg\b      ENABLE:  ENABLE Flash write.
 *  @arg\b      DISABLE: DISABLE Flash write.
 * @return
 * @exception   No
 * @note
 *******************************************************************************
 */
static void BSP_Flash_WriteFlash_Cmd (FunctionalState WREN)
{
    uint32_t RDAT;
    
    do
    {
        /* Write enable */
        FLASH_CEN = FLASH_CEN_ACTIVE;
        
        if(WREN==ENABLE)
        {
            BPS_Flash_InputData(1, FLASH_WRITE_ENABLE);
            FLASH_CEN = FLASH_CEN_NOACTIVE;
            
            /* Read state */
            FLASH_CEN = FLASH_CEN_ACTIVE;
            BPS_Flash_InputData(1,FLASH_READ_STATUS);
            
            RDAT = BSP_Flash_OutputData();
            FLASH_CEN = FLASH_CEN_NOACTIVE;
        }
        else
        {
            BPS_Flash_InputData(1,FLASH_WRITE_DISABLE);
            FLASH_CEN = FLASH_CEN_NOACTIVE;
            return;
        }
        
    /* Check WEL == 1 */
    }while((RDAT & 0x02) == 0x00);
}










