ARM定时器汇编代码.docx
《ARM定时器汇编代码.docx》由会员分享,可在线阅读,更多相关《ARM定时器汇编代码.docx(59页珍藏版)》请在冰豆网上搜索。
ARM定时器汇编代码
;
;BootloaderStage1的代码
;head.S
;====================================================================
;head.S(Stage1)程序流程说明
;
;0,开机启动,入口地址为0,转到启动开始处
;1,禁止看门狗定时器
;2,关闭所有中断
;3,初始化系统时钟,设置CPU工作频率
;4,初始化内存控制寄存器
;5,初始化堆栈
;6,将IsrIRQ标号的地址传给标号HandleIRQ指向的内存单元
;7,将NandFlash中的代码复制到SDRAM
;8,初始化数据区
;
;9,跳到SDRAM中执行
;中断向量:
;在0地址开始是8条跳转指令,占4*8=32字节;
;在SDRAM的最后256字节的开始,用4*8=32字节存放各种模式的服务子程序入口地址;
;然后用4*32个字节存放对应的IRQ中断服务子程序入口地址。
;当我们自己编写应用程序时,会用到这些地址。
;把我们自己写的中断服务子程序的开始地址送到这些单元中,
;当发生中断时才会执行我们编写的服务子程序。
;这些与广嵌提供的BIOS兼容。
;====================================================================
;main.c(Stage2)程序流程说明
;
;1,串口初始化
;2,校准延时
;3,点亮LED
;4,显示logo
;5,进入循环
;6,显示功能提示菜单
;7,等待按键,选择功能
;8,判断选择,如果有效,则执行相应程序
;9,输出空行进行显示分割
;10,回到循环开始
;
;可选择的功能有:
;1,通过串口下载文件到SDRAM
;2,将下载到SDRAM的文件写入NANDFlash。
;这些功能分别由不同的函数调用完成。
;1,下载文件,voidcomdownload(void),在comload.c中定义。
;2,写入NandFlash,voidNandWrite(void),在nand.c中定义。
;=====================================================================
;文件包含
GEToption.inc
GETmemcfg.inc
GET2410addr.inc
;=====================================================================
;importconfigconstants
;编译器定义符号引入,在后面程序中使用
IMPORT|Image$$RO$$Base|;BaseofROMcode
IMPORT|Image$$RO$$Limit|;EndofROMcode(=startofROMdata)
IMPORT|Image$$RW$$Base|;BaseofRAMtoinitialise
IMPORT|Image$$ZI$$Base|;Baseandlimitofarea
IMPORT|Image$$ZI$$Limit|;tozeroinitialise
;=====================================================================
;Pre-definedconstants
;定义符号常量,运行模式常数
USERMODEEQU0x10;用户模式
FIQMODEEQU0x11;FIQ模式
IRQMODEEQU0x12;IRQ模式
SVCMODEEQU0x13;管理模式
ABORTMODEEQU0x17;中止模式
UNDEFMODEEQU0x1b;未定义模式
MODEMASKEQU0x1f;模式屏蔽,与以上常数配合设置工作模式
NOINTEQU0xc0;中断屏蔽,屏蔽FIQ中断和IRQ中断
;=====================================================================
;Thelocationofstacks
;定义符号常量,表示各种工作模式下的堆栈开始地址
;_STACK_BASEADDRESSisdefinedinoption.incvalue=0x33ff8000
UserStackEQU(_STACK_BASEADDRESS-0x3800);0x33ff4800~用户模式
SVCStackEQU(_STACK_BASEADDRESS-0x2800);0x33ff5800~管理模式
UndefStackEQU(_STACK_BASEADDRESS-0x2400);0x33ff5c00~未定义模式
AbortStackEQU(_STACK_BASEADDRESS-0x2000);0x33ff6000~中止模式
IRQStackEQU(_STACK_BASEADDRESS-0x1000);0x33ff7000~IRQ模式
FIQStackEQU(_STACK_BASEADDRESS-0x0);0x33ff8000~FIQ模式
;系统模式没有考虑,没有使用
;=====================================================================
;gblsstring_1
downloadAddressequ0x30400000
filebufequ0x303fff00
;----------------------------------------------------------------------
;宏定义,重复使用,减轻编程负担
MACRO
$HandlerLabelHANDLER$HandleLabel
$HandlerLabel
subsp,sp,#4;decrementsp(tostorejumpaddress)
stmfdsp!
{r0}
;PUSHtheworkregistertostack
;(lrdoes'tpushbecauseitreturntooriginaladdress)
ldrr0,=$HandleLabel;loadtheaddressofHandleXXXtor0
ldrr0,[r0]
;loadthecontents(serviceroutinestartaddress)ofHandleXXX
strr0,[sp,#4];storethecontents(ISR)ofHandleXXXtostack
ldmfdsp!
{r0,pc};POPtheworkregisterandpc(jumptoISR)
MEND
;
;当产生IRQ中断时,PC先指向IRQ的中断入口0x18执行跳转到HandlerIRQ标号
;处。
假设SP=0x33ff8000,
;执行"subsp,sp,#4"后SP=0x33ff7ffc;
;
;"stmfdsp!
{r0}"指令的意义为SP先递减1(即减1个字,4字节)变成
;0x33fff7ff8,然后将r0的数据传给SP指向的地址,
;
;"ldrr0,=HandleIRQ"指令将标号HandleIRQ的地址(0x33ffff18)传给r0;
;
;"ldrr0,[r0]"指令将r0内容的内容传给r0,即将保存在表中的IsrIRQ
;标号的地址传给r0;
;
;
;"strr0,[sp,#4]"指令将r0值传给SP+4,即传给0x33ff7ff8,
;SP保持不变,此时0x33ff6ffc保存着中断处理函数的入口地址;
;"ldmfdsp!
{r8-r9,pc}"指令将SP指向的单元(0x33ff6ff4)的内容传给
;r8后递增1字,再将SP指向的单元(0x33ff6ff8)的内容传给r9后递增1字,
;再将SP指向的单元(0x33ff6ffc)的内容传给PC后增1字,
;此时SP=0x33ff7000,PC指向产生中断的中断源服务程序。
;====================================================================
;importMain;说明Main符号在其它文件中定义
;Main符号在Main.c中定义
;====================================================================
areaInit,code,readonly;声明代码段
entry;说明程序入口
start;标号
;=====================================================================
;设置中断向量表
bResetHandler;转到复位后开始执行的代码处
bHandlerUndef;handlerforUndefinedmode
bHandlerSWI;handlerforSWIinterrupt
bHandlerPabort;handlerforPAbort
bHandlerDabort;handlerforDAbort
b.;reserved
;bUart0RxInt;
;bIsrIRQ
bHandlerIRQ;handlerforIRQinterruptIRQ中断入口地址
bHandlerFIQ;handlerforFIQinterruptFIQ中断入口地址
;=====================================================================
;通过调用宏,编写中断服务子程序代码
HandlerFIQHANDLERHandleFIQ
;HandlerIRQHANDLERHandleIRQ
HandlerUndefHANDLERHandleUndef
HandlerSWIHANDLERHandleSWI
HandlerDabortHANDLERHandleDabort
HandlerPabortHANDLERHandlePabort
;---------------------------------------------------------------------
HandlerIRQ
;bIsrIRQ
;movr0,#'R'
;bluart_putch
;adrlr0,IsrIRQ
;adrlr0,Uart0RxInt
;movpc,r0
subsp,sp,#4;decrementsp(tostorejumpaddress)
stmfdsp!
{r0}
;PUSHtheworkregistertostack
;(lrdoes'tpushbecauseitreturntooriginal
;address)
ldrr0,=HandleIRQ;loadtheaddressofHandleXXXtor0
ldrr0,[r0]
;adrlr0,IsrIRQ;cannotldrr0,=IsrIRQ
;loadthecontents(serviceroutinestartaddress)
;ofHandleXXX
strr0,[sp,#4];storethecontents(ISR)ofHandleXXXtostack
ldmfdsp!
{r0,pc};POPtheworkregisterandpc(jumptoISR)
;=====================================================================
;以HandlerIRQHANDLERHandleIRQ为例,在汇编时,将展开形成如下代码
;
;HandlerIRQ;<===$HandlerLabel
;subsp,sp,#4;decrementsp(tostorejumpaddress)
;stmfdsp!
{r0}
;;sp先递减1(4字节),r0的内容存入sp指向的单元
;;PUSHtheworkregistertostack
;;(lrdoes'tpushbecauseitreturntooriginaladdress)
;ldrr0,=HandleIRQ;<==ldrr0,=$HandleLabel;loadtheaddressofHandleXXXtor0
;;HandleIRQ标号定义在RamData数据段
;;
;ldrr0,[r0]
;;loadthecontents(serviceroutinestartaddress)ofHandleXXX
;strr0,[sp,#4];storethecontents(ISR)ofHandleXXXtostack
;;r0中的值传送给sp+4指向的单元,sp的值不变。
;ldmfdsp!
{r0,pc};POPtheworkregisterandpc(jumptoISR)
;;
(1)先将sp指向的单元的内容传送给r0,sp递增1(4字节);
;;
(2)再将sp指向单元的内容传送给pc,sp递增1(4字节).
;=====================================================================
;IRQ中断服务子程序的入口,根据不同的IRQ中断,执行不同的IRQ服务子程序
;下面有代码将IsrIRQ标号的地址传给标号HandleIRQ指向的内存单元
;所以当发生IRQ中断时,HandlerIRQ程序会跳转到此处执行
IsrIRQ
;bUart0RxInt
;movr0,#'Q'
;bluart_putch
;subspc,lr,#4
subsp,sp,#4;reservedforPC
stmfdsp!
{r8-r9}
ldrr9,=INTOFFSET
ldrr9,[r9]
ldrr8,=HandleEINT0
addr8,r8,r9,lsl#2
ldrr8,[r8]
;adrlr8,Uart0RxInt;2013-9-15
strr8,[sp,#8]
ldmfdsp!
{r8-r9,pc}
;假设IRQ模式的SP=0x33ff7000,
;执行"subsp,sp,#4"后SP=0x33ff6ffc;
;
;"stmfdsp!
{r8-r9}"指令的意义为SP先递减1(即减1个字,4字节)变成
;0x33fff6ff8,然后将r9传给SP指向的地址,之后SP再递减,r8再传给SP指向
;地址,所以执行完该指令后,SP=0x33ff6ff4,0x33ff6ff8保存r9的内容,
;0x33ff6ff4保存r8的内容;
;
;"ldrr9,=INTOFFSET"指令将INTOFFSET寄存器地址传给r9;
;"ldrr9,[r9]"指令将r9的内容作为地址所指向的单元的内容传给r9,
;即将INTOFFSET寄存器的值传给r9;
;
;"ldrr8,=HandleEINT0"指令将中断服务程序入口地址表的HandleIRQ
;地址(0x33ffff20)传给r8;
;"addr8,r8,r9,lsl#2"指令将r9左移2位(即r9乘以4)再加上
;r8原先的内容再传给r8。
;这里r9左移2位是因为每个中断源在地址表中都占用4字节,而在INTOFFSET
;中的偏移量值只有1;
;"ldrr8,[r8]"指令将r8内容的内容传给r8,即将保存在表中的产生中断的
;中断源的中断处理函数入口地址传给r8;
;
;"strr8,[sp,#8]"指令将r8值传给SP+8,即传给0x33ff6ffc,
;SP保持不变,此时0x33ff6ffc保存着中断处理函数的入口地址;
;"ldmfdsp!
{r8-r9,pc}"指令将SP指向的单元(0x33ff6ff4)的内容传给
;r8后递增1字,再将SP指向的单元(0x33ff6ff8)的内容传给r9后递增1字,
;再将SP指向的单元(0x33ff6ffc)的内容传给PC后增1字,
;此时SP=0x33ff7000,PC指向产生中断的中断源服务程序。
;=====================================================================
;
;=================
;ENTRY
;复位后跳转到此处,执行复位程序
;=================
ResetHandler
;=====================================================================
;1关闭看门狗
ldrr0,=WTCON;watchdogdisable
ldrr1,=0x0
strr1,[r0]
;=====================================================================
;2关闭中断
ldrr0,=INTMSK
ldrr1,=0xffffffff;allinterruptdisable
strr1,[r0]
ldrr0,=INTSUBMSK
ldrr1,=0x3ff;allsubinterruptdisable
strr1,[r0]
;=====================================================================
;3初始化时钟系统
ldrr1,=LOCKTIME;0x4C000000;PLLlocktimecounter
ldrr2,=0x000FFFFF
strr2,[r1]
;ConfigureMPLL
;设置主频为约200MHz
ldrr0,=MPLLCON
ldrr1,=((0xa1<<12)+(0x03<<4)+1)
;Fin=12MHz,Fout=202.8MHz
;((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV);
strr1,[r0]
;设置FCLK:
HCLK:
PCLK=1:
2:
4
ldrr1,=CLKDIVN;0x4C000014;Clockdividercontrol
ldrr2,=0x3;FCLK:
HCLK:
PCLK=1:
2:
4
strr2,[r1]
;=====================================================================
;4初始化内存控制寄存器
;Setmemorycontrolregisters
[{true}
adrlr0,SMRDATA
;can'tuseldrr0,=xxxximportant!
!
!
;ADR伪指令,格式:
ADR{条件吗}寄存器组,标号
;标号:
非字对准地址-255~+255;字对准-1020~+1020
;生成ADD/SUBPC,#xx
;见符意德P68
ldrr1,=BWSCON;BWSCONAddress
addr2,r0,#52;EndaddressofSMRDATA
0
ldrr3,[r0],#4
strr3,[r1],#4
cmpr2,r0
bne%B0
]
;=====================================================================
;5,初始化堆栈
;Initializestacks
blInitStacks
;=====================================================================
;6,将IsrIRQ标号的地址传给标号HandleIRQ指向的内存单元
;SetupIRQhandler
ldrr0,=HandleIRQ
adrlr1,IsrIRQ;cannotldrr1,=IsrIRQ
strr1,[r0]
;Thisroutineisneededifthereisn't;'subspc,lr,#4'at0x18,0x1c
;=====================================================================
;7,将NandFlash中的代码复制到