什么是存储控制器?

S3C2440中文概述如下

存储器控制器

概述

S3C2440A 存储器控制器为访问外部存储的需要器提供了存储器控制信号。

S3C2440A 包含以下特性:

–大/小端(通过软件选择)

–地址空间:每个Bank 有128M字节(总共1G/8个Bank)

–大/小端(通过软件选择)

–除了BANK0(16/32位)之外,其它全部BANK都可编程访问宽度(8/16/32 位)

–总共8 个存储器Bank

6 个存储器Bank为ROM,SRAM等

其余2 个存储器Bank为ROM,SRAM,SDRAM等

–7 个固定的存储器Bank起始地址

–1 个可变的存储器Bank起始地址并Bank大小可编程

–所有存储器Bank 的访问周期可编程

–外部等待扩展总线周期

–支持SDRAM自刷新和掉电模式

 

 

 

 

 

S3c2440向外引出27根地址线,可实现128M的寻找空间;那他怎么实现1G的空间范围访问呢?

这就涉及到了nGCSx片选信号,由控制这几根信号线实现bank的切换,如下图所示:

wKiom1cRxtGS04ozAAMJf2QTUaE786.png


左边为norflash下;右边为nand flash

说到此又想起一概念,就是有关于nor flashnand flash启动方式;

一、norflash启动

简而言之,既是norflash启动模式下cpu启动就会从地址0x00000000开始执行

nor flash下是就是nor flash的首地址;其中原因为nor flash支持一种名为XIP的执行机制;

二、nandflash启动

nand flash下不支持XIP因此在执行nandflash的程序是,系统将会把nandflash的头4K(最大)启动代码拷贝至系统SRAM中既s3c2440中的steppingstone

 

S3c2440向外引出27根地址线,可实现128M的寻找空间;那他怎么实现1G的空间范围访问呢?

答案:

S3C2440有27根地址线ADDR[26:0],

8根片选信号ngcs0-ngcs7,对应bank0-bank7,当访问bankx的地址空间,ngcsx引脚为低电平,选中外设。

2^27=2^7 * 2^10 * 2^10 =128Mbyte

8*128Mbyte = 1Gbyte

所以S3C2440总的寻址空间是1Gbyte

选择的SDARM是HY57V561620F,4Mbit * 4bank *16,共32Mbyte。

在嵌入式中,存储控制器只是提供一种总线访问的形式,所接的外设不一定是内存。

 

 

 

 

 

 

本节讲解使用S3C2440的存储控制器,操控外部SDRAM

首先了解下SDRAM的寻址原理。

SDRAM内部是一个存储阵列。可以把它想象成一个表格。和表格的检索原理一样,先指定行,再指定列,就可以准确找到所需要的存储单元。

这个表格称为逻辑BANK。目前的SDRAM基本都是4个BANK。寻址的流程就是先指定BANK地址,再指定行地址,最后指定列地址。这就是SDRAM的寻址原理。

 

查看HY57V561620F的资料,这个SDRAM有

13根行地址线    RA0-RA12

9根列地址线   CA0-CA8 /与行地址复用,选低9位

2根L-BANK选择线    BA0-BA1/S3C2440要求用ADDRESS24,ADDRESS25控制SDRAM的L-BANK

 

SDRAM的地址引脚是分时复用的,在读写SDRAM存储单元时,操作过程是将地址分两次输入到芯片中,

两次送到芯片上去的地址分别称为行地址列地址。它们被锁存到芯片内部的行地址锁存器和列地址锁存器。

/RAS是行地址锁存信号,该信号将行地址锁存在芯片内部的行地址锁存器中;

/CAS是列地址锁存信号,该信号将列地址锁存在芯片内部的列地址锁存器中

 

DRAM的逻辑BANK概念是针对内存颗粒内部的。大家都知道 DRAM内部的存储单元是以阵列形式排列的。

如下图所示。行列地址总线分别经过行列地址译码器译码后分别指向一行和一列,行列重叠的单元就是我们所寻找的存储单元,这就是内存芯片寻址的基本原理。对于内存颗粒来说,这个阵列就是逻辑 Bank(Logical Bank,简称L-Bank)。

 

wKioL1cRx6jxwLqyAAHGax59Xog431.png


 

但是,在实际应用中,由于技术、成本等原因,不可能只做一个全容量的 L-BANK,而且最重要的是,由于 DRAM 的工作原理限制,单一的 L-Bank将会造成严重的寻址冲突,大幅降低内存效率。

所以人们在DRAM 内部分割成多个 L-Bank,每个 L-Bank 形状相同,彼此独立,可以独立工作。早期的DRAM 芯片内部分为2个L-Bank,后来是4个,DDR3 内存芯片为8个。

 

在进行寻址时需要先确定是哪个 L-Bank,然后再在这个选定的 L-Bank中选择相应的行与列进行寻址。对内存的访问,一次只能是一个L-Bank,而每次与 CPU交换的数据就是 L-Bank 存储阵列中一个“存储单元”的容量。SDRAM内存芯片一次传输的数据量就是芯片的位宽,那么这个存储单元的容量就是芯片的位宽(也是 L-Bank 的位宽)。上图为4BANK内存颗粒内部结构示意图。

  内存芯片容量的计算方法为:存储单元数量=行数×列数(得到一个 L-Bank 的存储单元数量)×L-Bank 的数量。在很多内存产品介绍文档中,都会用 M×W 的方式来表示芯片的容量。M 是该芯片中存储单元的总数,单位是兆,W 代表每个存储单元的容量,也就是 SDRAM 芯片的位宽(Width),单位是 bit。计算出来的芯片容量也是以 bit 为单位,但用户可以采用除以 8 的方法换算为字节(Byte)。


wKiom1cRxwTjHG6eAAS6RL6nUyc292.png

 

SDRAM 的行地址有13根 (RAS# ="L", CAS# = "H", WE# = "H", BAs = Bank, A0-A12 =Row Address)

SDRAM 的列地址有 9根  (RAS# = "H",CAS# = "L", WE# = "L", BAs = Bank, A10 = "L",A0-A8 = Column Address)

S3C2440存储控制器的地址线A24A25接到SDRAMBA0BA1,用来控制4 L-bank的选择



举个例子:SDRAM芯片就像小学生练字本,比如这个练字本有4(可以理解为SDRAM4L-bank)

每页有2^13行,每页有2^9列,每一行与列对应的单元格都是一个存储单元(EM63A165 16bit 此处的存储单元是16bit

容量计算:(2^13 * 2^9 *16 *4)/8=32M

解释:13位行地址译码器,对应有2^13行单元

                 09位列地址译码器,对应有2^9行单元   2^13* 2^9 = 4194304个存储单元/L-bank

每个存储单元是16bit,单片16bit SDRAM一次读取就是16bit,每片SDRAM4L-bank ,4194304*4=16777216个存储单元/每个sdram  

8bit是一个字节

16777216*16=268435456bit

有了L-bank行地址,列地址后,就可以访问sdram的任意一个单元了,


就像小学生,先翻开第几张纸,选哪一行,再选那一列,然后写下一个汉字(刚好16bit  GBK编码)

SDRAM芯片内部分为4bankBA0BA1用来选择第几个bank(相当于小学生准备读/写的这个汉字,你要存到那一页)

wKioL1cRx-bAhsC6AANxpvdSKVU949.png



 

 

 

 

 

实验:在SDRAM上,跑一个程序,LED闪烁

思路:

硬件平台准备JZ2440

配置相关寄存器【行地址,列地址,l-bank,刷新率等等

程序从nand  copy 4K sram

程序在sram中执行,把第二段程序 copysdram

跳到sdram中执行!

实验完成

 

 

 

 

1,硬件平台准备:JZ2440


wKiom1cRx0-whZnBAAvXJdhz0fI808.png


 


chunli@ubuntu:~/my03$ ll

total 12

-rw-rw-r-- 1 chunli chunli 2703 Apr 13 03:49 head.S

-rw-rw-r-- 1 chunli chunli  532 Apr 13 03:50 leds.c

-rw-rw-r-- 1 chunli chunli  312 Apr 13 03:50 Makefile


 

 

chunli@ubuntu:~/my03$ vim head.S  
@*************************************************************************
@ File:head.S
@ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到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中
    ldr pc, =on_sdram                   @ 跳到SDRAM中继续执行
on_sdram:
    ldr sp, =0x34000000                 @ 设置堆栈
    bl  main
halt_loop:
    b   halt_loop
 
disable_watch_dog:
    @ 往WATCHDOG寄存器写0即可
    mov r1,     #0x53000000
    mov r2,     #0x0
    str r2,     [r1]
    mov pc,     lr      @ 返回
 
copy_steppingstone_to_sdram:
    @ 将Steppingstone的4K数据全部复制到SDRAM中去
    @ Steppingstone起始地址为0x00000000,SDRAM中起始地址为0x30000000
     
    mov r1, #0
    ldr r2, =SDRAM_BASE
    mov r3, #4*1024
1:  
    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 = 54
1:  
    ldr r4,     [r2], #4            @ 读取设置值,并让r2加4
    str r4,     [r1], #4            @ 将此值写入寄存器,并让r1加4
    cmp r1,     r3                  @ 判断是否设置完所有13个寄存器
    bne 1b                          @ 若没有写成,继续
    mov pc,     lr                  @ 返回
 
 
.align 4
mem_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


 

 

chunli@ubuntu:~/my03$ vim leds.c 
 
#defineGPFCON     (*(volatile unsigned long *)0x56000050)
#defineGPFDAT     (*(volatile unsigned long *)0x56000054)
 
#defineGPF4_out    (1<<(4*2))
#defineGPF5_out    (1<<(5*2))
#defineGPF6_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;      // 将LED1,2,4对应的GPF4/5/6三个引脚设为输出
 
    while(1){
        wait(30000);
        GPFDAT = (~(i<<4));   // 根据i的值,点亮LED1,2,4
        if(++i == 8)
            i = 0;
    }
 
    return 0;
}


 

 

 

chunli@ubuntu:~/my03$ vim 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
 
chunli@ubuntu:~/my0


 

wKioL1cOR5fD_sImAACSCvG0KFs502.jpgwKioL1cOR5iRTJxTAACO1omFigI382.jpg

wKiom1cORuKTmIltAACPEJ6Huw4112.jpgwKiom1cORuLBZhnZAACCbzPgKZA581.jpg