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, #*1024             @ 4KB大的空间
:
ldr r4, [r1],#           @ 从steppintstone中读取4字节的数据到r4中,并让r4地址加4
str r4, [r2],#           @ 紧接着将刚刚刚读取到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, #           @ * = 54 r3 = r1 + 52, 基于base地址需要52个字节空间. 每个寄存器大小为4字节,共有13个寄存器
:
ldr r4, [r2], #    @ 将r2中存储寄存器中的地址保存到r4中, r2 = r2 + 4;指向下一个寄存器所代表的值
str r4, [r1], #          @ 将r4中的值取出来写到r1中, 以达到配寄存器的目的
cmp r1, r3 @ 比较一下是否写完了
bne 1b @ 如果没有,跳转到1标号处继续执行
mov pc, lr @ 否则函数返回 .align
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 > ; dly--);
} int main(void)
{
unsigned long i = ; GPFCON = GPF4_out|GPF5_out|GPF6_out; // while(){
wait();
GPFDAT = (~(i<<)); //
if(++i == )
i = ;
} return ;
}

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中验证一下.

韦东山嵌入式Linux学习笔记05--存储管理器的更多相关文章

  1. 韦东山嵌入式Linux学习笔记02--如何给开发板烧录程序

    购买韦东山嵌入式开发板jz2440 v3会标配两根usb线和一根网线,OpenJtag需要单独购买, 我暂时还没买到该工具. 下面介绍usb烧录以及通过网线烧录程序. 1.usb烧录程序: 借助DNW ...

  2. 韦东山嵌入式Linux学习笔记08--中断体系结构

    中断是什么? 举个栗子, 系统怎么知道你什么时候插入鼠标这个设备? 可以有两种处理方式: 1. 查询方式: 轮询去检测是否有设备插入; 2. 中断的方式 当鼠标插入这个事件发生时, 置位某个寄存器,告 ...

  3. 韦东山嵌入式Linux学习笔记07--Nandflash

    常用的flash有两种, Norflash和Nandflash, 前几年市场上的产品比较常见的方案时Norflash和Nandflash搭配使用, 因为norflash比较昂贵,相同的容量norfla ...

  4. 韦东山嵌入式Linux学习笔记04--点亮开发板的一个LED灯

    搜索开发板原理图LED的走线           LED8是网线接口的指示灯. 在这里我们尝试用汇编代码控制D10, 也就是LED1,它连接到EINT4/GPF4,读取芯片手册 有原理图可知,如果需要 ...

  5. 韦东山嵌入式Linux学习笔记03--如何搭建软件环境

    1. 从网上下一个虚拟机,比如vmvare station 2.下一个ubuntu镜像回来安装,  我下了14.04来安装.参考链接:  https://blog.csdn.net/qq1326702 ...

  6. 韦东山嵌入式Linux学习笔记01--转载: 板子ping不通PC怎么办

    请参考链接:https://blog.csdn.net/u013490896/article/details/71250060 我的环境: window 10 jz2440 v3 我采用的连接方式如下 ...

  7. 韦东山 嵌入式linux教程 笔记

    @ 目录 资源链接 一.常用命令 二.shell 三.如何更改PATH? 四.路径 五.vi编辑器 六.进阶命令 七.NAT配置网络 (第2篇-P34) 八.开发板挂载 Ubuntu 的 NFS 目录 ...

  8. 嵌入式Linux学习笔记之第一阶段---基础篇

    嵌入式Linux学习分五个阶段 第一阶段: 01嵌入式环境搭建初期 02C语言语法概述 03C语言内存操作 04c语言函数 05linux基础 06gun基础 第二阶段: 01-linux之io系统编 ...

  9. 嵌入式Linux学习笔记(三) 字符型设备驱动--LED的驱动开发

    在成功构建了一个能够运行在开发板平台的系统后,下一步就要正式开始应用的开发(这里前提是有一定的C语言基础,对ARM体系的软/硬件,这部分有疑问可能要参考其它教程),根据需求仔细分解任务,可以发现包含的 ...

随机推荐

  1. 由STL map调用clear后,内存不返还给操作系统的问题出发,探讨glibc malloc/free行为(转)

    1. 问题 我们的程序有几十个线程,每个线程拥有一个std::map,每个线程都要向自己的std::map中插入大量的数据,但每个数据只有几十字节:当使用完std::map,调用map.clear() ...

  2. Linux0.11之进程0创建进程1(1)

    进程0是由linus写在操作系统文件中的,是预先写死了的.那么进程0以后的进程是如何创建的呢?本篇文章主要讲述进程0创建进程1的过程. 在创建之前,操作系统先是进行了一系列的初始化,分别为设备号.块号 ...

  3. Windows 和 Office 大客户激活方法

    激活Windows 10 找到Powershell,然后右键管理员身份运行,依次输入下面的命令,注意将$host切换成为你组织的服务器地址: slmgr.vbs -upk slmgr.vbs -ipk ...

  4. 什么是maven?maven中的pom文件是做什么的?

    Maven 是专门用于构建和管理Java相关项目的管理工具. 1.使用Maven管理的Java 项目都有着相同的项目结构 2.统一维护jar包 POM是项目对象模型(Project Object Mo ...

  5. flask 之(四) --- 扩展|缓存|会话

    扩展 蓝图内置扩展 (实现的是路由的拆分) '''----------- app.py -------------''' from flask import Flask from users_view ...

  6. 【AMAD】django-extensions -- Django框架的自定义命令扩展集合

    动机 简介 个人评分 动机 使用Django进行开发的时候,会不会感觉开发工具少了一些.比如每次进入python shell调试的时候要重新import每个model. 简介 django-exten ...

  7. 【DSP开发】【VS开发】PCIE设备扫描过程

    初步了解完PCI总线标准之后,我们接下来正式开始PCIe设备的漫游之旅.从我们按下PC的电源按钮开始,BIOS就接管系统控制权开始工作,它会先进行一些内存和设备的初始化工作(当然,也包括我们的PCI设 ...

  8. C学习笔记-结构体

    结构体的定义和初始化 结构体是简单数据类型的综合 struct man { char name[100]; int age; }; struct man m = { "tom", ...

  9. 【linux杂谈】查看centOS系统的版本号和内核号

    因为种种原因,我们通常需要查看centOS系统的版本号和内核号. 这里以centOS 6为切入点,展示了几种查看版本号和内核号的方法,同时也验证了其在centOS 7上的可行性. 一.centOS 6 ...

  10. Centos8 安装ifconfig(net-tools.x86_64)

    情况: yum search net-tools.x86_64 没有找到结果 解决: 1.yum search net-tools 2. yum install -y net-tools.x86_64 ...