`

s3c44b0x启动代码分析

 
阅读更多

http://blog.csai.cn/user1/21439/archives/2007/11151.html

我的开发板是s3c44b0x的,2m
NORFLASH在bank0,8msdram在bank6.
  首先看看我们要解决的问题。有些ARM芯片有内嵌的RAM和FALSH.这样可以直接在片内运行程序,44B0X片内只有几K
CACHE,ROM和RAM都是外接的芯片。我们的程序是要写入FLASH中保存,但执行时是拷到SDRAM中执行的(如在ROM中执行速度会较慢)。要做到这一点需要把程序做成两个分程序:一个是实现你的系统功能的主程序,如果你用嵌入式系统,那就是UCOS和UCLINUX之类的程序,这个程序的代码保存在FLASH中,但执行时会拷到RAM中再执行;一个是引导程序,直接在FLASH中执行,负责把初始化芯片和外设,并把主程序从FLASH中拷到RAM中,然后跳到主程序去执行,对应的概念是UBOOT等常见的引导程序,这个程序会被写入0X0开始的地址,开机后自动执行。
  那么我们需要解决以下几个问题:
 1.如何编译和调试主程序
 2.如何使中断跳到RAM中的中断服务程序执行
 3.如何把引导程序和主程序写入FLASH中.
以下我们来解决这几个问题:
 1开始在仿真器中写代码和调试
 由于主程序会被拷贝到RAM中执行,则我们应该在编译时就把程序定位到RAM中。这里先要说说几个ADS的参数的意义,在ADS的ARM
LINKER页有RO,RW两个参数,此外还有一个ZI没有在页中给出,RO是只读代码的起始地址,由这个地址开始存放编译出来的程序指令;RW是程序的读写段的开始,即你程序中的数据存放的开始地址,ZI紧跟在RW区后,ZI区存放的是需要在程序运行时初始化为0的数据。
了解这几个链接参数的意义后我们可以设置这几个参数了:对于我的44B0X板8M
SDRAM在0XC00_0000.因此在开发时把ADS中的RO
BASE的地址指定为0XC00_0000;置于RW,在程序完成前可以预先估计一下程序的体积有多大,需要用到的数据区有多大,避免数据区太小或代码区覆盖掉前面的数据区就是了,我用了0XC10_0000,1M的代码空间,其他作数据区。这样,我们编译出来的程序代码就是在0XC00_0000中,可以直接由仿真器写入RAM中运行仿真运行。此外,在linker-〉layout页有个object
symbol和section的选项,要求你填入映像文件最开始的object文件名和段名,这两个参数在仿真时不填写也不会影响运行,因为仿真器会自动修改pc指针,但要建立能烧写的映像文件,则一定要填写好,具体填写什么后面分析程序时再讲。
  2中断问题
  和所有单片机一样,ARM复位后从地址0X0开始执行,而0X0后是一串默认的中断向量表。对51这样的芯片,我们会直接在这个中断向量表中填入跳转语句,让它跳到指定的ISR处理中断事件。由于我们的主程序是在RAM中执行的,编译时又和引导程序分开,不可能预先知道我们写的ISR具体地址,而预留的中断向量表只够每个中断一个跳转指令,因此我们需要做二次跳转。在内存中建立一个中断向量表,每个中断对应一个字,存放ISR的地址。尔后,对每个中断写一段短的代码,把ISR地址取出,填入PC。而0X0后面中断向量的跳转指令,则是跳到这小段程序中。
  3烧写flash,ADX中似乎有个写入flash的选项,我自己没有具体用过。但听说用jtag写flash会比较慢。由于nor
flash或nand
flash都是可以编程烧写的,即我们可以写个程序擦写flash,问题是如何读取编译出来的映像文件。这个也不用担心,adx中有个菜单把文件内容写入指定的地址中,把影响文件指定到一个ram地址,然后就用烧写程序把ram的内容拷入rom中就是了。我们有个boot程序,一个主程序要映射到rom中.假设我把0xc20_0000开始的2m地址作rom的映像,则把boot程序导入0xc20_0000,boot的程序非常短,在0xc20_1000开始放主程序。然后把0xc20_0000到0xc40_0000的内容全部拷入rom中(当然在导入文件前这些ram应该先被清空或写入ff.)。
  
让我们来看看相关的代码,具体认识一下该怎么处理前面说的这些问题,还有另外的一些问题。这里使用的代码是在44b0x的application
note的第三章中拿出来的,这个文件在网上应该很容易找到。
  程序的入口在44binit.s汇编文件中,其中一个Init段是整个程序的入口:
AREAInit,CODE,READONLY
ENTRY
bResetHandler;fordebug
bHandlerUndef;handlerUndef
bHandlerSWI;SWIinterrupthandler
bHandlerPabort;handlerPAbort
bHandlerDabort;handlerDAbort
b.;handlerReserved
bHandlerIRQ
关键字ENTRY告诉编译器保留这段代码。从代码看INIT段就是要写入0X0地址的原始中断向量,因此把这个文件编译生成的44BINIT.O和INTT填入上面提到的LAYOUT页对应项中。这样编译器会把该段代码编译到0X0地址。(仿真时你可以试试别填这两个项目,看看ADX中的反汇编代码入口被放到哪里)。
这段代码里除了reset句外,有每句都有一个HandlerXXX的标号,这就是前面提到的中断处理程序的入口,它是由前面的一个宏来定义的:
MACRO
$HandlerLabelHANDLER$HandleLabel
$HandlerLabel
subsp,sp,#4;decrementsp(tostorejumpaddress)
stmfdsp!,{r0}
;PUSHtheworkregistertostack(lrdoes'tpushbecauseitreturnto
originaladdress)
ldrr0,=$HandleLabel;loadtheaddressofHandleXXXtor0
ldrr0,[r0];loadthecontents(serviceroutinestartaddress)of
HandleXXX
strr0,[sp,#4];storethecontents(ISR)ofHandleXXXtostack
ldmfdsp!,{r0,pc};POPtheworkregisterandpc(jumptoISR)
MEND
 我自己没有写过宏,所以还是看编译出来的代码比较直接:
  HandlerSWI
    0x0c000198:  e24dd004  ..M.  SUB   r13,r13,#4
    0x0c00019c:  e92d0001  ..-.  STMFD  r13!,{r0}
    0x0c0001a0:  e59f0458  X...  LDR   r0,0xc000600
    0x0c0001a4:  e5900000  ....  LDR   r0,[r0,#0]
    0x0c0001a8:  e58d0004  ....  STR   r0,[r13,#4]
    0x0c0001ac:  e8bd8001  ....  LDMFD  r13!,{r0,pc}
这是ads输出的汇编代码,就是刚才的宏对应swi的一个实例,其中有两句
    LDR   r0,0xc000600
    LDR   r0,[r0,#0]
是把0x0c000600的内容载入r0,再把r0地址的ram单元载入r0.去看看0xc000600的内容,是0X0c7fff08,这是我设定的内存中的中断向量表地址之一,中断向量表的起始地址是0X0c7fff00,因此0X0c7fff08存放的刚好就是swi的isr地址。后面程序就跳到对应的ISR去了。(这段宏程序由于我不熟悉arm的汇编,只看过它怎么执行,实在我不知道中断向量表地址是如何被放入0x0c000600等地址的。希望有高手能再详细解释一下具体的编写,编译方法和原理。)
在c程序中,我们需要给每个中断向量定义一个宏:
 #definepISR_SWI(*(unsigned*)(_ISR_STARTADDRESS+0x08))
_ISR_STARTADDRESS是起始地址0X0c7fff00,假设ISR是以下函数:
void__irqSWI_UserIsr(void){……………}
则在系统初始化时用pISR_EINT0=(unsigned)SWI_UserIsr;这样的语句把ISR的地址填入中断向量表中,对所有中断作同样的处理,然后开中断,系统就能经过上面的宏把跳到ISR执行。
 44binit.s中还有几段值得留意的代码:以下的代码把rw段的数据拷入ram中,并初始化zi段,即把该段清零:
LDR  r0,=|Image$$RO$$Limit|
LDR  r1,=|Image$$RW$$Base|
LDR  r2,=|Image$$ZI$$Base| 
CMP  r0,r1        
   BEQ  %F1
0  CMP  r1,r3
   LDRCC r2,[r0],#4
   STRCC r2,[r1],#4
   BCC  %B0
1  LDR  r1,=|Image$$ZI$$Limit|
   MOV r2,#0
2  CMP  r3,r1
   STRCC r2,[r3],#4
   BCC  %B2
来看反汇编的代码:
    0x0c000ae0:  e59f0194  ....  LDR   r0,0xc000c7c
    0x0c000ae4:  e59f1194  ....  LDR   r1,0xc000c80
    0x0c000ae8:  e59f3194  .1..  LDR   r3,0xc000c84
0xc000c7c,开始的三个字的内容是:    
    0x0c000c7c:  0c000e10  ....  DCD  201330192
    0x0c000c80:  0c200000  ...  DCD  203423744
    0x0c000c84:  0c200000  ...  DCD  203423744
    0x0c000c88:  0c200004  ...  DCD  203423748
这些反汇编的代码是一个点led的程序的,可以看出我的小程序代码到0x0c000e10就结束了,0x0c200000是我指定的数据区起始地址。这段程序把|Image$$RO$$Limit|
开始的,长|Image$$ZI$$Base|-|Image$$RW$$Base|
的数据区拷到|Image$$RW$$Base|的对应单元,就是0x0c200000开始的一段ram中。后面还有|Image$$ZI$$Limit|,在我的代码中是0x0c000c88,内容是0x0c200004.这其实表明我的小程序并没有rw区,只有一个初始为0的变量。
 另外还有一段初始化ram控制器的代码:
  ;****************************************************
  ;*  Setmemorycontrolregisters          
  ;****************************************************
  ldr    r0,=SMRDATA
  ldmia r0,{r1-r13}
  ldr    r0,=0x01c80000 ;BWSCONAddress
  stmia r0,{r1-r13},
由于44b0x要求13个控制寄存器要一次完成填入,所以先把参数设定在SMRDATA的地址中,一次载入通用寄存器,在一次填入RAM控制寄存器中。4510的书上介绍调试前需要用SEMEM命令设置这些寄存器,但我自己没有那么做也可以跑的很好,也许是默认已经用了最保守的配置的原因吧!
  其余的代码解释比较清晰了,最后摘出我的LED程序和这个小程序的BOOT程序以及烧写程序。这几个程序的project都包括了44binit.s,
option.s,memcfg.s,option.h,44b.h几个从app
note中抄来的文件,这里只列了我自己写的主要c代码。其他这些文件我除了把ram和rom的对应配置改了一下外,都没有改动。我的引导程序编译出来是3k,led程序也是3k,因此我把他们分别定位在rom的0x0和0x2000处,一共写了8k。
LED程序中的44BINTT.S程序功能和LOAD中的44BINTT.S是重复的,主要是我懒得去修改这些汇编,由着他们占用一点时间吧!
 load程序负责把从0x20000处开始的4k程序(即led程序)拷到ram
0xc000000中,run函数把pc指到0x0c000000,开始执行led程序:
void(*Run)(void)=(void(*)(void))RAM_ADDR;
voidMain(void)
{  INT32Uk;
  INT32U*pulSource=(INT32U*)0x2000,;
  INT32U*pulDest=(INT32U*)0x0c000000;
  rSYSCFG=CACHECFG;
  PortInit();  
  for(k=0;k<2000>    *pulDest++=*pulSource++;  
  Run();  
}
led程序把两个通用io上连的led作不断的亮和灭:
voidMain(void)
{  INT32Uk;
  //INT16U*ptr;
  rSYSCFG=CACHECFG;
  PortInit();  
  while(1)
    {
      LedDisp(0);
      for(k=0;k      LedDisp(3);  
      for(k=0;k    }
}
最后是烧写的程序,详细的代码网上高手们写了不少,我只是给出最简单的实现。烧写时当程序执行到清理完0X0C30_0000到0X0C30_4000的RAM后,让程序中断下来,通过LOAD
MEMORYFORM
FILE命令把LOAD.BIN导入0X0C30_0000,LED.BIN导入0X0C30_2000中,继续运行程序直到一个LED亮起,烧写就完成了。拔去仿真器后再上电,可以看到两个LED同时亮灭。
#include"option.h"
#include"44b.h"
#include"def.h"
//#include"romdef.h"
//#include"stdio.h"
//#include"stdlib.h"

&nbsp&nbsp#defineFLASH_START_ADDR  0X0000
#defineFLASH_ADDR_UNLOCK1 0X5555
#defineFLASH_ADDR_UNLOCK2 0X2AAA
#defineFLASH_DATA_UNLOCK1 0XAAAA
#defineFLASH_DATA_UNLOCK2 0X5555
#defineFLASH_DATA_WRITE  0XA0A0
#defineFLASH_ERASE    0X8080
#defineFLASH_ERASE_SECTOR 0X3030
#defineFLASH_ERASE_BLOCK 0X5050
#defineFLASH_ERASE_CHIP  0X1010
#defineFLASH_SID_QUERY  0X9090
#defineFLASH_CFI_QUERY  0X9898
#defineFLASH_SID_EXIT   0XF0F0
#defineFLASH_OP_TIMEOUT  0Xffff

&nbsp&nbsp#defineLED_PORTC10  (1#defineLED_PORTC11    (1
#defineRAM_ADDR    0xc000000
void(*Run)(void)=(void(*)(void))RAM_ADDR;
voidinfoFlash(void);
intwait_flash_ready(INT16U*address,INT16Udata);
intwriteFlash(INT16U*Address,INT16UData);
interaseSector(INT16U*SectorAddr);
interaseChip(void);

&nbsp&nbspvoidPortInit(void);
voidLedDisp(intLedStatus);

&nbsp&nbsp//*****************************************
//    FLASHWIRTING
//*****************************************
voidMain(void)
{  INT32Uk;
  INT16U*pdist,*psrc;
  rSYSCFG=CACHECFG;
  PortInit();  
  //infoFlash();
  eraseChip();
  psrc="/blog/(INT16U"*)0xc300000;
  for(k=0;k<0x4000>   *psrc++=0x0;//clearram
  psrc="/blog/(INT16U"*)0xc300000;
  pdist=(INT16U*)0x0;
  for(k=0;k<0x4000kramto>    writeFlash(pdist++,*psrc++);
  while(1)
    {
      LedDisp(0);
      for(k=0;k      LedDisp(2);  
      for(k=0;k    }
}

&nbsp&nbsp
//*****************************************
//    inittheport
//*****************************************
voidPortInit(void)
{

&nbsp&nbsp  rPDATC=0xffff;    //AllIOishigh
  rPCONC=0x0f55ff54;  
  rPUPC =0x3000;    //PULLUPRESISTORshouldbeenabledtoI/O
}

&nbsp&nbsp//*****************************************
//    lightled
//*****************************************
voidLedDisp(intLedStatus)
{
  if((LedStatus&0x01)==0x01)
    rPDATC&=(~LED_PORTC10);  //LEDON
  else
    rPDATC|=LED_PORTC10;    //LEDOFF
  
  if((LedStatus&0x02)==0x02)
    rPDATC&=(~LED_PORTC11);  //LEDON
  else
    rPDATC|=LED_PORTC11;    //LEDOFF
}

&nbsp&nbsp//*****************************************
//    showtheflashsoftid
//*****************************************
voidinfoFlash()
{
  inti,j;
  INT16U*pFlash;
  *((volatileINT16U*)FLASH_START_ADDR)=FLASH_SID_EXIT;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_UNLOCK1;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK2)=FLASH_DATA_UNLOCK2;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_SID_QUERY;
  for(i=0;i  pFlash=FLASH_START_ADDR;
  i=0;j=0;
  i=(INT16U)*pFlash++;
  j=(INT16U)*pFlash;  
}
//*****************************************
//    eraseholdflash
//*****************************************
interaseChip()
{
  *((volatileINT16U*)FLASH_START_ADDR)=FLASH_SID_EXIT;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_UNLOCK1;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK2)=FLASH_DATA_UNLOCK2;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_ERASE;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_UNLOCK1;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK2)=FLASH_DATA_UNLOCK2;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_ERASE_CHIP;
  if(wait_flash_ready((INT16U*)FLASH_START_ADDR,0xffff))
   return1;
  elsereturn0;
}

&nbsp&nbsp//*****************************************
//    writeonefalshword(16bit)
//*****************************************
intwriteFlash(INT16U*Address,INT16UData)
{ *((volatileINT16U*)FLASH_START_ADDR)=FLASH_SID_EXIT;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_UNLOCK1;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK2)=FLASH_DATA_UNLOCK2;
  *((volatileINT16U
*)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_WRITE;
  *Address=Data;
  if(wait_flash_ready(Address,Data))
   return1;
  elsereturn0;
}

&nbsp&nbsp//*****************************************
//    waitforoperationfinish
//*****************************************
intwait_flash_ready(INT16U*address,INT16Udata)
{
 INT32Utmp;
 INT16U*p;
 tmp=0xff;
 p=address;
  while(((*p)&0x8080)!=(data&0x8080))
  {tmp--;
  if(tmp==0x0)
    return1; //timeout
  }
  return0;
}


分享到:
评论

相关推荐

    S3C44B0X启动代码分析

    非常详细的启动代码分析,,,,,,,,,,,,,,,,,,,,,

    论文研究-S3C44B0X中Blob源代码的设计与移植 .pdf

    S3C44B0X中Blob源代码的设计与移植,徐杰,罗桂娥,在嵌入式系统开发中,系统启动源代码的开发是一个技术难点。本文详细叙述基于在ARM7TDMI-S3C44B0X开发平台的blob(Boot Loader Object)的原理

    ARM.rar_s3c44b0x ads

    ARM S3C44B0X 的一段参考代码,虽然简单,但是对于初学者还是很有帮助的。包括配置(ADS环境下)和生成BIN文件。启动地址0x0C008000 需要根据具体情况修改。

    44b0启动代码中文注释

    嵌入式开发,学习,arm7,s3c44b0x 启动代码中文注释

    嵌入式系统/ARM技术中的关于三星S3C44B0X目标板的uClinux Bootloader

    其设计主要针对没有内存管理单元(MMU)的微处理器,例如基于ARM7TDMI内核的S3C44B0X。 嵌入式Linux系统通常由三部份组成:Bootloader、Kernel和File System。其中Bootloader是在系统启动之后、Kernel运行之前所执行的...

    基于S3C44B0X的嵌入式系统Bootloader设计与实现* (2008年)

    介绍了基于S3C44B0X处理器的嵌入式系统上电启动后的自举加载过程,采用文件系统中的文件操作函数设计出具有良好人机界面和可移植性的嵌入式系统初始化代码及加载代码的启动程序,实验结果表明该方法具有很好的稳定性...

    新plc程序_A.zip_PLC源代码_WERWERWERWERWERWER_创思_创思 tcp_创思通信

    硬件:思创黄金开发板(S3C44B0X/SST39VF160/RTL8019/10M OSC)。 硬件配置: CPU:S3C44B0X RAM:8M FLASH:SST39VF160 OSC:10M NET:RTL8019 符合上列配置,则除了网络以外,其他功能一般都能使用。如果8019的接法和...

    redboot-strong-rel-v0.2.tar.gz_SST39VF160_osc_redboot_tftp_xyzmo

    硬件:思创黄金开发板(S3C44B0X/SST39VF160/RTL8019/10M OSC)。 硬件配置: CPU:S3C44B0X RAM:8M FLASH:SST39VF160 OSC:10M NET:RTL8019 符合上列配置,则除了网络以外,其他功能一般都能使用。如果8019的接...

    学ARM和学单片机一样简单12

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单15

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单4

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单3

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单9

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单2

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单11

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单7

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单5

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单13

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单6

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

    学ARM和学单片机一样简单14

    (4)、S3C44B0X定时器介绍 3、邮箱的实现 (1)、邮箱的建立 (2)、程序流程分析 (3)、仿真演示实验 4、事件的实现 (1)、事件的建立 (2)、程序流程分析 (3)、仿真演示实验 5、uC/OS-II实现AD对...

Global site tag (gtag.js) - Google Analytics