SDRAM:
原理图如下:
jz2440 v3开发板上面用的内存芯片为钰创科技公司生产的EM63A165TS,一片内存大小为32MB大小,一共有两块,共64MB的大小.
SDRAM接的是BANK 6,所以他的起始地址是 0x30000000.
SDRAM的基本寻址关系
SDRAM的存储结构逻辑如上图, SDRAM内部是一个存储阵列,阵列就如同表格一样,将数据"填进去".和表格的检索原理一样,先指定一个行,再指定一个列,两点确定一个坐标,就可以准确地找到所需要的
单元格,这就是SDRAM寻址的基本原理.这个单元被称为存储单元,这个表格(存储阵列)就是逻辑Bank(就是L-Bank).SDRAM一般含有四个L-Bank.
对SDRAM的访问可以分为如下几个步骤:
1.CPU发出的片选信号nSCS0有效,它选中SDRAM芯片.
2.SDRAM有四个L-Bank,需要两根地址线来选中其中的一个,根据开发板的设计, 选用了ADDR24和ADDR25作为L-Bank的选择信号.
3.对被选中的芯片进行统一的行/列(存储单元)寻址.
根据SDRAM芯片的列地址线数目设置CPU的相关寄存器后,CPU就会从32位的自动分出L-Bank选择信号, 行地址信号,列地址信号,然后发出行地址信号,列地址信号. L-Bank选择信号在发出行地址信号的同时发出,并维持到列地址信号结束. 有原理图可以看出, 行列地址公用地址线ADDR2-ADDR14(因为DDR的数据位宽为32位,根据2440 datasheet可知,地址线应从A2开始.没有使用ADDR0/1.
使用nSRAS,nSCAS两个信号来区分他们.对于jz2440 v3开发板的SDRAM芯片EM63A165TS的行地址数为13,列地址数位9,所以当nSRAS信号有效时,ADDR2-ADDR14发出来的时行地址信号,它对应的
32位地址空间的bit[23:11](为什么?),当nSCAS信号有效时,ADDR2-ADDR10发出来的时列地址信号,它对应32位地址空间的bit[10:2];
4.找到存储芯片后,被选中的芯片就要进行统一的数据传输了.
开发板使用两片16位的SDRAM芯片并联组成32位的位宽,与CPU的32跟数据线相连(DATA0-DATA31).
BANK6的起始地址为0x30000000,所以SDRAM的访问地址为0x30000000-0x33FFFFFF,共64MB.
存储控制器的的寄存器的使用方法
存储控制器共有13个寄存器,BANK0-BANK5只需要设置BWSCON和BANKCONx两个寄存器,BANK6-BANK7外接SDRAM时, 除BWSCON和BANCONx外,还要设置REFLESH,BANKSIZE,MRSRB6,MRSRB7等4个寄存器.
由上图BANCON寄存器发现,每四位控制一个BANK,最高四位对应BANK7,以此类推.
STx: 启动/禁止SDRAM的数据掩码引脚,对于SDRAM,此位为0;对于SRAM,此位为1.
WSx: 是否使用寄存器的WAIT信号,通常设为0.
DWx: 使用两位来设置相应BANK的位宽,0b00对应8位,0b01应16位,0b10对应32位,0b11保留.
比较特殊的是BANK0,它没有ST0和WS0,DW0只读--由OM0和OM1上电前的电平决定,OM1一直为低,所以只有当OM0为高时,位宽为16bit, 当OM0为低时,选择Nandflash mode.
BWSCON可以设置成0010 0010 0000 0001 0001 0001 0001 0000 0x2201 1110
BANKCONx (x为0~5)
这几个寄存器用来控制BANK0-BANK5外接设备的访问时序,jz2440上使用默认的0x0700
BANKCONx (x为6~7)
在8个BANK中,只有BAN6 AND BAN7可以外接SRAM和SDRAM.BANKCON6和BANKCON7与其他BANK有所不同.
MT: 用于设置本BANK外接的时ROM/SRAM还是SDRAM.SRAM 0b00, SDRAM 0b11
当MT=0b00,此寄存器与BANKCON0---BANKCON5类似.
当MT=0b11,值如下设置
Trcd: RAS to CAS delay, 设为推荐之0b01
SCAN: SDRAM的列地址数,对于这个SDRAM来说, 为9, 所以SCAN=0b01.
这个寄存器应设为 0x00018005
刷新控制寄存器RFFRESH(REFRESH CONTROL REGISTER) 设为0x008c0000 + R_CNT
REFEN: 0= 禁止SDRAM的刷新功能, 1=开启SDRAM的刷新功能
TREFMD: SDRAM的刷新模式. 0 =CBR/auto Refresh,1=Self Refresh(一般在系统休眠时使用).
Trp: 设置为0即可.
Tsrc: 设为默认值0b11即可.
Refresh Counter: 即上述的R_CNT
R_CNT如下计算:(SDRAM时钟频率就是HCLK)
R_CNT = 2^11 + 1 - SDRAM时钟频率(Mhz) * SDRAM刷新周期(us)
如下图, 刷新周期 64ms/8192 = 7.8125us
在未使用PLL时, SDRAM时钟频率等于晶振频率12Mhz.
可以计算:
R_CNT= 2^11 + 1 - 12 * 7.8125 = 1955
所以在未使用PLL时, REFRESH = 0x008c0000 + 1955 = 0x8c07a3
BANKSIZW寄存器REFRESH (BANKSIZE REGISTER)
BURST_EN:
0: ARM核禁止突发传输
1: ARM核允许突发传输
SCKE_EN[5]:
0: 不使用信号令SDRAM进入省电模式,1使用SCKE信号令SDRAM进入省电模式.
SCKE_EN[4]:
0: 时刻发出SCLK信号,1=仅在访问SDRAM期间发出SCLK信号.
BK76MAP:
设置BANK7/6的大小.
BANK6/7对应的地址空间与BANK0-5不同. BANK0-5的地址空间大小都是固定的128MB,BANK6/7的地址空间大小都是可变的.以保持这两个空间的地址连续,即BANK7的起始地址会随它们的大小变化. BANK6/7的取值意义如下:
jz2440 v3开发板BANK6外接的时64M的SDRAM(两片32MB),令[2:0]=0b001(64M/64M),表示BANK6 BANK7的容量都是64M.虽然BANK7没有使用.
综上, BANKSIZE寄存器的值应该设为 0xB1
SDRAM模式设置寄存器MRSRBx
能修改的只有CL,这是SDRAM时序的一个时间参数; 由datasheet可知, SDRAM芯片支持CL =2或者3,开发板选择了3,所以 MRSRB6/7的值为0x30
操作实例: 使用SDRAM
从NAND Flash启动CPU时, CPU会通过内部硬件将NandFlash开始的4KB数据复制到称为Steppingston的4KB内部RAM中(起始地址为0),然后跳到地址0开始执行.
例子中先使用汇编设置好储存控制器,使外接的SDRAM可用,然后把程序本身从Steppintstone复制到SDRAM处;最后跳转到执行.
.equ MEM_CTL_BASE, 0x48000000 @命令用于把常量值设置为可以在文本段中使用的符号 .equ SDRAM_BASE, 0x30000000 .text .global _start _start: bl disable_watch_dog @ 关闭WATCHDOG否则CPU会不断重启. bl memsetup @ 拷贝之前,要先设置存储控制器,不然SDRAM用不了 bl copy_steppingstone_to_sdram @ 复制代码到SDRAM中 ldr pc, =on_sdram @ 跳转到中继续执行 on_sdram: ldr sp, =0x34000000 @ 随便设一个没用到的地址吗? bl main @ 跳转到main函数 halt_loop: @ 死循环 b halt_loop disable_watch_dog: mov r1, #0x53000000 @ 直接往这个寄存器写0就可以达到关闭看门狗的目的 mov r2, #0x0 str r2, [r1] mov pc, lr @不会自动返回吗? 还要将PC指向跳转函数bl保存的Lr值 copy_steppingstone_to_sdram: @ 这个函数主要实现将4K大小的数据从CPU内部SRAM拷贝到SDRAM mov r1, #0 @ 这个地址就是Steppingstone的起始地址. ldr r2, =SDRAM_BASE @ SDRAM的起始地址 mov r3, #4*1024 @ 4KB大的空间 1: ldr r4, [r1],#4 @ 从steppintstone中读取4字节的数据到r4中,并让r4地址加4 str r4, [r2],#4 @ 紧接着将刚刚刚读取到r4的数保存到r2所指向的内存单元中,r2一开始指向SDRAM的起始地址 cmp r1, r3 @ 比较是否已经拷贝4KB大小的数据了 bne 1b @ 如果不相等,说明还没由拷贝完,继续跳转到标号1处执行. mov pc, lr @ 如果相等,函数返回. memsetup: mov r1, #MEM_CTL_BASE @ 0x4800000000 adrl r2, mem_cfg_val @ ADRL 伪指令用于将一个地址加载到寄存器中。 add r3, r1, #52 @ 13*4 = 54 r3 = r1 + 52, 基于base地址需要52个字节空间. 每个寄存器大小为4字节,共有13个寄存器 1: ldr r4, [r2], #4 @ 将r2中存储寄存器中的地址保存到r4中, r2 = r2 + 4;指向下一个寄存器所代表的值 str r4, [r1], #4 @ 将r4中的值取出来写到r1中, 以达到配寄存器的目的 cmp r1, r3 @ 比较一下是否写完了 bne 1b @ 如果没有,跳转到1标号处继续执行 mov pc, lr @ 否则函数返回 .align 4 mem_cfg_val: .long 0x22011110 @ BWSCON .long 0x00000700 @ BANKCON0 .long 0x00000700 @ BANKCON1 .long 0x00000700 @ BANKCON2 .long 0x00000700 @ BANKCON3 .long 0x00000700 @ BANKCON4 .long 0x00000700 @ BANKCON5 .long 0x00018005 @ BANKCON6 .long 0x00018005 @ BANKCON7 .long 0x008C07A3 @ REFRESH .long 0x000000B1 @ BANKSIZE .long 0x00000030 @ MRSRB6 .long 0x00000030 @ MRSRB7
main函数, 可以不关注这个函数的功能,实现LED点亮的功能, 方便验证函数已经跑到这.
#define GPFCON (*(volatile unsigned long *)0x56000050) #define GPFDAT (*(volatile unsigned long *)0x56000054) #define GPF4_out (1<<(4*2)) #define GPF5_out (1<<(5*2)) #define GPF6_out (1<<(6*2)) void wait(volatile unsigned long dly) { for(; dly > 0; dly--); } int main(void) { unsigned long i = 0; GPFCON = GPF4_out|GPF5_out|GPF6_out; // while(1){ wait(30000); GPFDAT = (~(i<<4)); // if(++i == 8) i = 0; } return 0; }
Makefile
sdram.bin : head.S leds.c arm-linux-gcc -c -o head.o head.S arm-linux-gcc -c -o leds.o leds.c arm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elf arm-linux-objcopy -O binary -S sdram_elf sdram.bin arm-linux-objdump -D -m arm sdram_elf > sdram.dis clean: rm -f sdram.dis sdram.bin sdram_elf *.o
最后将程序烧录到nandflash中验证一下.
来源:https://www.cnblogs.com/cheyihaosky/p/11871368.html