;=============================================================================
上电和复位后,程序开始从位于0x0 执行b ResetHandler 程序跳转到这里执行,将看门狗,中断之类的程序关掉,以免打扰初始化程序的进行。
; ENTRY
;=============================================================================
ResetHandler
ldr r0,=WTCON ;watch dog disable
ldr r1,=0x0
str r1,[r0]
;WTCON 为看门狗控制寄存器,此处将其写入0x0,就是禁止它的所有功能,包括定时器定时,溢出中断及溢出复位。
ldr r0,=INTMSK
ldr r1,=0xffffffff ;all interrupt disable
str r1,[r0]
;INTMSK 为中断屏蔽寄存器,写入0xffffffff,就是禁止所有的中断产生,因为中断向量表还未初始化,如果此时产生中断会使程序进入未知的状态而跑飞。因为外设的中断太多,INTMSK 不够用,还需要将子中断INTSUBMSK 来将剩余的中断源也禁止掉。
ldr r0,=INTSUBMSK
ldr r1,=0x7fff ;all sub interrupt disable
str r1,[r0]
[ {FALSE} ;亮灯用的,可以用来调试用
;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
; Led_Display
ldr r0,=GPBCON
ldr r1,=0x155500
str r1,[r0]
ldr r0,=GPBDAT
ldr r1,=0x0
str r1,[r0]
]
;To reduce PLL lock time, adjust the LOCKTIME register.
ldr r0,=LOCKTIME ;设置pll 锁定时间
ldr r1,=0xffffff
str r1,[r0]
;LOCKTIME 为PLL 锁定时间计数寄存器,重新设定分频值时,PLL 进入锁定,输出稳定频率的时钟需要一定的时间。这里设置成默认的值,以满足锁定的要求。
[ PLL_ON_START ;在option.inc中定义,初始化为真
; Added for confirm clock divide. for 2440为2440添加时钟设备.
; Setting value Fclk:Hclk:Pclk
ldr r0,=CLKDIVN ;用于设定FCLK,HCLK和PCLK的比例
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.,在option.inc中有定义
str r1,[r0]
; MMU_SetAsyncBusMode and MMU_SetFastBusMode over 4K, so do not call here
; call it after copy
; [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
; bl MMU_SetAsyncBusMode
; |
; bl MMU_SetFastBusMode ; default value.
; ]
;三星手册里提供的MMU_SetAsyncBusMode 和 MMU_SetFastBusMode 函数都在4K代码以上(三星2440芯片就提供4K的内部SRAM),如果你想你编译出来的程序能在NAND上运行的话,就不能在这调用这两函数了.如果你不要求的话,你就可以直接调用.下面的代码就是实现和上面两函数一样的功能. 利用的协处理器的命令实现了对总线模式的设置
;program has not been copied, so use these directly
[ CLKDIV_VAL>1 ; means Fclk:Hclk is not 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
]
;配置UPLL一定要使最后的频率为48MHz,不然你甭想用USB接口了, 先赔UPLL再配MPLL,不能颠倒了
;Configure UPLL
ldr r0,=UPLLCON
ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV) ;Fin = 12.0MHz, UCLK = 48MHz
str r1,[r0]
nop ;在UPP 设定之后,必须等待7 个时钟的延迟,设定才会有效(因为5级流水线,搞不懂)
nop
nop
nop
nop
nop
nop
;Configure MPLL,设置MPLL, 2440主频可达400MHz
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin = 12.0MHz, FCLK = 400MHz
str r1,[r0]
]
;查看是否是由睡眠状态启动,如果是则跳转到WAKEUP_SLEEP状态
;Check if the boot is caused by the wake-up from SLEEP mode.
ldr r1,=GSTATUS2
ldr r0,[r1]
tst r0,#0x2 ;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
bne WAKEUP_SLEEP
EXPORT StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp
;初始化内存控制器其实就是对S3C2440 的memory bank 进行设置,使其扩展的存储器或外部设备能够被处理器通过内存控制器正确读写。由于S3C2440 的最终应用程序是在SDRAM(bank6)中运行,并与C 语言变量等的用户数据,各种模式的堆栈,中断向量表,都被定位在SDRAM 的空间,所以它必须在涉及这些处理之前完成初始化工作。
;Set memory control registers,设置存储器控制寄存器,SMRDATA中涉及的值请参考memcfg.inc程序
;ldr r0,=SMRDATA
adrl r0, SMRDATA ;be careful!不要用错,adr装载相对地址,ldr装载绝对地址,ro是数据区起始地址
ldr r1,=BWSCON ;BWSCON Address,BWSCON地址,r1是寄存器的起始地址
add r2, r0, #52 ;End address of SMRDATA,SMRDATA结束地址,r2是数据区结束地址
0
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0
;这段是功能寄存器初始化,把13 个存储控制器的内容批量的读取到了对应的特殊功能寄存器中,首先是下面有一个数据区SMRDATA,在程序的后面有定义,这个数据区给13 个寄存器分配52 字节的地址空间。在上面的代码中,r0 是这个数据区的起始地址,r2 是数据区的结束地址,r1 是寄存器的起始地址。这样,用一个判断语句就可以把内存中的数据赋给这13 个存储控制寄存器了。