
#include "corefmc.h"
#include "fmc.h"
#include "delay.h"

//----------------------------------------------------------------------------

void InitSDRAM(void);

//----------------------------------------------------------------------------

void InitCoreFmc(void)
{
	InitSDRAM();
}

//----------------------------------------------------------------------------

#define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)

//----------------------------------------------------------------------------

uint8_t SDRAM_SendCommand1(uint32_t CommandMode, uint32_t Bank, uint32_t RefreshNum, uint32_t RegVal)
{
	uint32_t CommandTarget;
	FMC_SDRAM_CommandTypeDef Command;

	if(Bank == 1)
		CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
	else if(Bank == 2)
		CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
	else
		CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;

	Command.CommandMode = CommandMode;
	Command.CommandTarget = CommandTarget;
	Command.AutoRefreshNumber = RefreshNum;
	Command.ModeRegisterDefinition = RegVal;
	if (HAL_SDRAM_SendCommand(&hsdram1, &Command, 0x1000) == HAL_OK)
	{
		return 1;
	}
	return 0;
}

uint8_t SDRAM_SendCommand2(uint32_t CommandMode, uint32_t Bank, uint32_t RefreshNum, uint32_t RegVal)
{
	uint32_t CommandTarget;
	FMC_SDRAM_CommandTypeDef Command;

	if(Bank == 1)
		CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
	else if(Bank == 2)
		CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
	else
		CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;

	Command.CommandMode = CommandMode;
	Command.CommandTarget = CommandTarget;
	Command.AutoRefreshNumber = RefreshNum;
	Command.ModeRegisterDefinition = RegVal;
	if (HAL_SDRAM_SendCommand(&hsdram2, &Command, 0x1000) == HAL_OK)
	{
		return 1;
	}
	return 0;
}

void InitSDRAM(void)
{
	uint32_t temp;

	// sdram1
	SDRAM_SendCommand1(FMC_SDRAM_CMD_CLK_ENABLE, 1, 1, 0);           //步骤3：使能时钟信号，SDCKE0 = 1
	DelayUs(500);                                                  	//步骤4：至少延时200us
	SDRAM_SendCommand1(FMC_SDRAM_CMD_PALL, 1, 1, 0);                 //步骤5：发送全部预充电命令
	SDRAM_SendCommand1(FMC_SDRAM_CMD_AUTOREFRESH_MODE, 1, 8, 0);     //步骤6：设置自动刷新次数

	temp =	SDRAM_MODEREG_BURST_LENGTH_1     		|					//设置突发长度：1
			SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL     |					//设置突发类型：连续
			SDRAM_MODEREG_CAS_LATENCY_3             |					//设置CAS值：3
			SDRAM_MODEREG_OPERATING_MODE_STANDARD   |					//设置操作模式：标准
			SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;    					//设置突发写模式：单点访问

	SDRAM_SendCommand1(FMC_SDRAM_CMD_LOAD_MODE, 1, 1, temp);			//步骤7：装载模式寄存器的值

	// SDRAM刷新周期是64ms，行数是8192行，时钟频率是180MHz/2=90MHz
	// 所以 COUNT = (64ms/8192)/(1/90us)-20 = 64000*90/8192-20 = 683
	HAL_SDRAM_ProgramRefreshRate(&hsdram1, 683);                    //步骤8：设置刷新速率

	// sdram2
	SDRAM_SendCommand2(FMC_SDRAM_CMD_CLK_ENABLE, 2, 1, 0);           //步骤3：使能时钟信号，SDCKE0 = 1
	DelayUs(500);                                                  	//步骤4：至少延时200us
	SDRAM_SendCommand2(FMC_SDRAM_CMD_PALL, 2, 1, 0);                 //步骤5：发送全部预充电命令
	SDRAM_SendCommand2(FMC_SDRAM_CMD_AUTOREFRESH_MODE, 2, 8, 0);     //步骤6：设置自动刷新次数

	temp =	SDRAM_MODEREG_BURST_LENGTH_1     		|					//设置突发长度：1
			SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL     |					//设置突发类型：连续
			SDRAM_MODEREG_CAS_LATENCY_3             |					//设置CAS值：3
			SDRAM_MODEREG_OPERATING_MODE_STANDARD   |					//设置操作模式：标准
			SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;    					//设置突发写模式：单点访问

	SDRAM_SendCommand2(FMC_SDRAM_CMD_LOAD_MODE, 2, 1, temp);			//步骤7：装载模式寄存器的值

	HAL_SDRAM_ProgramRefreshRate(&hsdram2, 683);                    //步骤8：设置刷新速率
}

//----------------------------------------------------------------------------


// 写入半字数据
void FmcWriteReg(u32 wAddr, u16 data)
{
	*((u16*)(wAddr)) = data;
}

// 读取半字数据
u16 FmcReadReg(u32 rAddr)
{
	return (*((vu16 *)(rAddr)));
}

void FmcWriteConstBuf(u32 wAddr, u16* pBuffer, u32 num)
{
//	printf("FmcWriteConstBuf, addr=0x%x, len=%d\r\n", wAddr, num);
	while(num != 0)
	{
		*((u16*)(wAddr)) = *pBuffer++;
		num--;
	}
}

void FmcReadConstBuf(u32 rAddr, u16* pBuffer, u32 num)
{
	while(num != 0)
	{
		*pBuffer++ = *((vu16*)(rAddr));
		num--;
	}
}
