/*
*********************************************************************************************************
*
*	模块名称 : 外部SRAM驱动模块
*	文件名称 : bsp_fsmc_sram.c
*	版    本 : V2.4
*	说    明 : 安富莱STM32-F4开发板标配的SRAM为 IS61WV102416BLL-10TL  容量2M字节，16Bit，10ns速度
*
*	修改记录 :
*		版本号  日期        作者     说明
*		V1.0    2013-02-01 armfly  正式发布
*
*	Copyright (C), 2013-2014, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/

#include "ext_sram.h"
#include <inttypes.h>

/*
*********************************************************************************************************
*	函 数 名: ext_sram_init
*	功能说明: 配置连接外部SRAM的GPIO和FSMC
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void ext_sram_init(void)
{
    FSMC_NORSRAMInitTypeDef       FSMC_NORSRAMInitStructure;
    FSMC_NORSRAMTimingInitTypeDef p;

    /* SRAM 的 GPIO ：
        PD0/FSMC_D2
        PD1/FSMC_D3
        PD4/FSMC_NOE
        PD5/FSMC_NWE
        PD8/FSMC_D13
        PD9/FSMC_D14
        PD10/FSMC_D15
        PD11/FSMC_A16
        PD12/FSMC_A17
        PD13/FSMC_A18
        PD14/FSMC_D0
        PD15/FSMC_D1

        PE0/FSMC_NBL0
        PE1/FSMC_NBL1
        PE3/FSMC_A19
        PE4/FSMC_A20	-- 参与片选的译码
        PE5/FSMC_A21	-- 参与片选的译码
        PE7/FSMC_D4
        PE8/FSMC_D5
        PE9/FSMC_D6
        PE10/FSMC_D7
        PE11/FSMC_D8
        PE12/FSMC_D9
        PE13/FSMC_D10
        PE14/FSMC_D11
        PE15/FSMC_D12

        PF0/FSMC_A0
        PF1/FSMC_A1
        PF2/FSMC_A2
        PF3/FSMC_A3
        PF4/FSMC_A4
        PF5/FSMC_A5
        PF12/FSMC_A6
        PF13/FSMC_A7
        PF14/FSMC_A8
        PF15/FSMC_A9

        PG0/FSMC_A10
        PG1/FSMC_A11
        PG2/FSMC_A12
        PG3/FSMC_A13
        PG4/FSMC_A14
        PG5/FSMC_A15
        PG10/FSMC_NE3	--- 片选主信号
    */

    /*-- FSMC Configuration ------------------------------------------------------*/
    p.FSMC_AddressSetupTime      = 3; /* 设置为2会出错; 3正常 */
    p.FSMC_AddressHoldTime       = 0;
    p.FSMC_DataSetupTime         = 2; /* 设置为1出错，2正常 */
    p.FSMC_BusTurnAroundDuration = 1;
    p.FSMC_CLKDivision           = 0;
    p.FSMC_DataLatency           = 0;
    p.FSMC_AccessMode            = FSMC_AccessMode_A;

    FSMC_NORSRAMInitStructure.FSMC_Bank                  = FSMC_Bank1_NORSRAM3;
    FSMC_NORSRAMInitStructure.FSMC_DataAddressMux        = FSMC_DataAddressMux_Disable;
    FSMC_NORSRAMInitStructure.FSMC_MemoryType            = FSMC_MemoryType_SRAM;
    FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth       = FSMC_MemoryDataWidth_16b;
    FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode       = FSMC_BurstAccessMode_Disable;
    FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait      = FSMC_AsynchronousWait_Disable;
    FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity    = FSMC_WaitSignalPolarity_Low;
    FSMC_NORSRAMInitStructure.FSMC_WrapMode              = FSMC_WrapMode_Disable;
    FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive      = FSMC_WaitSignalActive_BeforeWaitState;
    FSMC_NORSRAMInitStructure.FSMC_WriteOperation        = FSMC_WriteOperation_Enable;
    FSMC_NORSRAMInitStructure.FSMC_WaitSignal            = FSMC_WaitSignal_Disable;
    FSMC_NORSRAMInitStructure.FSMC_ExtendedMode          = FSMC_ExtendedMode_Disable;
    FSMC_NORSRAMInitStructure.FSMC_WriteBurst            = FSMC_WriteBurst_Disable;
    FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
    FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct     = &p;

    FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);

    /*!< Enable FSMC Bank1_SRAM3 Bank */
    FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE);
}

/*
*********************************************************************************************************
*	函 数 名: bsp_TestExtSRAM
*	功能说明: 扫描测试外部SRAM
*	形    参: 无
*	返 回 值: 0 表示测试通过； 大于0表示错误单元的个数。
*********************************************************************************************************
*/
uint8_t test_ext_sram(void)
{
    uint32_t      i;
    uint32_t     *pSRAM;
    uint8_t      *pBytes;
    uint32_t      err;
    const uint8_t ByteBuf[4] = {0x55, 0xA5, 0x5A, 0xAA};

    /* 写SRAM */
    pSRAM = (uint32_t *)EXT_SRAM_ADDR;
    for (i = 0; i < EXT_SRAM_SIZE / 4; i++)
    {
        *pSRAM++ = i;
    }

    /* 读SRAM */
    err   = 0;
    pSRAM = (uint32_t *)EXT_SRAM_ADDR;
    for (i = 0; i < EXT_SRAM_SIZE / 4; i++)
    {
        if (*pSRAM++ != i)
        {
            err++;
        }
    }

    if (err > 0)
    {
        return (4 * err);
    }

    /* 对SRAM 的数据求反并写入 */
    pSRAM = (uint32_t *)EXT_SRAM_ADDR;
    for (i = 0; i < EXT_SRAM_SIZE / 4; i++)
    {
        *pSRAM = ~*pSRAM;
        pSRAM++;
    }

    /* 再次比较SRAM的数据 */
    err   = 0;
    pSRAM = (uint32_t *)EXT_SRAM_ADDR;
    for (i = 0; i < EXT_SRAM_SIZE / 4; i++)
    {
        if (*pSRAM++ != (~i))
        {
            err++;
        }
    }

    if (err > 0)
    {
        return (4 * err);
    }

    /* 测试按字节方式访问, 目的是验证 FSMC_NBL0 、 FSMC_NBL1 口线 */
    pBytes = (uint8_t *)EXT_SRAM_ADDR;
    for (i = 0; i < sizeof(ByteBuf); i++)
    {
        *pBytes++ = ByteBuf[i];
    }

    /* 比较SRAM的数据 */
    err    = 0;
    pBytes = (uint8_t *)EXT_SRAM_ADDR;
    for (i = 0; i < sizeof(ByteBuf); i++)
    {
        if (*pBytes++ != ByteBuf[i])
        {
            err++;
        }
    }
    if (err > 0)
    {
        return err;
    }
    return 0;
}