SRAM(静态随机存取存储器)
静态随机存取存储器(Static Random-Access Memory,SRAM)是随机存取存储器的一种。所谓的“静态”,是指这种存储器只要保持通电,里面储存的数据就可以恒常保持。相对之下,动态随机存取存储器(DRAM)里面所储存的数据就需要周期性地更新。然而,当电力供应停止时,SRAM储存的数据还是会消失(被称为volatile memory),这与在断电后还能储存资料的ROM或闪存是不同的。
SDRAM(同步动态随机存取内存)
同步动态随机存取内存(synchronous dynamic random-access memory,简称SDRAM)需要不断的刷新,才能保存数据。而且是行列地址复用的,许多都有页模式。SDRAM之所以成为DRAM就是因为它要不断进行刷新(Refresh)才能保留住数据,因为刷新(Refresh)是DRAM最重要的操作。那么要隔多长时间重复一次刷新,目前公认的标准是,存储体中电容的数据有效保存期上限是64ms(毫秒,1/1000秒),也就是说每一行刷新的循环周期是64ms。
硬件:
F429 + W9825G6KH-6
W9825G6KH-6手册:
内部有4个bank。W9825G6KH-6大小 = 4 M x 4 BANKS x 16 BITS = 256Mb = 32MB
配置CAS Latency: 2 或者 3
W9825G6KH-6 :行地址:A0~A12(13bits)。 列地址:A0~A8(9bits)。
STM32CbueMX配置:
时钟树配置:外部晶振25MHz + 配置最大180MHz
1、Bank:由硬件决定;选择SDRAM bank 1
2、Number of column address bits:芯片决定9bits,列地址:A0~A8(9bits)
3、Number of row address bits:芯片决定13bits,行地址:A0~A12(13bits)
4、CAS latency:表示CAS潜伏期,即上面说的CL,该配置需要与之后的SDRAM模式寄存器的配置相同。
和SDRAM工作时钟选择有关,这里选2 memory clock cycles,133MHz,单个时钟周期为最小7.5ns。
5、Write protection 写保护,配置为Disabled
6、SDRAM common clock SDRAM 时钟配置,选择失能、2分频、3分频。从HCLK时钟分频,HCLK时钟最大是180MHz, 故SDCLK最大时钟就是90MHz.单个时钟周期为1s / 90MHz = 11.1ns,所以上面SDRAM 的时钟选择最低133MHz就可以了。
7、SDRAM common burst read 突发读,选择使能。
8、SDRAM common read pipe delay :CAS后延时多少个CLK读数据,一般配置成0;
9、Load mode register to active delay :加载模式寄存器到激活时间的延迟 tMRD / tRSD,最小15ns,F429一个周期是11.1ns,
故15 / 11 = 1......4,考虑到PCB走线等误差, 一般向上取,所以设置是2SDCLK
10、Exit self-refresh delay:退出自刷新延迟 tXSR = 72ns,72 / 11.1向上取整,7SDCLK
11、Self-refresh time:自刷新时间 tRAS = 42ns,故4SDCLK
12、SDRAM common row cycle delay:行循环延迟 tRC = 60ns,故6SDCLK
13、Write recovery time:等待延迟 tWR = 2tCK = 2SDCLK
14、SDRAM common row precharge delay:行预充电延迟 tRP = 15ns = 2SDCLK
15、Row to column delay:行到列延迟 tRCD = 15ns = 2SDCLK
最后生成代码。
SDRAM初始化过程:
SDRAM初始化过程,图片来源于《高手进阶,终极内存技术指南——完整》(这个初始化过程SDRAM通用)
初始化过程分为五步:
① 上电
此步,给SDRAM供电,使能CLK时钟,并发送NOP(No Operation命令)等待最少200us。
② 发送预充电命令
第二步,就是发送预充电命令,给所有Bank预充电。
③ 发送自动刷新命令
这一步,至少要发送发送8次自刷新命令。
④ 设置模式寄存器
这一步,发送模式寄存器的值,配置SDRAM的工作参数。
最后一步设置:SDRAM刷新定时器(图片来源于STM32F4XX中文参考手册)
W9825G6KH-6 行地址:A0~A12(13bits),即有8192(2^13)行,F429的SDRAM时钟是90MHz。
刷新速率 = 64ms / 8192行 = 7.81us。
SDRAM 的刷新周期 = 7.81us * 90Mhz - 20 = 682.9,取683
减20是为了有足够的时钟周期留个刷新。
#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)
/**
* @brief Perform the SDRAM exernal memory inialization sequence
* @param hsdram: SDRAM handle
* @param Command: Pointer to SDRAM command structure
* @retval None
*/
static void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{
__IO uint32_t tmpmrd = 0;
FMC_SDRAM_CommandTypeDef Command;
/* Configure a clock configuration enable command */
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, &Command, 0x1000);
/* Insert 10 ms delay */
HAL_Delay(10);
/* Configure a PALL (precharge all) command */
Command.CommandMode = FMC_SDRAM_CMD_PALL;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, &Command, 0x1000);
/* Configure a Auto-Refresh command */
Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 8;
Command.ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, &Command, 0x1000);
/* Program the external memory mode register */
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_8|
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_2 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = tmpmrd;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, &Command, 0x1000);
/* Set the refresh rate counter */
/* (7.81us x Freq) - 20 */
/* Set the device refresh counter */
HAL_SDRAM_ProgramRefreshRate(hsdram, 683);
}
最后说一下STM32 FMC地址映射关系,我使用的是SDRAM挂载在SDRAM Bank 1,所以开始地址是0xC0000000.
main.c
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_FMC_Init();
MX_USART1_UART_Init();
SDRAM_Initialization_Sequence(&hsdram1);
printf("sudaroot\r\n");
//使用SDRAM方法1
uint32_t i = 0;
uint16_t sdramtest[10] __attribute__((at(0XC0000000)));
for(i = 0; i < 10; i++)
{
sdramtest[i] = i;
}
for(i = 0; i < 10; i++)
{
printf("sdramtest[%d]:%d\r\n", i, sdramtest[i]);
}
//使用SDRAM方法2
uint32_t temp = 100;
*(__IO uint32_t*)(0XC0000400) = temp;
temp = 0;
temp = *(__IO uint32_t*)(0XC0000400);
printf("temp = %u\r\n", temp);
while (1)
{
}
}
现象:
全篇完。
本人是一个嵌入式未入门小白,博客仅仅代表我个人主观见解,记录成长笔记。
笔记是以最简单的方式,只展示最核心的原理。
若有与 大神大大 见解有歧义,我绝对坚信 大神大大 见解是对的,我的是错的。
若无积分等无法下载源码,可加入QQ群657407920下载交流经验。感谢~!