ARM9启动代码裸机版 所谓启动代码就是处理器在启动的时候执行.docx
- 文档编号:24598370
- 上传时间:2023-05-29
- 格式:DOCX
- 页数:16
- 大小:21.31KB
ARM9启动代码裸机版 所谓启动代码就是处理器在启动的时候执行.docx
《ARM9启动代码裸机版 所谓启动代码就是处理器在启动的时候执行.docx》由会员分享,可在线阅读,更多相关《ARM9启动代码裸机版 所谓启动代码就是处理器在启动的时候执行.docx(16页珍藏版)》请在冰豆网上搜索。
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;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ARM9启动代码裸机版 所谓启动代码就是处理器在启动的时候执行 ARM9 启动 代码 裸机 所谓 就是 处理器 时候 执行