个人修改的用于ADS1.2的2440init.s

来源:互联网 发布:林佳一是谁的女儿知乎 编辑:程序博客网 时间:2024/05/16 07:09
[cpp] view plaincopy
  1. ; 文件名: 2440INIT.s  
  2. ; 描述:   1).ARM 指令集,  
  3. ;       2).小端格式  
  4. ;       3).NOR Flash总线16位,大小2MB  
  5. ;       4).NAND Flash型号:K9F2G08,大小256MB  
  6. ;       5).GPIO总线32位,  
  7. ; 更改日期: 2012年1月31日   
  8. ;======================================================================================  
  9.       
  10.   
  11.   
  12.                 GET     2440addr.inc        ; 引入寄存器地址  
  13.       
  14. _STACK_BASEADDRESS      EQU     0x33FF8000  ; 堆栈基地址  
  15. _MMUTT_STARTADDRESS     EQU     0x33ff8000  ; 这个没用着啊~  
  16. _ISR_STARTADDRESS       EQU     0x33FFFF00  ; 定义第一级中断向量表的寻址地址  
  17.   
  18. ;============================== 系统时钟参数 ================================  
  19.   
  20. ; UCLK:UPLL固定为1:1,其中UCLK必须为48MHz(p7-24),UPLL由UPLLCON设置,后面的代码将其设置为48MHz  
  21. ; 可选择的是 Fclk:Hclk:Pclk 分频比,该分频比可通过CLKDIV_VAL来选择:  
  22. ; 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.  
  23.   
  24. CLKDIV_VAL      EQU     5   ;选择Fclk:Hclk:Pclk=1:4:8  
  25.   
  26. ; FCLK由MPLLCON寄存器设置,可通过M_MDIV,M_PDIV,M_SDIV来调整,此处设置为400MHz,见P7-21  
  27.   
  28. M_MDIV          EQU     92          ; Fin=12.0MHz FCLK=400MHz  
  29. M_PDIV          EQU     1  
  30. M_SDIV          EQU     1  
  31.   
  32.       
  33. ;============================= 预定义模式常量 ==============================  
  34.   
  35. ;用于设置CPSR的M[4:0],实现异常模式跳转  
  36.   
  37. USERMODE        EQU     0x10  
  38. FIQMODE         EQU     0x11  
  39. IRQMODE         EQU     0x12  
  40. SVCMODE         EQU     0x13  
  41. ABORTMODE       EQU     0x17  
  42. UNDEFMODE       EQU     0x1b  
  43. MODEMASK        EQU     0x1f  
  44. NOINT           EQU     0xc0  
  45.   
  46. ;============================== 栈地址定义 ==================================  
  47.   
  48. ; 各异常模式的栈在SDRAM内存中的地址  
  49.                                                         ;    地址    栈空间  
  50. UserStack       EQU     (_STACK_BASEADDRESS-0x3800)     ; 0x33ff4800,   未知   
  51. SVCStack        EQU     (_STACK_BASEADDRESS-0x2800)     ; 0x33ff5800,   4KB  
  52. UndefStack      EQU     (_STACK_BASEADDRESS-0x2400)     ; 0x33ff5c00,   1KB  
  53. AbortStack      EQU     (_STACK_BASEADDRESS-0x2000)     ; 0x33ff6000,   1KB   
  54. IRQStack        EQU     (_STACK_BASEADDRESS-0x1000)     ; 0x33ff7000,   4KB   
  55. FIQStack        EQU     (_STACK_BASEADDRESS-0x0)        ; 0x33ff8000,   4KB  
  56.                                                       
  57.   
  58. ;=================================  中断例程相关宏定义  ==================================  
  59. ;  
  60. ; 在本启动程序的最下面在SDRAM中定义一段空间,用于存放异常处理程序的入口地址,即异常向量表,  
  61. ; 除了ResetHandler外,其他异常在本启动程序入口跳转后执行的第一段程序就是下面宏定义这段程  
  62. ; 序,这段程序从SDRAM中取出异常处理程序的入口地址,并跳转到此地址处开始执行.要本启动程序中,  
  63. ; 复位异常几乎就是本启动程序,而IRQ异常处理程序是IsrIRQ,其他异常处理程序未定义.  
  64.   
  65.   
  66.                 MACRO  
  67. $HandlerLabel   HANDLER $HandleLabel        ; $HandlerLabel比$HandleLabel多了个‘r’,两者不一样!  
  68. $HandlerLabel  
  69.                 SUB     SP, SP, #4          ; SP=SP-4,此地址用于存放转跳地址,也即中断程序的入口地址  
  70.                 STMFD   SP!, {R0}           ; 把工作寄存器R0压入栈,sp=SP-4(sp先减)  
  71.                 LDR     R0, =$HandleLabel   ; 将HandleXXX的值放入r0  
  72.                 LDR     R0, [R0]            ; 把HandleXXX的值所指向的内容(也就是中断程序的入口地址)放入R0  
  73.                 STR     R0, [SP,#4]         ; 通过R0把中断服务程序(ISR)入口地址压入栈的sp=SP+4处  
  74.                 LDMFD   SP!, {R0,pc}        ; 出栈(sp后增),恢复r0的原值,pc值更新为中断服务程序的入口  
  75.                                             ; 地址(也就完成了到ISR的转跳)  
  76.                 MEND  
  77.   
  78. ;=====================================  RO RW ZI  =======================================  
  79. ;  
  80. ;   要了解RO,RW和ZI区是什么意思,需要首先了解以下知识:  
  81. ; 1)ARM程序的组成  
  82. ;   注意:此处所说的“ARM程序”是指在ARM系统中正在执行的程序,而非保存在ROM中的bin映像(image)文件。  
  83. ;   一个ARM程序包含3部分:RO区,RW区和ZI区  
  84. ;   RO是程序中的指令和常量,就是readonly  
  85. ;   RW是程序中的已初始化"全局"变量,就是read/write  
  86. ;   ZI是程序中的未初始化的"全局"变量,就是zero initialise(0初始化)  
  87. ; 2)ARM映像文件的组成  
  88. ;   所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。以下用Image文件来称呼它。  
  89. ; Image文件包含了RO和RW区数据,之所以Image文件不包含ZI区数据,是因为ZI区数据都是0,没必要包含,只  
  90. ; 要程序运行之前将ZI区数据所在的区域一律清零即可。包含进去反而浪费存储空间。  
  91. ; 3)ARM程序的执行过程  
  92. ;   从以上两点可以知道,烧录到ROM中的image文件与实际运行时的ARM程序之间并不是完全一样的。因此  
  93. ; 就有必要了解ARM程序是如何从ROM中的image到达实际运行状态的。实际上,RO区中的指令至少应该有这样  
  94. ; 的功能:  
  95. ;   1. 将RW区从ROM中搬到SDRAM内存中,因为RW区都是"全局"变量,不能存在ROM中,因为ROM只读不写  
  96. ;   2. 将ZI区所在的SDRAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI区地址  
  97. ;      及大小来将相应得RAM区域清零。ZI区也都是"全局"变量,同理,"全局"变量不能存在ROM/SROM中           
  98. ; 在main()执行前,RO中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含"全局"变量的代码。  
  99. ;  
  100. ;   RO区存放的起始地址 = RO base = |Image$RO$Base|,  
  101. ;   RO区存放的终止地址 = RO limit - 1 = |Image$RO$Limit| - 1  
  102. ;   RW区在SDRAM中存放的起始地址 = RW base = |Image$RW$Base|  
  103. ;   ZI区在SDRAM中存放的起始地址 = ZI base = |Image$ZI$Base|  
  104. ;   ZI区在SDRAM中存放的终止地址 = ZI limit - 1 = |Image$ZI$Limit| - 1  
  105. ;   RW区在SDRAM中存放的终止地址 = RW limit - 1 = ZI base - 1,所以没必要再给出  
  106. ;  
  107.   
  108.                 IMPORT      |Image$RO$Base| ; Base of ROM code  
  109.                 IMPORT      |Image$RO$Limit|  ; End of ROM code (=start of ROM data)  
  110.                 IMPORT      |Image$RW$Base|   ; Base of RAM to initialise  
  111.                 IMPORT      |Image$ZI$Base|   ; Base and limit of area  
  112.                 IMPORT      |Image$ZI$Limit|  ; to zero initialise  
  113.   
  114.   
  115. ;**************************************  代 码 段  ***************************************  
  116.       
  117.                 AREA    Init,CODE,READONLY  ; 代码段开始处  
  118.   
  119.                 ENTRY                       ; 标识程序入口处,要求编译器不将下面的异常跳转列表进行优化  
  120.       
  121.                 EXPORT  __ENTRY             ; 声明__ENTRY可用被其他源文件全局引用,应该是用于.c文件  
  122. __ENTRY  
  123.   
  124. ;====================================   异常跳转   ======================================  
  125.   
  126. ResetEntry                          ; 程序开始的地方                相对地址  
  127.                 B   ResetHandler    ;                               0x00000000  
  128.                 B   HandlerUndef    ; handler for Undefined mode,   0x00000004  
  129.                 B   HandlerSWI      ; handler for SWI interrupt,    0x00000008  
  130.                 B   HandlerPabort   ; handler for PAbort,           0x0000000C  
  131.                 B   HandlerDabort   ; handler for DAbort,           0x00000010  
  132.                 B   .               ; reserved,                     0x00000014  
  133.                 B   HandlerIRQ      ; handler for IRQ interrupt,    0x00000018  
  134.                 B   HandlerFIQ      ; handler for FIQ interrupt,    0x0000001C  
  135.                 B   EnterPWDN       ; 由正常模式进入低功耗模式(power down),地址必须是  
  136.                                     ; 0x00000020,貌似是约定好的  
  137.   
  138. ;=====================================  使用宏  ===================================  
  139. ;     
  140. ; 采用上面定义的HANDLER宏去建立Hander***和Handle***之间的联系  
  141.   
  142. HandlerFIQ      HANDLER     HandleFIQ  
  143. HandlerIRQ      HANDLER     HandleIRQ  
  144. HandlerUndef    HANDLER     HandleUndef  
  145. HandlerSWI      HANDLER     HandleSWI  
  146. HandlerDabort   HANDLER     HandleDabort  
  147. HandlerPabort   HANDLER     HandlePabort  
  148.   
  149. ;==================================   IRQ中断例程  ===============================  
  150. ;  
  151. ; IRQ中断可细分为多个中断源的中断,如果异常向量表是一级向量表的话,细分后的中  
  152. ; 断向量表就是二级向量表,下面的程序就是二级向量表的查询,下面会用到  
  153.   
  154. IsrIRQ  
  155.                 SUB     SP, SP, #4          ; reserved for PC,SP=SP-4  
  156.                 STMFD   SP!, {R8-R9}        ; SP=SP-8  
  157.   
  158.                 LDR     R9, =INTOFFSET      ; 把INTOFFSET寄存器的值装入R9,其值指向的存储地址存着中断的  
  159.                                             ; 偏移量(以字为单位,即4字节,见P14-16)  
  160.                 LDR     R9, [R9]            ; 中断的偏移量装入R9  
  161.                 LDR     R8, =HandleEINT0    ; 将HandleEINT0装入R8,其值为二级向量表的入口地址  
  162.                 ADD     R8, R8, R9, lsl #2  ; R8=R8+R9*4  
  163.                 LDR     R8, [R8]            ; 将所要的中断处理程序的入口地址装入R8  
  164.                 STR     R8, [SP,#8]         ; SP=SP+8,将中断处理程序的入口地址推入堆栈  
  165.                 LDMFD   SP!, {R8-R9,pc}     ; 出线,R8,R9还原其值,将中断处理程序的入口地址装入pc  
  166.       
  167.                 LTORG                       ; 文字池  
  168. ;-----------------------------------------------------------------------------------------  
  169.   
  170. ResetHandler  
  171.   
  172. ;================================= 关闭看门狗, 屏蔽所有中断 ==============================  
  173.   
  174.                 LDR     R0, =WTCON      ; 关看门狗定时器,p18-3  
  175.                 LDR     R1, =0x0  
  176.                 STR     R1, [R0]  
  177.   
  178.                 LDR     R0, =INTMSK  
  179.                 LDR     R1, =0xFFFFFFFF ; 关所有中断,p14-12  
  180.                 STR     R1, [R0]  
  181.   
  182.                 LDR     R0, =INTSUBMSK  
  183.                 LDR     R1, =0x7FFF     ; 关所有子中断,p14-18  
  184.                 STR     R1, [R0]  
  185.   
  186. ;================================== 配置系统时钟 =====================================  
  187.   
  188.                 ; 通过设置LOCKTIME寄存器,减少PLL锁存时间  
  189.                 LDR     R0, =LOCKTIME   ; P7-20,  
  190.                 LDR     R1, =0x01360136 ; p7-20,将S_LTIME和U_LTIME由初始值的OxFFFF改为0x136,只有310>300  
  191.                 STR     R1, [R0]  
  192.   
  193.                 LDR     R0, =CLKDIVN    ; CLKDIVN寄存器,p7-8,p7-24  
  194.                 LDR     R1, =CLKDIV_VAL ; CLKDIV_VAL在上面定义,为UCLK:UPLL和FCLK:HCLK:PCLK的分频比选项,UPLL下面设置为48MHz  
  195.                 STR     R1, [R0]        ; CLKDIVN取0x00000101,即5  
  196.       
  197. ; 如果FCLK:HCLK不是1:1的关系的话,就要转成异步总线模式。反之,如果是这个比例关系的话,就转  
  198. ; 成快速总线模式。  
  199. ; MMU_SetAsyncBusMode 和 MMU_SetFastBusMode 都在4K代码以上,不可能拷到4K大小的steppingstone中,   
  200. ; 而nandflash启动后,会将前4KB的引导代码拷到steppingstone(4KB大小)中执行,因此不能使用这两个  
  201. ; 函数如果你不想nandflash启动的话,就可以直接用上面的代码调用MMU_SetAsyncBusMode和MMU_SetFastBusMode  
  202. ; 下面的代码就是实现和上面两函数一样的功能. 利用的协处理器指令实现了对总线模式的设置  
  203. ; 至于为什么要用协处理器指令,代码是什么意思,我也不清楚。  
  204.   
  205.                 IF  CLKDIV_VAL>1                     ; 意味着Fclk:Hclk不是1:1.  
  206.                     MRC     p15, 0, R0, c1, c0, 0   ; MMU_SetAsyncBusMode,对协处理器15的c1和c0进行  
  207.                                                     ; 操作0(第0类),并将结果送入r0  
  208.                     ORR     R0, R0, #0xC0000000     ; R1_nF:OR:R1_iA  
  209.                     MCR     p15, 0, R0, c1, c0, 0  
  210.                 ELSE  
  211.                     MRC     p15, 0, R0, c1, c0, 0   ; MMU_SetFastBusMode  
  212.                     BIC     R0, R0, #0xC0000000     ; R1_iA:OR:R1_nF  
  213.                     MCR     p15, 0, R0, c1, c0, 0  
  214.                 ENDIF  
  215.                       
  216.                 ; 配置UPLL  
  217.                 LDR     R0, =UPLLCON  
  218.                 LDR     R1, =((56<<12)+(2<<4)+2)    ; UPLL=48MHz,Fin=12MHz  
  219.                 STR     R1, [R0]  
  220.                 NOP    ; 配置完UPLL后延迟7-clocks,才能配置MPLL,P7-21  
  221.                 NOP  
  222.                 NOP  
  223.                 NOP  
  224.                 NOP  
  225.                 NOP  
  226.                 NOP  
  227.                 ; 配置 MPLL  
  228.                 LDR     R0, =MPLLCON  
  229.                 LDR     R1, =((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)  ; Fin=12MHz  
  230.                 STR     R1, [R0]  
  231.                   
  232.                 ;检查这次启动是否是睡眠模式的唤醒导致的  
  233.                 LDR     R1, =GSTATUS2                           ; p9-35  
  234.                 LDR     R0, [R1]  
  235.                 TST     R0, #0x2  
  236.                 ;如果是则跳到SLEEP_WAKEUP handler  
  237.                 BNE     WAKEUP_SLEEP  
  238.       
  239. ;=============================  配置SDRAM内存控制寄存器 =====================================   
  240. ;  
  241. ;此段代码把13个存储控制器的内容批量的读取到了对应的特殊功能寄存器中首先是有一个数据区SMRDATA,  
  242. ;在程序的后面有定义,这个数据区给13个寄存器分配52字节的地址空间。BWSCON寄存器的地址0x48000000  
  243. ;貌似是所有寄存器中最低的,故从它开始设置。  
  244.   
  245.                 EXPORT StartPointAfterSleepWakeUp  
  246. StartPointAfterSleepWakeUp  
  247.   
  248.                 ;配置存储器控制寄存器  
  249.                 ADRL    R0, SMRDATA     ; 用adrl要比ldr要好,因为可以省去设置文字池的麻烦     
  250.                 LDR     R1,=BWSCON      ; BWSCON的地址,p5-14  
  251.                 ADD     R2, R0, #52     ; End address of SMRDATA  
  252.   
  253. 0  
  254.                 LDR     R3, [R0], #4  
  255.                 STR     R3, [R1], #4  
  256.                 CMP     R2, R0  
  257.                 BNE     %B0             ; 向后(BACK)搜索标号为0的行,以此实现循环,具体可看局部标号的知识  
  258.                   
  259.                 ; 延时等待SDRAM稳定运行,好像设置SDRAM寄存器后都要延时,只是没说要延时多久  
  260.                 MOV     R0, #256          
  261. 1  
  262.                 SUBS    R0, R0, #1      ; 向后(BACK)搜索标号为1的行,以此实现循环,具体可看局部标号的知识  
  263.                 BNE     %B1  
  264.   
  265. ;====================================  初始化栈 =====================================  
  266. ;  
  267. ; 下面这段用初始于初始化堆栈,所以不能用stmfd,ldmfd之类用到的堆栈指令,UndefStack,  
  268. ; AbortStack,IRQStack,FIQStack,SVCstack上面定义过。有一点要搞清楚,每一种模式都有专门  
  269. ; 的SP寄存器(r13,r13_fiq,r13_svc……),下面代码貌似在设置同一个SP寄存器,其实是设置不同的  
  270. ; SP寄存器!在工具包2.5以下版本, 'MSR cpsr,R1'可以代替'MSR cpsr_cxsf,R1',cpsr_cxsf相当于  
  271. ; cpsr_all,在s3c2440的datasheet中用的是cpsr_all(p3-21),但在ADS中用cpsr_all会报错,因为指  
  272. ; 令比较老,cpsr_cxsf的意思可参考arm_assembler_reference.pdf的P3-138  
  273.   
  274.                 MRS     R0, CPSR  
  275.                 BIC     R0, R0,#MODEMASK  
  276.                 ORR     R1, R0,#UNDEFMODE:OR:NOINT  
  277.                 MSR     cpsr_cxsf,R1        ; UndefMode  
  278.                 LDR     SP, =UndefStack     ; UndefStack=0x33FF5C00  
  279.   
  280.                 ORR     R1, R0, #ABORTMODE:OR:NOINT  
  281.                 MSR     cpsr_cxsf, R1       ; AbortMode  
  282.                 LDR     SP,=AbortStack      ; AbortStack=0x33FF6000  
  283.   
  284.                 ORR     R1, R0, #IRQMODE:OR:NOINT  
  285.                 MSR     cpsr_cxsf, R1       ; IRQMode  
  286.                 LDR     SP, =IRQStack       ; IRQStack=0x33FF7000  
  287.   
  288.                 ORR     R1, R0, #FIQMODE:OR:NOINT  
  289.                 MSR     cpsr_cxsf, R1       ; FIQMode  
  290.                 LDR     SP, =FIQStack       ; FIQStack=0x33FF8000  
  291.   
  292.                 BIC     R0, R0, #MODEMASK:OR:NOINT  
  293.                 ORR     R1, R0, #SVCMODE  
  294.                 MSR     cpsr_cxsf, R1       ; SVCMode  
  295.                 LDR     SP, =SVCStack       ; SVCStack=0x33FF5800  
  296.   
  297. ;================================== 初始化image运行域 ===================================  
  298.   
  299. ; BWSON(p5-14)寄存器的DW0[2:1]的值由硬件决定,也就是OM[1:0](p5-4)决定,"00"表示nandflash  
  300. ; 启动,"01""10"为norflash启动,"01"为16位宽度,"10"为32位宽度,"11"为Test mode  
  301.   
  302.                 LDR     R0, =BWSCON  
  303.                 LDR     R0, [R0]  
  304.                 ANDS    R0, R0, #6          ; 若OM[1:0] != 0, 则是NOR FLash启动  
  305.                 BNE     InitRam             ; 不读nand flash,跳到InitRam  
  306.                 ADR     R0, ResetEntry      ; 若OM[1:0] == 0, 则是NAND FLash启动  
  307.                 CMP     R0, #0              ; 如果入口不是0,即使用了仿真器,  
  308.                 BNE     InitRam             ; 则不在启动时读nand flash,跳到InitRam  
  309.       
  310. ;---------------------------------- NAND Flash 程序搬移 ------------------------------------  
  311. nand_boot_beg  
  312.   
  313.                 MOV     R5, #NFCONF         ; P6-12  
  314.                 ;set timing value  
  315.                 LDR     R0, =(3<<12):OR:(7<<8):OR:(7<<4)  
  316.                 STR     R0, [R5]            ; CLE &ALE duration setting value = 3/HCLK,CLE信号指定nandflash的  
  317.                                             ; 的指令周期,ALE信号指定nandflash的地址周期  
  318.                                             ; TWRPH0 duration setting value = (7+1)/HCLK  
  319.                                             ; TWRPH1 duration setting value = (7+1)/HCLK  
  320.                   
  321.                 ; 取消lock-tight,取消 soft lock,关闭非法访问中断,关闭RnB 中断,检测上升沿,锁住  
  322.                 ; spare ECC,锁住main数据区ECC生成码,初始化ECC译码器,取消片选,使能nandflash控制器  
  323.                 LDR     R0, =(0<<13):OR:(0<<12):OR:(0<<10):OR:(0<<9):OR:(0<<8):OR:(1<<6):OR:(1<<5):OR:(1<<4):OR:(1<<1):OR:(1<<0)  
  324.                 STR     R0, [R5, #4]        ; 配置NFCONT寄存器,其中(1<<1)取消了片选,P6-13  
  325.                   
  326.                 BL      ReadNandID          ; 按着读取NAND的ID号,结果保存在r5里  
  327.                 LDR     R0, =0xECAA         ; EC为maker ID,AA为K9F2G08R0A的设备ID  
  328.                 CMP     R5, R0   
  329.                 BLEQ    K9F2G08R0A_show     ; 若是K9F2G08R0A,则第一个LED灯亮              
  330.                 BEQ     %F2                 ; r5和r0相等的话就跳到下一个1标号处  
  331.                 LDR     R0, =0xECDA         ; EC为maker ID,DA为K9F2G08U0A的设备ID  
  332.                 CMP     R5, R0  
  333.                 BLEQ    K9F2G08U0A_show     ; 若是K9F2G08U0A,则第二个LED灯亮  
  334.                 BEQ     %F2                 ; r5和r0相等的话就跳到下一个1标号处  
  335.                 B       .  
  336. 2                     
  337.                 MOV     R8, #0              ; r8表示页号  
  338.                 LDR     R9, =ResetEntry     ; 取ResetEntry的绝对地址  
  339. 3     
  340.                 ANDS    R0, R8, #0x3f       ; 若r8为64的整数倍(因为1 block=64 pages)则继续执行,否则跳至后面标号为3处  
  341.                 BNE     %F4  
  342.                 MOV     R0, R8  
  343.                 BL      CheckBadBlk         ; 这个坏块检测程序应该不适合K9F2G08型号  
  344.                 CMP     R0, #0  
  345.                 ADDNE   R8, R8, #64         ; 若r0非零,则表示坏块,跳至下一个块。  
  346.                 BNE     %F0  
  347. 4     
  348.                 MOV     R0, R8  
  349.                 BL      ReadNandPage  
  350.                 ADD     R9, R9, #2048       ; 一页是2KB+64B,这里读的是main区  
  351.                 ADD     R8, R8, #1  
  352. 0  
  353.                 CMP     R8, #64             ; 复制64页,即搬移128KB代码到SDRAM中  
  354.                 BCC     %B3               
  355.                   
  356.                 MOV     R5, #NFCONF         ; DsNandFlash  
  357.                 LDR     R0, [R5, #4]  
  358.                 BIC     R0, R0, #1  
  359.                 STR     R0, [R5, #4]        ; nand flash controller disable(Don't work),见P6-14  
  360.   
  361.                 LDR     PC,=InitRam         ;从这一步开始,它就是在SDRAM中运行了!在内存中将RW区复制到RAM1中  
  362.   
  363. ;-----------------------------------  初始化RAM1 -------------------------------------  
  364. ;  
  365. ; 这段代码是将RW区复制到SDRAM中以BaseOfBSS为起始地址的内存中,如前所述,因ZI区全为0,  
  366. ; 故不需复制,只需清零ZI区在SDRAM内存中所在区域就行,BaseOfBSS和BaseOfZero-1分别人RW区  
  367. ; 的起始地址和末尾地址。BaseOfZero和EndOfBSS-1分别是ZI区的起始地址和末尾地址  
  368.           
  369. InitRam       
  370.                 LDR     R3, TopOfROM  
  371.                 ADRL    R0, ResetEntry   
  372.                 LDR     R2, BaseOfROM  
  373.                   
  374.                 SUB     R2, R2, R3      ; R2=BaseOfROM-TopOfROM  
  375.                 SUB     R0, R0, R2      ; R0=R0-R2=ResetEntry-(BaseOfROM-TopOfROM)=ResetEntry+代码长度  
  376.                                         ;   =ResetEntry+(TopOfROM-BaseOfROM)  
  377.                           
  378.                 ; 复制代码加载位置中的RW区到RW base,RW区大小为BaseOfZero-BaseOfBSS  
  379.                 LDR     R2, BaseOfBSS   ; R2<-BaseOfBSS的绝对地址  
  380.                 LDR     R3, BaseOfZero  ; R3<-BaseOfZero的绝对地址  
  381. 6  
  382.                 CMP     R2, R3          ; 复制的内容的大小为BaseOfZero-BaseOfBSS  
  383.                 LDRCC   R1, [R0], #4    ; 复制的内容的起始地址为r0,若在SDRAM内存中运行则为  
  384.                                         ; TopOfROM,否则为ResetEntry+TopOfROM-BaseOfROM  
  385.                 STRCC   R1, [R2], #4  
  386.                 BCC     %B6   
  387.   
  388.                 ; 用0初始化ZI区  
  389.                 MOV     R0, #0  
  390.                 LDR     R3, EndOfBSS          
  391. 7     
  392.                 CMP     R2, R3          ; R2=BaseOfZero, R3=EndOfBSS  
  393.                 STRCC   R0, [R2], #4    ; 以BaseOfZero为起始地址,将EndOfBSS-BaseOfZero大小的空间清零  
  394.                 BCC     %B7            
  395.   
  396.                   
  397. ;=================================== 保存中断例程地址 ====================================  
  398. ;  
  399. ; 因为只写了IRQ中断例程,故只保存IRQ中断例程的地址,以后若把其他中断例程补了,可在此保存中断例程地址  
  400. ;  
  401. ; RO、RW、ZI区复制分配完后,将二级向量表的中断查询例程的地址放到一级向量表IRQ异常向量中,使  
  402. ; 得IRQ向量指向二级向量表的中断查询例程  
  403.   
  404.                 ; Setup IRQ handler  
  405.                 LDR     R0, =HandleIRQ  ; IRQ异常向量的绝对地址->R0  
  406.                 LDR     R1, =IsrIRQ     ; R1 = 二级向量表的中断查询例程IsrIRQ的绝对地址  
  407.                 STR     R1, [R0]  
  408.   
  409. ;==================================== 跳转到C程序入口 =====================================  
  410. ;  
  411. ; 所有初始化配置做完后,跳到.c源文件中的Main函数  
  412. ; 下面的代码不能用[|]合成一段,不知为何  
  413.   
  414.                 IMPORT      Main        ; The main entry of mon program  
  415.                                         ; using_the_arm_assembler.pdf的p8-21  
  416.                     BL      Main        ; 注意这里用的是Main,不是main!故不能使用void main(),而应用void Main()  
  417.                     B       .           ; 死循环,注意小数点  
  418.   
  419.       
  420. ;==============================  NAND Flash ID号读取函数 ===================================  
  421. ;  
  422. ; 根据K9F2G08U0A.pdf的P42和P32说明,nandflash的ID有5个字节,以下面只读取第一个字节(即Maker Code)  
  423. ; 和第二个字节(即Device Code),读取ID的操作顺序是:1.发读ID命令0x90;2.发寻址信号0x00;3.读第一个  
  424. ; 字节;4.读第二个字节……据p10表格,nandflash忙状态下不能接受读ID命令0x90,故要测试是否处于忙状态  
  425. ; 另因所用nandflash型号只有8位I/O管脚,故NFDATA只有8位有效数字,故每次只读8位,见P6-6  
  426.   
  427. ReadNandID  
  428.                 MOV      R7, #NFCONF  
  429.                 LDR      R0, [R7,#4]        ; NFChipEn();  
  430.                 BIC      R0, R0, #2       
  431.                 STR      R0, [R7,#4]        ; 设置NFCONT,将Reg_nCE位清为0,即允许片选,见P6-14  
  432.                 MOV      R0, #0x90          ; WrNFCmd(RdIDCMD);  
  433.                 STRB     R0, [R7,#8]        ; 设置NFCMMD,发出读NANDflash ID的指令0x90,P6-15  
  434.                 MOV      R4, #0             ; WrNFAddr(0);  
  435.                 STRB     R4, [R7,#0xc]      ; 设置NFADDR,NAND flash存储器寻址值设为0,为何要在此置为0?P6-15  
  436. 8                                           ;while(NFIsBusy());  
  437.                 LDR      R0, [R7,#0x20]     ; 测试NFSTAT的RnB位,为1表示NAND flash空闲,为0则表示忙状态,循环等待其空闲,P6-18  
  438.                 TST      R0, #1  
  439.                 BEQ      %B8  
  440.                 LDRB     R0, [R7,#0x10]     ; id  = RdNFDat()<<8,从NFDATA寄存器中读第一个ID字节(即Maker Code)  
  441.                 MOV      R0, R0, lsl #8  
  442.                 LDRB     R1, [R7,#0x10]     ; id |= RdNFDat(),从NFDATA寄存器中读第二个ID字节(即Device Code)  
  443.                 ORR      R5, R1, R0  
  444.                 LDR      R0, [R7,#4]        ; NFChipDs();  
  445.                 ORR      R0, R0, #2  
  446.                 STR      R0, [R7,#4]        ; 设置NFCONT,将Reg_nCE位清为1,即取消片选,见P6-14  
  447.                 BX       LR   
  448.   
  449. WaitNandBusy  
  450.                 MOV      R0, #0x70          ; WrNFCmd(QUERYCMD);  
  451.                 MOV      R1, #NFCONF  
  452.                 STRB     R0, [R1,#8]        ; 设置NFCMMD,发出读nandflash状态指令0x70,见K9F2G080A.pdf的P41  
  453. 9                                           ; while(!(RdNFDat()&0x40));   
  454.                 LDRB     R0, [R1,#0x10]  
  455.                 TST      R0, #0x40          ; 判断I/O管脚是否为1,为1表示空闲,为0表示忙状态,见K9F2G080A.pdf的P41  
  456.                 BEQ      %B9  
  457.                 BX       LR  
  458.   
  459. ;====================================== NAND Flash 坏块检测 ==================================  
  460.   
  461. ;使用READ指令读出所检查块的第一页的2048列字节,若为FF,则表示此块正常,具体见K9F2G08U0A.pdf的P15  
  462.   
  463. CheckBadBlk  
  464.                 MOV      R7, LR             ; 因为此段程序有跳转,故要保存返回地址  
  465.                 MOV      R5, #NFCONF  
  466.                   
  467.                 BIC      R0, R0,#0x3F       ; Ox3F=64-1, 64为一个block的页数,这里是为保证R0是64的整数倍  
  468.                 LDR      R1, [R5,#4]        ; NFChipEn()  
  469.                 BIC      R1, R1,#2  
  470.                 STR      R1, [R5,#4]        ; 设置NFCONT,将Reg_nCE位清为0,即允许片选,见P6-14  
  471.   
  472.                 MOV      R1, #0x0           ; WrNFCmd(READCMD),发出读指令  
  473.                 STRB     R1, [R5,#8]  
  474.   
  475.                 MOV      R1, #0  
  476.                 MOV      R2, #8  
  477.                 STRB     R1, [R5,#0xc]      ; WrNFAddr(0)  
  478.                 STRB     R2, [R5,#0xc]      ; WrNFAddr(8),和上面的指令合在一起就是发出2048列地址(A0-A11)  
  479.                 STRB     R0, [R5,#0xc]      ; WrNFAddr(addr)  
  480.                 MOV      R1, R0,lsr #8      ; WrNFAddr(addr>>8)  
  481.                 STRB     R1, [R5,#0xc]  
  482.                 MOV      R1, R0,lsr #16     ; WrNFAddr(addr>>16),和上面的三个指令合在一起就是发出页地址(A12-A28)  
  483.                 STRB     R1, [R5,#0xc]  
  484.                   
  485.                 MOV      R1, #0x30            
  486.                 STRB     R1, [R5,#8]        ; 发出命令0x30  
  487.   
  488.                 BL       WaitNandBusy       ; WaitNFBusy()    
  489.   
  490.                 LDRB     R0, [R5,#0x10]     ; RdNFDat(),读取该block的第一页的第一个字节  
  491.                 SUB      R0, R0, #0xFF      ; 若此字节为FF,即R0为0,则表示该block正常  
  492.                               
  493.                 LDR      R1, [R5,#4]        ; NFChipDs()  
  494.                 ORR      R1, R1,#2  
  495.                 STR      R1, [R5,#4]        ; 设置NFCONT,将Reg_nCE位清为1,即取消片选,见P6-14  
  496.                   
  497.                 BX       R7  
  498.   
  499. ;================================= 读 NAND Flash 页内容 ================================  
  500.   
  501. ; r0表示页号,r9为resetentry的绝对地址,为RO base,也即BaseOfRom  
  502.       
  503. ReadNandPage  
  504.                 MOV      R7, LR             ; 因为此段程序有跳转,故要保存返回地址  
  505.                 MOV      R4, R9             ; r1为要复制的  
  506.                 MOV      R2, #0  
  507.                 MOV      R5, #NFCONF  
  508.   
  509.                 LDR      R1, [R5,#4]        ; NFChipEn()  
  510.                 BIC      R1, R1,#2  
  511.                 STR      R1, [R5,#4]        ; 设置NFCONT,将Reg_nCE位清为0,即允许片选,见P6-14      
  512.   
  513.                 MOV      R1, #0             ; WrNFCmd(READCMD0)  
  514.                 STRB     R1, [R5,#8]        ; 发出读命令0x00  
  515.                   
  516.                 STRB     R1, [R5,#0xc]      ; WrNFAddr(0)  
  517.                 STRB     R1, [R5,#0xc]      ; WrNFAddr(0)和上面的指令合在一起就是发出0x0列地址(A0-A11)  
  518.                 STRB     R0, [R5,#0xc]      ; WrNFAddr(addr)  
  519.                 MOV      R1, R0,lsr #8      ; WrNFAddr(addr>>8)  
  520.                 STRB     R1, [R5,#0xc]  
  521.                 MOV      R1, R0,lsr #16     ; WrNFAddr(addr>>16),和上面的三个指令合在一起就是发出页地址(A12-A28)  
  522.                 STRB     R1, [R5,#0xc]  
  523.   
  524.                 MOV      R1, #0x30            
  525.                 STRB     R1, [R5,#8]        ; 发出命令0x30  
  526.   
  527.                 BL       WaitNandBusy       ; WaitNFBusy()  
  528.           
  529. 12  
  530.                 LDRB     R1, [R5,#0x10]     ; buf[i] = RdNFDat(),循环一次读取一个字节的数据  
  531.                 STRB     R1, [R4,R2]        ; r4表示复制的SDRAM目标地址  
  532.                 ADD      R2, R2, #1  
  533.                 CMP      R2, #0x800         ; 0x800为2048,可我们所用的nandflash一页的大小为2K+64bit,这里只读main区  
  534.                 BCC      %B12  
  535.       
  536.                 LDR      R0, [R5,#4]        ; NFChipDs()  
  537.                 ORR      R0, R0, #2  
  538.                 STR      R0, [R5,#4]        ; 设置NFCONT,将Reg_nCE位清为1,即取消片选,见P6-14  
  539.                       
  540.                 BX       R7  
  541.   
  542. ;================================ NAND Flash 型号LED指示 ========================================  
  543.   
  544. K9F2G08R0A_show  
  545.                 MOV     R0, #0x56000000     ;GPACON寄存器的地址,见P9-8  
  546.                 MOV     R1, #0x0055           
  547.                 STR     R1, [R0, #0x50]     ;配置GPFCON寄存器,GPF0~GPF3为output,GPF4~GPF7为intput,见P9-18     
  548.                 MOV     R1, #0xFE  
  549.                 STR     R1, [R0, #0x54]     ;配置GPFDAT寄存器为0x50,即GPF0~GPF3输出0001,见P9-18  
  550.                 BX      LR  
  551.   
  552. K9F2G08U0A_show  
  553.                 MOV     R0, #0x56000000     ;GPACON寄存器的地址,见P9-8  
  554.                 MOV     R1, #0x0055           
  555.                 STR     R1, [R0, #0x50]     ;配置GPFCON寄存器,GPF0~GPF3为output,GPF4~GPF7为intput,见P9-18     
  556.                 MOV     R1, #0xFD  
  557.                 STR     R1, [R0, #0x54]     ;配置GPFDAT寄存器为0x50,即GPF0~GPF3输出0001,见P9-18  
  558.                 BX      LR  
  559.   
  560.                 LTORG   ;文字池  
  561.   
  562.   
  563.   
  564. SMRDATA         DATA  
  565. ;=============================== SDRAM寄存器配置值 =================================  
  566.   
  567. ; 下面的配置不一定是最优的  
  568.   
  569.                 DCD     0x2212d110      ; P5-14,BWSCON  
  570.                 DCD     0x00007FF4      ; GCS0, P5-16, BANKCON0,接NOR flash  
  571.                 DCD     0x00002e50      ; GCS1, P5-16, BANKCON1  
  572.                 DCD     0x00002e50      ; GCS2, P5-16, BANKCON2  
  573.                 DCD     0x00002e50      ; GCS3, P5-16, BANKCON3  
  574.                 DCD     0x00002e50      ; GCS4, P5-16, BANKCON4  
  575.                 DCD     0x00002e50      ; GCS5, P5-16, BANKCON5  
  576.                 DCD     0x00018005      ; GCS6, P5-17, BANKCON6,接SDRAM  
  577.                 DCD     0x00018005      ; GCS7, P5-17, BANKCON7  
  578.                 DCD     0x009404F5      ; P5-18,    REFRESH  
  579.                 DCD     0x32            ; SCLK power saving mode, P5-19, BANKSIZE,128M  
  580.                 DCD     0x30            ; MRSR6,CL=3clk, P5-20, MRSRB6  
  581.                 DCD     0x30            ; MRSR7,CL=3clk, P5-20, MRSRB7  
  582.   
  583. ;==================================================================================  
  584.           
  585. BaseOfROM       DCD     |Image$RO$Base|  
  586. TopOfROM        DCD     |Image$RO$Limit|  
  587. BaseOfBSS       DCD     |Image$RW$Base|  
  588. BaseOfZero      DCD     |Image$ZI$Base|  
  589. EndOfBSS        DCD     |Image$ZI$Limit|      
  590.   
  591. ;================================== 低功耗模式 ===================================  
  592.       
  593. ; Function for entering power down mode  
  594. ; 1. SDRAM should be in self-refresh mode.  
  595. ; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.  
  596. ; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh.  
  597. ; 4. The I-cache may have to be turned on.  
  598. ; 5. The location of the following code may have not to be changed.  
  599.   
  600. ; 下面这一段相当于c语言中的函数void EnterPWDN(int CLKCON),.c源文件可以调用这段代码  
  601. ; 以实现从正常模式进入低功耗模式,其中r0传递参数CLKCON,也即CLKCON寄存器要设置的值  
  602. ; 低功耗模式有三种:IDLE Mode, SLOW Mode,SLEEP Mode,其中IDLE Mode和SLOW Mode 本启动程  
  603. ; 序没写.一旦进行这两个模式,将进入死循环.  
  604.   
  605. EnterPWDN  
  606.                 MOV     R2, R0          ; R2即CLKCON要设置的值  
  607.                 TST     R0, #0x8  
  608.                 BNE     ENTER_SLEEP  
  609.                 B       .               ; 不是睡眠模式则死循环  
  610.   
  611. ;------------------------------------ --  进入睡眠模式 ------------------------------------  
  612.   
  613. ; 下面是进入睡眠模式的操作,是根据datasheet的P7-15的步骤来做的  
  614.   
  615. ENTER_SLEEP  
  616.                 ;GSTATUS3是通用状态寄存器,用户自定义其用途,其值在睡眠模式下不变  
  617.                 ;下面的代码将唤醒后开始执行的代码的地址存入GSTATUS3寄存器中  
  618.                 ADR     R0,StartPointAfterSleepWakeUp  
  619.                 LDR     R1,=GSTATUS3  
  620.                 STR     R0,[R1]  
  621.                   
  622.                 LDR     R0, =REFRESH        ; P5-18  
  623.                 LDR     R1, [R0]            ; R1=REFRESH寄存器的值  
  624.                 ORR     R1, R1, #(1<<22)  ; BIT_SELFREFRESH有前面定义了,为1<<22  
  625.                 STR     R1, [R0]            ; 允许 SDRAM 自刷新  
  626.   
  627.                 MOV     R1, #16             ; 延时等待刷新完毕,datasheet没说延时多久  
  628. 13                
  629.                 SUBS    R1, R1, #1  
  630.                 BNE     %B13  
  631.   
  632.                 LDR     R1, =MISCCR         ; MISCCR寄存器,P9-24  
  633.                 LDR     R0, [R1]  
  634.                 ORR     R0, R0,#(7<<17)   ; 使SCLK0=0, SCLK1=0, SDRAM自刷新保持使能  
  635.                 STR     R0, [R1]  
  636.   
  637.                 LDR     R0, =CLKCON         ; 将要配置的值送入CLKCON寄存器,进入SLEEP模式  
  638.                 STR     R2, [R0]  
  639.   
  640.                 B       .                   ; 死循环  
  641.   
  642. ;==================================== 睡眠模式的唤醒 ==================================  
  643.   
  644. ; 下面是唤醒睡眠模式的操作,是根据datasheet的P7-16的步骤来做的  
  645.   
  646. WAKEUP_SLEEP  
  647.                 ; 从睡眠模式唤醒后释放SCLKn  
  648.                 LDR     R1, =MISCCR         ; MISCCR寄存器,P9-24  
  649.                 LDR     R0, [R1]  
  650.                 BIC     R0, R0, #(7<<17)      ; SDRAM自刷新保持使能,SCLK0=SCLK, SCLK1=SCLK(SCLK是SDRAM时钟?SCLK0?SCLK1?)  
  651.                 STR     R0, [R1]  
  652.   
  653.                 ; 设置SDRAM内存控制器,总共有13个,它们的值在下面的SMRDATA数据区中一起指定了  
  654.                 ADRL    R0, SMRDATA       
  655.                 LDR     R1, =BWSCON         ; BWSCON Address,BWSCON寄存器的地址是13个中最低的  
  656.                 ADD     R2, R0, #52         ; 13*4=52  
  657. 14  
  658.                 LDR     R3, [R0], #4  
  659.                 STR     R3, [R1], #4  
  660.                 CMP     R2, R0  
  661.                 BNE     %B14  
  662.   
  663.                 MOV     R1, #256            ; 等待更新完毕,没说要延时多长时间  
  664. 15  
  665.                 SUBS    R1, R1, #1        
  666.                 BNE     %B15  
  667.   
  668.                 ; 下面程序默认用GSTATUS3来保存SLEEP模式唤醒后要跳往的地址了  
  669.                 LDR     R1, =GSTATUS3     
  670.                 LDR     R0, [R1]  
  671.                 BX      R0  
  672.   
  673. ;***************************************** 数 据 段 *****************************************  
  674.               
  675. ;=====================================  异常向量表 ==========================================  
  676.           
  677.                 AREA    RamData, DATA, READWRITE,ALIGN=2  
  678.                 MAP     _ISR_STARTADDRESS   ; _ISR_STARTADDRESS=0x33FFFF00,为第一级中断向量表的寻址地址,在上面有定义  
  679.   
  680.                                 ; 在SDRAM中的地址  
  681.   
  682. HandleReset     FIELD   4       ; 地址0x33FFFF00,这个用不着  
  683. HandleUndef     FIELD   4       ; 地址0x33FFFF04  
  684. HandleSWI       FIELD   4       ; 地址0x33FFFF08  
  685. HandlePabort    FIELD   4       ; 地址0x33FFFF0C  
  686. HandleDabort    FIELD   4       ; 地址0x33FFFF10  
  687. HandleReserved  FIELD   4       ; 地址0x33FFFF14  
  688. HandleIRQ       FIELD   4       ; 地址0x33FFFF18  
  689. HandleFIQ       FIELD   4       ; 地址0x33FFFF1C  
  690.   
  691. ;===================================  中断向量表 =================================  
  692.   
  693. ; Do not use the label 'IntVectorTable',  
  694. ; The value of IntVectorTable is different with the address you think it may be.  
  695. ; IntVectorTable  
  696. HandleEINT0     FIELD   4       ; 地址0x33FFFF20  
  697. HandleEINT1     FIELD   4       ; 地址0x33FFFF24  
  698. HandleEINT2     FIELD   4       ; 地址0x33FFFF28  
  699. HandleEINT3     FIELD   4       ; 地址0x33FFFF2C  
  700. HandleEINT4_7   FIELD   4       ; 地址0x33FFFF30  
  701. HandleEINT8_23  FIELD   4       ; 地址0x33FFFF34  
  702. HandleCAM       FIELD   4       ; 地址0x33FFFF38  
  703. HandleBATFLT    FIELD   4       ; 地址0x33FFFF3C  
  704. HandleTICK      FIELD   4       ; 地址0x33FFFF40  
  705. HandleWDT       FIELD   4       ; 地址0x33FFFF44  
  706. HandleTIMER0    FIELD   4       ; 地址0x33FFFF48  
  707. HandleTIMER1    FIELD   4       ; 地址0x33FFFF4C  
  708. HandleTIMER2    FIELD   4       ; 地址0x33FFFF50  
  709. HandleTIMER3    FIELD   4       ; 地址0x33FFFF54  
  710. HandleTIMER4    FIELD   4       ; 地址0x33FFFF58  
  711. HandleUART2     FIELD   4       ; 地址0x33FFFF5C  
  712.   
  713. HandleLCD       FIELD   4       ; 地址0x33FFFF60  
  714. HandleDMA0      FIELD   4       ; 地址0x33FFFF64  
  715. HandleDMA1      FIELD   4       ; 地址0x33FFFF68  
  716. HandleDMA2      FIELD   4       ; 地址0x33FFFF6C  
  717. HandleDMA3      FIELD   4       ; 地址0x33FFFF70  
  718. HandleMMC       FIELD   4       ; 地址0x33FFFF74  
  719. HandleSPI0      FIELD   4       ; 地址0x33FFFF78  
  720. HandleUART1     FIELD   4       ; 地址0x33FFFF7C  
  721. HandleNFCON     FIELD   4       ; 地址0x33FFFF80  
  722. HandleUSBD      FIELD   4       ; 地址0x33FFFF84  
  723. HandleUSBH      FIELD   4       ; 地址0x33FFFF88  
  724. HandleIIC       FIELD   4       ; 地址0x33FFFF8C  
  725. HandleUART0     FIELD   4       ; 地址0x33FFFF90  
  726. HandleSPI1      FIELD   4       ; 地址0x33FFFF94  
  727. HandleRTC       FIELD   4       ; 地址0x33FFFF98  
  728. HandleADC       FIELD   4       ; 地址0x33FFFF9C  
  729.                                 ; 地址0x33FFFFA0  
  730.                 END  
原创粉丝点击