历史上的今天
返回首页

历史上的今天

今天是:2024年09月16日(星期一)

2021年09月16日 | 初始化片外RAM,让程序有更大内存空间

2021-09-16 来源:eefocus

到目前为止,我们的程序只能使用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读写操作,从而为代码搬迁做好准备。

推荐阅读

史海拾趣

ERP公司的发展小趣事

为了进一步拓展市场和提高竞争力,电子智链开始寻求与其他企业建立生态合作关系。公司与多家电子制造设备供应商、原材料供应商和物流服务商建立了战略合作关系,共同打造了一个覆盖电子产业全链条的生态圈。这一合作模式不仅为客户提供了更加全面和高效的解决方案,还促进了整个电子产业的协同发展。

Barnbrook Systems Limited公司的发展小趣事

Barnbrook Systems Limited的创始人在电子工程领域拥有深厚的背景,他们看到了市场对于高效能计算设备的需求。于是,公司应运而生,初期专注于研发高性能的电路板。通过不断的技术创新和优化,Barnbrook成功开发出一款具有革命性的电路板,其稳定性和处理速度远超当时市场上的同类产品。这一突破性的技术为Barnbrook赢得了众多客户的青睐,也为公司的快速发展奠定了坚实的基础。

Denyo Europa Gmbh公司的发展小趣事

随着技术的成熟,Denyo Europa Gmbh公司开始将目光投向国际市场。公司利用自身的技术优势,结合对目标市场的深入调研,制定了一系列市场拓展策略。通过与当地合作伙伴的紧密合作,公司成功将产品打入多个国家和地区,实现了业务的全球化布局。这一过程中,公司不仅积累了宝贵的国际市场经验,也为公司的持续发展奠定了坚实基础。

ACCUTEK公司的发展小趣事

ACCUTEK公司成立于XXXX年,起初只是电子行业中的一家小型初创企业。创始人凭借对电子技术的深入理解和市场趋势的敏锐洞察,决定专注于高精度数控设备的研发和生产。公司初期面临着资金短缺、技术瓶颈和市场认可度低等挑战,但凭借团队的坚持和不懈努力,逐渐在市场中站稳脚跟,赢得了初步的客户信任。

Ambersil公司的发展小趣事

Ambersil公司深知人才是企业发展的核心力量。因此,公司一直注重人才培养和引进。公司建立了完善的人才培养和激励机制,鼓励员工不断学习和创新。同时,公司还积极引进外部优秀人才,为公司的发展注入新的活力。这些举措使得Ambersil公司的团队更加专业、高效,为公司的未来发展奠定了坚实的基础。

以上五个故事虽然基于虚构,但其中的元素和情节在电子行业的发展历程中并不罕见。它们或许能够为您了解电子行业内的公司发展提供一定的参考。如果需要更具体、更详细的故事,建议查阅相关公司的官方资料或行业报告。

联智(Celfras)公司的发展小趣事

为了更好地推动快充技术的发展和应用,联智加入了终端快充行业协会。作为该协会的成员,联智积极贡献自身在快充协议、电源管理无线充电芯片和方案研发方面的经验和技术,与协会其他成员共同推动充电技术的标准化、产业化应用和推广。这一举措不仅有助于提升联智在快充行业的知名度和影响力,还将促进整个行业的健康发展。

问答坊 | AI 解惑

LED数码管知识简介

replyreload += \',\' + 374455;Timson,如果您要查看本帖隐藏内容请回复…

查看全部问答>

Windows7与wince常用开发环境的兼容性问题

最近打算买台新电脑,想试试Windows7,不知道与wince的开发环境兼容性如何 我一般用到的软件有:PB5.0 EVC VS2005 VC++6.0 ADS1.2 Keil3…

查看全部问答>

关于TE2440-II 显示问题

TE2440-II的VGA是通过CH7026来把LCD信号转换成VGA信号的,我对比了下和阳初的BSP发现个问题,TE2440-II里找不到VGAinit,而且在KERNEL里的CFW.C文件中initdisplay函数中也没有关于VGA的初始化问题,请问TE2440-II的CH7026的控制程序在哪个地方啊(芯 ...…

查看全部问答>

求助

在微软的adocepbzip安装包的adocepb\\setup\\Data Access 3.1\\Program Files\\DataAccess31\\INCLUDE目录下,有这样两个文件adoce31.idl和adocec31.idl,在命令行中执行midl adoce31.idl和midl adocec31.idl即可生成.h文件. 为什么我的生不成啊 ...…

查看全部问答>

哪里有PowerPC开发培训

11月祥佑PowerPC嵌入式系统开发培训班 开始报名了 开课时间:2008年11月,为期三天。 上课地点:上海 课程教材:《PowerPC嵌入式开发系统实验教材》 收费标准: 4000元/人 注:本次开班7折优惠:2800元/人。(含讲义费,午餐费) 课程特点: ...…

查看全部问答>

力保产品质量 佛山发布LED筒灯联盟标准

 佛山本土的LED筒灯联盟标准近日在佛山市质监局发布。据悉,该标准由佛山市标准技术研究院、佛山市照明灯具协会、中山大学佛山研究院联合本土7家LED企业发起制定。   据悉,佛山是全国最大的筒灯生产基地,筒灯产量约占全国40%左右,目前已有120 ...…

查看全部问答>

Magafunction的用法

As design complexities increase, use of vendor-specific intellectual property (IP) blocks has become a common design methodology. Altera provides parameterizable megafunctions that are optimized for Altera device architectures. ...…

查看全部问答>

定时器0中断

本帖最后由 dontium 于 2015-1-23 13:29 编辑 我从EEWORLD网站上载了一些例子,学习2812。 没有电路板,只进行软件仿真。 其中一个定时器0中断,发现不进中断。 情况是这样的,观察定时器可以计数。 本来我定时器周期设为0XFFFFFFFF. 可是计 ...…

查看全部问答>

请教,在用IAR软件仿真单步运行程序时怎样才能使它不跳入中断?

请教,在用IAR软件单步运行程序时怎样才能使它不跳入中断?…

查看全部问答>

大家一起来讨论一哈16位计数器TAR的用法(针对169)

Q1:当Timer_A的捕获比较模块工作在捕获模式(即CAP = 1)时,TAR是里面的值表示什么含义?它是在对什么进行计数? Q2:TAR中的值写入CCRx后,TAR会自动清零吗?此时TAIFG的状态和TAR有关吗?…

查看全部问答>