
/******************************************************************************
*@file  : app.c
*@brief : application
*@ver   : 1.0.0
*@date  : 2022.2.8
******************************************************************************/

#include "app.h"   



/******************************************************************************
* @brief : EXMC Norflash GPIO initialization function.
* @param : None
* @return: None
******************************************************************************/
void Norflash_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_Init_Norflash;
    
    /* Enable GPIOs clock */
    __RCC_GPIOA_CLK_ENABLE();
    __RCC_GPIOB_CLK_ENABLE();
    __RCC_GPIOC_CLK_ENABLE();
    __RCC_GPIOD_CLK_ENABLE();
    __RCC_GPIOE_CLK_ENABLE();
    __RCC_GPIOF_CLK_ENABLE();

    /*-- GPIO 配置 -----------------------------------------------------*/

    /* 通用 GPIO 配置 */
    GPIO_Init_Norflash.Mode  = GPIO_MODE_AF_PP;       //配置为复用功能
    GPIO_Init_Norflash.Alternate = GPIO_FUNCTION_10;  
    GPIO_Init_Norflash.Drive = GPIO_DRIVE_LEVEL3;
    GPIO_Init_Norflash.Pull = GPIO_PULLUP;   

    /*A地址信号线 针对引脚配置*/
    GPIO_Init_Norflash.Pin = EXMC_A0_GPIO_PIN; 
    GPIO_Init(EXMC_A0_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A1_GPIO_PIN; 
    GPIO_Init(EXMC_A1_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A2_GPIO_PIN; 
    GPIO_Init(EXMC_A2_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A3_GPIO_PIN; 
    GPIO_Init(EXMC_A3_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A4_GPIO_PIN; 
    GPIO_Init(EXMC_A4_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A5_GPIO_PIN; 
    GPIO_Init(EXMC_A5_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A6_GPIO_PIN; 
    GPIO_Init(EXMC_A6_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A7_GPIO_PIN; 
    GPIO_Init(EXMC_A7_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A8_GPIO_PIN; 
    GPIO_Init(EXMC_A8_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A9_GPIO_PIN; 
    GPIO_Init(EXMC_A9_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A10_GPIO_PIN; 
    GPIO_Init(EXMC_A10_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A11_GPIO_PIN; 
    GPIO_Init(EXMC_A11_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A12_GPIO_PIN; 
    GPIO_Init(EXMC_A12_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A13_GPIO_PIN; 
    GPIO_Init(EXMC_A13_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A14_GPIO_PIN; 
    GPIO_Init(EXMC_A14_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A15_GPIO_PIN; 
    GPIO_Init(EXMC_A15_GPIO_PORT, &GPIO_Init_Norflash);	

    GPIO_Init_Norflash.Pin = EXMC_A16_GPIO_PIN; 
    GPIO_Init(EXMC_A16_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_A17_GPIO_PIN; 
    GPIO_Init(EXMC_A17_GPIO_PORT, &GPIO_Init_Norflash);


    /*DQ数据信号线 针对引脚配置*/
    GPIO_Init_Norflash.Pin = EXMC_D0_GPIO_PIN; 
    GPIO_Init(EXMC_D0_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D1_GPIO_PIN; 
    GPIO_Init(EXMC_D1_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D2_GPIO_PIN; 
    GPIO_Init(EXMC_D2_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D3_GPIO_PIN; 
    GPIO_Init(EXMC_D3_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D4_GPIO_PIN; 
    GPIO_Init(EXMC_D4_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D5_GPIO_PIN; 
    GPIO_Init(EXMC_D5_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D6_GPIO_PIN; 
    GPIO_Init(EXMC_D6_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D7_GPIO_PIN; 
    GPIO_Init(EXMC_D7_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D8_GPIO_PIN; 
    GPIO_Init(EXMC_D8_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D9_GPIO_PIN; 
    GPIO_Init(EXMC_D9_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D10_GPIO_PIN; 
    GPIO_Init(EXMC_D10_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D11_GPIO_PIN; 
    GPIO_Init(EXMC_D11_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D12_GPIO_PIN; 
    GPIO_Init(EXMC_D12_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D13_GPIO_PIN; 
    GPIO_Init(EXMC_D13_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D14_GPIO_PIN; 
    GPIO_Init(EXMC_D14_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_D15_GPIO_PIN; 
    GPIO_Init(EXMC_D15_GPIO_PORT, &GPIO_Init_Norflash);

    /*控制信号线*/
    GPIO_Init_Norflash.Pin = EXMC_NORFLASH_CS_GPIO_PIN; 
    GPIO_Init(EXMC_NORFLASH_CS_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_WE_GPIO_PIN; 
    GPIO_Init(EXMC_WE_GPIO_PORT, &GPIO_Init_Norflash);

    GPIO_Init_Norflash.Pin = EXMC_OE_GPIO_PIN; 
    GPIO_Init(EXMC_OE_GPIO_PORT, &GPIO_Init_Norflash);  

    GPIO_Init_Norflash.Pin = EXMC_PSRAM_CS_GPIO_PIN; 
    GPIO_Init_Norflash.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init_Norflash.Drive = GPIO_DRIVE_LEVEL3;
    GPIO_Init(EXMC_NORFLASH_CS_GPIO_PORT, &GPIO_Init_Norflash); 
    GPIO_WriteBit(EXMC_PSRAM_CS_GPIO_PORT, EXMC_PSRAM_CS_GPIO_PIN, GPIO_PIN_SET);    

}

/******************************************************************************
* @brief : EXMC Norflash initialization.
* @param : None
* @return: None
******************************************************************************/
void EXMC_Norflash_Init(void)
{
    EXMC_NORSRAMInitTypeDef hnorflash;
    EXMC_NORSRAMTimingInitTypeDef  readWriteTiming;
    
    EXMC_NORSRAMStructInit(&hnorflash);
    
    /* NOR device configuration */ 
    //HCLK = 120MHZ, 1/120M = 8.3ns        
    readWriteTiming.EXMC_AddressSetupTime       = 0;
    readWriteTiming.EXMC_AddressHoldTime        = 4;
    readWriteTiming.EXMC_DataSetupTime          = 4;
    readWriteTiming.EXMC_BusTurnAroundDuration  = 0;
    readWriteTiming.EXMC_CLKDivision            = 0;
    readWriteTiming.EXMC_DataLatency            = 0;
    readWriteTiming.EXMC_AccessMode             = EXMC_ACCESS_MODE_B;//norflash
    
    hnorflash.EXMC_Bank                         = EXMC_NORSRAM_BANK4;     //use CS4 control，Addr=0x6C000000
    hnorflash.EXMC_DataAddressMux               = EXMC_DATA_ADDRESS_MUX_DISABLE;
    hnorflash.EXMC_MemoryType                   = EXMC_MEMORY_TYPE_NOR;
    hnorflash.EXMC_MemoryDataWidth              = EXMC_NORSRAM_MEM_BUS_WIDTH_16;
    hnorflash.EXMC_BurstAccessMode              = EXMC_BURST_ACCESS_MODE_DISABLE;
    hnorflash.EXMC_WaitSignalPolarity           = EXMC_WAIT_SIGNAL_POLARITY_LOW;
    hnorflash.EXMC_WrapMode                     = EXMC_WRAP_MODE_DISABLE;
    hnorflash.EXMC_WaitSignalActive             = EXMC_WAITSIGNALACTIVE_BEFOREWAITSTATE;
    hnorflash.EXMC_WriteOperation               = EXMC_WRITEOPERATION_ENABLE;
    hnorflash.EXMC_WaitSignal                   = EXMC_WAIT_SIGNAL_DISABLE;
    hnorflash.EXMC_ExtendedMode                 = EXMC_EXTENDED_MODE_DISABLE;
    hnorflash.EXMC_AsynchronousWait             = EXMC_ASYNCHRONOUS_WAIT_DISABLE;
    hnorflash.EXMC_CRAMPageSize                 = EXMC_CRAMPAGE_SIZE_AUTO;  
    hnorflash.EXMC_WriteBurst                   = EXMC_WRITE_BURST_DISABLE;
    hnorflash.EXMC_ReadWriteTimingStruct        = &readWriteTiming;
    hnorflash.EXMC_WriteTimingStruct            = &readWriteTiming;    
    
    EXMC_NORSRAMCmd(hnorflash.EXMC_Bank, DISABLE);

    EXMC_NORSRAMInit(&hnorflash);
    
    EXMC_NORSRAMCmd(hnorflash.EXMC_Bank, ENABLE);
}



/******************************************************************************
* @brief : Reads NOR memory's Manufacturer and Device Code.
* @param : NOR_ID: pointer to a NOR_IDTypeDef structure which will hold
*                  the Manufacturer and Device Code.
* @return: None
******************************************************************************/
void EXMC_NOR_ReadID(NOR_IDTypeDef* NOR_ID)
{
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AAA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x0090);

    NOR_ID->Manufacturer_Code = *(vu16 *) ADDR_SHIFT(0x0000);
    NOR_ID->Device_Code1 = *(vu16 *) ADDR_SHIFT(0x0001);
    NOR_ID->Device_Code2 = *(vu16 *) ADDR_SHIFT(0x000E);
    NOR_ID->Device_Code3 = *(vu16 *) ADDR_SHIFT(0x000F);
}


/******************************************************************************
* @brief : Returns the NOR operation status.
* @param : NOR_ID: Timeout: NOR progamming Timeout.
* @return: NOR_StatusTypeDef:The returned value can be: NOR_SUCCESS, NOR_ERROR 
*                           or NOR_TIMEOUT
******************************************************************************/
NOR_StatusTypeDef EXMC_NOR_GetStatus(uint32_t Timeout)
{ 
    uint32_t index=0;
    uint16_t val1 = 0x00, val2 = 0x00;
    NOR_StatusTypeDef status = NOR_ONGOING; 
    uint32_t timeout = Timeout;
    /* Poll on NOR memory Ready/Busy signal ------------------------------------*/
    /* Get the NOR memory operation status -------------------------------------*/
    while((Timeout != 0x00) && (status != NOR_SUCCESS))
    {
        Timeout--;
        /* Read DQ6 and DQ5 */
        val1 = *(volatile uint16_t *)(EXMC_BANK_NORFLASH);
        val2 = *(volatile uint16_t *)(EXMC_BANK_NORFLASH);
        /* If DQ6 did not toggle between the two reads then return NOR_Success */
        if((val1 & NOR_MASK_STATUS_DQ6) == (val2 & NOR_MASK_STATUS_DQ6)) 
        {
            return NOR_SUCCESS;
        }
        val1 = *(vu16 *)(EXMC_BANK_NORFLASH);
        val2 = *(vu16 *)(EXMC_BANK_NORFLASH);

        if((val1 & NOR_MASK_STATUS_DQ6) == (val2 & NOR_MASK_STATUS_DQ6)) 
        {
            return NOR_SUCCESS;
        }
    }
    if(Timeout == 0x00)
    {
        status = NOR_TIMEOUT;
        printfS("Timeout\r\n");
    }

    /* Return the operation status */
    return (status);
}

/******************************************************************************
* @brief : Erases the specified Nor memory block.
* @param : BlockAddr: address of the block to erase.
* @return: NOR_StatusTypeDef:The returned value can be: NOR_SUCCESS, NOR_ERROR 
*                           or NOR_TIMEOUT
******************************************************************************/
NOR_StatusTypeDef EXMC_NOR_EraseBlock(uint32_t BlockAddr)
{
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AAA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x0080);
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AAA), 0x0055);
    NOR_WRITE((EXMC_BANK_NORFLASH + BlockAddr), 0x50);

    return (EXMC_NOR_GetStatus(BLOCKERASETIMEOUT));
}

/******************************************************************************
* @brief : Erases the entire chip.
* @param : None.
* @return: NOR_StatusTypeDef:The returned value can be: NOR_SUCCESS, NOR_ERROR 
*                           or NOR_TIMEOUT
******************************************************************************/
NOR_StatusTypeDef EXMC_NOR_EraseChip(void)
{
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AAA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x0080);
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AAA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x0010);

    return (EXMC_NOR_GetStatus(CHIPERASETIMEOUT));
}

/******************************************************************************
* @brief : Writes a half-word to the NOR memory.
* @param : WriteAddr : NOR memory internal address to write to.
* @param : Data : Data to write.
* @return: NOR_StatusTypeDef:The returned value can be: NOR_SUCCESS, NOR_ERROR 
*                           or NOR_TIMEOUT
******************************************************************************/
NOR_StatusTypeDef EXMC_NOR_WriteHalfWord(uint32_t WriteAddr, uint16_t Data)
{
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AAA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00A0);
    NOR_WRITE((EXMC_BANK_NORFLASH + WriteAddr), Data);

    return (EXMC_NOR_GetStatus(PROGRAMTIMEOUT));
}

/******************************************************************************
* @brief : Writes a Byte to the NOR memory.
* @param : WriteAddr : NOR memory internal address to write to.
* @param : Data : Data to write.
* @return: NOR_StatusTypeDef:The returned value can be: NOR_SUCCESS, NOR_ERROR 
*                           or NOR_TIMEOUT
******************************************************************************/
NOR_StatusTypeDef EXMC_NOR_WriteByte(uint32_t WriteAddr, uint8_t Data)
{
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AAA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00A0);
    NOR_WRITE((EXMC_BANK_NORFLASH + WriteAddr), Data);

    return (EXMC_NOR_GetStatus(PROGRAMTIMEOUT));
}

/******************************************************************************
* @brief : Writes a half-word buffer to the EXMC NOR memory. 
* @param : pBuffer : pointer to buffer. 
* @param : WriteAddr : NOR memory internal address from which the data will be written.
* @param : NumHalfwordToWrite : number of Half words to write.
* @return: NOR_StatusTypeDef:The returned value can be: NOR_SUCCESS, NOR_ERROR 
*                           or NOR_TIMEOUT
******************************************************************************/
NOR_StatusTypeDef EXMC_NOR_WriteBuffer(uint16_t* pBuffer, uint32_t WriteAddr, uint32_t NumHalfwordToWrite)
{
    NOR_StatusTypeDef status = NOR_ONGOING;

    do
    {
        /* Transfer data to the memory */
        status = EXMC_NOR_WriteHalfWord(WriteAddr, *pBuffer++);
        WriteAddr = WriteAddr + 2;
        NumHalfwordToWrite--;
    }
    while((status == NOR_SUCCESS) && (NumHalfwordToWrite != 0));

    return (status); 
}

/******************************************************************************
* @brief : Writes a half-word buffer to the EXMC NOR memory. This function 
*          must be used only with S29GL128P NOR memory.
* @param : pBuffer : pointer to buffer. 
* @param : WriteAddr : NOR memory internal address from which the data will be written.
* @param : NumHalfwordToWrite: number of Half words to write.
*          The maximum allowed value is 32 Half words (64 bytes).
* @return: NOR_StatusTypeDef:The returned value can be: NOR_SUCCESS, NOR_ERROR 
*                           or NOR_TIMEOUT
******************************************************************************/
NOR_StatusTypeDef EXMC_NOR_ProgramBuffer(uint16_t* pBuffer, uint32_t WriteAddr, uint32_t NumHalfwordToWrite)
{       
    uint32_t lastloadedaddress = 0x00;
    uint32_t currentaddress = 0x00;
    uint32_t endaddress = 0x00;

    /* Initialize variables */
    currentaddress = WriteAddr;
    endaddress = WriteAddr + NumHalfwordToWrite - 1;
    lastloadedaddress = WriteAddr;

    /* Issue unlock command sequence */
    NOR_WRITE(ADDR_SHIFT(0x005555), 0x00AA);

    NOR_WRITE(ADDR_SHIFT(0x02AAA), 0x0055); 

    /* Write Write Buffer Load Command */
    NOR_WRITE(ADDR_SHIFT(WriteAddr), 0x0025);
    NOR_WRITE(ADDR_SHIFT(WriteAddr), (NumHalfwordToWrite - 1));

    /* Load Data into NOR Buffer */
    while(currentaddress <= endaddress)
    {
        /* Store last loaded address & data value (for polling) */
        lastloadedaddress = currentaddress;

        NOR_WRITE(ADDR_SHIFT(currentaddress), *pBuffer++);
        currentaddress += 1; 
    }

    NOR_WRITE(ADDR_SHIFT(lastloadedaddress), 0x29);

    return(EXMC_NOR_GetStatus(PROGRAMTIMEOUT));
}

/******************************************************************************
* @brief : Reads a half-word from the NOR memory. 
* @param : ReadAddr : NOR memory internal address to read from.
* @return: Half-word read from the NOR memory.
******************************************************************************/
uint16_t EXMC_NOR_ReadHalfWord(uint32_t ReadAddr)
{
    NOR_WRITE(ADDR_SHIFT(0x005555), 0x00AA); 
    NOR_WRITE(ADDR_SHIFT(0x002AAA), 0x0055);  
    NOR_WRITE((EXMC_BANK_NORFLASH + ReadAddr), 0x00F0 );

    return (*(vu16 *)((EXMC_BANK_NORFLASH + ReadAddr)));
}
  
/******************************************************************************
* @brief : Reads a word from the NOR memory. 
* @param : ReadAddr : NOR memory internal address to read from.
* @return: word read from the NOR memory.
******************************************************************************/  
uint32_t EXMC_NOR_ReadWord(uint32_t ReadAddr)
{
    NOR_WRITE(ADDR_SHIFT(0x005555), 0x00AA); 
    NOR_WRITE(ADDR_SHIFT(0x002AAA), 0x0055);  
    NOR_WRITE((EXMC_BANK_NORFLASH + ReadAddr), 0x00F0 );

    return (*(vu32 *)((EXMC_BANK_NORFLASH + ReadAddr)));
}

/******************************************************************************
* @brief : Reads a block of data from the EXMC NOR memory.
* @param : pBuffer : pointer to the buffer that receives the data read 
*          from the NOR memory.
* @param : ReadAddr : NOR memory internal address to read from.
* @param : NumHalfwordToRead : number of Half word to read.
* @return: None.
******************************************************************************/ 
void EXMC_NOR_ReadBuffer(uint16_t* pBuffer, uint32_t ReadAddr, uint32_t NumHalfwordToRead)
{
    NOR_WRITE(ADDR_SHIFT(0x05555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AAA), 0x0055);
    NOR_WRITE((EXMC_BANK_NORFLASH + ReadAddr), 0x00F0);

    for(; NumHalfwordToRead != 0x00; NumHalfwordToRead--) /* while there is data to read */
    {
        /* Read a Halfword from the NOR */
        *pBuffer++ = *(vu16 *)((EXMC_BANK_NORFLASH + ReadAddr));
        ReadAddr = ReadAddr + 2; 
    }  
}

/******************************************************************************
* @brief : Returns the NOR memory to Read mode.
* @param : None.
* @return: None.
******************************************************************************/ 
NOR_StatusTypeDef EXMC_NOR_ReturnToReadMode(void)
{
    NOR_WRITE(EXMC_BANK_NORFLASH, 0x00F0);
    return (NOR_SUCCESS);
}

/******************************************************************************
* @brief : Returns the NOR memory to Read mode and resets the errors in
*          the NOR memory Status Register.
* @param : None.
* @return: NOR_SUCCESS.
******************************************************************************/ 
NOR_StatusTypeDef EXMC_NOR_Reset(void)
{
    NOR_WRITE(ADDR_SHIFT(0x005555), 0x00AA); 
    NOR_WRITE(ADDR_SHIFT(0x002AAA), 0x0055); 
    NOR_WRITE(EXMC_BANK_NORFLASH, 0x00F0);

    return (NOR_SUCCESS);
}

/******************************************************************************
* @brief : norflash 16-bits write and read test.
* @param : None.
* @return: None.
******************************************************************************/ 
static void Nor_Write_Read_Test()//16位写读
{
    uint32_t temp=0, i=0, j=0, errortime=0;

    EXMC_NOR_EraseBlock(0);

    for(i=0;i<SST39VF400A_BLOCK_SIZE/2;i++)
    {
        j++;
        if(j>0xffff)
        {
            j=0;
        }
        EXMC_NOR_WriteHalfWord(2*i, j); 
    }


    j=0;
    for(i=0;i<SST39VF400A_BLOCK_SIZE/2;i++)
    {
        j++;
        if(j>0xffff)
        {
            j=0;
        }
        temp = EXMC_NOR_ReadHalfWord(2*i);
        if(temp!=j)
        {    
            errortime++;
            printfS("Addr=%0.8x,W=%0.8x,R=%0.8x,\r\n",2*i,j,temp); 
            break;
        }
    }

    if(errortime==0)
    {
        printfS("Nor_Write_Read_Test Pass!\r\n"); 
    }
    else
    {
        printfS("Nor_Write_Read_TestError!\r\n"); 
    }
}

/******************************************************************************
* @brief : norflash function test.
* @param : None.
* @return: None.
******************************************************************************/ 
static void APP_Norflash_Test(void)
{  
    printfS("\r\n******** Norflash test Start ********\r\n");  
    NOR_IDTypeDef NOR_ID;
    
    Norflash_GPIO_Init();
    
    EXMC_Norflash_Init();
    EXMC_NOR_ReadID(&NOR_ID);
    printfS("Manufacturer_Code = 0x%04x\r\n", NOR_ID.Manufacturer_Code);
    printfS("Device_Code1 = 0x%04x\r\n", NOR_ID.Device_Code1);
    printfS("Device_Code2 = 0x%04x\r\n", NOR_ID.Device_Code2);
    printfS("Device_Code3 = 0x%04x\r\n", NOR_ID.Device_Code3);
    EXMC_NOR_ReturnToReadMode();
    Nor_Write_Read_Test();
    printfS("******** Norflash test finish ********\r\n");  
}

/******************************************************************************
* @brief : EXMC PSRAM GPIO initialization function.
* @param : None
* @return: None
******************************************************************************/
void PSRAM_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_Init_PSRAM;

    /* Enable GPIOs clock */
    __RCC_GPIOA_CLK_ENABLE();
    __RCC_GPIOB_CLK_ENABLE();
    __RCC_GPIOC_CLK_ENABLE();
    __RCC_GPIOD_CLK_ENABLE();
    __RCC_GPIOE_CLK_ENABLE();
    __RCC_GPIOF_CLK_ENABLE();

    /*-- GPIO 配置 -----------------------------------------------------*/

    /* 通用 GPIO 配置 */
    GPIO_Init_PSRAM.Mode  = GPIO_MODE_AF_PP;       //配置为复用功能
    GPIO_Init_PSRAM.Alternate = GPIO_FUNCTION_10;  
    GPIO_Init_PSRAM.Drive = GPIO_DRIVE_LEVEL3;
    GPIO_Init_PSRAM.Pull = GPIO_PULLUP;   

    /*A地址信号线 针对引脚配置*/
    GPIO_Init_PSRAM.Pin = EXMC_A0_GPIO_PIN; 
    GPIO_Init(EXMC_A0_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A1_GPIO_PIN; 
    GPIO_Init(EXMC_A1_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A2_GPIO_PIN; 
    GPIO_Init(EXMC_A2_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A3_GPIO_PIN; 
    GPIO_Init(EXMC_A3_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A4_GPIO_PIN; 
    GPIO_Init(EXMC_A4_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A5_GPIO_PIN; 
    GPIO_Init(EXMC_A5_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A6_GPIO_PIN; 
    GPIO_Init(EXMC_A6_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A7_GPIO_PIN; 
    GPIO_Init(EXMC_A7_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A8_GPIO_PIN; 
    GPIO_Init(EXMC_A8_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A9_GPIO_PIN; 
    GPIO_Init(EXMC_A9_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A10_GPIO_PIN; 
    GPIO_Init(EXMC_A10_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A11_GPIO_PIN; 
    GPIO_Init(EXMC_A11_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A12_GPIO_PIN; 
    GPIO_Init(EXMC_A12_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A13_GPIO_PIN; 
    GPIO_Init(EXMC_A13_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A14_GPIO_PIN; 
    GPIO_Init(EXMC_A14_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A15_GPIO_PIN; 
    GPIO_Init(EXMC_A15_GPIO_PORT, &GPIO_Init_PSRAM);	

    GPIO_Init_PSRAM.Pin = EXMC_A16_GPIO_PIN; 
    GPIO_Init(EXMC_A16_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A17_GPIO_PIN; 
    GPIO_Init(EXMC_A17_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A18_GPIO_PIN; 
    GPIO_Init(EXMC_A18_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A19_GPIO_PIN; 
    GPIO_Init(EXMC_A19_GPIO_PORT, &GPIO_Init_PSRAM);  

    GPIO_Init_PSRAM.Pin = EXMC_A20_GPIO_PIN; 
    GPIO_Init(EXMC_A20_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_A21_GPIO_PIN; 
    GPIO_Init(EXMC_A21_GPIO_PORT, &GPIO_Init_PSRAM);    

    /*DQ数据信号线 针对引脚配置*/
    GPIO_Init_PSRAM.Pin = EXMC_D0_GPIO_PIN; 
    GPIO_Init(EXMC_D0_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D1_GPIO_PIN; 
    GPIO_Init(EXMC_D1_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D2_GPIO_PIN; 
    GPIO_Init(EXMC_D2_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D3_GPIO_PIN; 
    GPIO_Init(EXMC_D3_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D4_GPIO_PIN; 
    GPIO_Init(EXMC_D4_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D5_GPIO_PIN; 
    GPIO_Init(EXMC_D5_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D6_GPIO_PIN; 
    GPIO_Init(EXMC_D6_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D7_GPIO_PIN; 
    GPIO_Init(EXMC_D7_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D8_GPIO_PIN; 
    GPIO_Init(EXMC_D8_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D9_GPIO_PIN; 
    GPIO_Init(EXMC_D9_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D10_GPIO_PIN; 
    GPIO_Init(EXMC_D10_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D11_GPIO_PIN; 
    GPIO_Init(EXMC_D11_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D12_GPIO_PIN; 
    GPIO_Init(EXMC_D12_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D13_GPIO_PIN; 
    GPIO_Init(EXMC_D13_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D14_GPIO_PIN; 
    GPIO_Init(EXMC_D14_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_D15_GPIO_PIN; 
    GPIO_Init(EXMC_D15_GPIO_PORT, &GPIO_Init_PSRAM);

    /*控制信号线*/
    GPIO_Init_PSRAM.Pin = EXMC_PSRAM_CS_GPIO_PIN; 
    GPIO_Init(EXMC_PSRAM_CS_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_WE_GPIO_PIN; 
    GPIO_Init(EXMC_WE_GPIO_PORT, &GPIO_Init_PSRAM);

    GPIO_Init_PSRAM.Pin = EXMC_OE_GPIO_PIN; 
    GPIO_Init(EXMC_OE_GPIO_PORT, &GPIO_Init_PSRAM);    

    GPIO_Init_PSRAM.Pin = EXMC_UDQM_GPIO_PIN; 
    GPIO_Init(EXMC_UDQM_GPIO_PORT, &GPIO_Init_PSRAM);  

    GPIO_Init_PSRAM.Pin = EXMC_LDQM_GPIO_PIN; 
    GPIO_Init(EXMC_LDQM_GPIO_PORT, &GPIO_Init_PSRAM);  

    GPIO_Init_PSRAM.Pin = EXMC_NWATI_GPIO_PIN; 
    GPIO_Init(EXMC_NWATI_GPIO_PORT, &GPIO_Init_PSRAM); 

    GPIO_Init_PSRAM.Pin = EXMC_CLK_GPIO_PIN; 
    GPIO_Init(EXMC_CLK_GPIO_PORT, &GPIO_Init_PSRAM); 

    GPIO_Init_PSRAM.Pin = EXMC_NADV_GPIO_PIN; 
    GPIO_Init(EXMC_NADV_GPIO_PORT, &GPIO_Init_PSRAM); 

//    GPIO_Init_PSRAM.Pin = PSRAM_CRE_GPIO_PIN; 
//    GPIO_Init_PSRAM.Mode = GPIO_MODE_OUTPUT_PP;
//    GPIO_Init_PSRAM.Drive = GPIO_DRIVE_LEVEL3;
//    GPIO_Init(PSRAM_CRE_GPIO_PORT, &GPIO_Init_PSRAM);  
    
    GPIO_Init_PSRAM.Pin = EXMC_NORFLASH_CS_GPIO_PIN; 
    GPIO_Init_PSRAM.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init_PSRAM.Drive = GPIO_DRIVE_LEVEL3;
    GPIO_Init(EXMC_NORFLASH_CS_GPIO_PORT, &GPIO_Init_PSRAM); 
    GPIO_WriteBit(EXMC_NORFLASH_CS_GPIO_PORT, EXMC_NORFLASH_CS_GPIO_PIN, GPIO_PIN_SET);
}

/******************************************************************************
* @brief : EXMC asynchronous mode initialization function.
* @param : None
* @return: None
******************************************************************************/
void EXMC_PSRAM_Init_Asynchronous(void)
{
    EXMC_NORSRAMInitTypeDef hpsram;
    EXMC_NORSRAMTimingInitTypeDef  readWriteTiming, writeTiming;
    
    EXMC_NORSRAMStructInit(&hpsram);
    
    /* PSRAM device configuration */ 
    //HCLK = 120MHZ, 1/120M = 8.3ns      
    readWriteTiming.EXMC_AddressSetupTime       = 2;
    readWriteTiming.EXMC_AddressHoldTime        = 6;
    readWriteTiming.EXMC_DataSetupTime          = 2;   
    readWriteTiming.EXMC_BusTurnAroundDuration  = 0x06;
    readWriteTiming.EXMC_CLKDivision            = 0;
    readWriteTiming.EXMC_DataLatency            = 0;
    readWriteTiming.EXMC_AccessMode             = EXMC_ACCESS_MODE_D;

    writeTiming.EXMC_AddressSetupTime         = 2;
    writeTiming.EXMC_AddressHoldTime          = 6;
    writeTiming.EXMC_DataSetupTime            = 2;   
    writeTiming.EXMC_BusTurnAroundDuration    = 0x06;
    writeTiming.EXMC_CLKDivision              = 0;
    writeTiming.EXMC_DataLatency              = 0;
    writeTiming.EXMC_AccessMode               = EXMC_ACCESS_MODE_D;
    
    hpsram.EXMC_Bank                          = EXMC_NORSRAM_BANK3;//use CS3 control，Addr=0x68000000
    hpsram.EXMC_DataAddressMux                = EXMC_DATA_ADDRESS_MUX_DISABLE;
    hpsram.EXMC_MemoryType                    = EXMC_MEMORY_TYPE_PSRAM;
    hpsram.EXMC_MemoryDataWidth               = EXMC_NORSRAM_MEM_BUS_WIDTH_16;
    hpsram.EXMC_BurstAccessMode               = EXMC_BURST_ACCESS_MODE_DISABLE;
    hpsram.EXMC_WaitSignalPolarity            = EXMC_WAIT_SIGNAL_POLARITY_HIGH;
    hpsram.EXMC_WrapMode                      = EXMC_WRAP_MODE_DISABLE;
    hpsram.EXMC_WaitSignalActive              = EXMC_WAITSIGNALACTIVE_BEFOREWAITSTATE;
    hpsram.EXMC_WriteOperation                = EXMC_WRITEOPERATION_ENABLE;    
    hpsram.EXMC_WaitSignal                    = EXMC_WAIT_SIGNAL_DISABLE;
    hpsram.EXMC_ExtendedMode                  = EXMC_EXTENDED_MODE_ENABLE;
    hpsram.EXMC_AsynchronousWait              = EXMC_ASYNCHRONOUS_WAIT_DISABLE;
    hpsram.EXMC_CRAMPageSize                  = EXMC_CRAMPAGE_SIZE_AUTO;
    hpsram.EXMC_WriteBurst                    = EXMC_WRITE_BURST_DISABLE;
    hpsram.EXMC_ReadWriteTimingStruct         = &readWriteTiming;
    hpsram.EXMC_WriteTimingStruct             = &writeTiming;      


    EXMC_NORSRAMCmd(hpsram.EXMC_Bank, DISABLE);

    EXMC_NORSRAMInit(&hpsram);
    
    EXMC_NORSRAMCmd(hpsram.EXMC_Bank, ENABLE);
}

/******************************************************************************
* @brief : psram 8/16/32-bits write and read test.
* @param : None.
* @return: None.
******************************************************************************/ 
static void PSRAM_Read_Write_Test(void)
{
    /*写入数据计数器*/
    uint32_t counter=0;

    /* 8位的数据 */
    uint8_t u8WriteData = 0x5A, u8ReadData = 0;  

    /* 16位的数据 */
    uint16_t u16WriteData = 0x3CC3, u16ReadData = 0; 

    /* 32位的数据 */
    uint32_t u32WriteData = 0x55AA33CC, u32ReadData = 0; 

    Delay_Simple(5000);
    
   
    printfS("Detecting PSRAM, reading and writing sdram in 8-bit mode...\r\n");

    for (counter = 0; counter < IS66WVC4M16EALL_SIZE; counter++)
    {
        *(__IO uint8_t*) (EXMC_BANK_PSRAM + counter) = (uint8_t)(0x00);
    }

    for (counter = 0; counter < IS66WVC4M16EALL_SIZE; counter++)
    {
        *(__IO uint8_t*) (EXMC_BANK_PSRAM + counter) = (uint8_t)(u8WriteData + counter);
    }

    for(counter = 0; counter< IS66WVC4M16EALL_SIZE;counter++ )
    {
        u8ReadData = *(__IO uint8_t*)(EXMC_BANK_PSRAM + counter);  //从该地址读出数据
        if(u8ReadData != (uint8_t)(u8WriteData + counter))      //检测数据，若不相等，跳出函数,返回检测失败结果。
        {
            printfS("8-bit data read and write errors,u8ReadData = 0x%02x,u8WriteData=0x%02x,counter=%d\r\n",u8ReadData,u8WriteData,counter);
            return;
        }
    }
  
    printfS("Detecting PSRAM, reading and writing sdram in 16-bit mode...\r\n");
    for (counter = 0; counter < IS66WVC4M16EALL_SIZE;counter+=2)
    {
        *(__IO uint16_t*) (EXMC_BANK_PSRAM + counter) = (uint16_t)(0x0000);
    } 
   
    for (counter = 0; counter < IS66WVC4M16EALL_SIZE;counter+=2)
    {
        *(__IO uint16_t*) (EXMC_BANK_PSRAM + counter) = (uint16_t)(u16WriteData + counter/2);
    }

    for(counter = 0; counter< IS66WVC4M16EALL_SIZE;counter+=2)
    {
        u16ReadData = *(__IO uint16_t*)(EXMC_BANK_PSRAM + counter);  //从该地址读出数据
        if(u16ReadData != (uint16_t)(u16WriteData + counter/2))       //检测数据，若不相等，跳出函数,返回检测失败结果。
        {
            printfS("16-bit data read and write errors,u16ReadData = 0x%04x,u16WriteData=0x%04x,counter=%d\r\n",u16ReadData,u16WriteData,counter);
            return;
        }
    }
   
    printfS("Detecting PSRAM, reading and writing sdram in 32-bit mode...\r\n");
    for (counter = 0; counter < IS66WVC4M16EALL_SIZE;counter+=4)
    {
        *(__IO uint32_t*) (EXMC_BANK_PSRAM + counter) = (uint32_t)(0x00000000);
    }

    for (counter = 0; counter < IS66WVC4M16EALL_SIZE;counter+=4)
    {
        *(__IO uint32_t*) (EXMC_BANK_PSRAM + counter) = (uint32_t)(u32WriteData + counter/4);
    }

    for(counter = 0; counter< IS66WVC4M16EALL_SIZE/4;counter+=4)
    {
        u32ReadData = *(__IO uint32_t*)(EXMC_BANK_PSRAM + counter);  //从该地址读出数据
        if(u32ReadData != (uint32_t)(u32WriteData + counter/4))      //检测数据，若不相等，跳出函数,返回检测失败结果。
        {
            printfS("32-bit data read and write errors,u32ReadData=0x%08x,u32WriteData=0x%08x,counter=%d\r\n",u32ReadData,u32WriteData,counter);
            return;
        }
    }

    printfS("PSRAM read and write test successful!\r\n"); 
}


/******************************************************************************
* @brief : psram function test.
* @param : None.
* @return: None.
******************************************************************************/ 
static void APP_PSRAM_Test(void)
{  
    uint32_t temp=0;
    
    printfS("\r\n******** PSRAM test Start ********\r\n"); 
    
    PSRAM_GPIO_Init();
    
    EXMC_PSRAM_Init_Asynchronous();
    
    Delay_Simple(5000);   
    
    *( uint16_t*) (EXMC_BANK_PSRAM+0) =   (uint16_t)0x5AA5; 
    *( uint16_t*) (EXMC_BANK_PSRAM+2) =   (uint16_t)0x3CC3; 
    *( uint16_t*) (EXMC_BANK_PSRAM+4) =   (uint16_t)0x55AA; 
    *( uint16_t*) (EXMC_BANK_PSRAM+6) =   (uint16_t)0xAA55; 
    *( uint16_t*) (EXMC_BANK_PSRAM+8) =   (uint16_t)0x33CC; 
    *( uint16_t*) (EXMC_BANK_PSRAM+10) =  (uint16_t)0xCC33; 
    
    temp =  *( uint16_t*) (EXMC_BANK_PSRAM+0); 
    printfS("data=0x%X \r\n",temp);   
    temp =  *( uint16_t*) (EXMC_BANK_PSRAM+2);   
    printfS("data=0x%X \r\n",temp);   
    temp =  *( uint16_t*)(EXMC_BANK_PSRAM+4);   
    printfS("data=0x%X \r\n",temp);   
    temp =  *( uint16_t*) (EXMC_BANK_PSRAM+6);
    printfS("data=0x%X \r\n",temp);   
    temp =  *( uint16_t*) (EXMC_BANK_PSRAM+8);   
    printfS("data=0x%X \r\n",temp); 
    temp =  *( uint16_t*) (EXMC_BANK_PSRAM+10);   
    printfS("data=0x%X \r\n",temp); 
    
    PSRAM_Read_Write_Test();
    
    printfS("******** PSRAM test finish ********\r\n"); 
}


/******************************************************************************
* @brief : Norflash and Psram write and read test.
* @param : None.
* @return: None.
******************************************************************************/ 
void APP_Test(void)
{
    APP_Norflash_Test();
    
    DelayMs(1000);
    
    APP_PSRAM_Test();
}







