
/**
 ******************************************************************************
 *
 * @file        Sample_SPI_Flash.c
 * @brief       Use SPI of MG32 to control MX25R512F standard read / write. 
 *
 * @par         Project
 *              MG32
 * @version     V1.05
 * @date        2022/05/18
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2021 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 "MG32.h"
#include "MG32_DMA_DRV.h"
#include "MG32_SPI_DRV.h"
#include "MG32_GPIO_DRV.h"
#include "Sample_SPI_Flash.h"


/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
FlashCTR_TypeDef Flash0;

static uint8_t Sample_SPI_ProgramFlashBuffer[10] = 
               {0x05, 0x30, 0x06, 0x15, 0x5A, 0xA5, 0x11, 0x20, 0x09 , 0x12};
static uint8_t Sample_SPI_ReadFlashBuffer[10];
static uint8_t Sample_QPI_ReadFlashBuffer[10];
static uint8_t Sample_SPI_ReadFlashBuffer_DMA[10];
static uint8_t Sample_QPI_ReadFlashBuffer_DMA[10];

/* Private function prototypes -----------------------------------------------*/
void Sample_SPI_SetData (uint8_t DataLen , uint32_t FlashData);
uint8_t Sample_SPI_ReadData (void);
void Sample_ReadDate_DMA (FlashCTR_TypeDef* FlashX);
void Sample_WriteData_DMA (FlashCTR_TypeDef* FlashX);
void Sample_SPI_WriteFlash_Cmd (FunctionalState WREN);
void Sample_SPI_CheckFlashBusy (void);
uint32_t Sample_SPI_ReadFlashRDID (void);
uint16_t Sample_SPI_ReadFlashRDCR (void);
DRV_Return Sample_SPI_QuadEnable_Cmd (FunctionalState QE);
void Sample_SPI_EraseFlash (Flash_ERASE_TypeDef EraseType , uint32_t Page_Num);
void Sample_SPI_ReadFlash (FlashCTR_TypeDef* FlashX);
void Sample_SPI_ReadFlash_DMA (FlashCTR_TypeDef* FlashX);
void Sample_QPI_ReadFlash (FlashCTR_TypeDef* FlashX);
#if defined(MG32_2ND) || defined(MG32_3RD) || defined(MG32_4TH)
    void Sample_QPI_ReadFlash_DMA (FlashCTR_TypeDef* FlashX);
#endif
void Sample_SPI_ProgramFlash (FlashCTR_TypeDef *FlashX);
void Sample_SPI_ProgramFlash_DMA (FlashCTR_TypeDef *FlashX);
void Sample_QPI_ProgramFlash (FlashCTR_TypeDef *FlashX);
void Sample_QPI_ProgramFlash_DMA (FlashCTR_TypeDef *FlashX);
void Sample_SPI_SPIMode_Init (void);
void Sample_SPI_MX25R512FFlash (void);

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




/**
 *******************************************************************************
 * @brief       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                        
 *******************************************************************************
 */
void Sample_SPI_SetData (uint8_t DataLen , uint32_t FlashData)
{
    SPI_SetTxData(SPIX, (Byte_Enum) DataLen, FlashData);
    while((SPI_GetAllFlagStatus(SPIX) & SPI_INT_TC) != SPI_INT_TC);
    SPI_ClearFlag(SPIX, (SPI_ALLF));
    SPI_ClearRxData(SPIX);
}


/**
 *******************************************************************************
 * @brief       SPI read data 
 * @details     SPI read 1 byte data
 * @return      SPI get data                  
 *******************************************************************************
 */
uint8_t Sample_SPI_ReadData (void)
{
    SPI_SetTxData(SPIX, SPI_1Byte, Flash_Dummy_Data);
    while((SPI_GetAllFlagStatus(SPIX) & SPI_INT_RX) != SPI_INT_RX);
    return((uint8_t)SPI_GetRxData(SPIX));
}


/**
 *******************************************************************************
 * @brief       Read Date DMA
 * @details     
 * @return      Read Date DMA
 *******************************************************************************
 */
void Sample_ReadDate_DMA (FlashCTR_TypeDef* FlashX)
{
    DMA_BaseInitTypeDef DMATestPattern;
    
    
    
    // Enable DMA
    DMA_Cmd(ENABLE);
    // Enable Channel0
    DMA_Channel_Cmd(DMAChannel0, ENABLE);
    // initial parameter
    DMA_BaseInitStructure_Init(&DMATestPattern);
    // modify parameter
    {   
        // external trigger pin and mode config
        DMATestPattern.ExtTrgPin = DMA_ExtTRG0;
        DMATestPattern.ExtTrgMode = DMA_DisableExtTrg;
        // DMA channel select
        DMATestPattern.DMAChx = DMAChannel0;
        // channel x loop mode config
        DMATestPattern.DMALoopCmd = DISABLE;
        // channel x source/destination auto increase address
        DMATestPattern.SrcSINCSel = DISABLE;        
        DMATestPattern.DestDINCSel = ENABLE;
        // DMA Burst size config
        DMATestPattern.BurstDataSize = DMA_BurstSize_4Byte;
        // DMA transfer data count initial number (? Bytes ???)
        DMATestPattern.DMATransferNUM = FlashX->Total_Length;
        // DMA source peripheral config
        DMATestPattern.SrcSymSel = DMA_SPI0_RX;
        // DMA destination peripheral config
        DMATestPattern.DestSymSel = DMA_MEM_Write;
        // source config
        DMATestPattern.DMADestinationAddr = FlashX->rBuffer;
    }
    // M2P(CH0) simple parameter
    DMA_Base_Init(&DMATestPattern);
    // Enable SPI RX DMA
    SPI_RXDMA_Cmd(SPI0, ENABLE);
    // start request
    DMA_StartRequest(DMAChannel0);
    
    // Wait DMA transfer complete  
    while(DMA_GetSingleFlagStatus(DMA, DMA_FLAG_CH0_TCF)== DRV_UnHappened);
    // Clear SPI TX & RX buffer
    SPIX->CR1.B[0] |= 0x03; 
    // Clear DMA CH0 transfer complete flag
    DMA_ClearFlag(DMA, DMA_FLAG_CH0_TCF);
//    while(SPI_GetSingleFlagStatus(SPIX, SPI_RXF) == DRV_Normal);
    SPI_ClearFlag(SPIX, SPI_ALLF);
}


/**
 *******************************************************************************
 * @brief       Write Date DMA
 * @details     
 * @return      Write Date DMA
 *******************************************************************************
 */
void Sample_WriteData_DMA (FlashCTR_TypeDef* FlashX)
{
    DMA_BaseInitTypeDef DMATestPattern;
    
    
    
    // SPI DMA TX EN 
    SPI_TXDMA_Cmd(SPI0, ENABLE);   
    // Enable DMA
    DMA_Cmd(ENABLE);
    // Enable Channel0
    DMA_Channel_Cmd(DMAChannel0, ENABLE);
    // initial parameter
    DMA_BaseInitStructure_Init(&DMATestPattern);
    // modify parameter
    {   
        // external trigger pin and mode config
        DMATestPattern.ExtTrgPin = DMA_ExtTRG0;
        DMATestPattern.ExtTrgMode = DMA_DisableExtTrg;
        // DMA channel select
        DMATestPattern.DMAChx = DMAChannel0;
        // channel x loop mode config
        DMATestPattern.DMALoopCmd = DISABLE;
        // channel x source/destination auto increase address
        DMATestPattern.SrcSINCSel = ENABLE;        
        DMATestPattern.DestDINCSel = DISABLE;
        // DMA Burst size config
        DMATestPattern.BurstDataSize = DMA_BurstSize_4Byte;
        // DMA transfer data count initial number (? Bytes ???)
        DMATestPattern.DMATransferNUM = FlashX->Total_Length;
        // DMA source peripheral config
        DMATestPattern.SrcSymSel = DMA_MEM_Read;
        // DMA destination peripheral config
        DMATestPattern.DestSymSel = DMA_SPI0_TX;
        // source config               
        DMATestPattern.DMASourceAddr = FlashX->pBuffer;
    }
    // M2P(CH0) simple parameter
    DMA_Base_Init(&DMATestPattern);
    // start request
    DMA_StartRequest(DMAChannel0);
    
    // Wiat DMA transfer complete
    while(DMA_GetSingleFlagStatus(DMA, DMA_FLAG_CH0_TCF)== DRV_UnHappened);
    // Clear DMA CH0 transfer complete flag
    DMA_ClearFlag(DMA, DMA_FLAG_CH0_TCF);
    
    // Wiating transfer data empty
    while(SPIX->STA.MBIT.TX_LVL != 0);
    // Waiting transfer not busy
    while(SPIX->STA.MBIT.BUSYF != 0);
    // Clear SPI all flag
    SPI_ClearFlag(SPIX, SPI_ALLF);
}


/**
 *******************************************************************************
 * @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                       
 *******************************************************************************
 */
void Sample_SPI_WriteFlash_Cmd (FunctionalState WREN)
{
    uint32_t RDAT;
    
    do
    {
        /* Write enable */
        Flash_nCS = FLASH_nCS_ACTIVE;
        
        if(WREN==ENABLE)
        {
            Sample_Flash_SetData(1, FLASH_WRITE_ENABLE);
            Flash_nCS = FLASH_nCS_NoACTIVE;
            
            /* Read status */
            Flash_nCS = FLASH_nCS_ACTIVE;
            Sample_Flash_SetData(1,FLASH_READ_STATUS);
            
            RDAT = Sample_Flash_ReadData();
            Flash_nCS = FLASH_nCS_NoACTIVE;
        }
        else
        {
            Sample_Flash_SetData(1,FLASH_WRITE_DISABLE);
            Flash_nCS = FLASH_nCS_NoACTIVE;
            return;
        }
        
    /* Check WEL == 1 */
    }while((RDAT & 0x02) == 0x00);
}


/**
 *******************************************************************************
 * @brief       Wait program or erase to end. 
 * @details     
 * @return                 
 *******************************************************************************
 */ 
void Sample_SPI_CheckFlashBusy (void)
{
    uint8_t RDAT;
    
    //============================================
    /* Read status register */
    Flash_nCS = FLASH_nCS_ACTIVE;
    
    
    Sample_Flash_SetData(1,FLASH_READ_STATUS);

    //===========================================
    /* Check erase or write complete */
    /* Get State */
    do
    {
        RDAT = Sample_Flash_ReadData();
    }while((RDAT & 0x01)==0x01);
    
    Flash_nCS = FLASH_nCS_NoACTIVE; 
}


/**
 *******************************************************************************
 * @brief       Read the flash manufacturer ID and memory type + memory density.
 * @details     
 * @return      Flash RDID                
 *******************************************************************************
 */ 
uint32_t Sample_SPI_ReadFlashRDID (void)
{
    ctype RDAT;
    
    Flash_nCS = FLASH_nCS_ACTIVE;     
    
    Sample_Flash_SetData(1,FLASH_READ_IDENTIFICATION);
    RDAT.B[0] = Sample_Flash_ReadData();
    RDAT.B[1] = Sample_Flash_ReadData();
    RDAT.B[2] = Sample_Flash_ReadData();
    RDAT.B[3] = 0;
    
    Flash_nCS = FLASH_nCS_NoACTIVE;

    return(RDAT.W);
}


/**
 *******************************************************************************
 * @brief   Read Configuration Register  
 * @details     
 * @return  
 *   @arg\b 1. Byte0 = Configuration register-1
 *   @arg\b 2. Byte1 = Configuration register-2              
 *******************************************************************************
 */ 
uint16_t Sample_SPI_ReadFlashRDCR (void)
{
    ctype RDAT;
    
    Flash_nCS = FLASH_nCS_ACTIVE;
    
    Sample_Flash_SetData(1,FLASH_READ_CONFIGURATION);
    RDAT.B[0] = Sample_Flash_ReadData();
    RDAT.B[1] = Sample_Flash_ReadData();
    
    Flash_nCS = FLASH_nCS_NoACTIVE;
    
    return(RDAT.H[0]);
}


/**
 *******************************************************************************
 * @brief   Read Configuration Register  
 * @details     
 * @return  
 *   @arg\b 1. Byte0 = Configuration register-1
 *   @arg\b 2. Byte1 = Configuration register-2              
 *******************************************************************************
 */
DRV_Return Sample_SPI_QuadEnable_Cmd (FunctionalState QE)
{
    DRV_Return State = DRV_Success;
    uint16_t REG;
    ctype RDAT;
    
    
    
    /* Enabl */
    Sample_SPI_WriteFlash_Cmd(ENABLE);
    
    /* Read status */
    Flash_nCS = FLASH_nCS_ACTIVE;
    Sample_Flash_SetData(1,FLASH_READ_STATUS);
    RDAT.B[0] = Sample_Flash_ReadData();
    Flash_nCS = FLASH_nCS_NoACTIVE;
    
    /* Read Configuration Register */
    REG = Sample_SPI_ReadFlashRDCR();
    RDAT.B[1] = (uint8_t) REG;
    RDAT.B[2] = (uint8_t) (REG >> 8);
    
    /* Setting Status Register QE */
    if(QE == DISABLE)
    {
        RDAT.B[0] &= ~0x40;
    }
    else
    {
        RDAT.B[0] |= 0x40;
    }
    
    /* Write WDSR */
    Flash_nCS = FLASH_nCS_ACTIVE;
    Sample_Flash_SetData(1, FLASH_WRITE_STATUS);
    Sample_Flash_SetData(3, RDAT.W);
    Flash_nCS = FLASH_nCS_NoACTIVE;
    
    /* Wait WIP == 0 */
    do
    {
        Flash_nCS = FLASH_nCS_ACTIVE;
        Sample_Flash_SetData(1,FLASH_READ_STATUS);
        RDAT.B[0] = Sample_Flash_ReadData();
        Flash_nCS = FLASH_nCS_NoACTIVE;
    }while((RDAT.B[0] & 0x01) != 0);
    
    Flash_nCS = FLASH_nCS_ACTIVE;
    Sample_Flash_SetData(1,FLASH_READ_STATUS);
    RDAT.B[0] = Sample_Flash_ReadData();
    Flash_nCS = FLASH_nCS_NoACTIVE;
    
    // When get status fail
    if((((RDAT.B[0] & 0x40) == 0) & (QE == ENABLE)) ||
       (((RDAT.B[0] & 0x40) != 0) & (QE == DISABLE)))
    {
        State = DRV_Failure;
    }
    
    return State;
}


/**
 *******************************************************************************
 * @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        To use the parameter "EraseType", please use the definition in "Flash_ERASE_TypeDef".
 * @par         Example
 * @code
    API_Flash_Erase (FLASH_ERASE_SECTOR, 1);    // Erase address is 0x1000 ~ 0x1FFF
 * @endcode
 *******************************************************************************
 */
void Sample_SPI_EraseFlash (Flash_ERASE_TypeDef EraseType , uint32_t Page_Num)
{
    ctype AddressIndex;

    
    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;    
        
//        default:
//        return;
    }
    
    if(AddressIndex.W > FLASH_MAXSIZE)
    {
        return;
    }

    Sample_SPI_WriteFlash_Cmd(ENABLE);
    
    
    Flash_nCS = FLASH_nCS_ACTIVE;
    
    Sample_Flash_SetData(1,EraseType);
    
    if(EraseType!=FLASH_ERASE_CHIP)
    {
        Sample_Flash_SetData(1,AddressIndex.B[2]);
        Sample_Flash_SetData(1,AddressIndex.B[1]);
        Sample_Flash_SetData(1,AddressIndex.B[0]);
    }

    Flash_nCS = FLASH_nCS_NoACTIVE;
    
    
    Sample_SPI_CheckFlashBusy();
}


/**
 *******************************************************************************
 * @brief       SPI Read flash data
 * @details     
 * @param[in]   FlashX: flash control parameter.
 * @return                      
 *******************************************************************************
 */ 
void Sample_SPI_ReadFlash (FlashCTR_TypeDef* FlashX)
{
    uint32_t  Tmp;
    
    
    Flash_nCS = FLASH_nCS_ACTIVE;
    
    //============================================
    //Read Command
    Sample_Flash_SetData(1, FLASH_FAST_READ);
    //===========================================
    //Read Address
    Sample_Flash_SetData(1, FlashX->Address.B[2]);
    Sample_Flash_SetData(1, FlashX->Address.B[1]);
    Sample_Flash_SetData(1, FlashX->Address.B[0]);
    Sample_Flash_SetData(1, Flash_Dummy_Data);
    
    //===========================================
    //Read Data
    for(Tmp=0;Tmp<FlashX->Total_Length;Tmp++)
    {
        FlashX->rBuffer[Tmp] = Sample_Flash_ReadData();
    }
    
    Flash_nCS = FLASH_nCS_NoACTIVE;
}


/**
 *******************************************************************************
 * @brief       SPI used DMA Read flash data
 * @details     
 * @param[in]   FlashX: flash control parameter.
 * @return                      
 *******************************************************************************
 */ 
void Sample_SPI_ReadFlash_DMA (FlashCTR_TypeDef* FlashX)
{
    Flash_nCS = FLASH_nCS_ACTIVE;
    //============================================
    //Read Command
    Sample_Flash_SetData(1, FLASH_FAST_READ);

    //===========================================
    //Read Address
    Sample_Flash_SetData(1, FlashX->Address.B[2]);
    Sample_Flash_SetData(1, FlashX->Address.B[1]);
    Sample_Flash_SetData(1, FlashX->Address.B[0]);
    Sample_Flash_SetData(1, Flash_Dummy_Data);
    
    //===========================================
    //Read Data
    Sample_ReadDate_DMA( FlashX);

    Flash_nCS = FLASH_nCS_NoACTIVE;
}


/**
 *******************************************************************************
 * @brief       QPI Read flash data
 * @details     
 * @param[in]   FlashX: flash control parameter.
 * @return                      
 *******************************************************************************
 */ 
void Sample_QPI_ReadFlash (FlashCTR_TypeDef* FlashX)
{
    uint32_t  Tmp;



    Flash_nCS = FLASH_nCS_ACTIVE;
    
    //============================================
    //Read Command
    Sample_Flash_SetData(1, FLASH_4IO_READ);
    
    SPI_DataLine_Select(SPIX, SPI_4LinesBidirection);
    SPI_BidirectionalOutput_Cmd(SPIX, ENABLE);
    
    //===========================================
    //Read Address
    Sample_Flash_SetData(1, FlashX->Address.B[2]);
    Sample_Flash_SetData(1, FlashX->Address.B[1]);
    Sample_Flash_SetData(1, FlashX->Address.B[0]);
    Sample_Flash_SetData(3, Flash_Dummy_Data);
    
    SPI_BidirectionalOutput_Cmd(SPIX, DISABLE);
    
    //===========================================
    //Read Data
    for(Tmp=0;Tmp<FlashX->Total_Length;Tmp++)
    {
        FlashX->rBuffer[Tmp] = Sample_Flash_ReadData();
    }
    
    Flash_nCS = FLASH_nCS_NoACTIVE;
    
    SPI_DataLine_Select(SPIX, SPI_Standard);
}


#if defined(MG32_2ND) || defined(MG32_3RD) || defined(MG32_4TH)
/**
 *******************************************************************************
 * @brief       QPI used DMA Read flash data
 * @details     
 * @param[in]   FlashX: flash control parameter.
 * @return                      
 *******************************************************************************
 */ 
void Sample_QPI_ReadFlash_DMA (FlashCTR_TypeDef* FlashX)
{
    Flash_nCS = FLASH_nCS_ACTIVE;
    //============================================
    //Read Command
    Sample_Flash_SetData(1, FLASH_4IO_READ);
    
    SPI_DataLine_Select(SPIX, SPI_4LinesBidirection);
    SPI_BidirectionalOutput_Cmd(SPIX, ENABLE);

    //===========================================
    //Read Address
    Sample_Flash_SetData(1, FlashX->Address.B[2]);
    Sample_Flash_SetData(1, FlashX->Address.B[1]);
    Sample_Flash_SetData(1, FlashX->Address.B[0]);
    Sample_Flash_SetData(3, Flash_Dummy_Data);
    
    SPI_BidirectionalOutput_Cmd(SPIX, DISABLE);
    
    //===========================================
    //Read Data
    Sample_ReadDate_DMA( FlashX);
    
    SPI_DataLine_Select(SPIX, SPI_Standard);

    Flash_nCS = FLASH_nCS_NoACTIVE;
}
#endif


/**
 *******************************************************************************
 * @brief       Program flash 
 * @details     
 * @param[in]   FlashX: flash control parameter.
 * @return                         
 *******************************************************************************
 */
void Sample_SPI_ProgramFlash (FlashCTR_TypeDef *FlashX)
{
    uint16_t DataCnt;
    ctype    AddressIndex;


    
    AddressIndex.W = FlashX->Address.W;
    FlashX->DataCnt = 0;
    
    do
    {
        if(FlashX->Total_Length > FLASH_PROGRAM_MAX)
        {
            FlashX->BLen = FLASH_PROGRAM_MAX;
        }
        else
        {
            FlashX->BLen = FlashX->Total_Length;
        }

        Sample_SPI_WriteFlash_Cmd(ENABLE);
        
        Flash_nCS = FLASH_nCS_ACTIVE;
        
        //===============================================
        //Program command
        Sample_Flash_SetData(1, FLASH_PAGE_PROGRAM);
        
        //==============================================
        //Program Addresss
        Sample_Flash_SetData(1,AddressIndex.B[2]);
        Sample_Flash_SetData(1,AddressIndex.B[1]);
        Sample_Flash_SetData(1,AddressIndex.B[0]);
        
        //===============================================
        //Data0 ~ DataN
        for(DataCnt = 0; DataCnt < FlashX->BLen; DataCnt++)
        {
            Sample_Flash_SetData(1,FlashX->pBuffer[FlashX->DataCnt]);
            FlashX->DataCnt = FlashX->DataCnt + 1;
        }
      
        
        Flash_nCS = FLASH_nCS_NoACTIVE;
        
        AddressIndex.W = AddressIndex.W + FlashX->BLen;
        FlashX->Total_Length = FlashX->Total_Length - FlashX->BLen;
        
        Sample_SPI_CheckFlashBusy(); 
    }while(FlashX->Total_Length!=0);
}


/**
 *******************************************************************************
 * @brief       SPI flash data
 * @details     
 * @param[in]   FlashX: flash control parameter.
 * @return                      
 *******************************************************************************
 */ 
void Sample_SPI_ProgramFlash_DMA (FlashCTR_TypeDef *FlashX)
{
    ctype    AddressIndex;



    AddressIndex.W = FlashX->Address.W;
    FlashX->DataCnt = 0;
    
    do
    {
        if(FlashX->Total_Length > FLASH_PROGRAM_MAX)
        {
            FlashX->BLen = FLASH_PROGRAM_MAX;
        }
        else
        {
            FlashX->BLen = FlashX->Total_Length;
        }

        Sample_SPI_WriteFlash_Cmd(ENABLE);
        
        Flash_nCS = FLASH_nCS_ACTIVE;
        
        //===============================================
        //Program command
        Sample_Flash_SetData(1, FLASH_PAGE_PROGRAM);
        
        //==============================================
        //Program Addresss
        Sample_Flash_SetData(1,AddressIndex.B[2]);
        Sample_Flash_SetData(1,AddressIndex.B[1]);
        Sample_Flash_SetData(1,AddressIndex.B[0]);
        
        //===============================================
        //Data0 ~ DataN
        Sample_WriteData_DMA(FlashX);
      
        Flash_nCS = FLASH_nCS_NoACTIVE;
        
        AddressIndex.W = AddressIndex.W + FlashX->BLen;
        FlashX->Total_Length = FlashX->Total_Length - FlashX->BLen;
        
        Sample_SPI_CheckFlashBusy(); 
    }while(FlashX->Total_Length!=0);
}


/**
 *******************************************************************************
 * @brief       Program flash 
 * @details     
 * @param[in]   FlashX: flash control parameter.
 * @return                         
 *******************************************************************************
 */
void Sample_QPI_ProgramFlash (FlashCTR_TypeDef *FlashX)
{
    uint16_t DataCnt;
    ctype    AddressIndex;


    
    AddressIndex.W = FlashX->Address.W;
    FlashX->DataCnt = 0;
    
    do
    {
        if(FlashX->Total_Length > FLASH_PROGRAM_MAX)
        {
            FlashX->BLen = FLASH_PROGRAM_MAX;
        }
        else
        {
            FlashX->BLen = FlashX->Total_Length;
        }

        // Write Enable
        Sample_SPI_WriteFlash_Cmd(ENABLE);
        
        Flash_nCS = FLASH_nCS_ACTIVE;
        //===============================================
        //Program command
        Sample_Flash_SetData(1, FLASH_QUADPAGE_PROGRAM);
        
        SPI_DataLine_Select(SPIX, SPI_4LinesBidirection);
        SPI_BidirectionalOutput_Cmd(SPIX, ENABLE);
        
        //==============================================
        //Program Addresss
        Sample_Flash_SetData(1,AddressIndex.B[2]);
        Sample_Flash_SetData(1,AddressIndex.B[1]);
        Sample_Flash_SetData(1,AddressIndex.B[0]);
        
        //===============================================
        //Data0 ~ DataN
        for(DataCnt = 0; DataCnt < FlashX->BLen; DataCnt++)
        {
            Sample_Flash_SetData(1,FlashX->pBuffer[FlashX->DataCnt]);
            FlashX->DataCnt = FlashX->DataCnt + 1;
        }

        Flash_nCS = FLASH_nCS_NoACTIVE;
        
        SPI_DataLine_Select(SPIX, SPI_Standard);
        SPI_BidirectionalOutput_Cmd(SPIX, DISABLE);

        AddressIndex.W = AddressIndex.W + FlashX->BLen;
        FlashX->Total_Length = FlashX->Total_Length - FlashX->BLen;
        
        Sample_SPI_CheckFlashBusy(); 
    }while(FlashX->Total_Length!=0);
}


/**
 *******************************************************************************
 * @brief       SPI flash data
 * @details     
 * @param[in]   FlashX: flash control parameter.
 * @return                      
 *******************************************************************************
 */ 
void Sample_QPI_ProgramFlash_DMA (FlashCTR_TypeDef *FlashX)
{
    ctype    AddressIndex;



    AddressIndex.W = FlashX->Address.W;
    FlashX->DataCnt = 0;
    
    do
    {
        if(FlashX->Total_Length > FLASH_PROGRAM_MAX)
        {
            FlashX->BLen = FLASH_PROGRAM_MAX;
        }
        else
        {
            FlashX->BLen = FlashX->Total_Length;
        }

        Sample_SPI_WriteFlash_Cmd(ENABLE);
        
        Flash_nCS = FLASH_nCS_ACTIVE;
        
        //===============================================
        //Program command
        Sample_Flash_SetData(1, FLASH_QUADPAGE_PROGRAM);
        
        SPI_DataLine_Select(SPIX, SPI_4LinesBidirection);
        SPI_BidirectionalOutput_Cmd(SPIX, ENABLE);
        
        //==============================================
        //Program Addresss
        Sample_Flash_SetData(1,AddressIndex.B[2]);
        Sample_Flash_SetData(1,AddressIndex.B[1]);
        Sample_Flash_SetData(1,AddressIndex.B[0]);
        
        //===============================================
        //Data0 ~ DataN
        Sample_WriteData_DMA(FlashX);
      
        Flash_nCS = FLASH_nCS_NoACTIVE;
        
        SPI_DataLine_Select(SPIX, SPI_Standard);
        SPI_BidirectionalOutput_Cmd(SPIX, DISABLE);
        
        AddressIndex.W = AddressIndex.W + FlashX->BLen;
        FlashX->Total_Length = FlashX->Total_Length - FlashX->BLen;
        
        Sample_SPI_CheckFlashBusy(); 
    }while(FlashX->Total_Length!=0);
}


/**
 *******************************************************************************
 * @brief       Set URT mode to SPI mode0
 * @details     
 * @return                      
 *******************************************************************************
 */ 
void Sample_SPI_SPIMode_Init (void)
{
    //===Set CSC init====
    //MG32_CSC_Init.h(Configuration Wizard)
    //Select CK_HS source = CK_IHRCO
    //Select IHRCO = 12Mz
    //Select CK_MAIN Source = CK_HS
    //Configure PLL->Select APB Prescaler = CK_MAIN/1
    
    /*=== 1. Enable CSC to SPI clock ===*/
    //[A] When Use Wizard
    //Configure Peripheral On Mode Clock->SPI0 = Enable and Select SPI0_PR Source = CK_APB
    //Configure Peripheral On Mode Clock->Port B = Enable
    //[B] When Use Driver
//    UnProtectModuleReg(CSCprotect);                             // Unprotect CSC module
//    CSC_PeriphOnModeClock_Config(CSC_ON_SPI0, ENABLE);          // Enable SPI0 module clock
//    CSC_PeriphOnModeClock_Config(CSC_ON_PortB, ENABLE);         // Enable PortB clock
//    CSC_PeriphProcessClockSource_Config(CSC_SPI0_CKS, CK_APB);  // CK_SPIx_PR = CK_APB = 12MHz
//    ProtectModuleReg(CSCprotect);                               // protect CSC module



    //==Set GPIO init
    //1. MOSI Pin
    //    (1).MG32_GPIO_Init.h(Configuration Wizard)->Use GPIOB->Pin3
    //    (2).GPIO port initial is 0xFFFF
    //    (3).Pin8 mode is PPO (Push pull output)
    //    (4).Pin8 pull-up resister Enable
    //    (5).Pin8 function SPI0_TX
    //2. MISO Pin
    //    (1).MG32_GPIO_Init.h(Configuration Wizard)->Use GPIOB->Pin1
    //    (2).GPIO port initial is 0xFFFF
    //    (3).Pin8 mode is PPO (Push pull output)
    //    (4).Pin8 pull-up resister Enable
    //    (5).Pin9 function SPI0_RX
    //3. SPICLK Pin
    //    (1).MG32_GPIO_Init.h(Configuration Wizard)->Use GPIOB->Pin2
    //    (2).GPIO port initial is 0xFFFF
    //    (3).Pin8 mode is PPO (Push pull output)
    //    (4).Pin8 pull-up resister Enable
    //    (5).Pin3 function SPI0_CLK
    //4. NSS Pin
    //    (1).MG32_GPIO_Init.h(Configuration Wizard)->Use GPIOB->Pin0
    //    (2).GPIO port initial is 0xFFFF
    //    (3).Pin8 mode is PPO (Push pull output)
    //    (4).Pin8 pull-up resister Enable
    //    (5).Pin3 function GPIO (the NSS is software control)
    //5. D2 Pin
    //    (1).MG32_GPIO_Init.h(Configuration Wizard)->Use GPIOB->Pin5
    //    (2).GPIO port initial is 0xFFFF
    //    (3).Pin8 mode is PPO (Push pull output)
    //    (4).Pin8 pull-up resister Enable
    //    (5).Pin8 function SPI0_D2
    //6. D3 Pin
    //    (1).MG32_GPIO_Init.h(Configuration Wizard)->Use GPIOB->Pin4
    //    (2).GPIO port initial is 0xFFFF
    //    (3).Pin8 mode is PPO (Push pull output)
    //    (4).Pin8 pull-up resister Enable
    //    (5).Pin8 function SPI0_D3
    
    
    
    //=====Set Clock=====//
    SPI_DeInit(SPIX);
    
    //---Set BaudRate---//
    SPI_Clock_Select(SPIX, SPI_CK_SPIx_PR);                 // SPI clock source 
    SPI_PreDivider_Select(SPIX, SPI_PDIV_1);                // SPI PDIV /1
    SPI_Prescaler_Select(SPI0, SPI_PSC_1);                  // SPI PSC /1
    SPI_Divider_Select(SPI0, SPI_DIV_2);                   // SPI DIV /8

    //=====Set Mode=====//
    //---Set Mode Select---//
    SPI_ModeAndNss_Select(SPI0, SPI_Master);                // SPI master mode without NSS

    //---Set DataLine Select---//
    SPI_DataLine_Select(SPI0, SPI_Standard);                // Srandard SPI
    
    //==Set SPI Mode = (CPHA = 0 , CPOL = 0)====//
    SPI_ClockPhase_Select(SPI0, SPI_LeadingEdge);           // Leading edge
    SPI_ClockPolarity_Select(SPI0, SPI_Low);                // Clock idle low

    Flash_nCS = FLASH_nCS_NoACTIVE;                         // nCS no active
    
    //=====Set Data Control=====//
    SPI_FirstBit_Select(SPI0, SPI_MSB);                     // First bit MSB
    SPI_DataSize_Select(SPI0, SPI_8bits);                   // Data size 8bit

    //=====Enable URT=====//
    SPI_Cmd(SPIX, ENABLE);
}


/**
 *******************************************************************************
 * @brief       Simple flash sample code. 
 * @details     
 * 	@arg\b     1. Check Flash ID
 *  @arg\b     2. Erase Flash (sector erase)
 *  @arg\b     3. Program Flash.
 *  @arg\b     4. Read Flash.
 * @return                     
 *******************************************************************************
 */ 
void Sample_SPI_MX25R512FFlash (void)
{
    uint8_t Tmp;



    //==================================
    //Inital URT mode = SPI mode.
    Sample_SPI_SPIMode_Init();
    
    //==================================
    //Check Flash ID
    if(Sample_SPI_ReadFlashRDID()!= FLASH_RDID_CMP)
    {
        //RDID fail to do......
    }
    else
    {
        //============================
        /* Erase flash */
        //Flash sector erase 
        Sample_SPI_EraseFlash(FLASH_ERASE_SECTOR,1);            // Erase sector 1 ( Address = 0x1000 ~ 0x1FFF)

        //===========================
        /* Program flash */// 
        // SPI program flash
        Flash0.Address.W = 0x1040;                              // Define address of flash program. 
        Flash0.pBuffer = &Sample_SPI_ProgramFlashBuffer[0];     // Define datas of flash program.
        Flash0.Total_Length = 10;                               // Define size of flash program.
        Sample_SPI_ProgramFlash(&Flash0);                       // SPI program

        // SPI use DMA program flash
        Flash0.Address.W = 0x1050;                              // Define address of flash program.
        Flash0.pBuffer = &Sample_SPI_ProgramFlashBuffer[0];     // Define datas of flash program.
        Flash0.Total_Length = 10;                               // Define size of flash program.
        Sample_SPI_ProgramFlash_DMA(&Flash0);                   // SPI DMA program

#if defined(MG32_2ND) || defined(MG32_3RD) || defined(MG32_4TH)
        // QPI program flash
        Sample_SPI_QuadEnable_Cmd(ENABLE);
        Flash0.Address.W = 0x1060;                              // Define address of flash program. 
        Flash0.pBuffer = &Sample_SPI_ProgramFlashBuffer[0];     // Define datas of flash program.
        Flash0.Total_Length = 10;                               // Define size of flash program.
        Sample_QPI_ProgramFlash(&Flash0);                       // QPI program

        // QPI use DMA program flash
        Sample_SPI_QuadEnable_Cmd(ENABLE);
        Flash0.Address.W = 0x1070;                              // Define address of flash program. 
        Flash0.pBuffer = &Sample_SPI_ProgramFlashBuffer[0];     // Define datas of flash program.
        Flash0.Total_Length = 10;                               // Define size of flash program.
        Sample_QPI_ProgramFlash_DMA(&Flash0);                   // QPI DMA program
#endif

        //===========================
        /* Read flash */
        // SPI read flash 
        Flash0.Address.W = 0x1040;                              // Define address of flash program. 
        Flash0.rBuffer = &Sample_SPI_ReadFlashBuffer[0];        // Define storage address of receive data from flash.
        Flash0.Total_Length = 10;                               // Define size of read data from flash.
        Sample_SPI_ReadFlash(&Flash0);                          // SPI read flash  

        // SPI use DMA read flash
        Flash0.Address.W = 0x1050;                              // Define address of flash program.
        Flash0.rBuffer = &Sample_SPI_ReadFlashBuffer_DMA[0];    // Define storage address of receive data from flash.
        Flash0.Total_Length = 10;                               // Define size of read data from flash.
        Sample_SPI_ReadFlash_DMA(&Flash0);                      // SPI use DMA read flash 

#if defined(MG32_2ND) || defined(MG32_3RD) || defined(MG32_4TH)
        // QPI read flash 
        Sample_SPI_QuadEnable_Cmd(ENABLE);
        Flash0.Address.W = 0x1060;                              // Define address of flash program.
        Flash0.rBuffer = &Sample_QPI_ReadFlashBuffer[0];        // Define storage address of receive data from flash.
        Flash0.Total_Length = 10;                               // Define size of read data from flash.
        Sample_QPI_ReadFlash(&Flash0);                          // QPI read flash 

        // QPI use DMA read flash
        Sample_SPI_QuadEnable_Cmd(ENABLE);
        Flash0.Address.W = 0x1070;                              // Define address of flash program.
        Flash0.rBuffer = &Sample_QPI_ReadFlashBuffer_DMA[0];    // Define storage address of receive data from flash.
        Flash0.Total_Length = 10;                               // Define size of read data from flash.
        Sample_QPI_ReadFlash_DMA(&Flash0);                      // QPI use DMA read flash
#endif

        //==========================
        //Compare data
        for(Tmp=0;Tmp<Flash0.Total_Length;Tmp++)
        {
            //----------------------------------------
            //Read data and write data is no same.
            if(Sample_SPI_ReadFlashBuffer[Tmp] != Sample_SPI_ProgramFlashBuffer[Tmp])
            {          
                //to do...... 
            }
            
            if(Sample_SPI_ReadFlashBuffer_DMA[Tmp] != Sample_SPI_ProgramFlashBuffer[Tmp])
            {          
                //to do...... 
            }
            
            if(Sample_QPI_ReadFlashBuffer[Tmp] != Sample_SPI_ProgramFlashBuffer[Tmp])
            {      
                //to do...... 
            }
            
            if(Sample_QPI_ReadFlashBuffer_DMA[Tmp] != Sample_SPI_ProgramFlashBuffer[Tmp])
            {
                //to do...... 
            }
        }
    }
}

