到目前为止,我们的程序只能使用S3C2440的片内4KB的RAM。这么小的内存空间,显然不能应付实际的应用。是时候使用片外的RAM了,本文将详细介绍片外RAM的初始化过程。
0 ROM,RAM,SRAM,DRAM,SDRAM傻傻分不清
作为软件出身的软男,很难从根本上弄清楚ROM,RAM,SDRAM,SRAM等等的原理,这里我们只要了解基本的特性就可以了。
ROM,NorFlash: 只读内存,掉电不丢失。只读指的是不能通过正常的写入接口写入数据,但是可以通过特殊的烧写逻辑写入。这就意味之,我们的程序可以直接在ROM中执行,但是程序执行时无法在ROM中保存数据。测试表明,写入操作可以执行,但是没有任何效果。TQ2440搭配了2MB的NorFlash ROM,我们的程序烧入ROM后能直接执行,但是由于不能写内存,所以程序功能收到很大限制。为此实验环境选择了从Nandflash启动,应为S3C2440硬件直接会把Nandflash的头4KB数据拷贝到片内的SRAM执行。
SRAM:(Static RAM)可读写,掉电丢失数据,但是无需定期电路刷新。这种东西非常昂贵,集成度不高,性能也相当好。多用于CPU的cache等关键场合。S3C2440A片内集成了4KB的SRAM,已经相当不错了。到目前为止,我们的实验程序都是运行在这块SRAM上的。
DRAM:(Dynamic RAM)可读写,掉电丢失数据,而且必须定期充电刷新。这种RAM相对便宜,集成度高,性能较SRAM差点,但是也相当不错了。
SDRAM:(Synchronous DRAM)同步DRAM。首先它是DRAM,只是额外需要同步时钟才能正常工作。这也是TQ2440板子上搭配的主要内存。核心板子上配备了2块,一共64MB。本文的目的就是配置使用着64MB的SDRAM。
1 内存地址的转换全过程
对内存的操作是所有程序的最基本需求,而对内存进行寻址是所有内存操作的前提。高级编程语言里,一般会使用各种符号名来代表内存地址,例如如下C语言代码:
int main()
{
int a=10;
printf("hellon");
}
main,a,printf都是符号,它在编译后会被实际的内存地址取代。C语言提供了直接操作内存地址的强大工具—指针,这也是C语言能在底层开发领域统治多年的法宝。
int *pa = &a;
int *p = (int*)0x00001010;
C语言不仅允许我们获得变量的内存地址,而且允许直接使用内存地址。那么这里的0x00001010地址数据到底是如何对应到内存芯片上的实际物理存储单元的呢?这种对应需要2个步骤:
1.1 从虚拟地址到物理地址
上面代码中的内存地址数据 0x00001010是核心CPU看到的地址,被称作虚拟地址。对于低端的单片机,这个虚拟地址直接作为物理地址发送到地址总线。而现代高级CPU内部一般都集成了一个被称作MMU的内存管理单元,CPU核心发出的虚拟地址首先进入MMU,MMU负责把虚拟地址转换为地址总线上的物理地址,然后发送到地址总线。
虚拟地址—(MMU)—物理地址
MMU是Windows,Linux等操作系统运行的基础,也是多进程实现的基础。S3C2440A的ARM核心也继承了MMU,只是默认MMU是不启动的,这就意味着虚拟地址和物理地址完全一样。我们的实验程序也没有启动MMU,所以在程序中使用的内存地址可以直接理解成物理地址。
1.2 从物理地址到内存存储单元的行列地址和片选信号
物理地址是一个线性地址,一般不能够直接用来寻址内存单元。中间需要通过内存控制器来把物理地址转换成内存单元的行列地址以及片选信号。
物理地址—(内存控制器)—行列地址及片选信号
总之,只要不同的物理地址最终被映射到不同的内存单元就满足硬件设计的要求,而不管CPU地址总线,CPU引脚,RAM芯片引脚到底是如何组合的。如何组合是硬件设计师的工作,我们软件工程师只要使用就可以了。
2 TQ2440的SDRAM硬件配置
2.1 S3C2440内存硬件设计
内存地址相关的引脚共有35个,其中行列地址引脚A26,A25,…A0共27个,片选信号引脚nGCS0,nGCS1,…,nGCS7共8个。可见外部引脚最大寻址空间为8*2^27,正好是1GB。1GB以上的空间仅供CPU内部寄存器使用。
S3C2440把每一个片选信号对应的空间称作一个BANK,每个BANK大小128M。
2.2 TQ2440开发板SDRAM搭配硬件设计
TQ2440搭配了2片32MB的SDRM,共64MB。这两片内存并联成32位数据宽度供CPU使用。
图中看出,每个内存芯片的行列地址有13位,数据宽度为2个字节,这样可寻址:2^13*2 = 64KB。啥?不是每个芯片32MB吗?这里的玄机在于对于SDRAM来说,行列地址共用一组引脚,首先通过A0-A12读取行地址并暂存起来,然后下一个周期还是通过A0-A12读取列地址,然后把行列地址拼装起来成为最后的行列地址。
RAM芯片上还有BA1,BA0两个引脚,这也是单元地址的一部分,叫做LogicalBank,注意这里的Bank和S3C2440的内存空间BANK没有什么关系。内存控制器要只有把物理地址转换为【(BA1,BA0),(A0-A12),片选信号】,并且产生正确的时序才能完成内存单元的寻址。
开发板上SDRAM芯片信号为:LogicalBank大小为4M,共有4个LogicalBank,内存单元大小为16位(2字节),所以单片容量为:4 x 4 x 2 = 32MB。然后两个内存芯片并联后接入BANK6。
如何把物理地址转换为行列地址是内存控制器的工作,这也是初始化SDRAM的重要步骤。
3 S3C2440片外内存初始化方法
从前面的分析,我们知道程序内存地址到SDRAM内存单元地址的整个转换过程为:
虚拟地址---(MMU)---物理地址(内存控制器)---LogicalBank,行列地址,片选信号
目前我们没有启用MMU,也无需配置。现在要做的就是配置内存控制器,使其能够正确地把物理地址转换为行列地址和片选信号。
S3C2440片内集成了完整的内存控制器,我们只需要向相应的控制寄存器写入合适的数值即可完成配置。
2.1 与SDRAM有关的控制寄存器
BWSCON
BANKCON6
REFRESH
BANKSIZE
MRSR6
其中有些时间周期参数的设置依赖于HCLK的值,故需要记住在设置MPLL时产生的HCLK。上篇博文中我们设置的HCLK=200MHz,这个数值太大无法满足设置REFRESH中Tsrc的要求,所以本文实验时同时把HCLK修改成了100MHz,PCLK设置成了50MHz。由于此时FCLK:HCLK不再是1:1而是1:2,所以需要设置CPU的总线模式为异步模式,增加了相关设置代码。
在我们的试验中,FCLK=200MHz,HCLK=100MHz,也就是周期是10ns。
上述寄存器需要设置的值都在源码中了,在此贴出完整的设置代码:
2.2 配置源码
.equ WTCON, 0x53000000
.equ INTMSK, 0x4a000008
/* Fin=12MHz, FCLK=200MHz */
.equ MPLLCON, 0x4c000004
.equ M_MDIV, 92
.equ M_PDIV, 4
.equ M_SDIV, 1
/* Fin=12MHz, UPLLCLK = 48MHz */
.equ UPLLCON, 0x4c000008
.equ U_MDIV, 56
.equ U_PDIV, 2
.equ U_SDIV, 2
/* HCLK=FCLK/2=100MHz, PCLK=HCLK/2=50MHz, UCLK=UPLLCLK=48MHz */
.equ CLKDIVN, 0x4c000014
/*
if If HDIVN is not 0 and the CPU bus mode is the fast bus mode,
the CPU will operate by the HCLK
*/
.equ HDIVN, 1
.equ DIVN_UPLL, 0
.equ PDIVN, 1
/* SDRAM */
.equ BWSCON, 0x48000000
.equ BANKCON6, 0x4800001c
.equ REFRESH, 0x48000024
.equ BANKSIZE, 0x48000028
.equ MRSRB6, 0x4800002c
/* BWSCON */
.equ BWSCON_WS6, 0 /* wait status: disable */
.equ BWSCON_DW6, 2 /* data width : 32 */
/* BANKCON6 */
.equ B6_MT, 3 /* memory type: SDRAM */
.equ B6_Trcd, 0 /* Row to Col delay: 2 clocks,(min: 20ns)*/
.equ B6_SCAN, 1 /* Column address number */
/* BANKSIZE */
.equ BANKSIZE_VAL, 0xB1 /* 64MB for BANK7,6 */
/* REFRESH */
.equ REFRESH_ENABLE, 1
.equ REFRESH_MODE, 0
.equ REFRESH_Trp, 0
.equ REFRESH_Tsrc, 1
.equ REFRESH_COUNT, 1268
/* MRSRB6 */
.equ MRSRB6_VAL, 0x30 /* CL: 3 clock (min: 2.5ns )*/
.text
.global ResetEntry
/* interrupt vector */
ResetEntry:
b ResetHandler
b ResetHandler
b ResetHandler
b ResetHandler
b ResetHandler
b ResetHandler
b ResetHandler
b ResetHandler
/* The first instruction to run */
ResetHandler:
/* ----------- disable watch dog-------- */
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0]
/* ------- disable all interrupts------- */
ldr r0, =INTMSK
ldr r1, =0xffffffff
str r1, [r0]
/* -----------set clock--------------- */
ldr r0, =CLKDIVN
ldr r1, =(DIVN_UPLL<<3) + (HDIVN<<1) + PDIVN
str r1, [r0]
/*switch to asynchronous bus mode*/
.if HDIVN>1
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0xc0000000
mcr p15, 0, r0, c1, c0, 0
.endif
/* set up upll */
ldr r0, =UPLLCON
ldr r1, =(U_MDIV<<12) + (U_PDIV<<4) + U_SDIV
str r1, [r0]
nop
nop
nop
nop
nop
nop
nop
/* set up mpll */
ldr r0, =MPLLCON
ldr r1, =(M_MDIV<<12) + (M_PDIV<<4) + M_SDIV
str r1, [r0]
/* ----------------- set sdram -------------*/
ldr r0, =BWSCON
ldr r1, [r0]
ldr r2, =(1<<26 | 3<<24)
bic r1, r1, r2
ldr r2, =((BWSCON_WS6<<26) | (BWSCON_DW6<<24))
orr r1, r1, r2
str r1, [r0]
ldr r0, =BANKCON6
ldr r1, [r0]
ldr r2, =((1<<16) | (1<<15) | 0xF)
bic r1, r1, r2
ldr r2, =(B6_MT<<15 | B6_Trcd<<2 | B6_SCAN)
orr r1, r1, r2
str r1, [r0]
ldr r0, =REFRESH
ldr r1, [r0]
ldr r2, =(1<<23 | 1<<22 | 3<<20 | 3<<18 | 0x7FF)
bic r1, r1, r2
ldr r2, =(REFRESH_ENABLE<<23 | REFRESH_MODE<<22 | REFRESH_Trp<<20 | REFRESH_COUNT)
orr r1, r1, r2
str r1, [r0]
ldr r0, =BANKSIZE
ldr r1, =BANKSIZE_VAL
str r1, [r0]
ldr r0, =MRSRB6
ldr r1, =MRSRB6_VAL
str r1, [r0]
/* --------------set statck----------------- */
ldr sp, =0x34000000 /* must be aligned by 4 bytes */
/* call C function */
b Main
.end
4 开始使用片外内存
现在已经可以使用64MB的SDRAM了,这相对于片内的4KB SRAM来说已经相当大了,而且足以可以运行大型软件了。虽然目前我们的程序本身被加载到片内SRAM上运行,但是我们在代码中是可以使用[0x30000000,0x34000000)这个范围的SDRAM内存了。
首先我们可以把堆栈指针SP指向SDRAM中,这样C语言的函数参数和局部变量就自动被放到SDRAM里了。
其次我们可以直接通过C指针直接操作SDRAM的。
3.1 把堆栈设置到片外内存上
ldr sp, =0x34000000
就是这么简单的一条命令,就可以让C程序的堆栈搬迁到SDRAM中。
3.2 在片外内存上读写数据
void Main(void)
{
led_init();
int a = 10;
/* 测试栈是否在SDRAM上 */
if(((unsigned)&a) > 0x30000000) {
led_on(2);
}else{
led_off(2);
}
/* 在SDRAM上直接读写内存*/
int *pInt = (int*)0x30000000;
*pInt = 99;
if(*pInt == 99){
led_on(1);
}else{
led_off(1);
}
while(1){
;
}
}
5 下一步:把程序加载到SDRAM中
尽管目前我们可以直接操作SDRAM,但是程序代码本身并没有在SDRAM中运行。为此我们需要写一个loader,把程序加载到SDRAM中。loader可以和程序混合成一个程序,也可以两者分开。如果混合在一起那就是一个完整的能独立启动的程序,例如U-Boot。如果将两者分开,那么必须首先安装loader到NandFlash中,然后启动,通过命令加指定的程序到SDRAM执行。
下一步,将实验NANDFLASH读写操作,从而为代码搬迁做好准备。
上一篇:TQ2440开发板学习纪实(9)--- 利用Undefined异常模拟BLX指令
下一篇:TQ2440开发板学习纪实(3)--- 设置时钟频率,让CPU运行的更快
推荐阅读最新更新时间:2024-11-11 10:21
推荐帖子
- GPS原理与应用
- 介绍卫星导航概念、坐标系、GPS组成、卫星信号、接收机、干扰等内容,给出了许多工程实践知识。领域可能有点偏。GPS原理与应用
- linjingui 汽车电子
- 我是新来的,求大侠指导~
- 我是一个新手,有c基础,汇编以前也学过,现在想做嵌入式开发,不知道应该学那些东西,希望高手老师们能给我指点具体的学习里程,比如看什么书,先看什么后看什么,谢谢感谢你`~我是新来的,求大侠指导~看操作系统,具体的WINCE/LINUX这些东西上的驱动开发,应用开发吧呵呵光看书是不解决问题的OJT有问题请先GOOGLE,BAIDU有点难度哦以后需再关注,现在先帮你顶一下要做好工程师,必须动手。呵呵呵。引用8楼gooogleman的回复:要做好工程师,必须动手。
- lixiyuan999 嵌入式系统
- 我要为几天之后的电子设计大赛设计滤波器,频率比较高
- 论坛中的朋友们大家好,为了几天之后的电子设计大赛,我要设计一个矩形性质比较好的,较高频率的带通滤波器。老师提示我用L,C元件和集成运算放大器来设计,但是我接触到的资料都是RC有源滤波器,频率带宽等等条件不太满足,希望能得到各位的帮助。我要为几天之后的电子设计大赛设计滤波器,频率比较高参差放大器!它可以很好地满足所需。
- 张乡夫 模拟电子
- LED无线通信技术 "光照上网"或将实现,中国也参与研究了?
- 在英国爱丁堡大学任教的德国物理学家哈拉尔德·哈斯13日晚为公众作了一场报告,名为“我的Li-Fi革命”。他说,Li-Fi光照上网利用LED(发光二极管)照明灯以极高频率闪烁形成的脉冲来传输数据,最近的实验表明,单色5毫瓦LED照明灯和接收设备在1米和10米的距离上,数据传输速率可分别达到3.5Gbps和1.1Gbps(1bps为每秒1比特),用不同颜色的光还可以成倍提高数据传输速率。1.哪些因素影响传输速率?接收距离、光的颜色、光线强度2.光照上网有哪些优点?不
- qwqwqw2088 LED专区
- CC4008 四位二进制超前进位全加器
- 本文很详细的说明了CC4008四位二进制超前进位全加器的原理和过程CC4008四位二进制超前进位全加器
- rain 模拟电子
- 赵厚麟:运营商如何把握知识产权的运用
- IT时代周刊 在中国电信市场上,3G对整个电信市场格局从由“语音时代”向“信息多媒体时代”转换的影响是非常巨大的。运营商需要重新培育自己在业务、服务、综合运营方面的能力,同时也不能忽略在转型过程中所面临的潜在的知识产权问题。 一位参与通信标准制定的专利专家形象地比喻说:“在知识产权方面,现在我们仅仅感受到了在铺设3G道路时‘怎么修路’和‘怎么造车’的专利问题,而对于在这条信息高速公路上运营时‘交通管理’和‘有效配载货物’所涉及到的专利问题,我们还来不及关注,这方面的知识产权问题,对于我
- mdreamj RF/无线
设计资源 培训 开发板 精华推荐
- TAR5SB33 点稳压器(低压差稳压器)的典型应用
- IS31IO7328-QFLS4-EB,基于IS31IO7328多功能I/O驱动器的评估板
- 【物联网】鸿蒙智能WIFI开关+4238284A
- AM1DR-1209SH30Z 9V 1 瓦 DC-DC 转换器的典型应用
- 51时钟温度显示钟表(机器人协会样例)
- MAXREFDES1182:采用MAX17595的3.5W 3.3V离线反激转换器
- 使用 Analog Devices 的 LT1305CS8 的参考设计
- esp8266.T12焊台
- 用于 Intel 486TM DX4TM Overdrive 微处理器的 LT1584IT-3.3 3.3V/7A 低压差稳压器的典型应用
- 应用示例 - STM32F101xx 和 STM32F103xx 内核和系统外设中的 19 个
- ams光谱传感技术助力ELDIM快速检测出COVID-19
- SCHURTER PSE EX系列开关获得 ATEX / IECEx 认证,可用于防爆环境
- 扩大碳化硅供应,英飞凌联手GT Advanced Technologies
- IoXt提出八大嵌入式设备安全倡议
- 北京110个充电站将获2020年度第二批单位内部公用充电设施建设补助
- 800V功率模块,用IGBT还是SiC器件?
- 113kWh电池容量、830公里续航里程!解读Lucid Air电池系统
- 多地开放自动驾驶路测范围 智能汽车发展超预期
- 北斗星通最新一代 22nm 厘米级高精度定位芯片亮相
- Vishay推出超小型高性能器件,扩充TNPW e3系列高稳定性薄膜扁平片式电阻器