本文共 3085 字,大约阅读时间需要 10 分钟。
SDRAM:Synchronous Dynamic Random Access Memory,同步动态随机存储器,同步是指内存工作需要同步时钟,内部的命令的发送与数据的传输都以它为基准;动态是指存储阵列需要不断的刷新来保证数据不丢失;随机是指数据不是线性依次存储,而是自由指定地址进行数据读写
原理图如下:
存储逻辑结构:
可以看出SDRAM的内部是一个阵列,就像表格一样,其寻址方式是按照块、行、列来的,即先选定SDRAM芯片,然后发出块信号确定那一块,再发出行信号确定哪一行,再发出列信号确定哪一列。
CPU对SDRAM的访问可以分为以下几步:
看起来很简单,但是我们要考虑到,不同规格SDRAM对应着不同的寻址方式,因为不同的SDRAM可能行列数不一样,对时序要求不一样,所以在访问SDRAM之前,我们要配置存储控制器中的一些寄存器来匹配SDRAM!!!
存储控制器一共有13个寄存器,6种寄存器,对BANK0~BANK5进行访问时,只需要配置BWSCON和BANKCONx寄存器,但是对SDRAM访问,不仅仅需要对这俩个寄存器进行配置,还需要额外配置4个寄存器。
下面以访问SDRAM为例子介绍一下这些寄存器(按照芯片手册中的顺序来介绍):
位宽&等待控制寄存器
所以,BWSCON寄存器要或运算的值为:0x02000000
BANK控制寄存器,用来控制外接设备的访问时序的,BANK0~BANK5默认0X0700
对于SDRAM的访问,我们需要配置的就是图中阴影部分的:
MT:决定BANK外接的是SDRAM还是SRAM,SDRAM选择11.
Trcd:行列信号之间的延迟时间,根据芯片手册得知最小为21ns,而我们的HCLK时钟为100MHz,一个clock10ns,所以保险起见选择30ns,即:01。
SCAN:设置列地址位,这里使用的SDRAM列地址一共9位,所以为:01.
所以,BANKCON6寄存器要或运算的值为:0x00018005
刷新控制寄存器,用来控制SDRAM的刷新模式和刷新频率。我们知道,SDRAM中的存储阵列需要不断的刷新来保证数据不丢失,所以就要配置刷新控制寄存器。
REFEN:决定使能刷新功能,当然是开启了,值为:1
TREFMD:刷新的模式,一般自动刷新,值为:0
Trp:根据芯片手册得知20ns保险,对应2clocks,值为:00
Tsrc:默认即可
Refresh Counter:刷新计数的值,查SDRAM的手册可得8192个刷新周期为64ms,则每一个刷新周期为7.8125ns,通过公式计算可得刷新计数的值为:1955
所以,REFRESH寄存器要或运算的值为:0x008c07a3所以,BANKSIZE寄存器要或运算的值为:0x000000b1
SDRAM模式设置寄存器
只有CL的值是可以修改的,查询芯片手册:
可知,CL可以是2clock或者是3clock,保险起见,值为:011
所以,MRSR寄存器要或运算的值为:0x00000030
/**********************************************************************************************************************/
综上所述,对SDRAM初始化的代码为:void SDRAM_Init(void){ /* 对BANK6进行配置 以访问SDRAM */ BWSCON |= 0x02000000;//对SDRAM使用数据掩码、不使用WAIT信号、设置BANK6位宽32bit BANKCON6 = 0x00018005;//BANK6外接SDRAM、行列信号间延迟3clocks、设置列地址位数 REFRESH = 0x008c07a3;//配置刷新模式及刷新计数值 BANKSIZE = 0x000000b1;//设置BANK6大小为64MB MRSRB6 = 0x00000030;//设置CL为3clocks}
对SDRAM进行配置之后,进行读写操作,看看写进去的值和读出来的值是否统一。
测试就直接写在main.c中吧:
#include "s3c2440_soc.h"#include "uart.h"void SDRAM_Init(void){ /* 对BANK6进行配置 以访问SDRAM */ BWSCON |= 0x02000000;//对SDRAM使用数据掩码、不使用WAIT信号、设置BANK6位宽32bit BANKCON6 = 0x00018005;//BANK6外接SDRAM、行列信号间延迟3clocks、设置列地址位数 REFRESH = 0x008c07a3;//配置刷新模式及刷新计数值 BANKSIZE = 0x000000b1;//设置BANK6大小为64MB MRSRB6 = 0x00000030;//设置CL为3clocks}int SDRAM_Test(void){ /* BANK6 基地址0x30000000 */ volatile unsigned char *p = (volatile unsigned char *)(0x30000000); int n; /* 写入20Byte数据 */ for( n=0;n<20;n++ ) { *(p+n) = 0xbb; } for( n=0;n<20;n++ ) { if( 0xbb != *(p+n) ) return 0; } return 1;}int main(void){ SDRAM_Init(); uart0_init(); if( SDRAM_Test() ) puts("OK!!!\n"); else puts("NOT OK!!!\n"); return 0; }
代码亲测可以。
转载地址:http://epwzi.baihongyu.com/