ARM2440ddr.h文件解读

发布者:cwm6269310最新更新时间:2015-01-15 来源: 51hei关键字:ARM2440  ddr  文件解读 手机看文章 扫描二维码
随时随地手机看文章
板子上电后就会从这里开始执行,主要完成基本初始化,还有判断是从nor还是nand启动,再实现把程序搬到SDRAM当中,在搬运成功后再跳到main函数里面执行。
 
我们现在开始来看看它的具体代码吧!
 
GET和INCLUDE的功能是相同的,功能都是引进一些编译过的文件。
 
 GET option.inc
 GET memcfg.inc
 GET 2440addr.inc
 
定义SDRAM工作在Reflesh模式下,SDRAM有两种刷新模式:selfreflesh,autoreflesh。后者是在其使用过程当中设置的。
 
 BIT_SELFREFRESH EQU (1<<22)
 
下面是对arm处理器模式寄存器对应的常数进行赋值,arm处理器有一个CPSR寄存器,它的后五位决定了处理器处于哪个模式下。可以看出常数的定义都不会超过后5位的。
 
USERMODE    EQU  0x10
FIQMODE     EQU  0x11
IRQMODE     EQU  0x12
SVCMODE     EQU  0x13
ABORTMODE   EQU  0x17
UNDEFMODE   EQU  0x1b
MODEMASK    EQU  0x1f
NOINT       EQU  0xc0
各个异常模式的堆栈
 
UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~
SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;0x33ff5800 ~
UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;0x33ff5c00 ~
AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;0x33ff6000 ~
IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;0x33ff7000 ~
FIQStack EQU (_STACK_BASEADDRESS-0x0) ;0x33ff8000 ~
这一段是统一arm的工作状态和对应的软件编译方式(16位编译环境使用tasm.exe编译)。arm处理器的工作状态分为两种:32位,arm执行字对齐的arm指令集;16位,arm执行半字对齐的Thumb指令集。不同的工作状态,编译方式也不一样。所以下面的程序就是判断arm的工作方式来确定它的编译方式。
 
 GBLL    THUMBCODE//定义THUMBCODE 这个变量GBLL 声明一个全局逻辑变量并初始化为{FALSE}
 [ {CONFIG} = 16//"["表示"if","|"表示"else","]"表示"endif",对于CONFIG是在ADS编译中定义的内部变量。
THUMBCODE SETL  {TRUE}
     CODE32
   |
THUMBCODE SETL  {FALSE}
    ]//如果ARM是在16位的工作状态的话,就使全局变量THUMBCODE设置为ture。
 
   MACRO//这个是宏定义的关键字
 MOV_PC_LR//作用是子程序返回
   [ THUMBCODE
     bx lr//当目标程序是Thumb时,就要使用BX跳转返回,并转换模式。
   |
     mov pc,lr//目标程序是ARM指令集,直接把lr赋给pc就可以了。
   ]
 MEND//宏定义的结束标志。
 
   MACRO
 MOVEQ_PC_LR//这个是带“相等”条件的子程序返回。和上面说的类似。
   [ THUMBCODE
        bxeq lr
   |
     moveq pc,lr
   ]
 MEND
 
在宏定义下面的handlexxx HANDLER handlexxx都会展成以下的程序段,这段程序主要把中断服务程序的入口地址传送给pc,在程序的用34字空间来存放中断服务程序的入口地址,每个字空间都会有一个标号,以handlerxxx开头的。
 
 MACRO
$HandlerLabel HANDLER $HandleLabel
 
$HandlerLabel
 sub sp,sp,#4 //先预留空间,为了存储跳转地址。
 
 stmfd sp!,{r0} //把工作寄存器按入堆栈。
 ldr     r0,=$HandleLabel
 ldr     r0,[r0] //这两句的功能是把中断程序的入口地址先放在中间变量r0处。
 
 str     r0,[sp,#4]//把中断服务程序的入口地址按入堆栈。     
 ldmfd   sp!,{r0,pc}//最后把堆栈中的中断程序入口地址弹给pc寄存器,这样就可以执行相应的中断服务程序了。    
 MEND
 
S3C2440有两种中断模式:一种有中断向量表的,一种则没有。有表的话实时性比较好。当一个外部中断0发生后,程序自动跳转到地址0x20处,0x20地址单元的指令为“ldr pc, = HandlerEINT0”,因此程序跳转到HandlerEINT0处执行这个宏操作,就是把外部中断地址赋给PC。
 
一个arm程序是由R0,RW,ZI三个段组成。其中R0为代码段,RW是已经初始化的全局变量,ZI是未初始化的全局变量,BOOTLOADER要将RW段复制到RAM中并将ZI段清零。
 
编译器使用下列段来记录各段的起始地址和结束地址
|Image$$RO$$Base| ; RO 段起始地址|Image$$RO$$Limit| ; RO 段结束地址加1|Image$$RW$$Base| ; RW 段起始地址
 
|Image$$RW$$Limit| ; RW 段结束地址加1|Image$$ZI$$Base| ; ZI 段起始地址|Image$$ZI$$Limit| ; ZI 段结束地址加1
 
这些标号的值是通过编译器的设定来确定的如编译软件中对ro-base 和rw-base 的设定,例如ro-base=0xc000000 rw-base=0xc5f0000,在这里用IMPORT 伪指令( 和c 语言的extren 一样) 引入|Image$$RO$$Base|,|Image$$RO$$Limit|...等比较古怪的变量是编译器生成的。RO, RW, ZI 这三个段都保存在Flash 中,但RW,ZI 在Flash 中的地址肯定不是程序运行时变量所存储的位置,因此我们的程序在初始化时应该把Flash 中的RW,ZI 拷贝到RAM 的对应位置。这些变量是通过ADS 的工程设置里面设定的RO Base 和RW Base 设定的,最终由编译脚本和连接程序导入程序.
 
IMPORT |Image$$RO$$Base|
 
IMPORT |Image$$RO$$Limit|
 
IMPORT |Image$$RW$$Base|
 
IMPORT |Image$$ZI$$Base|
 
IMPORT |Image$$ZI$$Limit|
 
引入外部变量mmu的快速总线模式和同步总线模式两个变量
 
IMPORT MMU_SetAsyncBusMode
IMPORT MMU_SetFastBusMode
 
我们所熟知的main函数
 
IMPORT  Main
 
把镜像从Nandflash拷贝到SDRAM的函数
 
IMPORT  RdNF2SDRAM
 
定义arm汇编程序段,段名叫init段,为只读段
 
       AREA    Init,CODE,READONLY
 
       ENTRY
 
       EXPORT __ENTRY//导出__ENTRY标号
__ENTRY
ResetEntry
 
ASSERT :DEF:ENDIAN_CHANGE//判断模式改变是否定义过(ASSERT是伪指令,:DEF:lable判断lable是否定义过了)
 
[ ENDIAN_CHANGE
  ASSERT  :DEF:ENTRY_BUS_WIDTH//判断是否定义了总线宽度
 
  [ ENTRY_BUS_WIDTH=32//如果存储器是32位的总线宽度
   b ChangeBigEndian     ;DCD 0xea000007
  ]
 
  [ ENTRY_BUS_WIDTH=16//如果存储器是16位的总线宽度
   andeq r14,r7,r0,lsl #20   ;DCD 0x0007ea00
  ]
 
  [ ENTRY_BUS_WIDTH=8//如果是存储器是8位总线宽度
   streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
  ]
 
|//如果总线宽度没有定义的话,就直接跳转到复位中断
  b ResetHandler//程序执行的地跳跳转指令
 
]
 
 b HandlerUndef ;handler for Undefined mode
 b HandlerSWI ;handler for SWI interrupt
 b HandlerPabort ;handler for PAbort
 b HandlerDabort ;handler for DAbort
 b .  ;reserved
 b HandlerIRQ ;handler for IRQ interrupt
 b HandlerFIQ ;handler for FIQ interrupt
 
;@0x20
 b EnterPWDN ; Must be @0x20.//进入powerdown模式
 
以上8条跳转指令,是8个异常中断处理向量,一定要按照顺序排好,据我了解,每次出现异常的话,是由硬件自行查表的。
 
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
 
下面这段程序很重要,他是实现第二次查表的程序。arm把所有中断都归为一个IRQ和一个FIRQ中断异常,我们为了要知道具体的中断,从而才可以跳到中断对应的中断服务程序。
 
IsrIRQ
 sub sp,sp,#4       //保留pc寄存器的值
 stmfd sp!,{r8-r9}//把r8 r9按入堆栈
 
 ldr r9,=INTOFFSET//把中断偏移INTOFFSET的地址装入r9里面
 ldr r9,[r9]//取出INTOFFSET单元里面的值给r9
 ldr r8,=HandleEINT0//向量表的入口地址赋给r8
 add r8,r8,r9,lsl #2//求出具体中断向量的地址
 ldr r8,[r8]//中断向量里面存储的中断服务程序的入口地址赋给r8
 str r8,[sp,#8]//按入堆栈
 ldmfd sp!,{r8-r9,pc}//堆栈弹出,跳转到相应的中断服务程序
 
 
 
 LTORG//声明文字池
 
板子上电后就,程序就执行0x00处的b ResetHandler
 
ResetHandler
 ldr r0,=WTCON     //关闭看门狗  
 ldr r1,=0x0
 str r1,[r0]
 
 
 
 ldr r0,=INTMSK
 ldr r1,=0xffffffff  //关闭所有中断
 str r1,[r0]
 
 ldr r0,=INTSUBMSK
 ldr r1,=0x7fff  //关闭所有子中断
 
 str r1,[r0]
 
 
 
 [ {FALSE}
  ;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
  ; Led_Display
  ldr r0,=GPBCON
  ldr r1,=0x155500
  str r1,[r0]//使GPB10~GPB4为输出口,GPB3~GPB0为输入口
  ldr r0,=GPBDAT
  ldr r1,=0x0
  str r1,[r0]//使GPB10~GPB4输出为低电平,GPB3~GPB0输入为低电平
 ]
 
通过数据手册可以发现,当输出为1时,LED灭,反之亦然。
 
LOCKTIME是pll的lock time计数器。为了减少pll的lock time,调整LOCKTIME寄存器。
 
 ldr r0,=LOCKTIME
 ldr r1,=0xffffff//赋给这个值后,UPLL和MPLL的locktime的值都会设定好了。具体为什么是设定这个值,你就去问问三星公司吧,我也不太懂。
 str r1,[r0]
说到这里,大家可能不太懂。我就在这里细说一下吧。这个涉及到arm9的时钟模块的知识。arm9有个时钟控制逻辑,它可以产生cpu的FCLK时钟、AHB总线外围接口器件的HCLK时钟以及APB总线外围接口器件的PCLK时钟。arm9有两个锁相环PLL,一个用于FCLK、HCLK、HCLK。一个用于USB模块。这两个PLL我们分别称之为MPLL和UPLL。在系统复位之后,PLL按照默认的配置进行操作,由于认为它这时是一个不稳定的状态,所以这时用外部时钟作为FCLK时钟的输出。只有当向PLLCON寄存器设置相应的值后,PLL就会按照软件设置的频率运行了。这时就换成使用PLL的输出作为FCLK了。对于FCLK先后不是有两次不同时钟作为输入,这样就余姚一个适应的时间,这个时间的设定就是我们这里在LOCKTIME寄存器里面设置的常数啦。
 
[ PLL_ON_START//设置CLKDIVN的值在PLL锁存时间之后有效。
 
  ldr r0,=CLKDIVN
 
  ldr r1,=CLKDIV_VAL  ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.
  str r1,[r0]
 
可以看出是对FCLK、PCLK以及HCLK三者的比率设置。只要通过对CLKDIVN执行操作就可以得到相应需要的比率了。
 
  [ CLKDIV_VAL>1   //如果 Fclk:Hclk不是1:1的话执行下面
 
    mrc p15,0,r0,c1,c0,0
    orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA
    mcr p15,0,r0,c1,c0,0
   |
    mrc p15,0,r0,c1,c0,0
    bic r0,r0,#0xc0000000;R1_iA:OR:R1_nF
    mcr p15,0,r0,c1,c0,0
  ] 
 
这里可以看出,如果FCLK:HCLK不是1:1的关系的话,就要转成异步总线模式。反之,如果是这个比例关系的话,就转成快速总线模式。
 
  ldr r0,=UPLLCON//对UPLL进行配置
  ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)//这里就是非常熟悉的PMS啦,Fin = 12.0MHz, UCLK = 48MHz
  str r1,[r0]
  nop ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed.
  nop
  nop
  nop
  nop
  nop
  nop
  ldr r0,=MPLLCON//对MPLL进行配置
  ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)    ;Fin = 12.0MHz, FCLK = 400MHz
  str r1,[r0]
 ]
 
 ldr r1,=GSTATUS2
 ldr r0,[r1]
 tst r0,#0x2
 
判断是否是从休眠模式唤醒的,对GSTATUS2[2]的检测就可以判断出是否从休眠模式唤醒的。
 
bne WAKEUP_SLEEP//如果是的话就跳转。
 
EXPORT StartPointAfterSleepWakeUp//定义一个外部的StartPointAfterSleepWakeUp
 
StartPointAfterSleepWakeUp
 
    adrl r0, SMRDATA 
    ldr r1,=BWSCON 
    add r2, r0, #52 
 
0
    ldr r3, [r0], #4
    str r3, [r1], #4
    cmp r2, r0
    bne %B0
 
这段代码的作用就是设置存储控制器。在代码的后面有一个SMRDATA的数据区,用r0来定义它的起始地址,用r2来定义它的结束地址。r3是代表那13个存储控制器.代码很明显,就是把内存的数据赋给这13个存储控制器里面的。
 
 ldr r0,=GPFCON
 ldr r1,=0x0
 str r1,[r0]//对GPF设置为输入的功能
 ldr r0,=GPFUP
 ldr r1,=0xff
 str r1,[r0]//禁止上拉电阻
 
 ldr r1,=GPFDAT
 ldr r0,[r1]
 bic r0,r0,#(0x1e<<1)//bic是r0与#(0x1e<<1)的反码按位相与。
 tst r0,#0x1//这里就是测试最后一位是否为0,为0时说明是有按键按下了。
 bne %F1//当按键0没有被按下的时候,就跳转啦。
这段代码是检测EINT0是否被按下了。
 
 ldr r0,=GPFCON
 ldr r1,=0x55aa
 str r1,[r0]//GPF7~GPF4设置为输出,GPF3~GPF0设置为EINT0~EINT3
 
 ldr r0,=GPFDAT
 ldr r1,=0x0
 str r1,[r0] //很明显,GPF7~GPF4设置为LED灯的控制,低电平全部亮了。起到指示的用途。
 
 mov r1,#0
 mov r2,#0
 mov r3,#0
 mov r4,#0
 mov r5,#0
 mov r6,#0
 mov r7,#0
 mov r8,#0
 
 
 
 ldr r9,=0x4000000   ;64MB
 ldr r0,=0x30000000
 
 
 
 stmia r0!,{r1-r8}
 subs r9,r9,#32
 bne %B0
 
很明显可以看出,程序利用r1~r8这几个寄存器把0x30000000到0x34000000的内存全部清零了。
 
1
 
 bl InitStacks//初始化堆栈
 
 
 ldr r0, =BWSCON
 ldr r0, [r0]
 ands r0, r0, #6//OM[1:0] != 0, 从NOR FLash或者内存启动,不用读取NAND FLASH
 bne copy_proc_beg//不需要从NAND FLASH启动就在这里跳转啦
 
 adr r0, ResetEntry//OM[1:0] == 0,就从NAND FLash启动 
 cmp r0, #0//在进行比较,是否入口地址是在0处,如果不是则是用仿真器   
 bne copy_proc_beg//仿真器也不需要在NAND FLASH启动
 
nand_boot_beg
 [ {TRUE}
  bl RdNF2SDRAM
 ]
 
  ldr pc, =copy_proc_beg
 
我们来看下RdNF2SDRAM具体是怎么工作的,这段代码的作用就是把NAND的程序读到RAM里面。
 
 void RdNF2SDRAM( )
{
  U32 i;
  U32 start_addr = 0x0;
  unsigned char * to = (unsigned char *)0x30000000;
  U32 size = 0x100000;//可以算出是8M的大小。
  rNF_Init();//我们来仔细看看这个函数吧。
 
  如下:
 
         static void rNF_Init(void)
{
 rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);//TACLS=1,TWRPH0=4,TWRPH1=0初始化ECC,CLE&ALE持续时间的设置,TWRPH0和TWRPH1持续时间的设置。
 rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);//在读写NANDFLASH之前,对6,5,4位的设置是确保可以使用ECC;对13位清零,使得可以写,擦除还有读0x4E000038~0x4E00003C区域的内容;由于对于这范围区域的读写我们不加任何限制,所以我们就不用设置中断来通知系统这个范围的区域被读写了,也就是10位清零了;RnB是表示存储器现在是否处于忙碌状态,9位的设置为1时,表示可以用中断来通知CPU现在存储器的状态,而8位的设置是用来说明是上升沿触发还是下降沿触发。
 
 rNFSTAT = 0;
 rNF_Reset();
}
 
我们来看下rNF_Reset()它的具体代码吧,代码如下:
 
static void rNF_Reset()
{
 NF_CE_L();
 NF_CLEAR_RB();
 NF_CMD(CMD_RESET); 
 NF_DETECT_RB();
 NF_CE_H();
}
 
代码看上去很烦人,其实不是的,就是一堆宏定义,我直接翻译一下吧,翻译如下:
 
rNFCONT &= ~(1<<1); //位1清零,表示片选使能,这样片子就可以工作了。
 
rNFSTAT |= (1<<2);//清零2位,这里不需要判断片子是否忙碌。
 
rNFCMD  = (CMD_RESET);//其中CMD_RESET=0xff。
 
while(!(rNFSTAT&(1<<2)));//当RnB从低电平变换到高电平的时候,就会跳出这个循环。就是在等待NANDFLASH操作完毕。
 
rNFCONT |= (1<<1);//使片子停止工作。
 
这样NANDFLASH的初始化工作终于完成了。我们现在回到RdNF2SDRAM里面来,接着往下分析。
 
switch(rNF_ReadID())我们来分析一下里面这个函数吧,代码如下:
 
static char rNF_ReadID()
{
 char pMID;
 char pDID;
 char nBuff;
 char n4thcycle;
 int i;
 
 
 NF_nFCE_L();//又是使能片子工作   
 NF_CLEAR_RB();//清除NFSTAT的2位,为以后判断片子是否工作完毕。
 NF_CMD(CMD_READID); //往NFCMD送读ID指令。
 NF_ADDR(0x0);//往NFADDR送地址
 for ( i = 0; i < 100; i++ );
 
 pMID = NF_RDDATA8();
 pDID = NF_RDDATA8();
 
 nBuff     = NF_RDDATA8();
 n4thcycle = NF_RDDATA8();
 NF_nFCE_H();
 
 
 return (pDID);
}//最后返回pDID为什么会有其它值,我就不太理解了。我们再返回到主程序里面看看。
 
switch(rNF_ReadID())
 {
  case 0x76:
   for(i = (start_addr >> 9); size > 0; )//在这种情况下,认为一页的大小为512字节
   {
    rSB_ReadPage(i, to);
    size -= 512;
    to += 512;
    i ++;
   }
   break;
  case 0xf1:
  case 0xda:
  case 0xdc:
  case 0xd3:
   for(i = (start_addr >> 11); size > 0; )//在这种情况下,认为是2048字节为一页
   {
    rLB_ReadPage(i, to);
    size -= 2048;
    to += 2048;
    i ++;
   }
   break;
 }
}  
 
其实都是把NANDFLASH的开始第二页的内容存放在一个指针数组里面,这个指针数组的起始地址在0x30000000。就是我们等下在下面看到的to[i]数组了。下面两个函数完成的功能是一样的,只是区别在于一页是多大,512或者是2048。
 
static void rSB_ReadPage(U32 addr, unsigned char * to)
{
 U32 i;
 
 rNF_Reset();
 
 //  Enable the chip
 NF_nFCE_L();
 NF_CLEAR_RB();
 
 // Issue Read command
 NF_CMD(CMD_READ);
 
 //  Set up address
 NF_ADDR(0x00);
 NF_ADDR((addr) & 0xff);
 NF_ADDR((addr >> 8) & 0xff);
 NF_ADDR((addr >> 16) & 0xff);
 
 
 NF_DETECT_RB();  // wait tR(max 12us)
 
 for (i = 0; i < 512; i++)
 {
  to[i] =  NF_RDDATA8();
 }
 
 NF_nFCE_H();
 
}
static void rLB_ReadPage(U32 addr, unsigned char * to)
{
 U32 i;
 
 rNF_Reset();
 
 //  Enable the chip
 NF_nFCE_L();  
 NF_CLEAR_RB();
 
 // Issue Read command
 NF_CMD(CMD_READ);
 
 //  Set up address
 NF_ADDR(0x00);
 NF_ADDR(0x00);
 NF_ADDR((addr) & 0xff);
 NF_ADDR((addr >> 8) & 0xff);
 NF_ADDR((addr >> 16) & 0xff);
 
 NF_CMD(CMD_READ3);
 
 NF_DETECT_RB();  // wait tR(max 12us)
 
 for (i = 0; i < 2048; i++)
 {
  to[i] =  NF_RDDATA8();
 }
 
 NF_nFCE_H();
 
}
 
可以看出刚开始的时候都是先复位一下的,不同的地方在于每次是怎样把传进来的地址经过转换再付给NFADDR寄存器的,具体怎么样要看NAND的数据手册。
 
 我们接着回到2440init.s的程序来,接着就有以下一句:
 
ldr pc, =copy_proc_beg
 
在前面也看到copy_proc_beg这个标号出现很多次,这个标号下面的代码完成的功能就是把nand flash的内容拷贝到ram当中。
 
copy_proc_beg
 adr r0, ResetEntry
 ldr r2, BaseOfROM
 cmp r0, r2//两个进行比较
 ldreq r0, TopOfROM//如果相同的话,为r0赋上R0的结束位置,也是RW的起始位置。
 beq InitRam //如果相同的话,就跳到这个标号的位置。
 
 ldr r3, TopOfROM//以下代码是针对代码在NOR FLASH时的拷贝方法。
 ldmia r0!, {r4-r7}
 stmia r2!, {r4-r7}
 cmp r2, r3
 bcc %B0//这几段代码的功能就是把ResetEntry的内容搬到BaseOfROM(R0的起始位置,后面有声明的)。
 
 sub r2, r2, r3
 sub r0, r0, r2 //这里使 ResetEntry的位置往下移,为了后面的数据拷贝做准备。  
  
InitRam 
 ldr r2, BaseOfBSS
 ldr r3, BaseOfZero 
0
 cmp r2, r3
 ldrcc r1, [r0], #4
 strcc r1, [r2], #4
 bcc %B0 //可以看出这一段是对ResetEntry里面定义好的数据拷贝到RW段。
 
 mov r0, #0
 ldr r3, EndOfBSS
 cmp r2, r3
 strcc r0, [r2], #4
 bcc %B1//如果拷贝完数据后还剩下多余的空间的话,就往里面填充0
 
 ldr pc, =%F2  ;goto compiler address
2
 
 ldr r0,=HandleIRQ 
 ldr r1,=IsrIRQ 
 str r1,[r0]//这三条语句很明显就是说明了,HandleIRQ这个中断向量的存储单元被赋上了IsrIRQ标号的地址,这样发生IRQ中断后就会直接去到二级表,去确认具体发生哪个中断。
 
 
 
    [ :LNOT:THUMBCODE
   bl Main //到这里,我们就看到了进入MAIN函数了。
   b .
    ]
 
    [ THUMBCODE  ;for start-up code for Thumb mode
   orr lr,pc,#1
   bx lr
   CODE16
   bl Main //可以看到以上代码表示如果arm是在THUMBCODE指令模式下的话,就进行模式转换。
 
   b .
  CODE32
    ]
 
到这里,我们已经把2440init.s的启动代码分析了一遍了。如有任何错误的话,请大家指出!谢谢!
关键字:ARM2440  ddr  文件解读 引用地址:ARM2440ddr.h文件解读

上一篇:基于ARM的海洋环境地磁场三分量测量仪的设计
下一篇:基于ARM7和CAN总线的电子送经卷取系统设计

推荐阅读最新更新时间:2024-03-16 13:51

arm2440的nandflash相关函数
K9F2G08U0A nand flash 的容量为256M byte,其内部有2048块,每块有64页,每页有2K+64字节,其中每页会分为main区(主域)和spare区(备用域),main区一般用来存入主要数据,spare一般用来存放ECC校验码。 下面几点是编程时需要注意的: 1.NAND FLASH芯片手册里说的column是指页内地址,row是指页地址,page也是指页; 2.删除时是以块为单位的,但是删除块时写的是row地址,自动会删除row所在的块; 3.读写方式有页读写,或随机读写,所谓的随机读写就是可以在页内的任一地方读写一个字节; 4.ECC校验码分为main区的ECC和spare区的ECC,它们一
[单片机]
Spartan-3A 的 DDR 2 接口数据采集
1 引言 DDR2(Double Data Rate2)SDRAM是由JEDEC(电子设备工程联合委员会)制定的新生代内存技术标准,它与上一代DDR内存技术标准最大的不同:虽然采用时钟的上升/下降沿同时传输数据的基本方式,但DDR2却拥有2倍的DDR预读取能力(即4位预存取技术)。此外,DDR2还增加ODT(内建核心终结电阻器)功能,内建合适的终结电阻,避免了以往因片外连接大片终结电阻带来的制板成本增加。 基于FPGA的SDRAM控制器,以高可靠性、强可移植性、易于集成的特点,逐渐取代以往的专用控制器而成为主流解决方案。本文采用Xilinx公司的Spartan-3A系列FPGA和Hynix公司的DDR2 SDRAM器件HY5P
[嵌入式]
Spartan-3A 的 <font color='red'>DDR</font> 2 接口数据采集
三星推出全球最佳性能32GB DDR3内存模组
  三星电子于24日宣布,将从本月开始在全球率先量产30纳米级4Gb(bit) DDR3(Double Data Rate 3) DRAM基板的32GB(byte)内存模块。据悉,30纳米级32GB DDR3内存模组具有高性能、低功耗、大容量等特点,能够在1.35伏的电压下达到1.866Mbps传输速度,最适合应用于最新高性能的服务器,和现有的40纳米级32GB DDR3模组(1.5伏/1.333 Mbps )相比,不仅可以节省18%的能耗,而且将数据传输速度提高了40%。   而据记者的了解,原有的40纳米 32GB DDR3内存于2011年获得了美国CES国际消费电子展评选的环保产品创新奖,这样对比看来,30纳米级32GB
[嵌入式]
三星推出全球最佳性能32GB <font color='red'>DDR</font>3内存模组
奇梦达DDR3 UDIMM通过英特尔芯片组验证
  内存供货商奇梦达(Qimonda)宣布,其1GB及2GB的DDR3无缓冲双信道内存模块(Unbuffered Dual In-Line Memory Modules,UDIMMs),已通过即将推出的英特尔Core 7处理器和英特尔X58 Express芯片组的验证,使奇梦达的内存产品能在新一代高端台式机平台充分发挥其散热效率和性能。   DDR3 1067 non-ECC UDIMMs已通过英特尔新平台Core 7(预计将于今年年底发表)的验证,具备了比DDR2内存快达两倍的数据传输速率,同时也改善了电源效率达30%。奇梦达DDR3组件是于一年多前发表,其模块也已通过多个英特尔平台的验证。   英特尔Core 7微架构配有
[焦点新闻]
支持双通道DDR4内存:国产全新自主X86处理器发布
芯片自主化国产化,是目前整个国家的重中之重,而在这样的大环境下,一些国产厂商开始投入更大的精力,来研制更有竞争力的产品。 据科技日报报道称,国产芯片公司兆芯发布了一款自主研发的国产x86处理器,而开先KX-5000系列是兆芯第一款采用SOC设计的通用CPU,同时也是国内第一款支持双通道DDR4内存的国产通用CPU。 从官方晒出的图看,相比上一代开先KX-5000同位2GHz主频,但性能有了巨大的提升,而按照官方的话来说,新的自主处理器在性能、体验上等,与国际主流CPU几乎没有差别。 兆芯负责人叶峻表示,开先KX-5000系列处理器采用了全新的微架构设计,核心架构、核心间架构等方面均大幅改进,并且芯片集成度更高,CPU、内存控制器
[嵌入式]
泰克为下一代DDR3提供全方位测试
  泰克日前宣布为DDR2和DDR3技术推出完善的系列测试工具。DDR3是下一代双倍数据速率(DDR)同步动态随机访问存储器(SDRAM),将提供性能更高的数据速率。泰克为工程客户提供了完整的DDR3测试解决方案。   DDR3标准通过400 MHz - 800 MHz的时钟频率分别支持800 MT/s – 1600 MT/s的数据速率,其速度是DDR2技术的两倍。DDR3适用于高性能应用,如文件服务器、影视点播、编码和解码、游戏、三维可视化等。   对数字验证和调试,TLA7000逻辑分析仪和新的TLA7BB4采集模块提供了唯一能够满足DDR、DDR2和DDR3所有速度的逻辑分析解决方案,包括DDR3-1600。此外,与现有方法
[新品]
平板亮点-帧像技术全接触
“帧像”技术是康佳平板电视在图象显示领域的革命性突破,“帧像”技术的基本原理是在刷新频率为120HZ的屏幕基础上,搭载以180兆双倍速处理IC和海量DDR内存为基础的第七代芯片平台,并通过特有的倍帧加速、分帧消影,精帧还原等一系列先进的运算,从而得到更稳定、更流畅、更逼真的画质效果。 为了迎合消费者的口味,同时也为康佳在平板电视领域取得好的销售战绩,康佳“帧像”技术一度推出了3大系列、20余款新品液晶电视,包括6款“靓影”20系列、10款“红舞”26系列及2款“光彩”29系列。刘丹表示,目前3大系列产品已全部到位,即将全面上市。其中,“红舞”系列新品是康佳力推的重点。该类产品有三大特点:特别订制的“零亮点”顶级品质显示屏;四大色彩
[嵌入式]
DDR测试技术与工具
  DDR是双倍数据速率的SDRAM内存,如今大多数计算机系统、服务器产品的主流存储器技术,并且不断向嵌入式系统应用领域渗透。孰不知,随着iPhone等大牌智能手机的采纳,DDR内存俨然成为智能手机转变的方向之一,例如韩国泛泰去年底最新推出的Android智能手机Vega X就搭载了512MB的DDR2内存。   DDR技术不断发展,并行总线达到了串行技术的速度,时钟速度达到1GHz。目前,DDR3现在已经具备1.6Gb/s的数据速率,而DDR3-1866及更高速率版本正在开发中,很快就会出现在市场上。目前主流的DDR2也有多种速度、多种容量和多种规格,从DDR-266的266MT/S、133MHz、2.5V电压,已经发展到了现
[测试测量]
<font color='red'>DDR</font>测试技术与工具
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved