存储控制器--SDRAM

来源:互联网 发布:北京肝病三甲医院 知乎 编辑:程序博客网 时间:2024/04/30 13:52

2存储控制器

上一节写的太细,这节写重点
正如在GPIO里面说的
这个ARM统一编址(1G~4G留给寄存器)
0x0000_0000~0x4000_0000这1G
给外设用的,硬件把这些地址分成8块
叫做BANK0~BANK7
BANK0地址是0~128
BANK7是(1G-128M)~1G
那么一块的大小是多少呢?!
1G/8=128M。。。。
上面有NOR FLASH IDE 网卡A 网卡B 串口芯片 内存



这些BANK就是由存储控制器管理的。

存储管理器实际上是管理类似于内存这样直接寻址的外设

出厂的时候这些外设就已经粘在这些BANK上面
一开始是没法使用的,所以当然是要设置好这个存储管理器了。

这里我们就配置存储管理器使用SDRAM内存

因为我们S3C2440硬件上对外的地址线只有27根,所以寻址128M
要加上8个片选,用来选择那个BANK,一共1G
寄存器当然是不用对外地址线了
不过这些跟我们没关系,他们是透明的,我们写代码也不需要指定那个BANK
只需要给地址,CPU会自己处理

如图BANK6接的外设是内存,正是我们今天要弄明白的内存。
显然BANK6的地址是0x3000_0000~0x3800_0000这128M了,我们这个S3C2440的内存SDRAM没用完,万恶的资本家只用了64M的内存设备在上面

2.1 BANK寄存器


现在来介绍一下BANK的操作方法,就是在BANK寄存器地址操作了
那么BANK需要几个寄存器操作呢!?
一共是
BWSCON
BANKCON0~BANKCON7
REFRESH
BANKSIZE
MRSRB6~MRSRB7
一共1+8+1+1+2=13个吧
其中

BWSCON控制0~7
BANKCONx控制自己对应的BANK
REFRESH控制BANK6~BANK7
BANKSIZE控制6~7
MRSPBx也是控制6~7

我们只讨论BANK6
因为这个接内存SDRAM,显然内存是很复杂的东西,不然为什么那么贵
SDRAM这种内存,是要刷新的,所以没办法,要靠REFRESH,所以它只能接BANK6
BANKSIZE是用于处理BANK6和BANK7的关系
一下是依次介绍

就不多介绍0~5的BANK了,因为没有例子

2.11BWSCON



每4位控制一个BANK,以6作参考
ST6 启动SRDAM的数据掩码引脚,不知道什么意思,反正SDRAM就要是0的意思 SRAM是1,其他外设也是0
WS6 WAIT信号,设为0
DW6 位宽,我SDRAM是32位,所以当然是10了

BANK7是和BANK6一伙的,这里我也不理解,我开发板程序也没用过BANK7
不过就是说BANK7直接和BANK6数据一致就对了。

说白了,实际上这东西只要管DW这个位宽,就是外设的位宽

我开发板BANK6的SDRAM是32位,BANK5的扩展串口是8位,其余BANK0~BANK4都是16位
那么分别DW就是
0b10
0b00 
0b01

那么最后BWSCON就是0x22011110

为什么BANK0是0b00呢,那是因为
我也不知道。不过它是特殊的。因为它只读,而且只有DW没有ST和WS

2.12BANKCONx


这是BANK6/7专用的
BANK0~5就是中间那段PMC~Tacs  0~14位了
BANK6.7如果把MT=00,就是BANK0~5无差别
MT是11则使用SCAN Trcd这一共4位
当然我们这里MT是11了
SCAN是知名列地址位数的,这是SDRAM在硬件上的构造,我这里是9位的
所以是0b01
MT=11
Trcd=0b01 推荐
内存行地址传输到列地址的延迟时间。

这里看芯片手册,建议是3clocks

SCAN=01

加起来就是

0x0001_8005

2.13REFRESH

顾名思义就是设置刷新频率的

Refresh Counter:
有用的一共5个值,先从最重要的Refresh Counter说起
这个值就是用来设置SDRAM的刷新周期,至于为什么SDRAM要刷新,因为他是动态RAM,说白了成本比静态RAM低,所以要刷新维持值。
我SDRAM的刷新周期是7.8125us,即每7.8125us要刷一次
这里还设计HCLK,即时钟频率,我们这里SDRAM时钟频率是晶振频率,这是裸板是12MHz
一般而言1/周期=频率
周期和频率我们都有了,现在就是要求那个
这里公式大致成立,只是那东西不是1,在这里他式子是2^11+1-refresh_count
这样就可以把refresh_count算出来,我算了是1955
REFEN:使能刷新,显然是呀1了
TREFMD:刷新模式,我们选择自动率先年
Trp:百度
Tsrc:百度
这些刷新clocks之类的不用管那么多了,使用默认就好
最后整个寄存器就是0x008C07A3

2.14BANKSIZE

这个也比较好理解
其中
介绍BK76MAP,我因为我至今不理解BANK6/7如何实现空间地址连续。
不过既然是64M的SDRAM,我就设置成64M好了
其他的3个值就请自行查找了,这里不重要
值就是0xB1

2.15MRSPBx

不重要,直接给值0x30

2.2使用SDRAM

现在我们知道寄存器要设置成什么值,然后才能配合BANK6的32位,列地址是9的SDRAM了
那么是不是只要我们设置了这些寄存器就可以使用这个SDRAM呢?
那么简单?
很明显---------

是的
当你设置好这些寄存器,BANK6激活。
SDRAM起作用。地址是在0x3000_0000
意味着从0x3000_0000后的64M都可以把代码拷到上面执行

--------------那么问题来了
之前的GPIO实验的代码不是在内存里面跑的的吗!?

还真不是,
之前的代码是烧写在NAND Flash(硬盘),执行在Steppingstone(CPU自带RAM,只有4k)

烧写在NAND Flash上的代码是在NAND FLASH开头的,CPU上电会自动把头4K(那个GPIO程序<<4k)复制到Steppingstone,然后执行。
Steppingstone一下简称片内内存
那么我们为了验证SDRAM,当然要代码在SDRAM上运行了

-------------------------------------------------------------------------------------
完成步骤:

1.把片内内存复制到SDRAM的地址0x3000_0000上面
2.跳到0x3000_0000上面

实现方法:

1:就是通过寄存器和地址之间的复制了,命令当然就是ldr/str

2:这里需要先了解一个概念,就是代码运行的地方,这里指的是CPU认为这个代码运行的地方。并未实际运行的地方。
那么我们可以让CPU认为这个代码运行在0x3000_0000上面。
使用绝对跳转指令(给pc寄存器赋值A,但A不是具体地址,而是代码上的一个标识符)就可以跳到上面了。
只要让这个标识符被CPU认为实在SDRAM上面就可以了。
这里就要使用arm-linux-ld在链接是指定代码段的起始地址了参数是-Ttext 

-------------------------------------------------------------------------------------------------

3.代码

那么综合步骤就是
1 初始化存储器
2 片内内存复制到内存SDRAM
3 跳到SDRAM
.equ        MEM_CTL_BASE,       0x48000000.equ        SDRAM_BASE,         0x30000000.text.global _start_start:    bl  disable_watch_dog               @ 关闭WATCHDOG,否则CPU会不断重启    bl  memsetup                        @ 设置存储控制器    bl  copy_steppingstone_to_sdram     @ 复制代码到SDRAM中    <span style="background-color: rgb(255, 153, 0);">ldr pc, =on_sdram</span>                   @ 跳到SDRAM中继续执行on_sdram:    ldr sp, =0x34000000                 @ 设置堆栈    bl  mainhalt_loop:    b   halt_loop----------------以上就是全部步骤,下面是封装的函数-------------------------------------------------disable_watch_dog:    @ 往WATCHDOG寄存器写0即可    mov r1,     #0x53000000    mov r2,     #0x0    str r2,     [r1]    <span style="background-color: rgb(51, 255, 255);">mov pc,     lr</span>      @ 返回copy_steppingstone_to_sdram:    @ 将Steppingstone的4K数据全部复制到SDRAM中去    @ Steppingstone起始地址为0x00000000,SDRAM中起始地址为0x30000000        mov r1, #0    ldr r2, =SDRAM_BASE    mov r3, #4*10241:      ldr r4, [r1],#4     @ 从Steppingstone读取4字节的数据,并让源地址加4    str r4, [r2],#4     @ 将此4字节的数据复制到SDRAM中,并让目地地址加4    cmp r1, r3          @ 判断是否完成:源地址等于Steppingstone的未地址?    bne 1b              @ 若没有复制完,继续    mov pc,     lr      @ 返回memsetup:    @ 设置存储控制器以便使用SDRAM等外设    mov r1,     #MEM_CTL_BASE       @ 存储控制器的13个寄存器的开始地址    adrl    r2, mem_cfg_val         @ 这13个值的起始存储地址    add r3,     r1, #52             @ 13*4 = 541:      ldr r4,     [r2], #4            @ 读取设置值,并让r2加4    str r4,     [r1], #4            @ 将此值写入寄存器,并让r1加4    cmp r1,     r3                  @ 判断是否设置完所有13个寄存器    bne 1b                          @ 若没有写成,继续    <span style="background-color: rgb(51, 255, 255);">mov pc,     lr</span>                  @ 返回.align 4mem_cfg_val:    @ 存储控制器13个寄存器的设置值    .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

上面只有橙色底的是跳到SDRAM的绝对跳转指令。其
其余如蓝色底虽然也是绝对跳转,但是不会跳到SDRAM,因为lr寄存器存的是片内内存的地址。push进栈麻麻嘛。。。

看看makefile
<span style="background-color: rgb(255, 255, 255);">sdram.bin : head.S  leds.carm-linux-gcc  -c -o head.o head.Sarm-linux-gcc -c -o leds.o leds.carm-linux-ld </span><span style="background-color: rgb(255, 153, 0);">-Ttext 0x30000000</span><span style="background-color: rgb(255, 255, 255);"> head.o leds.o -o sdram_elfarm-linux-objcopy -O binary -S sdram_elf sdram.binarm-linux-objdump -D -m arm  sdram_elf > sdram.disclean:rm -f   sdram.dis sdram.bin sdram_elf *.o</span>

看到链接到0x3000_0000了。就是说CPU认为这段代码在这个地址运行
具体就是标识符(程序标号_start,on_sdram等等)都是表示0x3000_0000之后的地址
而且很明显我们知道C语言地址是摆在这个汇编之后的

yoghourt_man
0 0
原创粉丝点击