历史上的今天

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

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

发布者:chaohuangmeitao 来源: eefocus关键字:TQ2440  初始化  片外RAM  内存空间 手机看文章 扫描二维码
随时随地手机看文章

到目前为止,我们的程序只能使用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  初始化  片外RAM  内存空间 引用地址: 初始化片外RAM,让程序有更大内存空间

上一篇:TQ2440开发板学习纪实(9)--- 利用Undefined异常模拟BLX指令
下一篇:TQ2440开发板学习纪实(3)--- 设置时钟频率,让CPU运行的更快

推荐阅读

展会时间:2019年3月13日- 15日 展会地点:苏州国际博览中心B1、C1号馆 主办单位:中国物联网产业应用联盟、深圳市智慧零售协会、深圳市连锁经营协会、深圳市零售商业行业协会 承办单位:深圳市物联传媒有限公司、深圳市易信物联网络有限公司、苏州友智信物联网络有限公司 展会官网:www.urexpo.com.cn  同期活动: 展会:第十一届国际物联网博览...
原因串口进入了OR(过载错误)中断解决方法必须添加if(UART1_GetITStatus(UART1_IT_RXNE )!= RESET),若不添加,会导致UART1->DR被异常读取,不断进入中断处理函数若UART的RXNE状态位已经被置1,串口又收到数据,将会进入OR(过载错误)中断,需要先读取UART_SR,再读取UART_DR才可把OR位中断状态清零,调用UART1_GetITStatus(UART1_IT_RXNE )即是读取U...
仁宝受惠于产品组合改善,外资看好下半年毛利率表现将大幅改善,本季毛利率将达到3.3%,优于第2季的3.14%与去年同期的3.23%;第4季进入旺季,毛利率将进一步走扬。业内人士认为,虽然仁宝本季营收恐低于第2季,但仍看好获利、每股纯益有望优于上季。外资预估,仁宝本季营收将季减约3%至5%,但受惠于教育笔电需求畅旺、利润更高的非PC /非EMS业务带动下,...
具体实现功能本系统由STC89C51/52单片机+LCD1602显示模块+5mm红外接收管+LM358运放电路+按键模块等构成。具体功能:(1)手指放到红外对管中,2秒内读出心率;(2)LCD1602液晶显示当前的心率(心率/分钟);(3)按键可以设置报警的上下限心率,当测得的心率值超过报警值时发出报警。设计背景随着科学技术的发展,脉搏测量技术也越来越先进,对脉搏的测量...

史海拾趣

问答坊 | AI 解惑

有想去华为做嵌入式的吗?

华为一个新建立的部门。主要做嵌入式。 可以做内部推荐。用人比较急。 要求:本科生两年以上工作经验 研究生一年以上工作经验 方向与嵌入式 单片机 硬件驱动相关即可。 有意者发简历给我 jiaxinyu2008@yahoo.com.cn…

查看全部问答∨

晶振计算工具

晶振计算工具 晚上补充附件…

查看全部问答∨

DS18B20单总线温度传感器

DS18B20单总线温度传感器…

查看全部问答∨

会汇编语言对学习基于ARM的嵌入式编程有帮助吗?

会汇编语言对学习基于ARM的嵌入式编程有帮助吗? 谢谢~~…

查看全部问答∨

linux tftp启动的问题

rpm -q 存在tftp 和 tftp-server 进入vi /etc/xinetd.d/tftp 都配好了,disable =no 服务地址 /tftpboot 加了-s -c 也启动了xinetd,可就是启动不了tftp,测试的时候总是超时 在服务里tftp那项“开始”和“停止”都是灰的。也就是说没启动或者 ...…

查看全部问答∨

WINCE6下自动运行程序和任务栏相关问题

WINCE6下开机自动运行自己的应用程序,但偶尔会出现CE6的任务栏,怎么才能把任务栏给disable呢?…

查看全部问答∨

关于GX.DLL

客户要求我们的平台提供GX.DLL的支持,平台是Telechips 7901+wince 5.0. 以前没有搞过这个东东,从网上找了一些gx.dll都不合适,客户说,这个dll是根据我们的BSP自己编译出来的,我们也没有源码,不知道该如何做。 请用过gx.dll的大侠帮帮忙,我 ...…

查看全部问答∨

4200脉冲IV测量CMOS晶体管系统配置

4200-PIV[1]包在4200-SCS[2]主机更高编号的插槽中增加了2个卡,如图2所示。此外,脉冲IV的互连也显示在图2和3中。 图2. PIV的连接图     图3. 4200-SCP2侧视图。4200-SCP2[3]连接的适配器细节显示了示波器通道输入的BNC到SMA ...…

查看全部问答∨

求LPC11xx IAR启动文件

小弟想把keil mdk下的LPC1114工程移植到IAR for ARM下,目前来说已经成了一个半成品,在keil下工程调试时可以在IDE中复位MCU,然后从头开始运行。但这个功能在IAR下不知道为何就是无法正常使用,如果点击回到程序开头那个按钮,程序依然不会回去到m ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved