12.4内存控制器与SDRAM_SDRAM的设置
本节将讲解如何设置SDRAM,如果想对内存有更多的了解,可以在网上搜索看下这篇文档“高手进阶_终极内存技术指南——完整/进阶版”。
在JZ2440上接有64M的SDRAM,如果想要使用SDRAM,需要对内存控制器做一些设置。 在前面第一节讲到,CPU将数据或地址发给内存控制器,内存控制器再去访问外部的SDRAM,因此设置内存控制器就说本节的核心。
如图是SDRAM存储结构逻辑图:

SDRAM总共有4个块(Banks),可以认为每个块就是一个表格,里面的每个格子表示的是16bit数据。
问题1:怎样访问里面的某个格子呢?
1. 首先发出一个片选信号,选中整个芯片;
2. 发出Bank地址,选择是哪一个Bank(块,即表格);
3. 发出行地址;
4. 最后发出列地址,才能选中是个格子;
问题2:那么多的信号有谁发出呢?
由内存控制器发出,所以我们需要设置内存控制器,CPU只是简单的执行读写内存的命令,其他的都交给内存控制起来处理。 例如 :

1. CPU把0x30000000这个地址发给内存控制器,内存控制器根据这个地址,判断属于哪个范围,然后发出相应的片选信号。
2. 根据类型(比如SDRAM)拆分成三部分:发出Bank地址、发出行地址、发出列地址。
对于上面的三个,怎样拆分呢?
行地址线有几条,列地址线有几条,都要设置内存控制器里面相关寄存器。
3. 读数据
综上所述:对SDRAM的访问可以分为如下步:
1. CPU发出的片选信号nSCS6有效,它选中SDRAM芯片。
2. SDRAM中有4个L-Bank,需要两根地址信号来选中其中之一,根据原理图,可知使用ADDR24,ADDR25作为L-Bank的选择信号。
3. 对被选中的芯片进行统一的行/列(存储单元)寻址。
根据SDRAM芯片的列地址线数目设置CPU的相关寄存器后,CPU就会从32位的地址中自动分出L_Bank片选信号,行地址信号,列地址信号,然后先后发出行地址信号,列地址信号。L_Bank选择信号在发出行地址信号的同时发出,并维持到列地址信号结束。
根据原理图可知:
地址、列地址共用地线ADDR2—ADDRI4(BANK6位宽为32,ADDRO/I没有使用),使用nSRAS、nSCAS两个信号来区分它们。
比如本开发板中,使用两根地址线ADDR24、ADDR25作为L-Bank的选择信号:SDRAM芯片K4s5m632的行地址数为13,列地址数为9,所以当nSRAS信号有时,ADDR2—ADDR14上发出是行地址信号,它对应32位地址空间的b可23m]:当nSCAS信号有效时,ADDR2—ADDR10上发出的是列地址信号,它对应32位地址空间的bit[0:2];由于BANK6以32位的宽度外接DRAM,ADDR0、ADDR1恒为0,不参与译码。
4. 找到了存储单元后,被选中的芯片就要进行统一的数据传输了。
开发板中使用两片16位的SDRAM芯片并联组成32位的位宽,与CPU的32根数据线(DATA0—DATA31)相连。 BANK6的起始地址为0x30000000,所以SDRAM的访问地址为0x30000000~低0x33FFFFFF,共64MB。
2440内存控制器设置:
内存控制器共有13个寄存器,
BANK0--BANK5只需要设置BWSCON和BANKCONx(x为0~5)两个寄存器;
BANK6、BANK7外接SDRAM时,除BWSCON和BANKCONx(x为6、7)外,还要设置REFRESH、BANKSIZE、MRSRB6、MRSRB7等4个寄存器。
下面分类说明各个寄存起的设置。
1.位宽和等待控制寄存器BWSCON(BUSWIDTH&WAITCONTROLREGISTER)

BWSCON中每4位控制一个BANK,最高4位对应BANK7(没有使用)、接下来4位对应BANK6。
(1)ST6[27]: 启动/禁止SDRAM的数据掩码引脚,对于SDRAM,此位为0:对于SRAM此位为1。
(2)WS6[26]:是否使用存储器的WAIT信号,通常设为0。
(3)DW6[25:24]:使用两位来设置相应BANK的位宽,0b00对应8位,0b01对应16位,0b10对应32位(开发板用的就是32位的),0b11表示保留。
因此BWSCON寄存器的值为:0x22000000。
2. BANK控制寄存器BANKCON6(BANKCONTROLREGISTER)
在8个BANK中,只有BANK6和BANK7可以外接SRAM或SDRAM。

(1)MT[16:15]:用于设置本BANK外接的是ROM/SRAM还是SDRAM,SRAM:0b00,SDRAM:0b11(开发板使用的是SDRAM)。
当MT[16:15]设置为00时,此寄存器与BANKC0N0、BANKCON5类似,不再赘述。
当MT[16:15]设置为11时,此寄存器其他值如下设置。

(2)Trcd[3:2]:行地址和列地址间隔多长时间,看芯片手册时间间隔是20ns,本来开发板的HCLK是100MHZ,clocks为10ns,所以设置为推荐值0b00(2clocks)。
(3)SCAN[1:0]:SDRAM的列地址位数,对于本开发板使用的SDRAMK4S561632。列地址位数为9,所以SCAN=0b010如果使用其他型号的SDRAM,需要查看其数据手册。来决定SCAN的取值。0b00表示8位,0b01表示9位,0b10表示10位。
综上所述,本开发板中BANKCON6设为0x018001。
3. 刷新控制寄存器REFRESH(REFRESHCONTROLREGISTER)

(1)REFEN[23]:0=禁止SDRAM的刷新功能,1:开启SDRAM的刷新功能(设置开启SDRAM的刷新功能)。
(2)TREFMD[22]:SDRAM的刷新模式,0=CBR/AutoRefresh,1=SelfRefresh(一般在系统休眠时使用),我们设置默认值。
(3)Trp[21:20):根据芯片手册设为0即可。
(4)Tsrc[19:18]:根据芯片手册设为默认值0b01即可。
(5)RefreshCounter[10:0]:即R_CNT
R_CNT可如下汁算(SDRAM时钟频率就是HCLK):
R_CNT=2^11+1-SDRAM时钟频率(MZ)*SDRAM刷新周期(us)
SDRAM的刷新周期在SDRAM的数据手册上有标明,在本开发板使用的SDRAM:K4S561632的数据手册上,可看见这么一行“64msrefreshpenod(8KCycle)所以,刷新周期=64ms/8192=7.8125us。
Refreshcount=2^11+1-100x7.8=1269=0x4F5
因此,本开发板中REFRESH设为0x8404F5。
4. BANKSIZE寄存器REFRESH(BANKSIZEREG ISTER)

(1)BURST_EN[7]:0=ARM核禁上突发传输,1=ARM核支持突发传输(推荐);
(2)SCKEEN[5]:0=不使用SCKE信号令SDRAM进入省电模式,1=使用SCKE信号令SDRAM进入省电模式(推荐);
(3)SCLK-EN[4]:0=时刻发出SCLK信号,1=仅在访问SDRAM期间发出SCLK信号(推荐);
(4)BK76MAP[2:0]:设置BANK6的大小。本开发板BANK6外接64MB的SDRAM,令[2:0]=b001(64M/64M),表示BANK6/7的容量都是64MB,虽然BANK7没有使用。
因此,本开发板中BANKSIZE设为0xB1。
5. SDRAM模式设置寄存器MRSRBx6(SDRAM MODE REGISTER SET REGISTER)

能修改的只有位CL[6:4],这是SDRAM时序的一个时间参数,表示发出行、列地址后,等多久才返回收到数据, CL可以取值为0b0l0(2 clocks)或0b011(3 clocks)。
本开发板取最保守的值0b010,所以MRSRB6的值为0x20。
下面开始写程序:
在init.c里面进行对内存控制器的寄存器依次进行设置:

再写一个测试函数,向SDRAM里面连续写1000个数,再读出数据对比是否是设置的数,返回对比结果:

在主函数里调用sdram_test()测试函数,如果测试成功,LED闪烁:

实验结果:
LED按预期闪烁,屏蔽掉sdram_init()后,LED不闪烁。