银杏科技有限公司旗下技术文档发布平台 |
技术支持电话 | 0379-69926675-801 |
技术支持邮件 | Gingko@vip.163.com |
版本 | 日期 | 作者 | 修改内容 |
V1.0 | 2020-07-12 | gingko | 初次建立 |
实验三十七:SDRAM实验——读写SDRAM
一、 实验目的与意义
了解STM32 SDRAM结构。
了解STM32 SDRAM特征。
掌握SDRAM的使用方法。
掌握STM32 HAL库中SDRAM属性的配置方法。
掌握KEILMDK 集成开发环境使用方法。
二、 实验设备及平台
-
-
Micro USB线缆。
Keil MDK 开发平台。
STM32CubeMX开发平台。
装有WIN XP(及更高版本)系统的计算机。
三、 实验原理
1、SDRAM简介
SDRAM,英文名是:Synchronous Dynamic Random Access Memory,即同步动态随机存储器,相较于SRAM(静态存储器),SDRAM具有:容量大和价格便宜的特点。STM32F767支持SDRAM,因此,我们可以外挂SDRAM,从而大大降低外扩内存的成本。
同步动态随机存取内存(SDRAM)是有一个同步接口的动态随机存取内存(DRAM)。通常DRAM是有一个异步接口的,这样它可以随时响应控制输入的变化。而SDRAM有一个同步接口,在响应控制输入前会等待一个时钟信号,这样就能和计算机的系统总线同步。时钟被用来驱动一个有限状态机,对进入的指令进行管线(Pipeline)操作。这使得SDRAM与没有同步接口的异DRAM(asynchronous DRAM)相比,可以有一个更复杂的操作模式。管线意味着芯片可以在处理完之前的指令前,接受一个新的指令。在一个写入的管线中,写入命令在另一个指令执行完之后可以立刻执行,而不需要等待数据写入存储队列的时间。在一个读取的流水线中,需要的数据在读取指令发出之后固定数量的时钟频率后到达,而这个等待的过程可以发出其它附加指令。
SDRAM是多Bank结构,例如在一个具有两个Bank的SDRAM的模组中,其中一个Bank在进行预充电期间,另一个Bank却马上可以被读取,这样当进行一次读取后,又马上去读取已经预充电Bank的数据时,就无需等待而是可以直接读取了,这也就大大提高了存储器的访问速度。为了实现这个功能,SDRAM需要增加对多个Bank的管理,实现控制其中的Bank进行预充电。在一个具有2个以上Bank的SDRAM中,一般会多一根叫做BAn的引脚,用来实现在多个Bank之间的选择。
SDRAM具有多种工作模式,内部操作是一个复杂的状态机。SDRAM器件的引脚分为以下几类。
SDRAM的所有操作都同步于时钟。根据时钟上升沿控制管脚和地址输入的状态,可以产生多种输入命令:
模式寄存器设置命令
激活命令
预充命令
读命令
写命令
带预充的读命令
带预充的写命令
自动刷新命令
自我刷新命令
突发停命令
空操作命令
根据输入命令,SDRAM状态在内部状态间转移。内部状态包括模式寄存器设置状态、激活状态、预充状态、写状态、读状态、预充读状态、预充写状态、自动刷新状态及自我刷新状态。
SDRAM支持的操作命令有初始化配置、预充电、行激活、读操作、写操作、自动刷新、自刷新等。所有的操作命令通过控制线CS#、RAS#、CAS#、WE#和地址线、体选地址BA输入。
2、SDRAM信号线
3、SDRAM存储单元
对于这个存储阵列,我们可以将其看成是一个表格,只需要给定行地址和列地址,就可以确定其唯一位置,这就是SDRAM寻址的基本原理。而一个SDRAM芯片内部,一般又有4个这样的存储单元(BANK),所以,在SDRAM内部寻址的时候,先指定BANK号和行地址,然后再指定列地址,就可以查找到目标地址。
SDRAM的存储结构示意图,如图下所示,寻址的时候,首先RAS信号为低电平,选通行地址,地址线A0~A12所表示的地址,会被传输并锁存到行地址译码器里面,最为行地址,同时BANK地址线上面的BS0,BS1所表示的BANK地址,也会被锁存,选中对应的BANK,然后,CAS信号为低电平,选通列地址,地址线A0~A12所表示的地址,会被传输并锁存到列地址译码器里面,作为列地址,这样,就完成了一次寻址。
4、数据传输
在完成寻址以后,数据线DQ0~DQ15上面的数据会通过数据控制逻辑写入(或读出)存储阵列。特别注意:因为SDRAM的位宽,可以达到32位,也就是最多有32条数据线,在实际使用的时候,我们可能会以:8位、16位、24位和32位等宽度来读写数据,这样的话,并不是每条数据线,都会被使用到,未被用到的数据线上面的数据,必须被忽略,这个时候就需要用到数据掩码(DQM)线来控制了,每一个数据掩码线,对应8个位的数据,低电平表示对应数据位有效,高电平表示对应数据位无效。
SDRAM的驱动需要用到一些命令,常用的命令如图所示:
5、原理图
四、 实验程序
1、主函数
int main(void)
{
int i,j;
/* MCU 配置*/
/* 重置所有外设, 初始化Flash 接口和Systick. */
HAL_Init();
/* 系统时钟配置 */
SystemClock_Config();
/* 初始化所有已配置的外设 */
MX_GPIO_Init();
//SDRAM初始化
BSP_SDRAM_Init();
LED_BLUE_ON;
//向SDRAM中写入0x5555并读取校验
for(i = 0;i < SDRAM_SIZE;i++){
write_sdram(i,0x5555);
}
for(i = 0;i < SDRAM_SIZE;i++){
if(0x5555 != read_sdram(i)){
while(1){
LED_RED_ON;
HAL_Delay(500);
LED_RED_OFF;
HAL_Delay(500);
}
}
}
//向SDRAM中写入0xAAAA并读取校验
for(i = 0;i < SDRAM_SIZE;i++){
write_sdram(i,0xAAAA);
}
for(i = 0;i < SDRAM_SIZE;i++){
if(0xAAAA != read_sdram(i)){
while(1){
LED_RED_ON;
HAL_Delay(500);
LED_RED_OFF;
HAL_Delay(500);
}
}
}
//向SDRAM中写入0x0000~0xFFFF并读取校验
for(j = 0; j < 256; j++){
for(i = 0;i < 65536;i++){
write_sdram((65536 * j + i),i);
}
}
for(j = 0; j < 256; j ++){
for(i = 0;i < 65536;i++){
if(i != read_sdram((65536 * j + i))){
while(1){
LED_RED_ON;
HAL_Delay(500);
LED_RED_OFF;
HAL_Delay(500);
}
}
}
}
//测试成功
LED_BLUE_OFF;
LED_GREEN_ON;
while (1)
{
}
}
2、SDRAM初始化
uint8_t BSP_SDRAM_Init(void)
{
static uint8_t sdramstatus = SDRAM_ERROR;
/* SDRAM设备配置 */
/* SDRAM时钟频率为100Mhz的定时配置(系统时钟最高为200Mhz) */
Timing.LoadToActiveDelay = 2;
Timing.ExitSelfRefreshDelay = 7;
Timing.SelfRefreshTime = 4;
Timing.RowCycleDelay = 7;
Timing.WriteRecoveryTime = 2;
Timing.RPDelay = 2;
Timing.RCDDelay = 2;
sdramHandle.Init.SDBank = FMC_SDRAM_BANK1;
sdramHandle.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
sdramHandle.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
sdramHandle.Init.MemoryDataWidth = SDRAM_MEMORY_WIDTH;
sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
sdramHandle.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
sdramHandle.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
sdramHandle.Init.SDClockPeriod = SDCLOCK_PERIOD;
sdramHandle.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
sdramHandle.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;
/* SDRAM控制器初始化 */
BSP_SDRAM_MspInit(&sdramHandle, NULL); /* __weak函数可以被应用程序重写*/
if(HAL_SDRAM_Init(&sdramHandle, &Timing) != HAL_OK)
{
sdramstatus = SDRAM_ERROR;
}
else
{
sdramstatus = SDRAM_OK;
}
/* SDRAM初始化顺序 */
BSP_SDRAM_Initialization_sequence(REFRESH_COUNT);
return sdramstatus;
}
3、SDRAM读写函数
#define SDRAM_SIZE SDRAM_DEVICE_SIZE
#define write_sdram(offset,data) *(volatile unsigned short int *)(SDRAM_DEVICE_ADDR + (offset << 1)) = data
#define read_sdram(offset) *(volatile unsigned short int *)(SDRAM_DEVICE_ADDR + (offset << 1))
五、 实验步骤
把仿真器与iCore4的SWD调试口相连(直接相连或者通过转接器相连);
把iCore4通过Micro USB线与计算机相连,为iCore4供电;
打开Keil MDK 开发环境,并打开本实验工程;
烧写程序到iCore4上;
也可以进入Debug模式,单步运行或设置断点验证程序逻辑。
六、 实验现象