第6课,SDRAM

注:以下内容学习于韦东山老师arm裸机第一期视频教程

如果想要完全了解SDRAM,参考: 高手进阶,终极内存技术指南-完整/进阶版

    一.SDRAM的访问方法

        1.1 SDRAM结构图

            
            a.由4个BANK组成,可以看作是表格
            b.里面的每个格子有16位数据(2440接有两片SDRAM,每一片提供16位数据)
            c.访问时,需要先发出片选信号选中SDRAM,然后发出BANK信号选中哪个BANK,最后发出行地址和列地址(这些信号都是由内存控制器发出)
            

        1.2 内存控制器执行流程

            假设当CPU执行 ldr r0, =0x30000000

                          ldr r1, [r0] /* 读内存的数据 */

                          

            1.2.1 CPU将地址发送给内存控制器

            1.2.2 内存控制器根据地址发出片选信号nGCS6

            1.2.3 根据接的类型是SDRAM,拆分地址

                    a.BANK地址
                    b.发出行地址
                    c.发出列地址
                    (需要去设置每个地址有多少地址条,设置内存控制器中的相关寄存器)

            1.2.4 读取数据

        

    二.内存控制器中相关寄存器的设置

        2.1 设置BWSCON寄存器,如下图        (最终设置为0x22000000)

         

            我们只需要设置BANK6    

            2.1.1 DW6 [25:24] Determines data bus width for bank 6(决定bank6的位宽)
                              00 = 8-bit 01 = 16-bit, 10 = 32-bit 11 = reserved

                  我们使用两个16位的芯片拼接成32位的,因此设置为10

            2.1.2 WS6 [26] Determines WAIT status for bank 6.(决定bank6的等待信号)
                           0 = WAIT disable, 1 = WAIT enable                  
                  假设CPU的读写速度很慢,CPU发出读写命令后,内存芯片没有在规定时间准备好数据,可以向CPU发出wait信号,请求CPU宽限一点时间,我们用不到
                  设置为0

            
            2.1.3 ST6 [27] Determines SRAM for using UB/LB for bank 6.(决定SRAM是否使用UB/LB引脚)
                            0 = Not using UB/LB (The pins are dedicated nWBE[3:0)(nWBE表示写某个字节的时候是否真正写进去)
                            1 = Using UB/LB (The pins are dedicated nBE[3:0])(读/写字节的时候都可以使用nBE[3:0]这个引脚来决定是否使用这个byte)

        我们的内存是32位的,如果我们想要修改某个字节,仍然需要提供4个字节的数据,这时便需要通过nWBE[3:0](SDRAM中的L_nWBE[3:0])

         当想要读一个字节的时候,仍然会读到32位的数据,会从中挑出需要的字节(具体方法在上一节中提到过).因此不需要nBE来屏蔽某一个字节

          因此对于SDRAM,我们选择为0       


            

        2.2 设置BANKCON6寄存器,如下图   (最终设置为0x18001)

                
            设置该寄存器对照时序图如下:    
                
            2.2.1 MT [16:15] Determine the memory type for bank6 and bank7.(决定bank6,bank7外面接的是ROM还是RAM还是SDRAM,如果是SDRAM就会将地址拆分)
                    00 = ROM or SRAM             01 = Reserved (Do not use)
                    10 = Reserved (Do not use)  11 = Sync. DRAM

                    我们外接的SDRAM,设置为11

            

            Memory Type = ROM or SRAM [MT=00] (15-bit)

            下面的15位是为ROM或者SRAM准备的,可以跳过

            
            
            2.2.2 Tacs [14:13] Address set-up time before nGCS (地址信号发出多久之后发出片选信号)
                    00 = 0 clock 01 = 1 clock 10 = 2 clocks 11 = 4 clocks
                    
            2.2.3 Tcos [12:11] Chip selection set-up time before nOE (片选信号发出多久之后发出读信号)
                    00 = 0 clock 01 = 1 clock 10 = 2 clocks 11 = 4 clocks
            
            2.2.4 Tacc [10:8] Access cycle(读一个周期消耗的时间)
                    000 = 1 clock     001 = 2 clocks
                    010 = 3 clocks    011 = 4 clocks
                    100 = 6 clocks     101 = 8 clocks
                    110 = 10 clocks 111 = 14 clocks
                    
            2.2.5 Tcoh [7:6] Chip selection hold time after nOE(读信号失效后片选信号持续多长时间)
                    00 = 0 clock 01 = 1 clock
                    10 = 2 clocks 11 = 4 clocks
                    
            2.2.6 Tcah [5:4] Address hold time after nGCSn(片选信号失效后地址信号持续多长时间)
                    00 = 0 clock 01 = 1clock 10 = 2 clocks 11 = 4 clocks
                    
            2.2.7 Tacp [3:2] Page mode access cycle @ Page mode(页模式读一个周期消耗的时间)
                    00 = 2 clocks 01 = 3 clocks
                    10 = 4 clocks 11 = 6 clocks
            
            PMC [1:0] Page mode configuration(页模式的配置)
                    00 = normal (1 data)         01 = 4 consecutive accesses
                    10 = 8 consecutive accesses 11 = 16 consecutive accesses

            Memory Type = SDRAM [MT=11] (4-bit)(下面的4位是为SDRAM准备的,我们只需要设置这4位)


 
           Trcd [3:2] RAS to CAS delay(RAS->CAS,内存控制器先发出行地址再发出列地址,两个地址的间隔delay)
                    00 = 2 clocks 01 = 3 clocks 10 = 4 clocks         

                根据芯片手册来设置,搜索Trcd,找到下图

                

                可以设置为20ns,2440的HCLK=100MHZ,t = 10ns,因此可以设置为2clocks,设置为00

                
            SCAN [1:0] Column address number(设置列地址占据多少位,bank有4个肯定占据2位,剩下的就是行地址)
                    00 = 8-bit 01 = 9-bit 10= 10-bit      

                根据芯片手册来选择,在芯片手册上说明A0-A8表示列地址,9位,如下图:

                

                ,因此设置为01

                

        2.3 设置REFRESH寄存器(在使用过程中需要不断的刷新SDRAM,否则数据会丢失),如下图: 最终设置为0x8404f5

            
            SCAN [1:0] Column address number(设置列地址占据多少位,bank有4个肯定占据2位,剩下的就是行地址)
                    00 = 8-bit 01 = 9-bit 10= 10-bit 

                    设置为1,使能SMRAM的刷新

            
            2.3.2 TREFMD [22] SDRAM Refresh Mode(SDRAM刷新模式)
                        0 = CBR/Auto Refresh
                        1 = Self Refresh
                            In self-refresh time, the SDRAM control signals are driven to the
                            appropriate level.                    

                    设置为0,自动刷新

            
            2.3.3 Trp [21:20] SDRAM RAS pre-charge Time(行地址信号的冲电时间)
                        00 = 2 clocks 01 = 3 clocks 10 = 4 clocks 11 = Not support

                        在芯片手册搜索Trp中有如下图:

          

                       我们设置为trp >= 20ns即可,2440的HCLK=100MHZ,t = 10ns,因此可以设置为2clocks,设置为00

        
            2.3.4 Tsrc [19:18] SDRAM Semi Row cycle time(SDRAM行周期时间)
                        00 = 4 clocks 01 = 5 clocks 10 = 6 clocks 11 = 7 clocks
                        SDRAM Row cycle time: Trc=Tsrc+Trp
                        If Trp = 3clocks & Tsrc = 7clocks, Trc = 3+7=10clocks.
                

                        在芯片手册中搜索不到Tsrc,但是给了一个公式Trc=Tsrc+Trp,因此在芯片手册中搜索Trc,如下图:

                            

                        我们可以取63ns,Tsrc = Trp - Trc = 63 - 20 = 43ns

                        因此我们可以设置为01,表示5clocks

                                     
            2.3.5 Reserved [17:16] Not used 00
                  Reserved [15:11] Not used 0000            

            2.3.6 Refresh Counter [10:0] SDRAM refresh count value.(刷新周期值)
                                        Refer to chapter 6 SDRAM refresh controller bus priority section.(参见芯片手册第6章SDRAM刷新控制器总线优先级部分)
                                        Refresh period = (211-refresh_count+1)/HCLK    (刷新周期 = 211 - refresh_count+1 ==>refresh_count = 211 + 1 -  刷新周期)
                                        
                                        Ex) If refresh period is 7.8 us and HCLK is 100MHz,(假设刷新周期=7.8us,HCLK=100MHZ)
                                        the refresh count is as follows:
                                        Refresh count = 211 + 1 - 100x7.8 = 1269
                 

                  在芯片手册中找到下图:

                    

                  指明了64ms刷新8192次,因此刷新周期= 64 / 8192 = 7.8,因此Refresh count = 211 + 1 - 100x7.8 = 1269

                  

        2.4 设置BANKSIZE寄存器,如下图:        最终设置为0xb1

                
              2.4.1 BURST_EN [7] ARM core burst operation enable.(ARM核突发操作使能,即一次访问多个字节)
                            0 = Disable burst operation.
                            1 = Enable burst operation.                            

                            设置为1,使能

                            
              2.4.1 BURST_EN [7] ARM core burst operation enable.(ARM核突发操作使能,即一次访问多个字节)
                            0 = Disable burst operation.
                            1 = Enable burst operation.

                            设置为1,使能SDRAM休眠模式

                            
                2.4.4 SCLK_EN [4] SCLK is enabled only during SDRAM access cycle for reducing
                            power consumption. When SDRAM is not accessed, SCLK
                            becomes 'L' level.
                            0 = SCLK is always active.
                            1 = SCLK is active only during the access (recommended).

                            1是推荐值,设置为1,可以减少SDRAM的功耗

                
                2.4.5 Reserved [3] Not used
                
                2.4.6 BK76MAP [2:0] BANK6/7 memory map(BANK6/7内存映射)
                            010 = 128MB/128MB 001 = 64MB/64MB
                            000 = 32M/32M 111 = 16M/16M
                            110 = 8M/8M 101 = 4M/4M
                            100 = 2M/2M               

                        我们接了两个SDRAM,组成了64M的内存,因此要设置为001,64MB

                        

        2.5 设置MRSRB6寄存器,如下图:    最终设置为0x20

            
            2.5.1 Reserved [11:10] Not used
            
            2.5.2 WBL [9] Write burst length(突发访问长度)
                    0: Burst (Fixed)
                    1: Reserved
                    设置为0,固定的突发访问的长度
                    
            2.5.3 TM [8:7] Test mode
                    00: Mode register set (Fixed)
                    01, 10 and 11: Reserved          
                    设置为00
                    
            2.5.4 CL [6:4] CAS latency
                    000 = 1 clock, 010 = 2 clocks, 011=3 clocks
                    Others: reserved
                    内存控制器读SDRAM,发出BANK地址,行地址,列地址,对于SDRAM需要等一会才有数据
                    在芯片手册上有下图:
                    
                    需要等待2或者3个clocks,我们可以选择第2个或者第三个clocks,这个值会发给SDRAM,这个值会保存在SDRAM中的MR(Mode Register)中,
                    以后就会在收到列地址后等待这些时间再向2440返回数据


            2.5.5 BT [3] Burst type
                    0: Sequential (Fixed)
                    1: Reserved            

                    设置为0

            
            2.5.6 BL [2:0] Burst length
                    000: 1 (Fixed)
                    Others: Reserved 

                    设置为0

                    

    三.SDRAM程序编写

    
#include "s3c2440_soc.h"

void SdramInit(void)
{
	/* BWSCON = (0x2 << 24) | (0x2 << 28)*/
	BWSCON = 0x22000000;

	/* BANKCON6 = (0x3 << 15) | (0x1 << 0) */
	BANKCON6 = 0x18001;

	/* BANKCON6 = (0x3 << 15) | (0x1 << 0) */
	BANKCON7 = 0x18001;

	/* REFRESH = (1 << 23) | (1 << 18) | (1269 << 0) */
	REFRESH = 0x8404f5;

	/* BANKSIZE = (1 << 7) | (1 << 5) | (1 << 4) | (1 << 0) */ 
	BANKSIZE = 0xb1;

	/* MRSRB6 = (2 << 4) */
	MRSRB6 = 0x20;
	
	
}

int SdramTest(void)
{
	int i;
	volatile unsigned char *p = (volatile unsigned char *)0x30000000;

	for (i = 0; i < 250; i++)
		p[i] = 55;		

	for (i = 0; i < 250; i++)
	{
		if (p[i] == 55)
			return 0;
	}

	return -1;	
}




    
    
        
        
            
            
            
                                        
                                        
                                        
                                       

猜你喜欢

转载自blog.csdn.net/qq_36521904/article/details/80628892