shuizhongling 发表于 2012-2-1 00:23:09

2440init.s更改版

;======================================================================================
; 文件名: 2440INIT.s
; 描述:        1).ARM 指令集,
;                2).小端格式
;                3).NOR Flash总线16位,大小2MB
;                4).NAND Flash型号:K9F2G08,大小256MB
;                5).GPIO总线32位,
; 更改日期: 2012年1月31日
;======================================================================================
       


                                GET         2440addr.inc                ; 引入寄存器地址
       
_STACK_BASEADDRESS                EQU         0x33FF8000        ; 堆栈基地址
_MMUTT_STARTADDRESS                EQU         0x33ff8000        ; 这个没用着啊~
_ISR_STARTADDRESS                EQU         0x33FFFF00        ; 定义第一级中断向量表的寻址地址

;============================== 系统时钟参数 ================================

; UCLK:UPLL固定为1:1,其中UCLK必须为48MHz(p7-24),UPLL由UPLLCON设置,后面的代码将其设置为48MHz
; 可选择的是 Fclk:Hclk:Pclk 分频比,该分频比可通过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.

CLKDIV_VAL                EQU                5        ;选择Fclk:Hclk:Pclk=1:4:8

; FCLK由MPLLCON寄存器设置,可通过M_MDIV,M_PDIV,M_SDIV来调整,此处设置为400MHz,见P7-21

M_MDIV                        EQU                92                        ; Fin=12.0MHz FCLK=400MHz
M_PDIV                        EQU                1
M_SDIV                        EQU                1

       
;============================= 预定义模式常量 ==============================

;用于设置CPSR的M,实现异常模式跳转

USERMODE            EQU         0x10
FIQMODE           EQU         0x11
IRQMODE           EQU         0x12
SVCMODE           EQU         0x13
ABORTMODE           EQU         0x17
UNDEFMODE           EQU         0x1b
MODEMASK            EQU         0x1f
NOINT               EQU         0xc0

;============================== 栈地址定义 ==================================

; 各异常模式的栈在SDRAM内存中的地址
                                                                                                          ;    地址           栈空间
UserStack                EQU                (_STACK_BASEADDRESS-0x3800)                ; 0x33ff4800,        未知
SVCStack                EQU                (_STACK_BASEADDRESS-0x2800)                ; 0x33ff5800,        4KB
UndefStack                EQU                (_STACK_BASEADDRESS-0x2400)                ; 0x33ff5c00,        1KB
AbortStack                EQU                (_STACK_BASEADDRESS-0x2000)                ; 0x33ff6000,        1KB
IRQStack                EQU                (_STACK_BASEADDRESS-0x1000)                ; 0x33ff7000,        4KB
FIQStack                EQU                (_STACK_BASEADDRESS-0x0)                ; 0x33ff8000,        4KB
                                                                                                          

;=================================中断例程相关宏定义==================================
;
; 在本启动程序的最下面在SDRAM中定义一段空间,用于存放异常处理程序的入口地址,即异常向量表,
; 除了ResetHandler外,其他异常在本启动程序入口跳转后执行的第一段程序就是下面宏定义这段程
; 序,这段程序从SDRAM中取出异常处理程序的入口地址,并跳转到此地址处开始执行.要本启动程序中,
; 复位异常几乎就是本启动程序,而IRQ异常处理程序是IsrIRQ,其他异常处理程序未定义.


                                MACRO
$HandlerLabel         HANDLER $HandleLabel                ; $HandlerLabel比$HandleLabel多了个‘r’,两者不一样!
$HandlerLabel
                                SUB        SP, SP, #4          ; SP=SP-4,此地址用于存放转跳地址,也即中断程序的入口地址
                                STMFD        SP!, {R0}                        ; 把工作寄存器R0压入栈,sp=SP-4(sp先减)
                                LDR   R0, =$HandleLabel   ; 将HandleXXX的值放入r0
                                LDR   R0,                     ; 把HandleXXX的值所指向的内容(也就是中断程序的入口地址)放入R0
                                STR   R0,               ; 通过R0把中断服务程序(ISR)入口地址压入栈的sp=SP+4处
                                LDMFD   SP!, {R0,pc}           ; 出栈(sp后增),恢复r0的原值,pc值更新为中断服务程序的入口
                                                                                        ; 地址(也就完成了到ISR的转跳)
                                MEND

;=====================================RO RW ZI=======================================
;
;        要了解RO,RW和ZI区是什么意思,需要首先了解以下知识:
; 1)ARM程序的组成
;        注意:此处所说的“ARM程序”是指在ARM系统中正在执行的程序,而非保存在ROM中的bin映像(image)文件。
;        一个ARM程序包含3部分:RO区,RW区和ZI区
;        RO是程序中的指令和常量,就是readonly
;        RW是程序中的已初始化"全局"变量,就是read/write
;        ZI是程序中的未初始化的"全局"变量,就是zero initialise(0初始化)
; 2)ARM映像文件的组成
;        所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。以下用Image文件来称呼它。
; Image文件包含了RO和RW区数据,之所以Image文件不包含ZI区数据,是因为ZI区数据都是0,没必要包含,只
; 要程序运行之前将ZI区数据所在的区域一律清零即可。包含进去反而浪费存储空间。
; 3)ARM程序的执行过程
;        从以上两点可以知道,烧录到ROM中的image文件与实际运行时的ARM程序之间并不是完全一样的。因此
; 就有必要了解ARM程序是如何从ROM中的image到达实际运行状态的。实际上,RO区中的指令至少应该有这样
; 的功能:
;        1. 将RW区从ROM中搬到SDRAM内存中,因为RW区都是"全局"变量,不能存在ROM中,因为ROM只读不写
;        2. 将ZI区所在的SDRAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI区地址
;           及大小来将相应得RAM区域清零。ZI区也都是"全局"变量,同理,"全局"变量不能存在ROM/SROM中                     
; 在main()执行前,RO中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含"全局"变量的代码。
;
;        RO区存放的起始地址 = RO base = |Image$$ER_ROM1$$RO$$Base|,
;         RO区存放的终止地址 = RO limit - 1 = |Image$$ER_ROM1$$RO$$Limit| - 1
;         RW区在SDRAM中存放的起始地址 = RW base = |Image$$RW_RAM1$$RW$$Base|
;         ZI区在SDRAM中存放的起始地址 = ZI base = |Image$$RW_RAM1$$ZI$$Base|
;         ZI区在SDRAM中存放的终止地址 = ZI limit - 1 = |Image$$RW_RAM1$$ZI$$Limit| - 1
;         RW区在SDRAM中存放的终止地址 = RW limit - 1 = ZI base - 1,所以没必要再给出
;
;                RO base 为 Target Options 中设置的ROM1 start , RO limit = ROM1 start + 代码长度,根据ROM1 start
;        的不同设置,RO区可能存放在NOR flash中,也可能在SDRAM中.
;           RW base 为 Target Options 中设置的RAM1 start , RW limit = ROM1 start + 已初始化全局变量长度
;   ZI base = RW limit, ZI limit = ZI base +未初始化全局变量长度.        RW,ZI区一定或者说必须在SDRAM中

                                IMPORT|Image$$ER_ROM1$$RO$$Base|                ; Base of ROM code
                                IMPORT         |Image$$ER_ROM1$$RO$$Limit|                ; End of ROM code (=start of ROM data)
                                IMPORT|Image$$RW_RAM1$$RW$$Base|                ; Base of RAM to initialise
                                IMPORT|Image$$RW_RAM1$$ZI$$Base|                ; Base of area to zero initialise
                                IMPORT|Image$$RW_RAM1$$ZI$$Limit|                ; limit of area to zero initialise


;**************************************代 码 段***************************************
                                PRESERVE8                                        ; 不知何用
       
                                AREA    RESET,CODE,READONLY        ; 代码段开始处

                                ENTRY                                                ; 标识程序入口处,要求编译器不将下面的异常跳转列表进行优化
       
                                EXPORT        __ENTRY                                ; 声明__ENTRY可用被其他源文件全局引用,应该是用于.c文件
__ENTRY

;====================================   异常跳转   ======================================

ResetEntry                                                        ; 程序开始的地方                               相对地址
                                B        ResetHandler        ;                                                                0x00000000
                                B        HandlerUndef        ; handler for Undefined mode,        0x00000004
                                B        HandlerSWI                ; handler for SWI interrupt,        0x00000008
                                B        HandlerPabort        ; handler for PAbort,                        0x0000000C
                                B        HandlerDabort        ; handler for DAbort,                        0x00000010
                                B        .                                ; reserved,                                                0x00000014
                                B        HandlerIRQ                ; handler for IRQ interrupt,        0x00000018
                                B        HandlerFIQ                ; handler for FIQ interrupt,        0x0000001C
                                B        EnterPWDN                ; 由正常模式进入低功耗模式(power down),地址必须是
                                                                        ; 0x00000020,貌似是约定好的

;=====================================使用宏===================================
;       
; 采用上面定义的HANDLER宏去建立Hander***和Handle***之间的联系

HandlerFIQ      HANDLER         HandleFIQ
HandlerIRQ      HANDLER         HandleIRQ
HandlerUndef    HANDLER         HandleUndef
HandlerSWI      HANDLER         HandleSWI
HandlerDabort   HANDLER               HandleDabort
HandlerPabort   HANDLER         HandlePabort

;==================================   IRQ中断例程===============================
;
; IRQ中断可细分为多个中断源的中断,如果异常向量表是一级向量表的话,细分后的中
; 断向量表就是二级向量表,下面的程序就是二级向量表的查询,下面会用到

IsrIRQ
                                SUB                SP, SP, #4               ; reserved for PC,SP=SP-4
                                STMFD        SP!, {R8-R9}                ; SP=SP-8

                                LDR                R9, =INTOFFSET                ; 把INTOFFSET寄存器的值装入R9,其值指向的存储地址存着中断的
                                                                                        ; 偏移量(以字为单位,即4字节,见P14-16)
                                LDR                R9,                         ; 中断的偏移量装入R9
                                LDR                R8, =HandleEINT0         ; 将HandleEINT0装入R8,其值为二级向量表的入口地址
                                ADD                R8, R8, R9, lsl #2        ; R8=R8+R9*4
                                LDR                R8,                         ; 将所要的中断处理程序的入口地址装入R8
                                STR                R8,                         ; SP=SP+8,将中断处理程序的入口地址推入堆栈
                                LDMFD        SP!, {R8-R9,pc}                ; 出线,R8,R9还原其值,将中断处理程序的入口地址装入pc
       
                                LTORG                                                ; 文字池
;-----------------------------------------------------------------------------------------

ResetHandler

;================================= 关闭看门狗, 屏蔽所有中断 ==============================

                                LDR                R0, =WTCON                ; 关看门狗定时器,p18-3
                                LDR                R1, =0x0
                                STR                R1,

                                LDR                R0, =INTMSK
                                LDR                R1, =0xFFFFFFFF        ; 关所有中断,p14-12
                                STR                R1,

                                LDR                R0, =INTSUBMSK
                                LDR                R1, =0x7FFF                ; 关所有子中断,p14-18
                                STR                R1,

;================================== 配置系统时钟 =====================================

                                ; 通过设置LOCKTIME寄存器,减少PLL锁存时间
                                LDR                R0, =LOCKTIME        ; P7-20,
                                LDR                R1, =0x01360136        ; p7-20,将S_LTIME和U_LTIME由初始值的OxFFFF改为0x136,只有310>300
                                STR                R1,

                                LDR                R0, =CLKDIVN        ; CLKDIVN寄存器,p7-8,p7-24
                                LDR                R1, =CLKDIV_VAL        ; CLKDIV_VAL在上面定义,为UCLK:UPLL和FCLK:HCLK:PCLK的分频比选项,UPLL下面设置为48MHz
                                STR                R1,                 ; CLKDIVN取0x00000101,即5
       
; 如果FCLK:HCLK不是1:1的关系的话,就要转成异步总线模式。反之,如果是这个比例关系的话,就转
; 成快速总线模式。
; MMU_SetAsyncBusMode 和 MMU_SetFastBusMode 都在4K代码以上,不可能拷到4K大小的steppingstone中,
; 而nandflash启动后,会将前4KB的引导代码拷到steppingstone(4KB大小)中执行,因此不能使用这两个
; 函数如果你不想nandflash启动的话,就可以直接用上面的代码调用MMU_SetAsyncBusMode和MMU_SetFastBusMode
; 下面的代码就是实现和上面两函数一样的功能. 利用的协处理器指令实现了对总线模式的设置
; 至于为什么要用协处理器指令,代码是什么意思,我也不清楚。

                                IF        CLKDIV_VAL>1                                         ; 意味着Fclk:Hclk不是1:1.
                                        MRC         p15, 0, R0, c1, c0, 0        ; MMU_SetAsyncBusMode,对协处理器15的c1和c0进行
                                                                                                        ; 操作0(第0类),并将结果送入r0
                                        ORR         R0, R0, #0xC0000000                ; R1_nF:OR:R1_iA
                                        MCR         p15, 0, R0, c1, c0, 0
                                ELSE
                                        MRC         p15, 0, R0, c1, c0, 0        ; MMU_SetFastBusMode
                                        BIC         R0, R0, #0xC0000000                ; R1_iA:OR:R1_nF
                                        MCR         p15, 0, R0, c1, c0, 0
                                ENDIF
                                       
                                ; 配置UPLL
                                LDR                R0, =UPLLCON
                                LDR                R1, =((56<<12)+(2<<4)+2)        ; UPLL=48MHz,Fin=12MHz
                                STR                R1,
                                NOP           ; 配置完UPLL后延迟7-clocks,才能配置MPLL,P7-21
                                NOP
                                NOP
                                NOP
                                NOP
                                NOP
                                NOP
                                ; 配置 MPLL
                                LDR                R0, =MPLLCON
                                LDR                R1, =((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)        ; Fin=12MHz
                                STR                R1,
                               
                                ;检查这次启动是否是睡眠模式的唤醒导致的
                                LDR                R1, =GSTATUS2                                                        ; p9-35
                                LDR                R0,
                                TST                R0, #0x2
                                ;如果是则跳到SLEEP_WAKEUP handler
                                BNE                WAKEUP_SLEEP
       
;=============================配置SDRAM内存控制寄存器 =====================================
;
;此段代码把13个存储控制器的内容批量的读取到了对应的特殊功能寄存器中首先是有一个数据区SMRDATA,
;在程序的后面有定义,这个数据区给13个寄存器分配52字节的地址空间。BWSCON寄存器的地址0x48000000
;貌似是所有寄存器中最低的,故从它开始设置。

                                EXPORT StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp

                                ;配置存储器控制寄存器
                                ADRL        R0, SMRDATA                ; 用adrl要比ldr要好,因为可以省去设置文字池的麻烦       
                                LDR                R1,=BWSCON                ; BWSCON的地址,p5-14
                                ADD                R2, R0, #52                ; End address of SMRDATA

0
                                LDR                R3, , #4
                                STR                R3, , #4
                                CMP                R2, R0
                                BNE                %B0                                ; 向后(BACK)搜索标号为0的行,以此实现循环,具体可看局部标号的知识
                               
                                ; 延时等待SDRAM稳定运行,好像设置SDRAM寄存器后都要延时,只是没说要延时多久
                                MOV                R0, #256               
1
                                SUBS        R0, R0, #1                ; 向后(BACK)搜索标号为1的行,以此实现循环,具体可看局部标号的知识
                                BNE                %B1

;====================================初始化栈 =====================================
;
; 下面这段用初始于初始化堆栈,所以不能用stmfd,ldmfd之类用到的堆栈指令,UndefStack,
; AbortStack,IRQStack,FIQStack,SVCstack上面定义过。有一点要搞清楚,每一种模式都有专门
; 的SP寄存器(r13,r13_fiq,r13_svc……),下面代码貌似在设置同一个SP寄存器,其实是设置不同的
; SP寄存器!在工具包2.5以下版本, 'MSR cpsr,R1'可以代替'MSR cpsr_cxsf,R1',cpsr_cxsf相当于
; cpsr_all,在s3c2440的datasheet中用的是cpsr_all(p3-21),但在ADS中用cpsr_all会报错,因为指
; 令比较老,cpsr_cxsf的意思可参考arm_assembler_reference.pdf的P3-138

                                MRS                R0, CPSR
                                BIC                R0, R0,#MODEMASK
                                ORR                R1, R0,#UNDEFMODE:OR:NOINT
                                MSR                CPSR_CXSF,R1                ; UndefMode
                                LDR                SP, =UndefStack                ; UndefStack=0x33FF5C00

                                ORR                R1, R0, #ABORTMODE:OR:NOINT
                                MSR                CPSR_CXSF, R1                ; AbortMode
                                LDR                SP,=AbortStack                ; AbortStack=0x33FF6000

                                ORR                R1, R0, #IRQMODE:OR:NOINT
                                MSR                CPSR_CXSF, R1                ; IRQMode
                                LDR                SP, =IRQStack                ; IRQStack=0x33FF7000

                                ORR                R1, R0, #FIQMODE:OR:NOINT
                                MSR                CPSR_CXSF, R1                ; FIQMode
                                LDR                SP, =FIQStack                ; FIQStack=0x33FF8000

                                BIC                R0, R0, #MODEMASK:OR:NOINT
                                ORR                R1, R0, #SVCMODE
                                MSR                CPSR_CXSF, R1                ; SVCMode
                                LDR                SP, =SVCStack                ; SVCStack=0x33FF5800

;================================== 初始化image运行域 ===================================

; BWSON(p5-14)寄存器的DW0的值由硬件决定,也就是OM(p5-4)决定,"00"表示nandflash
; 启动,"01"或"10"为norflash启动,"01"为16位宽度,"10"为32位宽度,"11"为Test mode

                                LDR                R0, =BWSCON
                                LDR                R0,
                                ANDS        R0, R0, #6                        ; 若OM != 0, 则是NOR FLash启动
                                BNE                InitRam                                ; 不读nand flash,跳到InitRam
                                ADR                R0, ResetEntry                ; 若OM == 0, 则是NAND FLash启动
                                CMP                R0, #0                                ; 如果入口不是0,即使用了仿真器,
                                BNE                InitRam                                ; 则不在启动时读nand flash,跳到InitRam
       
;---------------------------------- NAND Flash 程序搬移 ------------------------------------
nand_boot_beg

                                MOV                R5, #NFCONF                        ; P6-12
                                ;set timing value
                                LDR                R0,        =(3<<12):OR:(7<<8):OR:(7<<4)
                                STR                R0,                                ; CLE &ALE duration setting value = 3/HCLK,CLE信号指定nandflash的
                                                                                        ; 的指令周期,ALE信号指定nandflash的地址周期
                                                                                        ; TWRPH0 duration setting value = (7+1)/HCLK
                                                                                        ; TWRPH1 duration setting value = (7+1)/HCLK
                               
                                ; 取消lock-tight,取消 soft lock,关闭非法访问中断,关闭RnB 中断,检测上升沿,锁住
                                ; spare ECC,锁住main数据区ECC生成码,初始化ECC译码器,取消片选,使能nandflash控制器
                                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)
                                STR                R0,                 ; 配置NFCONT寄存器,其中(1<<1)取消了片选,P6-13
                               
                                BL                 ReadNandID                ; 按着读取NAND的ID号,结果保存在r5里
                                LDR         R0, =0xECAA                 ; EC为maker ID,AA为K9F2G08R0A的设备ID
                                CMP         R5, R0
                                BLEQ        K9F2G08R0A_show         ; 若是K9F2G08R0A,则第一个LED灯亮                       
                                BEQ         %F2                                   ; r5和r0相等的话就跳到下一个1标号处
                                LDR         R0, =0xECDA                 ; EC为maker ID,DA为K9F2G08U0A的设备ID
                                CMP         R5, R0
                                BLEQ        K9F2G08U0A_show                ; 若是K9F2G08U0A,则第二个LED灯亮
                                BEQ         %F2                                   ; r5和r0相等的话就跳到下一个1标号处
                                B                .
2                                       
                                MOV                R8, #0                                ; r8表示页号
                                LDR                R9, =ResetEntry                ; 取ResetEntry的绝对地址
3       
                                ANDS        R0, R8, #0x3f                ; 若r8为64的整数倍(因为1 block=64 pages)则继续执行,否则跳至后面标号为3处
                                BNE                %F4
                                MOV                R0, R8
                                BL                CheckBadBlk                        ; 这个坏块检测程序应该不适合K9F2G08型号
                                CMP                R0, #0
                                ADDNE        R8, R8, #64                        ; 若r0非零,则表示坏块,跳至下一个块。
                                BNE                %F0
4       
                                MOV                R0, R8
                                BL                ReadNandPage
                                ADD                R9, R9, #2048                ; 一页是2KB+64B,这里读的是main区
                                ADD                R8, R8, #1
0
                                CMP                R8, #64                                ; 复制64页,即搬移128KB代码到SDRAM中
                                BCC                %B3                               
                               
                                MOV                R5, #NFCONF                        ; DsNandFlash
                                LDR                R0,
                                BIC         R0, R0, #1
                                STR                R0,                 ; nand flash controller disable(Don't work),见P6-14

                                LDR                PC,=InitRam                        ;从这一步开始,它就是在SDRAM中运行了!在内存中将RW区复制到RAM1中

;-----------------------------------初始化RAM1 -------------------------------------
;
; 这段代码是将RW区复制到SDRAM中以BaseOfBSS为起始地址的内存中,如前所述,因ZI区全为0,
; 故不需复制,只需清零ZI区在SDRAM内存中所在区域就行,BaseOfBSS和BaseOfZero-1分别人RW区
; 的起始地址和末尾地址。BaseOfZero和EndOfBSS-1分别是ZI区的起始地址和末尾地址
               
InitRam               
                                LDR         R3, TopOfROM
                                ADRL         R0, ResetEntry
                                LDR         R2, BaseOfROM
                               
                                SUB                R2, R2, R3                ; R2=BaseOfROM-TopOfROM
                                SUB                R0, R0, R2                ; R0=R0-R2=ResetEntry-(BaseOfROM-TopOfROM)=ResetEntry+代码长度
                                                                                ;   =ResetEntry+(TopOfROM-BaseOfROM)
                                               
                                ; 复制代码加载位置中的RW区到RW base,RW区大小为BaseOfZero-BaseOfBSS
                                LDR         R2, BaseOfBSS   ; R2<-BaseOfBSS的绝对地址
                                LDR         R3, BaseOfZero; R3<-BaseOfZero的绝对地址
6
                                CMP                R2, R3                        ; 复制的内容的大小为BaseOfZero-BaseOfBSS
                                LDRCC        R1, , #4        ; 复制的内容的起始地址为r0,若在SDRAM内存中运行则为
                                                                                ; TopOfROM,否则为ResetEntry+TopOfROM-BaseOfROM
                                STRCC        R1, , #4
                                BCC                %B6       

                                ; 用0初始化ZI区
                                MOV                R0,        #0
                                LDR                R3,        EndOfBSS               
7       
                                CMP                R2,        R3                        ; R2=BaseOfZero, R3=EndOfBSS
                                STRCC        R0, , #4        ; 以BaseOfZero为起始地址,将EndOfBSS-BaseOfZero大小的空间清零
                                BCC                %B7                       

                               
;=================================== 保存中断例程地址 ====================================
;
; 因为只写了IRQ中断例程,故只保存IRQ中断例程的地址,以后若把其他中断例程补了,可在此保存中断例程地址
;
; RO、RW、ZI区复制分配完后,将二级向量表的中断查询例程的地址放到一级向量表IRQ异常向量中,使
; 得IRQ向量指向二级向量表的中断查询例程

                                ; Setup IRQ handler
                                LDR                R0, =HandleIRQ        ; IRQ异常向量的绝对地址->R0
                                LDR                R1, =IsrIRQ                  ; R1 = 二级向量表的中断查询例程IsrIRQ的绝对地址
                                STR                R1,

;==================================== 跳转到C程序入口 =====================================
;
; 所有初始化配置做完后,跳到.c源文件中的Main函数
; 下面的代码不能用[|]合成一段,不知为何

                                IMPORT        Main            ; The main entry of mon program
                                                                                ; using_the_arm_assembler.pdf的p8-21
                                        BL                Main                ; 注意这里用的是Main,不是main!故不能使用void main(),而应用void Main()
                                        B                 .                        ; 死循环,注意小数点

       
;==============================NAND Flash ID号读取函数 ===================================
;
; 根据K9F2G08U0A.pdf的P42和P32说明,nandflash的ID有5个字节,以下面只读取第一个字节(即Maker Code)
; 和第二个字节(即Device Code),读取ID的操作顺序是:1.发读ID命令0x90;2.发寻址信号0x00;3.读第一个
; 字节;4.读第二个字节……据p10表格,nandflash忙状态下不能接受读ID命令0x90,故要测试是否处于忙状态
; 另因所用nandflash型号只有8位I/O管脚,故NFDATA只有8位有效数字,故每次只读8位,见P6-6

ReadNandID
                                MOV      R7, #NFCONF
                                LDR      R0,                 ; NFChipEn();
                                BIC      R0, R0, #2               
                                STR      R0,                 ; 设置NFCONT,将Reg_nCE位清为0,即允许片选,见P6-14
                                MOV      R0, #0x90                        ; WrNFCmd(RdIDCMD);
                                STRB   R0,                 ; 设置NFCMMD,发出读NANDflash ID的指令0x90,P6-15
                                MOV      R4, #0                                ; WrNFAddr(0);
                                STRB   R4,                 ; 设置NFADDR,NAND flash存储器寻址值设为0,为何要在此置为0?P6-15
8                                                                                        ;while(NFIsBusy());
                                LDR      R0,                 ; 测试NFSTAT的RnB位,为1表示NAND flash空闲,为0则表示忙状态,循环等待其空闲,P6-18
                                TST      R0, #1
                                BEQ      %B8
                                LDRB   R0,                 ; id= RdNFDat()<<8,从NFDATA寄存器中读第一个ID字节(即Maker Code)
                                MOV      R0, R0, lsl #8
                                LDRB   R1,                 ; id |= RdNFDat(),从NFDATA寄存器中读第二个ID字节(即Device Code)
                                ORR      R5, R1, R0
                                LDR      R0,                 ; NFChipDs();
                                ORR      R0, R0, #2
                                STR      R0,                 ; 设置NFCONT,将Reg_nCE位清为1,即取消片选,见P6-14
                                BX               LR       

WaitNandBusy
                                MOV      R0, #0x70                        ; WrNFCmd(QUERYCMD);
                                MOV      R1, #NFCONF
                                STRB   R0,                 ; 设置NFCMMD,发出读nandflash状态指令0x70,见K9F2G080A.pdf的P41
9                                                                                        ; while(!(RdNFDat()&0x40));       
                                LDRB   R0,
                                TST      R0, #0x40                        ; 判断I/O管脚是否为1,为1表示空闲,为0表示忙状态,见K9F2G080A.pdf的P41
                                BEQ               %B9
                                BX               LR

;====================================== NAND Flash 坏块检测 ==================================

;使用READ指令读出所检查块的第一页的2048列字节,若为FF,则表示此块正常,具体见K9F2G08U0A.pdf的P15

CheckBadBlk
                                MOV               R7, LR                                ; 因为此段程序有跳转,故要保存返回地址
                                MOV               R5, #NFCONF
                               
                                BIC               R0, R0,#0x3F                ; Ox3F=64-1, 64为一个block的页数,这里是为保证R0是64的整数倍
                                LDR               R1,                 ; NFChipEn()
                                BIC      R1, R1,#2
                                STR      R1,                 ; 设置NFCONT,将Reg_nCE位清为0,即允许片选,见P6-14

                                MOV      R1, #0x0                        ; WrNFCmd(READCMD),发出读指令
                                STRB   R1,

                                MOV               R1, #0
                                MOV               R2, #8
                                STRB   R1,                 ; WrNFAddr(0)
                                STRB   R2,                 ; WrNFAddr(8),和上面的指令合在一起就是发出2048列地址(A0-A11)
                                STRB   R0,                 ; WrNFAddr(addr)
                                MOV      R1, R0,lsr #8                ; WrNFAddr(addr>>8)
                                STRB   R1,
                                MOV      R1, R0,lsr #16                ; WrNFAddr(addr>>16),和上面的三个指令合在一起就是发出页地址(A12-A28)
                                STRB   R1,
                               
                                MOV      R1, #0x30                       
                                STRB   R1,                 ; 发出命令0x30

                                BL       WaitNandBusy                ; WaitNFBusy()       

                                LDRB       R0,                 ; RdNFDat(),读取该block的第一页的第一个字节
                                SUB               R0, R0, #0xFF                ; 若此字节为FF,即R0为0,则表示该block正常
                                                       
                                LDR      R1,                 ; NFChipDs()
                                ORR      R1, R1,#2
                                STR      R1,                 ; 设置NFCONT,将Reg_nCE位清为1,即取消片选,见P6-14
                               
                                BX               R7

;================================= 读 NAND Flash 页内容 ================================

; r0表示页号,r9为resetentry的绝对地址,为RO base,也即BaseOfRom
       
ReadNandPage
                                MOV               R7, LR                                ; 因为此段程序有跳转,故要保存返回地址
                                MOV      R4, R9                                ; r1为要复制的
                                MOV               R2, #0
                                MOV      R5, #NFCONF

                                LDR      R1,                 ; NFChipEn()
                                BIC      R1, R1,#2
                                STR      R1,                 ; 设置NFCONT,将Reg_nCE位清为0,即允许片选,见P6-14       

                                MOV      R1, #0                                ; WrNFCmd(READCMD0)
                                STRB   R1,                 ; 发出读命令0x00
                               
                                STRB   R1,                 ; WrNFAddr(0)
                                STRB   R1,                 ; WrNFAddr(0)和上面的指令合在一起就是发出0x0列地址(A0-A11)
                                STRB   R0,                 ; WrNFAddr(addr)
                                MOV      R1, R0,lsr #8                ; WrNFAddr(addr>>8)
                                STRB   R1,
                                MOV      R1, R0,lsr #16                ; WrNFAddr(addr>>16),和上面的三个指令合在一起就是发出页地址(A12-A28)
                                STRB   R1,

                                MOV      R1, #0x30                       
                                STRB   R1,                 ; 发出命令0x30

                                BL       WaitNandBusy                ; WaitNFBusy()
               
12
                                LDRB   R1,                 ; buf = RdNFDat(),循环一次读取一个字节的数据
                                STRB   R1,                 ; r4表示复制的SDRAM目标地址
                                ADD      R2, R2, #1
                                CMP      R2, #0x800                        ; 0x800为2048,可我们所用的nandflash一页的大小为2K+64bit,这里只读main区
                                BCC      %B12
       
                                LDR      R0,                 ; NFChipDs()
                                ORR      R0, R0, #2
                                STR      R0,                 ; 设置NFCONT,将Reg_nCE位清为1,即取消片选,见P6-14
                                       
                                BX               R7

;================================ NAND Flash 型号LED指示 ========================================

K9F2G08R0A_show
                                MOV                R0, #0x56000000                ;GPACON寄存器的地址,见P9-8
                                MOV                R1, #0x0055                       
                                STR                R1,                 ;配置GPFCON寄存器,GPF0~GPF3为output,GPF4~GPF7为intput,见P9-18       
                                MOV                R1, #0xFE
                                STR                R1,                 ;配置GPFDAT寄存器为0x50,即GPF0~GPF3输出0001,见P9-18
                                BX                LR

K9F2G08U0A_show
                                MOV                R0, #0x56000000                ;GPACON寄存器的地址,见P9-8
                                MOV                R1, #0x0055                       
                                STR                R1,                 ;配置GPFCON寄存器,GPF0~GPF3为output,GPF4~GPF7为intput,见P9-18       
                                MOV                R1, #0xFD
                                STR                R1,                 ;配置GPFDAT寄存器为0x50,即GPF0~GPF3输出0001,见P9-18
                                BX                LR

                                LTORG        ;文字池



SMRDATA                 DATA
;=============================== SDRAM寄存器配置值 =================================

; 下面的配置不一定是最优的

                                DCD         0x2212d110                ; P5-14,BWSCON
                                DCD         0x00007FF4                 ; GCS0, P5-16, BANKCON0,接NOR flash
                                DCD         0x00002e50                ; GCS1, P5-16, BANKCON1
                                DCD         0x00002e50                ; GCS2, P5-16, BANKCON2
                                DCD                0x00002e50        ; GCS3, P5-16, BANKCON3
                                DCD         0x00002e50        ; GCS4, P5-16, BANKCON4
                                DCD         0x00002e50                ; GCS5, P5-16, BANKCON5
                                DCD                0x00018005                ; GCS6, P5-17, BANKCON6,接SDRAM
                                DCD         0x00018005                ; GCS7, P5-17, BANKCON7
                                DCD         0x009404F5                ; P5-18,        REFRESH
                                DCD         0x32                  ; SCLK power saving mode, P5-19, BANKSIZE,128M
                                DCD         0x30                  ; MRSR6,CL=3clk, P5-20, MRSRB6
                                DCD         0x30                          ; MRSR7,CL=3clk, P5-20, MRSRB7

;==================================================================================
               
BaseOfROM                DCD                |Image$$ER_ROM1$$RO$$Base|        ; Base of ROM code
TopOfROM                DCD                |Image$$ER_ROM1$$RO$$Limit|        ; End of ROM code (=start of ROM data)
BaseOfBSS                DCD                |Image$$RW_RAM1$$RW$$Base|        ; Base of RAM to initialise
BaseOfZero                DCD                |Image$$RW_RAM1$$ZI$$Base|        ; Base and limit of area
EndOfBSS                DCD                |Image$$RW_RAM1$$ZI$$Limit|        ; to zero initialise       

;================================== 低功耗模式 ===================================
       
; Function for entering power down mode
; 1. SDRAM should be in self-refresh mode.
; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.
; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh.
; 4. The I-cache may have to be turned on.
; 5. The location of the following code may have not to be changed.

; 下面这一段相当于c语言中的函数void EnterPWDN(int CLKCON),.c源文件可以调用这段代码
; 以实现从正常模式进入低功耗模式,其中r0传递参数CLKCON,也即CLKCON寄存器要设置的值
; 低功耗模式有三种:IDLE Mode, SLOW Mode,SLEEP Mode,其中IDLE Mode和SLOW Mode 本启动程
; 序没写.一旦进行这两个模式,将进入死循环.

EnterPWDN
                                MOV                R2, R0                  ; R2即CLKCON要设置的值
                                TST                R0, #0x8
                                BNE                ENTER_SLEEP
                                B                .                                ; 不是睡眠模式则死循环

;------------------------------------ --进入睡眠模式 ------------------------------------

; 下面是进入睡眠模式的操作,是根据datasheet的P7-15的步骤来做的

ENTER_SLEEP
                                ;GSTATUS3是通用状态寄存器,用户自定义其用途,其值在睡眠模式下不变
                                ;下面的代码将唤醒后开始执行的代码的地址存入GSTATUS3寄存器中
                                ADR                R0,StartPointAfterSleepWakeUp
                                LDR                R1,=GSTATUS3
                                STR                R0,
                               
                                LDR         R0, =REFRESH                ; P5-18
                                LDR         R1,                         ; R1=REFRESH寄存器的值
                                ORR         R1, R1, #(1<<22)        ; BIT_SELFREFRESH有前面定义了,为1<<22
                                STR         R1,                         ; 允许 SDRAM 自刷新

                                MOV         R1, #16                                ; 延时等待刷新完毕,datasheet没说延时多久
13                               
                                SUBS         R1, R1, #1
                                BNE         %B13

                                LDR                R1, =MISCCR                        ; MISCCR寄存器,P9-24
                                LDR                R0,
                                ORR                R0, R0,#(7<<17)        ; 使SCLK0=0, SCLK1=0, SDRAM自刷新保持使能
                                STR                R0,

                                LDR         R0, =CLKCON                        ; 将要配置的值送入CLKCON寄存器,进入SLEEP模式
                                STR         R2,

                                B                .                                        ; 死循环

;==================================== 睡眠模式的唤醒 ==================================

; 下面是唤醒睡眠模式的操作,是根据datasheet的P7-16的步骤来做的

WAKEUP_SLEEP
                                ; 从睡眠模式唤醒后释放SCLKn
                                LDR                R1, =MISCCR                        ; MISCCR寄存器,P9-24
                                LDR                R0,
                                BIC                R0, R0, #(7<<17)        ; SDRAM自刷新保持使能,SCLK0=SCLK, SCLK1=SCLK(SCLK是SDRAM时钟?SCLK0?SCLK1?)
                                STR                R0,

                                ; 设置SDRAM内存控制器,总共有13个,它们的值在下面的SMRDATA数据区中一起指定了
                                ADRL        R0, SMRDATA               
                                LDR                R1, =BWSCON                        ; BWSCON Address,BWSCON寄存器的地址是13个中最低的
                                ADD                R2, R0, #52                        ; 13*4=52
14
                                LDR                R3, , #4
                                STR                R3, , #4
                                CMP                R2, R0
                                BNE                %B14

                                MOV         R1, #256                        ; 等待更新完毕,没说要延时多长时间
15
                                SUBS         R1, R1, #1               
                                BNE         %B15

                                ; 下面程序默认用GSTATUS3来保存SLEEP模式唤醒后要跳往的地址了
                                LDR         R1, =GSTATUS3        
                                LDR         R0,
                                BX        R0

;***************************************** 数 据 段 *****************************************
                       
;=====================================异常向量表 ==========================================
               
                                AREA         RamData, DATA, READWRITE,ALIGN=2
                                MAP           _ISR_STARTADDRESS        ; _ISR_STARTADDRESS=0x33FFFF00,为第一级中断向量表的寻址地址,在上面有定义

                                                                ; 在SDRAM中的地址

HandleReset         FIELD   4                ; 地址0x33FFFF00,这个用不着
HandleUndef         FIELD   4                ; 地址0x33FFFF04
HandleSWI                FIELD   4                ; 地址0x33FFFF08
HandlePabort    FIELD   4                ; 地址0x33FFFF0C
HandleDabort    FIELD   4                ; 地址0x33FFFF10
HandleReservedFIELD   4                ; 地址0x33FFFF14
HandleIRQ                FIELD   4                ; 地址0x33FFFF18
HandleFIQ                FIELD   4                ; 地址0x33FFFF1C

;===================================中断向量表 =================================

; Do not use the label 'IntVectorTable',
; The value of IntVectorTable is different with the address you think it may be.
; IntVectorTable
HandleEINT0                FIELD   4                ; 地址0x33FFFF20
HandleEINT1                FIELD   4                ; 地址0x33FFFF24
HandleEINT2                FIELD   4                ; 地址0x33FFFF28
HandleEINT3                FIELD   4                ; 地址0x33FFFF2C
HandleEINT4_7        FIELD   4                ; 地址0x33FFFF30
HandleEINT8_23        FIELD   4                ; 地址0x33FFFF34
HandleCAM                FIELD   4                ; 地址0x33FFFF38
HandleBATFLT        FIELD   4                ; 地址0x33FFFF3C
HandleTICK                FIELD   4                ; 地址0x33FFFF40
HandleWDT                FIELD   4                ; 地址0x33FFFF44
HandleTIMER0         FIELD   4                ; 地址0x33FFFF48
HandleTIMER1         FIELD   4                ; 地址0x33FFFF4C
HandleTIMER2         FIELD   4                ; 地址0x33FFFF50
HandleTIMER3         FIELD   4                ; 地址0x33FFFF54
HandleTIMER4         FIELD   4                ; 地址0x33FFFF58
HandleUART2        FIELD   4                ; 地址0x33FFFF5C

HandleLCD                 FIELD   4                ; 地址0x33FFFF60
HandleDMA0                FIELD   4                ; 地址0x33FFFF64
HandleDMA1                FIELD   4                ; 地址0x33FFFF68
HandleDMA2                FIELD   4                ; 地址0x33FFFF6C
HandleDMA3                FIELD   4                ; 地址0x33FFFF70
HandleMMC                FIELD   4                ; 地址0x33FFFF74
HandleSPI0                FIELD   4                ; 地址0x33FFFF78
HandleUART1                FIELD   4                ; 地址0x33FFFF7C
HandleNFCON                FIELD   4                ; 地址0x33FFFF80
HandleUSBD                FIELD   4                ; 地址0x33FFFF84
HandleUSBH                FIELD   4                ; 地址0x33FFFF88
HandleIIC                FIELD   4                ; 地址0x33FFFF8C
HandleUART0         FIELD   4                ; 地址0x33FFFF90
HandleSPI1                 FIELD   4                ; 地址0x33FFFF94
HandleRTC                 FIELD   4                ; 地址0x33FFFF98
HandleADC                 FIELD   4                ; 地址0x33FFFF9C
                                                                ; 地址0x33FFFFA0
                                END

shuizhongling 发表于 2012-2-1 03:08:25

这是源文件
点击此处下载 ourdev_715320PXKNGQ.rar(文件大小:11K) (原文件名:2440init.rar)
页: [1]
查看完整版本: 2440init.s更改版