到目前为止,我们的程序只能使用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运行的更快
推荐阅读
史海拾趣
为了保持市场竞争力,Allied公司始终注重技术升级和品质提升。公司投入大量资金引进先进的生产设备和技术,不断提高产品的技术含量和附加值。同时,公司还建立了严格的质量管理体系,从原材料采购到产品出厂的每一个环节都进行严格把控,确保产品的品质和性能达到最高标准。
Allied公司深知客户是公司发展的核心动力。因此,公司始终将客户服务放在首位,为客户提供全方位、个性化的服务支持。无论是产品咨询、技术支持还是售后服务,Allied公司都力求做到最好,赢得了客户的信任和好评。同时,公司还积极与合作伙伴建立长期稳定的合作关系,共同开拓市场,实现互利共赢。
Allied公司成立于XXXX年,起初是一家小型电线电缆供应商。在创业初期,公司创始人凭借对电线电缆行业的深刻理解和丰富的行业经验,成功开发出了一系列质量上乘、性能稳定的电线电缆产品。通过不懈的努力和优质的客户服务,Allied公司逐渐在市场中树立起了良好的口碑,为后续的发展奠定了坚实的基础。
进入21世纪后,德利威电子加速了其国际化布局的步伐。2000年,公司在中国大陆东莞成立了德利威电子厂,并成功推动了5S运动(整理、整顿、清扫、清洁、素养),进一步提升了公司的管理水平。同时,公司还取得了ISO-9001国际认证标准,标志着其质量管理体系的进一步完善。此外,德利威电子还取得了德国TUV产品安规认证,进一步增强了其产品的国际竞争力。
Avalon Photonics始终坚持以客户需求为导向,不断进行产品创新。公司研发团队根据市场反馈,不断优化产品性能,同时推出了一系列定制化服务。某知名科研机构需要一种特殊规格的光子探测器,Avalon团队迅速响应,为其量身定制了解决方案。这一成功案例不仅赢得了客户的赞誉,也为公司带来了更多的定制化订单。
面对电子行业的快速变化,HANBIT Electronics始终保持敏锐的市场洞察力。2025年,公司宣布与一家领先的物联网技术公司达成战略合作,共同开发智能家居解决方案。这一跨界合作不仅为HANBIT Electronics带来了新的增长点,也使其能够借助物联网技术的力量,进一步拓展在智能家居、智慧城市等新兴领域的应用。通过不断探索和尝试,HANBIT Electronics在保持传统业务优势的同时,也为公司的未来发展开辟了新的道路。
华为一个新建立的部门。主要做嵌入式。 可以做内部推荐。用人比较急。 要求:本科生两年以上工作经验 研究生一年以上工作经验 方向与嵌入式 单片机 硬件驱动相关即可。 有意者发简历给我 jiaxinyu2008@yahoo.com.cn… 查看全部问答∨ |
|
rpm -q 存在tftp 和 tftp-server 进入vi /etc/xinetd.d/tftp 都配好了,disable =no 服务地址 /tftpboot 加了-s -c 也启动了xinetd,可就是启动不了tftp,测试的时候总是超时 在服务里tftp那项“开始”和“停止”都是灰的。也就是说没启动或者 ...… 查看全部问答∨ |
|
4200-PIV[1]包在4200-SCS[2]主机更高编号的插槽中增加了2个卡,如图2所示。此外,脉冲IV的互连也显示在图2和3中。 图2. PIV的连接图 图3. 4200-SCP2侧视图。4200-SCP2[3]连接的适配器细节显示了示波器通道输入的BNC到SMA ...… 查看全部问答∨ |
小弟想把keil mdk下的LPC1114工程移植到IAR for ARM下,目前来说已经成了一个半成品,在keil下工程调试时可以在IDE中复位MCU,然后从头开始运行。但这个功能在IAR下不知道为何就是无法正常使用,如果点击回到程序开头那个按钮,程序依然不会回去到m ...… 查看全部问答∨ |