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

来源:互联网 发布:js中字符串是引用类型 编辑:程序博客网 时间:2024/06/04 23:24
;======================================================================================
; 文件名: 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_BASEADDRESSEQU 0x33FF8000; 堆栈基地址_MMUTT_STARTADDRESSEQU 0x33ff8000; 这个没用着啊~_ISR_STARTADDRESSEQU 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_VALEQU5;选择Fclk:Hclk:Pclk=1:4:8; FCLK由MPLLCON寄存器设置,可通过M_MDIV,M_PDIV,M_SDIV来调整,此处设置为400MHz,见P7-21M_MDIVEQU92; Fin=12.0MHz FCLK=400MHzM_PDIVEQU1M_SDIVEQU1;============================= 预定义模式常量 ==============================;用于设置CPSR的M[4:0],实现异常模式跳转USERMODE    EQU 0x10FIQMODE     EQU 0x11IRQMODE     EQU 0x12SVCMODE     EQU 0x13ABORTMODE   EQU 0x17UNDEFMODE   EQU 0x1bMODEMASK    EQU 0x1fNOINT       EQU 0xc0;============================== 栈地址定义 ==================================; 各异常模式的栈在SDRAM内存中的地址    ;    地址   栈空间UserStackEQU(_STACK_BASEADDRESS-0x3800); 0x33ff4800,未知 SVCStackEQU(_STACK_BASEADDRESS-0x2800); 0x33ff5800,4KBUndefStackEQU(_STACK_BASEADDRESS-0x2400); 0x33ff5c00,1KBAbortStackEQU(_STACK_BASEADDRESS-0x2000); 0x33ff6000,1KB IRQStackEQU(_STACK_BASEADDRESS-0x1000); 0x33ff7000,4KB FIQStackEQU(_STACK_BASEADDRESS-0x0); 0x33ff8000,4KB   ;=================================  中断例程相关宏定义  ==================================;; 在本启动程序的最下面在SDRAM中定义一段空间,用于存放异常处理程序的入口地址,即异常向量表,; 除了ResetHandler外,其他异常在本启动程序入口跳转后执行的第一段程序就是下面宏定义这段程; 序,这段程序从SDRAM中取出异常处理程序的入口地址,并跳转到此地址处开始执行.要本启动程序中,; 复位异常几乎就是本启动程序,而IRQ异常处理程序是IsrIRQ,其他异常处理程序未定义.MACRO$HandlerLabel HANDLER $HandleLabel; $HandlerLabel比$HandleLabel多了个‘r’,两者不一样!$HandlerLabelSUB  SP, SP, #4          ; SP=SP-4,此地址用于存放转跳地址,也即中断程序的入口地址STMFDSP!, {R0}; 把工作寄存器R0压入栈,sp=SP-4(sp先减)LDR     R0, =$HandleLabel   ; 将HandleXXX的值放入r0LDR     R0, [R0]    ; 把HandleXXX的值所指向的内容(也就是中断程序的入口地址)放入R0STR     R0, [SP,#4]      ; 通过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$RO$Base|,; RO区存放的终止地址 = RO limit - 1 = |Image$RO$Limit| - 1; RW区在SDRAM中存放的起始地址 = RW base = |Image$RW$Base|; ZI区在SDRAM中存放的起始地址 = ZI base = |Image$ZI$Base|; ZI区在SDRAM中存放的终止地址 = ZI limit - 1 = |Image$ZI$Limit| - 1; RW区在SDRAM中存放的终止地址 = RW limit - 1 = ZI base - 1,所以没必要再给出;IMPORT  |Image$RO$Base|; Base of ROM codeIMPORT  |Image$RO$Limit|  ; End of ROM code (=start of ROM data)IMPORT  |Image$RW$Base|   ; Base of RAM to initialiseIMPORT  |Image$ZI$Base|   ; Base and limit of areaIMPORT  |Image$ZI$Limit|  ; to zero initialise;**************************************  代 码 段  ***************************************AREA    Init,CODE,READONLY; 代码段开始处ENTRY; 标识程序入口处,要求编译器不将下面的异常跳转列表进行优化EXPORT__ENTRY; 声明__ENTRY可用被其他源文件全局引用,应该是用于.c文件__ENTRY;====================================   异常跳转   ======================================ResetEntry; 程序开始的地方 相对地址BResetHandler;0x00000000BHandlerUndef; handler for Undefined mode,0x00000004BHandlerSWI; handler for SWI interrupt,0x00000008BHandlerPabort; handler for PAbort,0x0000000CBHandlerDabort; handler for DAbort,0x00000010B.; reserved,0x00000014BHandlerIRQ; handler for IRQ interrupt,0x00000018BHandlerFIQ; handler for FIQ interrupt,0x0000001CBEnterPWDN; 由正常模式进入低功耗模式(power down),地址必须是; 0x00000020,貌似是约定好的;=====================================  使用宏  ===================================;; 采用上面定义的HANDLER宏去建立Hander***和Handle***之间的联系HandlerFIQ      HANDLER HandleFIQHandlerIRQ      HANDLER HandleIRQHandlerUndef    HANDLER HandleUndefHandlerSWI      HANDLER HandleSWIHandlerDabort   HANDLER HandleDabortHandlerPabort   HANDLER HandlePabort;==================================   IRQ中断例程  ===============================;; IRQ中断可细分为多个中断源的中断,如果异常向量表是一级向量表的话,细分后的中; 断向量表就是二级向量表,下面的程序就是二级向量表的查询,下面会用到IsrIRQSUBSP, SP, #4       ; reserved for PC,SP=SP-4STMFDSP!, {R8-R9}; SP=SP-8LDRR9, =INTOFFSET; 把INTOFFSET寄存器的值装入R9,其值指向的存储地址存着中断的; 偏移量(以字为单位,即4字节,见P14-16)LDRR9, [R9]; 中断的偏移量装入R9LDRR8, =HandleEINT0 ; 将HandleEINT0装入R8,其值为二级向量表的入口地址ADDR8, R8, R9, lsl #2; R8=R8+R9*4LDRR8, [R8]; 将所要的中断处理程序的入口地址装入R8STRR8, [SP,#8]; SP=SP+8,将中断处理程序的入口地址推入堆栈LDMFDSP!, {R8-R9,pc}; 出线,R8,R9还原其值,将中断处理程序的入口地址装入pcLTORG; 文字池;-----------------------------------------------------------------------------------------ResetHandler;================================= 关闭看门狗, 屏蔽所有中断 ==============================LDRR0, =WTCON; 关看门狗定时器,p18-3LDRR1, =0x0STRR1, [R0]LDRR0, =INTMSKLDRR1, =0xFFFFFFFF; 关所有中断,p14-12STRR1, [R0]LDRR0, =INTSUBMSKLDRR1, =0x7FFF; 关所有子中断,p14-18STRR1, [R0];================================== 配置系统时钟 =====================================; 通过设置LOCKTIME寄存器,减少PLL锁存时间LDRR0, =LOCKTIME; P7-20,LDRR1, =0x01360136; p7-20,将S_LTIME和U_LTIME由初始值的OxFFFF改为0x136,只有310>300STRR1, [R0]LDRR0, =CLKDIVN; CLKDIVN寄存器,p7-8,p7-24LDRR1, =CLKDIV_VAL; CLKDIV_VAL在上面定义,为UCLK:UPLL和FCLK:HCLK:PCLK的分频比选项,UPLL下面设置为48MHzSTRR1, [R0]; CLKDIVN取0x00000101,即5; 如果FCLK:HCLK不是1:1的关系的话,就要转成异步总线模式。反之,如果是这个比例关系的话,就转; 成快速总线模式。; MMU_SetAsyncBusMode 和 MMU_SetFastBusMode 都在4K代码以上,不可能拷到4K大小的steppingstone中, ; 而nandflash启动后,会将前4KB的引导代码拷到steppingstone(4KB大小)中执行,因此不能使用这两个; 函数如果你不想nandflash启动的话,就可以直接用上面的代码调用MMU_SetAsyncBusMode和MMU_SetFastBusMode; 下面的代码就是实现和上面两函数一样的功能. 利用的协处理器指令实现了对总线模式的设置; 至于为什么要用协处理器指令,代码是什么意思,我也不清楚。IFCLKDIV_VAL>1 ; 意味着Fclk:Hclk不是1:1.MRC p15, 0, R0, c1, c0, 0; MMU_SetAsyncBusMode,对协处理器15的c1和c0进行; 操作0(第0类),并将结果送入r0ORR R0, R0, #0xC0000000; R1_nF:OR:R1_iAMCR p15, 0, R0, c1, c0, 0ELSEMRC p15, 0, R0, c1, c0, 0; MMU_SetFastBusModeBIC R0, R0, #0xC0000000; R1_iA:OR:R1_nFMCR p15, 0, R0, c1, c0, 0ENDIF; 配置UPLLLDRR0, =UPLLCONLDRR1, =((56<<12)+(2<<4)+2)  ; UPLL=48MHz,Fin=12MHzSTRR1, [R0]NOP   ; 配置完UPLL后延迟7-clocks,才能配置MPLL,P7-21NOPNOPNOPNOPNOPNOP; 配置 MPLLLDRR0, =MPLLCONLDRR1, =((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV); Fin=12MHzSTRR1, [R0];检查这次启动是否是睡眠模式的唤醒导致的LDRR1, =GSTATUS2; p9-35LDRR0, [R1]TSTR0, #0x2;如果是则跳到SLEEP_WAKEUP handlerBNEWAKEUP_SLEEP;=============================  配置SDRAM内存控制寄存器 ===================================== ;;此段代码把13个存储控制器的内容批量的读取到了对应的特殊功能寄存器中首先是有一个数据区SMRDATA,;在程序的后面有定义,这个数据区给13个寄存器分配52字节的地址空间。BWSCON寄存器的地址0x48000000;貌似是所有寄存器中最低的,故从它开始设置。EXPORT StartPointAfterSleepWakeUpStartPointAfterSleepWakeUp;配置存储器控制寄存器ADRLR0, SMRDATA; 用adrl要比ldr要好,因为可以省去设置文字池的麻烦LDRR1,=BWSCON; BWSCON的地址,p5-14ADDR2, R0, #52; End address of SMRDATA0LDRR3, [R0], #4STRR3, [R1], #4CMPR2, R0BNE%B0; 向后(BACK)搜索标号为0的行,以此实现循环,具体可看局部标号的知识; 延时等待SDRAM稳定运行,好像设置SDRAM寄存器后都要延时,只是没说要延时多久MOVR0, #2561SUBSR0, 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-138MRSR0, CPSRBICR0, R0,#MODEMASKORRR1, R0,#UNDEFMODE:OR:NOINTMSRcpsr_cxsf,R1; UndefModeLDRSP, =UndefStack; UndefStack=0x33FF5C00ORRR1, R0, #ABORTMODE:OR:NOINTMSRcpsr_cxsf, R1; AbortModeLDRSP,=AbortStack; AbortStack=0x33FF6000ORRR1, R0, #IRQMODE:OR:NOINTMSRcpsr_cxsf, R1; IRQModeLDRSP, =IRQStack; IRQStack=0x33FF7000ORRR1, R0, #FIQMODE:OR:NOINTMSRcpsr_cxsf, R1; FIQModeLDRSP, =FIQStack; FIQStack=0x33FF8000BICR0, R0, #MODEMASK:OR:NOINTORRR1, R0, #SVCMODEMSRcpsr_cxsf, R1; SVCModeLDRSP, =SVCStack; SVCStack=0x33FF5800;================================== 初始化image运行域 ===================================; BWSON(p5-14)寄存器的DW0[2:1]的值由硬件决定,也就是OM[1:0](p5-4)决定,"00"表示nandflash; 启动,"01"或"10"为norflash启动,"01"为16位宽度,"10"为32位宽度,"11"为Test modeLDRR0, =BWSCONLDRR0, [R0]ANDSR0, R0, #6; 若OM[1:0] != 0, 则是NOR FLash启动BNEInitRam; 不读nand flash,跳到InitRamADRR0, ResetEntry; 若OM[1:0] == 0, 则是NAND FLash启动CMPR0, #0; 如果入口不是0,即使用了仿真器,BNEInitRam; 则不在启动时读nand flash,跳到InitRam;---------------------------------- NAND Flash 程序搬移 ------------------------------------nand_boot_begMOVR5, #NFCONF; P6-12;set timing valueLDRR0,=(3<<12):OR:(7<<8):OR:(7<<4)STRR0,[R5]; 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控制器LDRR0, =(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)STRR0, [R5, #4]; 配置NFCONT寄存器,其中(1<<1)取消了片选,P6-13BL ReadNandID  ; 按着读取NAND的ID号,结果保存在r5里LDR R0, =0xECAA ; EC为maker ID,AA为K9F2G08R0A的设备IDCMP R5, R0 BLEQK9F2G08R0A_show ; 若是K9F2G08R0A,则第一个LED灯亮BEQ %F2   ; r5和r0相等的话就跳到下一个1标号处LDR R0, =0xECDA ; EC为maker ID,DA为K9F2G08U0A的设备IDCMP R5, R0BLEQK9F2G08U0A_show; 若是K9F2G08U0A,则第二个LED灯亮BEQ %F2   ; r5和r0相等的话就跳到下一个1标号处B.2MOVR8, #0; r8表示页号LDRR9, =ResetEntry; 取ResetEntry的绝对地址3ANDSR0, R8, #0x3f; 若r8为64的整数倍(因为1 block=64 pages)则继续执行,否则跳至后面标号为3处BNE%F4MOVR0, R8BLCheckBadBlk; 这个坏块检测程序应该不适合K9F2G08型号CMPR0, #0ADDNER8, R8, #64; 若r0非零,则表示坏块,跳至下一个块。BNE%F04MOVR0, R8BLReadNandPageADDR9, R9, #2048; 一页是2KB+64B,这里读的是main区ADDR8, R8, #10CMPR8, #64; 复制64页,即搬移128KB代码到SDRAM中BCC%B3MOVR5, #NFCONF; DsNandFlashLDRR0, [R5, #4]BIC R0, R0, #1STRR0, [R5, #4]; nand flash controller disable(Don't work),见P6-14LDRPC,=InitRam;从这一步开始,它就是在SDRAM中运行了!在内存中将RW区复制到RAM1中;-----------------------------------  初始化RAM1 -------------------------------------;; 这段代码是将RW区复制到SDRAM中以BaseOfBSS为起始地址的内存中,如前所述,因ZI区全为0,; 故不需复制,只需清零ZI区在SDRAM内存中所在区域就行,BaseOfBSS和BaseOfZero-1分别人RW区; 的起始地址和末尾地址。BaseOfZero和EndOfBSS-1分别是ZI区的起始地址和末尾地址InitRamLDR R3, TopOfROMADRL R0, ResetEntry LDR R2, BaseOfROMSUBR2, R2, R3; R2=BaseOfROM-TopOfROMSUBR0, R0, R2; R0=R0-R2=ResetEntry-(BaseOfROM-TopOfROM)=ResetEntry+代码长度;   =ResetEntry+(TopOfROM-BaseOfROM); 复制代码加载位置中的RW区到RW base,RW区大小为BaseOfZero-BaseOfBSSLDR R2, BaseOfBSS   ; R2<-BaseOfBSS的绝对地址LDR R3, BaseOfZero  ; R3<-BaseOfZero的绝对地址6CMPR2, R3; 复制的内容的大小为BaseOfZero-BaseOfBSSLDRCCR1, [R0], #4; 复制的内容的起始地址为r0,若在SDRAM内存中运行则为; TopOfROM,否则为ResetEntry+TopOfROM-BaseOfROMSTRCCR1, [R2], #4BCC%B6; 用0初始化ZI区MOVR0,#0LDRR3,EndOfBSS7CMPR2,R3; R2=BaseOfZero, R3=EndOfBSSSTRCCR0, [R2], #4; 以BaseOfZero为起始地址,将EndOfBSS-BaseOfZero大小的空间清零BCC%B7  ;=================================== 保存中断例程地址 ====================================;; 因为只写了IRQ中断例程,故只保存IRQ中断例程的地址,以后若把其他中断例程补了,可在此保存中断例程地址;; RO、RW、ZI区复制分配完后,将二级向量表的中断查询例程的地址放到一级向量表IRQ异常向量中,使; 得IRQ向量指向二级向量表的中断查询例程; Setup IRQ handlerLDRR0, =HandleIRQ; IRQ异常向量的绝对地址->R0LDRR1, =IsrIRQ  ; R1 = 二级向量表的中断查询例程IsrIRQ的绝对地址STRR1, [R0];==================================== 跳转到C程序入口 =====================================;; 所有初始化配置做完后,跳到.c源文件中的Main函数; 下面的代码不能用[|]合成一段,不知为何IMPORT  Main    ; The main entry of mon program; using_the_arm_assembler.pdf的p8-21BLMain; 注意这里用的是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-6ReadNandIDMOV      R7, #NFCONFLDR      R0, [R7,#4]; NFChipEn();BIC      R0, R0, #2STR      R0, [R7,#4]; 设置NFCONT,将Reg_nCE位清为0,即允许片选,见P6-14MOV      R0, #0x90; WrNFCmd(RdIDCMD);STRB     R0, [R7,#8]; 设置NFCMMD,发出读NANDflash ID的指令0x90,P6-15MOV      R4, #0; WrNFAddr(0);STRB     R4, [R7,#0xc]; 设置NFADDR,NAND flash存储器寻址值设为0,为何要在此置为0?P6-158;while(NFIsBusy());LDR      R0, [R7,#0x20]; 测试NFSTAT的RnB位,为1表示NAND flash空闲,为0则表示忙状态,循环等待其空闲,P6-18TST      R0, #1BEQ      %B8LDRB     R0, [R7,#0x10]; id  = RdNFDat()<<8,从NFDATA寄存器中读第一个ID字节(即Maker Code)MOV      R0, R0, lsl #8LDRB     R1, [R7,#0x10]; id |= RdNFDat(),从NFDATA寄存器中读第二个ID字节(即Device Code)ORR      R5, R1, R0LDR      R0, [R7,#4]; NFChipDs();ORR      R0, R0, #2STR      R0, [R7,#4]; 设置NFCONT,将Reg_nCE位清为1,即取消片选,见P6-14BX LRWaitNandBusyMOV      R0, #0x70; WrNFCmd(QUERYCMD);MOV      R1, #NFCONFSTRB     R0, [R1,#8]; 设置NFCMMD,发出读nandflash状态指令0x70,见K9F2G080A.pdf的P419; while(!(RdNFDat()&0x40));LDRB     R0, [R1,#0x10]TST      R0, #0x40; 判断I/O管脚是否为1,为1表示空闲,为0表示忙状态,见K9F2G080A.pdf的P41BEQ %B9BX LR;====================================== NAND Flash 坏块检测 ==================================;使用READ指令读出所检查块的第一页的2048列字节,若为FF,则表示此块正常,具体见K9F2G08U0A.pdf的P15CheckBadBlkMOV R7, LR; 因为此段程序有跳转,故要保存返回地址MOV R5, #NFCONFBIC R0, R0,#0x3F; Ox3F=64-1, 64为一个block的页数,这里是为保证R0是64的整数倍LDR R1, [R5,#4]; NFChipEn()BIC      R1, R1,#2STR      R1, [R5,#4]; 设置NFCONT,将Reg_nCE位清为0,即允许片选,见P6-14MOV      R1, #0x0; WrNFCmd(READCMD),发出读指令STRB     R1, [R5,#8]MOV R1, #0MOV R2, #8STRB     R1, [R5,#0xc]; WrNFAddr(0)STRB     R2, [R5,#0xc]; WrNFAddr(8),和上面的指令合在一起就是发出2048列地址(A0-A11)STRB     R0, [R5,#0xc]; WrNFAddr(addr)MOV      R1, R0,lsr #8; WrNFAddr(addr>>8)STRB     R1, [R5,#0xc]MOV      R1, R0,lsr #16; WrNFAddr(addr>>16),和上面的三个指令合在一起就是发出页地址(A12-A28)STRB     R1, [R5,#0xc]MOV      R1, #0x30STRB     R1, [R5,#8]; 发出命令0x30BL       WaitNandBusy; WaitNFBusy()LDRB R0, [R5,#0x10]; RdNFDat(),读取该block的第一页的第一个字节SUB R0, R0, #0xFF; 若此字节为FF,即R0为0,则表示该block正常LDR      R1, [R5,#4]; NFChipDs()ORR      R1, R1,#2STR      R1, [R5,#4]; 设置NFCONT,将Reg_nCE位清为1,即取消片选,见P6-14BX R7;================================= 读 NAND Flash 页内容 ================================; r0表示页号,r9为resetentry的绝对地址,为RO base,也即BaseOfRomReadNandPageMOV R7, LR; 因为此段程序有跳转,故要保存返回地址MOV      R4, R9; r1为要复制的MOV R2, #0MOV      R5, #NFCONFLDR      R1, [R5,#4]; NFChipEn()BIC      R1, R1,#2STR      R1, [R5,#4]; 设置NFCONT,将Reg_nCE位清为0,即允许片选,见P6-14MOV      R1, #0; WrNFCmd(READCMD0)STRB     R1, [R5,#8]; 发出读命令0x00STRB     R1, [R5,#0xc]; WrNFAddr(0)STRB     R1, [R5,#0xc]; WrNFAddr(0)和上面的指令合在一起就是发出0x0列地址(A0-A11)STRB     R0, [R5,#0xc]; WrNFAddr(addr)MOV      R1, R0,lsr #8; WrNFAddr(addr>>8)STRB     R1, [R5,#0xc]MOV      R1, R0,lsr #16; WrNFAddr(addr>>16),和上面的三个指令合在一起就是发出页地址(A12-A28)STRB     R1, [R5,#0xc]MOV      R1, #0x30STRB     R1, [R5,#8]; 发出命令0x30BL       WaitNandBusy; WaitNFBusy()12LDRB     R1, [R5,#0x10]; buf[i] = RdNFDat(),循环一次读取一个字节的数据STRB     R1, [R4,R2]; r4表示复制的SDRAM目标地址ADD      R2, R2, #1CMP      R2, #0x800; 0x800为2048,可我们所用的nandflash一页的大小为2K+64bit,这里只读main区BCC      %B12LDR      R0, [R5,#4]; NFChipDs()ORR      R0, R0, #2STR      R0, [R5,#4]; 设置NFCONT,将Reg_nCE位清为1,即取消片选,见P6-14BX R7;================================ NAND Flash 型号LED指示 ========================================K9F2G08R0A_showMOVR0, #0x56000000;GPACON寄存器的地址,见P9-8MOVR1, #0x0055STRR1, [R0, #0x50];配置GPFCON寄存器,GPF0~GPF3为output,GPF4~GPF7为intput,见P9-18MOVR1, #0xFESTRR1, [R0, #0x54];配置GPFDAT寄存器为0x50,即GPF0~GPF3输出0001,见P9-18BXLRK9F2G08U0A_showMOVR0, #0x56000000;GPACON寄存器的地址,见P9-8MOVR1, #0x0055STRR1, [R0, #0x50];配置GPFCON寄存器,GPF0~GPF3为output,GPF4~GPF7为intput,见P9-18MOVR1, #0xFDSTRR1, [R0, #0x54];配置GPFDAT寄存器为0x50,即GPF0~GPF3输出0001,见P9-18BXLRLTORG;文字池SMRDATA DATA;=============================== SDRAM寄存器配置值 =================================; 下面的配置不一定是最优的DCD 0x2212d110; P5-14,BWSCONDCD 0x00007FF4 ; GCS0, P5-16, BANKCON0,接NOR flashDCD 0x00002e50; GCS1, P5-16, BANKCON1DCD 0x00002e50; GCS2, P5-16, BANKCON2DCD0x00002e50  ; GCS3, P5-16, BANKCON3DCD 0x00002e50  ; GCS4, P5-16, BANKCON4DCD 0x00002e50  ; GCS5, P5-16, BANKCON5DCD0x00018005; GCS6, P5-17, BANKCON6,接SDRAMDCD 0x00018005; GCS7, P5-17, BANKCON7DCD 0x009404F5; P5-18,REFRESHDCD 0x32    ; SCLK power saving mode, P5-19, BANKSIZE,128MDCD 0x30    ; MRSR6,CL=3clk, P5-20, MRSRB6DCD 0x30    ; MRSR7,CL=3clk, P5-20, MRSRB7;==================================================================================BaseOfROMDCD|Image$RO$Base|TopOfROMDCD|Image$RO$Limit|BaseOfBSSDCD|Image$RW$Base|BaseOfZeroDCD|Image$ZI$Base|EndOfBSSDCD|Image$ZI$Limit|;================================== 低功耗模式 ===================================; 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 本启动程; 序没写.一旦进行这两个模式,将进入死循环.EnterPWDNMOVR2, R0    ; R2即CLKCON要设置的值TSTR0, #0x8BNEENTER_SLEEPB.; 不是睡眠模式则死循环;------------------------------------ --  进入睡眠模式 ------------------------------------; 下面是进入睡眠模式的操作,是根据datasheet的P7-15的步骤来做的ENTER_SLEEP;GSTATUS3是通用状态寄存器,用户自定义其用途,其值在睡眠模式下不变;下面的代码将唤醒后开始执行的代码的地址存入GSTATUS3寄存器中ADRR0,StartPointAfterSleepWakeUpLDRR1,=GSTATUS3STRR0,[R1]LDR R0, =REFRESH; P5-18LDR R1, [R0]; R1=REFRESH寄存器的值ORR R1, R1, #(1<<22); BIT_SELFREFRESH有前面定义了,为1<<22STR R1, [R0]; 允许 SDRAM 自刷新MOV R1, #16; 延时等待刷新完毕,datasheet没说延时多久13SUBS R1, R1, #1BNE %B13LDRR1, =MISCCR; MISCCR寄存器,P9-24LDRR0, [R1]ORRR0, R0,#(7<<17)  ; 使SCLK0=0, SCLK1=0, SDRAM自刷新保持使能STRR0, [R1]LDR R0, =CLKCON; 将要配置的值送入CLKCON寄存器,进入SLEEP模式STR R2, [R0]B.; 死循环;==================================== 睡眠模式的唤醒 ==================================; 下面是唤醒睡眠模式的操作,是根据datasheet的P7-16的步骤来做的WAKEUP_SLEEP; 从睡眠模式唤醒后释放SCLKnLDRR1, =MISCCR; MISCCR寄存器,P9-24LDRR0, [R1]BICR0, R0, #(7<<17)  ; SDRAM自刷新保持使能,SCLK0=SCLK, SCLK1=SCLK(SCLK是SDRAM时钟?SCLK0?SCLK1?)STRR0, [R1]; 设置SDRAM内存控制器,总共有13个,它们的值在下面的SMRDATA数据区中一起指定了ADRLR0, SMRDATALDRR1, =BWSCON; BWSCON Address,BWSCON寄存器的地址是13个中最低的ADDR2, R0, #52; 13*4=5214LDRR3, [R0], #4STRR3, [R1], #4CMPR2, R0BNE%B14MOV R1, #256; 等待更新完毕,没说要延时多长时间15SUBS R1, R1, #1BNE %B15; 下面程序默认用GSTATUS3来保存SLEEP模式唤醒后要跳往的地址了LDR R1, =GSTATUS3 LDR R0, [R1]BX  R0;***************************************** 数 据 段 *****************************************;=====================================  异常向量表 ==========================================AREA RamData, DATA, READWRITE,ALIGN=2MAP   _ISR_STARTADDRESS; _ISR_STARTADDRESS=0x33FFFF00,为第一级中断向量表的寻址地址,在上面有定义; 在SDRAM中的地址HandleReset FIELD   4; 地址0x33FFFF00,这个用不着HandleUndef FIELD   4; 地址0x33FFFF04HandleSWIFIELD   4; 地址0x33FFFF08HandlePabort    FIELD   4; 地址0x33FFFF0CHandleDabort    FIELD   4; 地址0x33FFFF10HandleReserved  FIELD   4; 地址0x33FFFF14HandleIRQFIELD   4; 地址0x33FFFF18HandleFIQFIELD   4; 地址0x33FFFF1C;===================================  中断向量表 =================================; Do not use the label 'IntVectorTable',; The value of IntVectorTable is different with the address you think it may be.; IntVectorTableHandleEINT0FIELD   4; 地址0x33FFFF20HandleEINT1FIELD   4; 地址0x33FFFF24HandleEINT2FIELD   4; 地址0x33FFFF28HandleEINT3FIELD   4; 地址0x33FFFF2CHandleEINT4_7FIELD   4; 地址0x33FFFF30HandleEINT8_23FIELD   4; 地址0x33FFFF34HandleCAMFIELD   4; 地址0x33FFFF38HandleBATFLTFIELD   4; 地址0x33FFFF3CHandleTICKFIELD   4; 地址0x33FFFF40HandleWDTFIELD   4; 地址0x33FFFF44HandleTIMER0 FIELD   4; 地址0x33FFFF48HandleTIMER1 FIELD   4; 地址0x33FFFF4CHandleTIMER2 FIELD   4; 地址0x33FFFF50HandleTIMER3 FIELD   4; 地址0x33FFFF54HandleTIMER4 FIELD   4; 地址0x33FFFF58HandleUART2  FIELD   4; 地址0x33FFFF5CHandleLCD FIELD   4; 地址0x33FFFF60HandleDMA0FIELD   4; 地址0x33FFFF64HandleDMA1FIELD   4; 地址0x33FFFF68HandleDMA2FIELD   4; 地址0x33FFFF6CHandleDMA3FIELD   4; 地址0x33FFFF70HandleMMCFIELD   4; 地址0x33FFFF74HandleSPI0FIELD   4; 地址0x33FFFF78HandleUART1FIELD   4; 地址0x33FFFF7CHandleNFCONFIELD   4; 地址0x33FFFF80HandleUSBDFIELD   4; 地址0x33FFFF84HandleUSBHFIELD   4; 地址0x33FFFF88HandleIICFIELD   4; 地址0x33FFFF8CHandleUART0 FIELD   4; 地址0x33FFFF90HandleSPI1 FIELD   4; 地址0x33FFFF94HandleRTC FIELD   4; 地址0x33FFFF98HandleADC FIELD   4; 地址0x33FFFF9C; 地址0x33FFFFA0END


原创粉丝点击