一、硬件环境
野火stm32F429第一代开发板,主频180。SDRAM为:IS42S16400J,容量8M/byte。
接线如下:
如何接线,需要参考两个文件。一个是stm32参考手册,一个是SDRAM数据手册。
stm32参考手册中关于FMC引脚说明如下:
SDRAM数据手册,太容易找就不贴出来了。
需要注意的是,FMC映射到SDRAM有两个bank可以选择。从上图可知选择不同的bank SDRAM需要接到MCU不同的
SDCKE以及SDNE引脚,且程序中应根据引脚选择驱动对应的bank。
二、初始化程序
程序初始化,只需按照SDRAM DATASHEET提供的时序初始化SDRAM芯片,填充FMC中SDRAM有关结构体的时序参数即可。
FMC控制SDRAM的初始化结构体主要有3个。
(1)初始化参数结构体
FMC_SDRAMInitTypeDef FMC_SDRAMInitStructure;
在此结构体设置FMC映射的SDRAM bank,突发模式,行列长度,ram的bank数量,时钟分频等参数:
(2)时序结构体
这个结构体主要设置SDRAM的读、写、预充电等的时序,具体填充的参数参考SDRAM手册:
需要注意的是,结构体并没有清楚写出tMRD,tRAS等字样,需要自己了解结构体成员的意义,才能从SDRAM
的手册中找到对应的参数填充。
(3)命令结构体
这个结构体主要使用来完成SDRAM的初始化步骤,按照SDRAM手册提供的步骤进行即可:
一个个步骤进行,即可成功初始化SDRAM:
最后切记,要设置刷新计数器,相关计算方法如下:
/* 设置刷新计数器 */
/*刷新速率 = (COUNT + 1) x SDRAM 频率时钟
COUNT =( SDRAM 刷新周期/行数) - 20*/
/* 64ms/4096=15.62us (15.62 us x FSDCLK) - 20 =1386 */
FMC_SetRefreshCount(1386);
/* 发送上述命令*/
while(FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET)
{
}
模式寄存器参数解析如下图:
三、SDRAM读写
底层的时序由FMC完成,我们只需要像操控内存一样操控SDRAM即可。而SDRAM映射的地址,则可根据我们选择的bank
因为填充FMC结构体的时候是选择了Bnak2的,所以对应的地址:0xD000 0000 就是SDRAM的起始地址。
结束地址根据SDRAM的容量计算可知是:0xD07F FFFF。
完整的初始化代码如下:
/**
* @brief 初始化配置使用SDRAM的FMC及GPIO接口,
* 本函数在SDRAM读写操作前需要被调用
* @param None
* @retval None
*/
void SDRAM_Init(void)
{
FMC_SDRAMInitTypeDef FMC_SDRAMInitStruct;
FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingStruct;
FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStruct;
//1、初始化GPIO
SDRAM_GPIO_Config();
//2、开启时钟与配置SDRAM结构体
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);
FMC_SDRAMTimingStruct.FMC_ExitSelfRefreshDelay = 6; //tXSR
FMC_SDRAMTimingStruct.FMC_LoadToActiveDelay = 2; //tMRD
FMC_SDRAMTimingStruct.FMC_RCDDelay = 2; //tRCD
FMC_SDRAMTimingStruct.FMC_RowCycleDelay = 6; //tRC
FMC_SDRAMTimingStruct.FMC_RPDelay = 2; //tRP
FMC_SDRAMTimingStruct.FMC_SelfRefreshTime = 4; //tRAS
FMC_SDRAMTimingStruct.FMC_WriteRecoveryTime = 2; //tWR
FMC_SDRAMInitStruct.FMC_Bank = FMC_Bank2_SDRAM;
FMC_SDRAMInitStruct.FMC_CASLatency = FMC_CAS_Latency_2;
FMC_SDRAMInitStruct.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;
FMC_SDRAMInitStruct.FMC_RowBitsNumber = FMC_RowBits_Number_12b;
FMC_SDRAMInitStruct.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
FMC_SDRAMInitStruct.FMC_ReadBurst = FMC_Read_Burst_Enable;
FMC_SDRAMInitStruct.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_0; //读延迟
FMC_SDRAMInitStruct.FMC_SDClockPeriod = FMC_SDClock_Period_2; //2分频
FMC_SDRAMInitStruct.FMC_SDMemoryDataWidth = FMC_SDMemory_Width_16b;
FMC_SDRAMInitStruct.FMC_WriteProtection = FMC_Write_Protection_Disable;
FMC_SDRAMInitStruct.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingStruct;
FMC_SDRAMInit(&FMC_SDRAMInitStruct);
//3、按照SDRAM初始化顺序初始化SDRAM
//CLK使能
FMC_SDRAMCommandStruct.FMC_AutoRefreshNumber = 0;
FMC_SDRAMCommandStruct.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled;
FMC_SDRAMCommandStruct.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStruct.FMC_ModeRegisterDefinition = 0;
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET);
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStruct);
//所有bank预充电
FMC_SDRAMCommandStruct.FMC_AutoRefreshNumber = 0;
FMC_SDRAMCommandStruct.FMC_CommandMode = FMC_Command_Mode_PALL;
FMC_SDRAMCommandStruct.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStruct.FMC_ModeRegisterDefinition = 0;
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET);
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStruct);
//自动刷新2次
FMC_SDRAMCommandStruct.FMC_AutoRefreshNumber = 2;
FMC_SDRAMCommandStruct.FMC_CommandMode = FMC_Command_Mode_AutoRefresh;
FMC_SDRAMCommandStruct.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStruct.FMC_ModeRegisterDefinition = 0;
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET);
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStruct);
//设置模式寄存器
FMC_SDRAMCommandStruct.FMC_AutoRefreshNumber = 1; //此处设置为0也能通过测试
FMC_SDRAMCommandStruct.FMC_CommandMode = FMC_Command_Mode_LoadMode;
FMC_SDRAMCommandStruct.FMC_CommandTarget = FMC_Command_Target_bank2;
FMC_SDRAMCommandStruct.FMC_ModeRegisterDefinition =
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL| \
SDRAM_MODEREG_OPERATING_MODE_STANDARD| \
SDRAM_MODEREG_CAS_LATENCY_2 | \
SDRAM_MODEREG_BURST_LENGTH_8| \
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET);
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStruct);
/* 设置刷新计数器 */
/*刷新速率 = (COUNT + 1) x SDRAM 频率时钟
COUNT =( SDRAM 刷新周期/行数) - 20*/
/* 64ms/4096=15.62us (15.62 us x FSDCLK) - 20 =1386 */
FMC_SetRefreshCount(1386);
while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET);
FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStruct);
}