ARM9启动代码裸机版.docx

上传人:b****6 文档编号:12917375 上传时间:2023-06-09 格式:DOCX 页数:16 大小:20.78KB
下载 相关 举报
ARM9启动代码裸机版.docx_第1页
第1页 / 共16页
ARM9启动代码裸机版.docx_第2页
第2页 / 共16页
ARM9启动代码裸机版.docx_第3页
第3页 / 共16页
ARM9启动代码裸机版.docx_第4页
第4页 / 共16页
ARM9启动代码裸机版.docx_第5页
第5页 / 共16页
ARM9启动代码裸机版.docx_第6页
第6页 / 共16页
ARM9启动代码裸机版.docx_第7页
第7页 / 共16页
ARM9启动代码裸机版.docx_第8页
第8页 / 共16页
ARM9启动代码裸机版.docx_第9页
第9页 / 共16页
ARM9启动代码裸机版.docx_第10页
第10页 / 共16页
ARM9启动代码裸机版.docx_第11页
第11页 / 共16页
ARM9启动代码裸机版.docx_第12页
第12页 / 共16页
ARM9启动代码裸机版.docx_第13页
第13页 / 共16页
ARM9启动代码裸机版.docx_第14页
第14页 / 共16页
ARM9启动代码裸机版.docx_第15页
第15页 / 共16页
ARM9启动代码裸机版.docx_第16页
第16页 / 共16页
亲,该文档总共16页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

ARM9启动代码裸机版.docx

《ARM9启动代码裸机版.docx》由会员分享,可在线阅读,更多相关《ARM9启动代码裸机版.docx(16页珍藏版)》请在冰点文库上搜索。

ARM9启动代码裸机版.docx

ARM9启动代码裸机版

ARM9启动代码(裸机版)

所谓启动代码,就是处理器在启动的时候执行的一段代码,主要任务是初始化处理器模式,设置堆栈,初始化变量等等。

由于以上的操作均与处理器体系结构和系统配置密切相关,所以一般由汇编来编写。

在一般32位ARM应用系统中,软件大多数采用c语言进行编程,并且以嵌入式操作系统为开发平台,这样就大大提高了开发效率和软件性能。

为了能够进行系统初始化,通常采用一个汇编文件作启动代码。

它可以实现向量表定义、堆栈初始化、系统变量初始化、中断系统初始化、I/O初始化、地址重映射等操作。

启动代码是芯片复位后进入c语言的main函数前执行的一段代码,主要是为运行c语言程序提供基本运行环境。

在实际应用中,为提高系统的实时性,加快代码的执行速度,系统启动后程序往往要被搬移到RAM中,因为RAM的存取速度要比ROM快得多,这样大大提升系统的性能。

启动程序要完成的任务包括:

硬件初始化,系统存储系统的配置,复制二级中断向量表。

启动程序大概过程如下:

(1)系统硬件初始化

系统上电或复位后,程序从位于地址0x0的ResetExceptionVector处开始执行,因此需要在这里放置bootloader的第一条指令:

bReset,跳转到标号为Reset处进行第一阶段的硬件初始化,主要内容为:

关看门狗定时器,关中断,初始化PLL和时钟,初始化存储器系统。

执行完以上程序后,系统进行堆栈和存储器的初始化。

系统堆栈初始化取决于用户使用了哪些中断,以及系统需要处理哪些错误类型。

一般情况下,管理者堆栈必须设置,如果使用了IRQ中断,则IRQ堆栈也必须设置。

如果系统使用了外设,则需要设置相关的寄存器,以确定其刷新频率、总线宽度等信息。

(2)代码复制到RAM中运行

因为嵌入式系统的代码通常都是固化在ROM或Flash中,上电后开始运行。

由于ROM和Flash的读取速度相对较慢,这样无疑会降低代码的执行速度和系统的运行效率。

因此,需要把系统的代码复制到RAM中运行。

(3)建立二级中断向量表

在ARM系统中,中断向量表位于0x0开始的地址处,意味着无论运行什么样的上层软件,一旦发生中断,程序就得到Flash存储器的中断向量表里去,降低系统的运行效率。

因此在RAM中建立自己的二级中断向量表,当中断发生后,程序直接从RAM中取中断向量进入中断子程序。

(4)MMU的应用

MMU是存储器管理单元的缩写,是用来管理虚拟内存系统的器件。

MMU完成的两个主要功能是:

将虚地址转换成物理地址,控制存储器存取允许。

MMU关掉时,虚地址直接输出到物理地址总线。

由于跑的是裸机,没有用到操作系统,以下启动代码不包含MMU的应用。

@下面是对arm处理器模式寄存器对应的常数进行赋值,arm处理器有一个CPSR寄存器,

@它的后五位决定了处理器处于哪个模式下。

可以看出常数的定义都不会超过后5位的。

*/

@Pre-definedconstants

.equUSERMODE,0x10

.equFIQMODE,0x11

.equIRQMODE,0x12

.equSVCMODE,0x13

.equABORTMODE,0x17

.equUNDEFMODE,0x1b

.equMODEMASK,0x1f

.equNOINT,0xc0

@各个异常模式的堆栈

@Thelocationofstacks

.equ_STACK_BASEADDRESS,0x33ff8000

.equ_ISR_STARTADDRESS,0x31ffff00

.equUserStack,(_STACK_BASEADDRESS-0x3800)@0x33ff4800~

.equSVCStack,(_STACK_BASEADDRESS-0x2800)@0x33ff5800~

.equUndefStack,(_STACK_BASEADDRESS-0x2400)@0x33ff5c00~

.equAbortStack,(_STACK_BASEADDRESS-0x2000)@0x33ff6000~

.equIRQStack,(_STACK_BASEADDRESS-0x1000)@0x33ff7000~

.equFIQStack,(_STACK_BASEADDRESS-0x0)@0x33ff8000~

.equINTMSK,0x4a000008@Interruptmaskcontrol

.equINTSUBMSK,0x4a00001c@Interruptsubmask

.equINTOFFSET,0x4a000014@Interruotrequestsourceoffset

 

.macroHANDLERHandleLabel

subsp,sp,#4@decrementsp(tostorejumpaddress)

stmfdsp!

{r0}@PUSHtheworkregistertostack(lrdoesnotpushbecauseitreturntooriginaladdress)

ldrr0,=\HandleLabel@loadtheaddressofHandleXXXtor0

ldrr0,[r0]@loadthecontents(serviceroutinestartaddress)ofHandleXXX

strr0,[sp,#4]@storethecontents(ISR)ofHandleXXXtostack

ldmfdsp!

{r0,pc}@POPtheworkregisterandpc(jumptoISR)

.endm

.externmain

.text

.global_start

_start:

@********************************************************************

@中断向量

@********************************************************************

bReset

@0x04:

未定义指令中止模式的向量地址

bHandlerUndef

@0x08:

管理模式的向量地址,通过SWI指令进入此模式

bHandlerSWI

@0x0c:

指令预取终止导致的异常的向量地址

bHandlerPrefetchAbort

@0x10:

数据访问终止导致的异常的向量地址

bHandlerDataAbort

@0x14:

保留

bHandlerNotUsed

@0x18:

中断模式的向量地址

bHandlerIRQ

@0x1c:

快中断模式的向量地址

bHandlerFIQ

Reset:

ldrsp,=4096@设置栈指针,以下都是C函数,调用前需要设好栈

bldisable_watch_dog@关闭WATCHDOG,否则CPU会不断重启

ldrr0,=INTMSK

ldrr1,=0xffffffff@allinterruptdisable

strr1,[r0]

ldrr0,=INTSUBMSK

ldrr1,=0x7fff@allsubinterruptdisable

strr1,[r0]

blclock_init@设置MPLL,改变FCLK、HCLK、PCLK

blmemsetup@设置存储控制器以使用SDRAM

bls3c2440_nand_init

ldrr0,=0x30000000@1.目标地址=0x30000000,这是SDRAM的起始地址

movr1,#4096@2.源地址=4096,运行地址在SDRAM中的代码保存在NANDFlash4096地址开始处

movr2,#180*1024@3.复制长度=16K,对于本实验,这是足够了

blCopyCode2SDRAM@调用C函数CopyCode2SDRAM

blclean_bss@清除bss段,未初始化或初值为0的全局/静态变量保存在bss段

blInitStacks@initalthestack

@SetupIRQhandler

ldrr0,=HandleIRQ@Thisroutineisneeded

ldrr1,=IsrIRQ@ifthereisnot'subspc,lr,#4'at0x18,0x1c

strr1,[r0]@这三条语句很明显就是说明了,HandleIRQ这个中断向量

@的存储单元被赋上了IsrIRQ标号的地址,这样发生IRQ中

@断后就会直接去到二级表,去确认具体发生哪个中断。

ldrpc,=on_sdram@跳到SDRAM中继续执行

on_sdram:

msrcpsr_c,#0x5f@设置I-bit=0,开IRQ中断

ldrsp,=0x34000000@设置栈指针,

ldrlr,=halt_loop@设置返回地址

ldrpc,=main@调用main函数

halt_loop:

bhalt_loop

HandlerFIQ:

HANDLERHandleFIQ

HandlerIRQ:

HANDLERHandleIRQ

HandlerUndef:

HANDLERHandleUndef

HandlerSWI:

HANDLERHandleSWI

HandlerDataAbort:

HANDLERHandleDabort

HandlerPrefetchAbort:

HANDLERHandlePabort

HandlerNotUsed:

b.

InitStacks:

@DonotuseDRAM,suchasstmfd,ldmfd......

@SVCstackisinitializedbefore

@Undertoolkitver2.5,'msrcpsr,r1'canbeusedinsteadof'msrcpsr_cxsf,r1'

mrsr0,cpsr

bicr0,r0,#MODEMASK

orrr1,r0,#UNDEFMODE|NOINT

msrcpsr_c,r1@UndefMode

ldrsp,=UndefStack@UndefStack=0x33FF_5C00

orrr1,r0,#ABORTMODE|NOINT

msrcpsr_c,r1@AbortMode

ldrsp,=AbortStack@AbortStack=0x33FF_6000

orrr1,r0,#IRQMODE|NOINT

msrcpsr_c,r1@IRQMode

ldrsp,=IRQStack@IRQStack=0x33FF_7000

orrr1,r0,#FIQMODE|NOINT

msrcpsr_c,r1@FIQMode

ldrsp,=FIQStack@FIQStack=0x33FF_8000

bicr0,r0,#MODEMASK|NOINT

orrr1,r0,#SVCMODE

msrcpsr_c,r1@SVCMode

ldrsp,=SVCStack@SVCStack=0x33FF_5800

@USERmodehasnotbeinitialized.

movpc,lr

@theLRregisterwillnotbevalidifthecurrentmodeisnotSVCmode.

IsrIRQ:

sublr,lr,#4@计算返回地址

stmfdsp!

{r0-r12,lr}@保存使用到的寄存器

subsp,sp,#4@reservedforPC;保留pc寄存器的值

stmfdsp!

{r8-r9}@把r8r9按入堆栈

ldrlr,=int_return@设置调用ISR即EINT_Handle函数后的返回地址

ldrr9,=INTOFFSET@把中断偏移INTOFFSET的地址装入r9里面

ldrr9,[r9]@取出INTOFFSET单元里面的值给r9

ldrr8,=HandleEINT0@向量表的入口地址赋给r8

addr8,r8,r9,lsl#2@求出具体中断向量的地址

ldrr8,[r8]@中断向量里面存储的中断服务程序的入口地址赋给r8

strr8,[sp,#8]@按入堆栈

ldmfdsp!

{r8-r9,pc}@堆栈弹出,跳转到相应的中断服务程序

int_return:

ldmfdsp!

{r0-r12,pc}^@中断返回,^表示将spsr的值复制到cpsr

.align4

.section.data

.equHandleReset,(_ISR_STARTADDRESS+0x0)

.equHandleUndef,(_ISR_STARTADDRESS+0x4)

.equHandleSWI,(_ISR_STARTADDRESS+0x8)

.equHandlePabort,(_ISR_STARTADDRESS+0xc)

.equHandleDabort,(_ISR_STARTADDRESS+0x10)

.equHandleReserved,(_ISR_STARTADDRESS+0x14)

.equHandleIRQ,(_ISR_STARTADDRESS+0x18)

.equHandleFIQ,(_ISR_STARTADDRESS+0x1c)

@Donotusethelabel'IntVectorTable',

@ThevalueofIntVectorTableisdifferentwiththeaddressyouthinkitmaybe.

@IntVectorTable

@0x33FF_FF20

.equHandleEINT0,(_ISR_STARTADDRESS+0x20)

.equHandleEINT1,(_ISR_STARTADDRESS+0x24)

.equHandleEINT2,(_ISR_STARTADDRESS+0x28)

.equHandleEINT3,(_ISR_STARTADDRESS+0x2c)

.equHandleEINT4_7,(_ISR_STARTADDRESS+0x30)

.equHandleEINT8_23,(_ISR_STARTADDRESS+0x34)

.equHandleCAM,(_ISR_STARTADDRESS+0x38)@Addedfor2440.

.equHandleBATFLT,(_ISR_STARTADDRESS+0x3c)

.equHandleTICK,(_ISR_STARTADDRESS+0x40)

.equHandleWDT,(_ISR_STARTADDRESS+0x44)

.equHandleTIMER0,(_ISR_STARTADDRESS+0x48)

.equHandleTIMER1,(_ISR_STARTADDRESS+0x4c)

.equHandleTIMER2,(_ISR_STARTADDRESS+0x50)

.equHandleTIMER3,(_ISR_STARTADDRESS+0x54)

.equHandleTIMER4,(_ISR_STARTADDRESS+0x58)

.equHandleUART2,(_ISR_STARTADDRESS+0x5c)

@0x33FF_FF60

.equHandleLCD,(_ISR_STARTADDRESS+0x60)

.equHandleDMA0,(_ISR_STARTADDRESS+0x64)

.equHandleDMA1,(_ISR_STARTADDRESS+0x68)

.equHandleDMA2,(_ISR_STARTADDRESS+0x6c)

.equHandleDMA3,(_ISR_STARTADDRESS+0x70)

.equHandleMMC,(_ISR_STARTADDRESS+0x74)

.equHandleSPI0,(_ISR_STARTADDRESS+0x78)

.equHandleUART1,(_ISR_STARTADDRESS+0x7c)

.equHandleNFCON,(_ISR_STARTADDRESS+0x80)@Addedfor2440.

.equHandleUSBD,(_ISR_STARTADDRESS+0x84)

.equHandleUSBH,(_ISR_STARTADDRESS+0x88)

.equHandleIIC,(_ISR_STARTADDRESS+0x8c)

.equHandleUART0,(_ISR_STARTADDRESS+0x90)

.equHandleSPI1,(_ISR_STARTADDRESS+0x94)

.equHandleRTC,(_ISR_STARTADDRESS+0x98)

.equHandleADC,(_ISR_STARTADDRESS+0x9c)

 

以下部分是我们bootloader中调用到的c程序部分,主要是完成:

关看门狗、初始化存储器、初始化时钟、从Nandflash将代码拷贝到SDRAM、初始化数据段。

/*

*关闭WATCHDOG,否则CPU会不断重启

*/

voiddisable_watch_dog(void)

{

WTCON=0;//关闭WATCHDOG很简单,往这个寄存器写0即可

}

#defineS3C2410_MPLL_200MHZ((0x5c<<12)|(0x04<<4)|(0x00))

#defineS3C2440_MPLL_200MHZ((0x5c<<12)|(0x01<<4)|(0x02))

/*

*对于MPLLCON寄存器,[19:

12]为MDIV,[9:

4]为PDIV,[1:

0]为SDIV

*有如下计算公式:

*S3C2410:

MPLL(FCLK)=(m*Fin)/(p*2^s)

*S3C2410:

MPLL(FCLK)=(2*m*Fin)/(p*2^s)

*其中:

m=MDIV+8,p=PDIV+2,s=SDIV

*对于本开发板,Fin=12MHz

*设置CLKDIVN,令分频比为:

FCLK:

HCLK:

PCLK=1:

2:

4,

*FCLK=200MHz,HCLK=100MHz,PCLK=50MHz

*/

voidclock_init(void)

{

//LOCKTIME=0x00ffffff;//使用默认值即可

CLKDIVN=0x03;//FCLK:

HCLK:

PCLK=1:

2:

4,HDIVN=1,PDIVN=1

/*如果HDIVN非0,CPU的总线模式应该从“fastbusmode”变为“asynchronousbusmode”*/

__asm__(

"mrcp15,0,r1,c1,c0,0\n"/*读出控制寄存器*/

"orrr1,r1,#0xc0000000\n"/*设置为“asynchronousbusmode”*/

"mcrp15,0,r1,c1,c0,0\n"/*写入控制寄存器*/

);

/*判断是S3C2410还是S3C2440*/

if((GSTATUS1==0x32410000)||(GSTATUS1==0x32410002))

{

MPLLCON=S3C2410_MPLL_200MHZ;/*现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz*/

}

else

{

MPLLCON=S3C2440_MPLL_200MHZ;/*现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz*/

}

}

 

//设置存储控制器以使用SDRAM

#defineMEM_CTL_BASE0x48000000//存储器控制器寄存器的起始地址

#defineSDRAM_BASE0x30000000

voidmemsetup(void)

{

volatileunsignedlong*p=(volatileunsignedlong*)MEM_CTL_BASE;

/*这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值

*写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到

*SDRAM之前就可以在steppingstone中运行

*/

/*存储控制器13个寄存器的值*/

p[0]=0x22011110;//BWSCON

p[1]=0x00000700;//BANKCON0

p[2]=0x00000700;//BANKCON1

p[3]=0x00000700;//BANKCON2

p[4]=0x00000700;//BANKCON3

p[5]=0x00000700;//BANKCON4

p[6]=0x00000700;//BANKCON5

p[7]=0x00018005;//BANKCON6

p[8]=0x00018005;//BANKCON7

/*REFRESH,

*HCLK=12MHz:

0x008C07A3,

*HCLK=100MHz:

0x008C04F4

*/

p[9]=0x008C04F4;

p[10]=0x000000B1;//BANKSIZE

p[11]=0x00000030;//M

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2