




已阅读5页,还剩55页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
U-BOOT编写(基于OK6410) Written by water1.U-BOOT工作原理及设计蓝图 在所有章节开始必须首先介绍一下U-BOOT,所谓U-BOOT就是bootloader的一种,可用于多种cpu(x86,ARM等),在不同系统像Linux,Vxworks,QNX等上运行调试。它能起到在上电后能对硬件,存储器,内核等完成初始化,并且引导内核和文件系统正常工作的作用。U-BOOT并不是单纯的裸机程序,在学完此课程后,可以完成大部分裸机程序的调试,移植与开发。最后得说明,我所用的开发板是OK6410,而我所做的学习笔记完全是建立在国嵌视频上的,我会在这个笔记中对视频的内容进行总结,顺序会有所调整。1.1 U-BOOT工作原理要讲解这个首先需要让大家看一张图(注:这张图是2440的机理图,放在这里是为了能方便讲解和理解):这张图共分为两部分,左边部分是用于nor flash启动,而右边这部分就是用于nand flash启动了,这个也是我们讲的重点。首先需要明确一点,上电后第一条程序,肯定是从0地址(0x00000000)开始执行的。左图显示0地址是在SROM中,这个我们不去管它,而右图显示第一条指令是从SRAM中执行的,而这个存储器只有4K,在这里我们就需要先明确一下“垫脚石(Stepping Stone)”这个概念了。在2440选择从nand flash启动刚上电时,系统会自动将nand flash中bootloader的前4K,放入到我们前面所述的0地址,也就是Boot internal SRAM中,此时系统会执行bootloader的前4K,同时系统还会将整个bootloader复制到我们的内存,前4k执行完后,就跳转至内存继续执行剩余的bootloader,而我们这里4K大小的SRAM就是垫脚石(stepping stone)。为什么需要它,这点很简单,两图对比,我们就能发现我们的nand flash没参与我们的统一编址,所以只能借stepping stone作为我们的桥梁。介绍完2440,我们来看看6410。先给大家几张图: 图1 图2 图3我们先看图2,从图2我们可以看出6410可以从哪些部分启动,而那些部分又被存放在哪儿,我们可以注意到nand flash是被存放在IROM中的。接下来我们看图2,我们可以看到0地址处放的是一个最大可达到128M的存储器,描述和备注我就不赘述了,可以看出他是个镜像存储器,接下来就是IROM和stepping stone,下面的存储器我们暂时不研究,不说了。看完两张图,可能最有疑问的是最后一张图,我们说过上电执行的第一条程序应该在0地址处,为什么那里不像2440一样放的是stepping stone,而是一个镜像存储器呢。其实聪明一些的话,应该已经注意到了,既然是镜像存储器,那当上电后,我们的IROM和stepping stone(两个最大都能达到64M),会被镜像入0地址处的存储器(最大可达128M)中,然后剩下的就和2440一样了。在这里可能大家还会有疑问,2440是直接从stepping stone中直接启动,6410前面突然多了个IROM,好象有些不适应。我们来看图1。图1是6410bootloader的工作原理图,我们可以看到IROM里存放的是BL0,这个BL0他会首先完成对硬件的初始化,同时会将BL1也就是BL的前8k(6410的steeping stone为8K)放入垫脚石中,然后就和2440一样,将BL放入内存继续执行。至此,bootloader的工作原理讲解完毕。现在必须要分析bootloader启动流程以完成我们自己的bootloader的架构设计。我们采用分析U-BOOT的方法,来建立属于我们自己的bootloader。由于分析的过程冗长耗时,在这里我就不分析了,但我会给出一张分析出的结果图:2.U-BOOT编写2.1 一些需要知道的知识概述首先大家必须先要了解的是ARM处理器的七种工作模式:图1图2两张图表明ARM处理器一共有7种工作模式,在这里我列一张表格来叙述其名称及作用:用户模式usr用于普通状态下正常执行程序系统模式sys运行具有特权的操作系统任务管理模式svc对操作系统的保护模式数据访问中断模式abt当数据或指令预取终止时进入该模式,可用于虚拟存储或存储保护未定义指令终止模式und当未定义的指令执行时进入该模式,可用于支持硬件外部中断模式irq用于通用的中断处理快速中断模式fiq用于高速数据传输或信道处理有几点需要说明普通的应用程序是在usr下运行,而我们的内核和bootloader是在svc下运行。至此,7种工作模式交代完毕,而图1中0bxxxxx,这种东西是用于CPSR,即程序状态寄存器使用的。这也是我们接下来要说的,我们的处理器一共有37个寄存器,如图2,其中有31个通用寄存器和6个程序状态寄存器,r0-r7为不分组寄存器,r8-r14为分组寄存器,最后还有个r15,也就是我们所熟知的程序计数器(pc)。其实这当中还有些特殊的寄存器,比如r13(堆栈指针sp),r14(链接寄存器)。这个我们以后会说的。这部分内容相对简单,我也不想细说,如有疑问,请自己查资料。接下来我们来谈谈CPSR(程序状态寄存器)和SPSR(程序状态保存寄存器),我这里先给出一张表:图3然后我们再来谈谈CPSR和SPSR的作用和工作原理,看完图2,再查完一些资料,应该会对这个有一定的了解,先研究图2,图2显示我们所说的7种工作模式下都有CPSR,而SPSR只有5种工作模式下存在,这5种工作模式被我们称为异常模式,除usr以外的其他工作模式被称为特权模式,那我们就要问,为什么要这样设计?或者说,这样的设计能反映CPSR和SPSR怎样的工作原理?这个问题很好回答,首先当我们在usr下运行时,我们的程序会在CPSR下存有备份,现在可以把它理解成备份,这个时候出现中断,我们这个时候就切入了异常模式,我们会先将状态从CPSR转移至SPSR,等处理器处理完了此次中断,然后在将SPSR的数据返还至CPSR,使状态回复至之前的状态。解释完了这些,我们现在来看看图3,它反映的是SPSR和CPSR的寄存器数据格式。这里我们我们不需要全部记下来,但有5位需要注意,分别是N,Z,I,F,M。我这里只做简单叙述,详情请查阅ARM Architecture Reference Mannual。N位占31位,当两数相减结果为负时置位。Z位占30位,当两数相减结果为0时置位。I位占7位,当被置位时,irq不可用。F位占6位,当被置位时,fiq不可用。M位占0-4位,这里是设置各种模式用的,图1的0bxxxxx就是用在这里的。到这里我们就把所有的模式及寄存器讲完了,接下来我们就需要编程了,编程我是不会在学习笔记中赘述的,但我会截图说明,涉及到原理的,我可能会大篇叙述,如有疑问大家请自己查阅资料。2.1 汇编框架的编写及异常向量表既然是汇编文件,我们肯定需要一个.S的汇编文件,除此之外,我们编写的bootloader可能文件有些繁杂,所以我们需要一个makefile文件,最后还需要一个.lds的汇编器脚本文件。我们先编写汇编器脚本:然后我们再来编写makefile文件:最后,我们来编写start.S这个文件,要编写这个,我们必须要先查阅一下ARM Architecture Reference Mannual。图1在这里,我们先来解释一下异常(Exception)的概念,异常指因为内部或者外部的一些事件,使处理器不得不停下正在处理的事件,转而去处理这些发生的事件。我们说ARM处理器共有7种工作模式,其中有5种异常模式,而在这些异常模式下又有7种异常,它们分别是Reset(复位),Undefined instructions(未定义指令),SWI(软中断),Prefetch Abort(指令预取失败),Data Abort(数据预取失败),IRQ(外部中断),FIQ(快速中断)。我们再来解释一下什么叫异常向量,当有异常发生时,ARM处理器会自动跳转到对应该异常的一个固定的地址来执行异常处理程序,而这个固定地址就是异常向量。这个就对应图1后面的address两列,第一列是我们通常情况下使用的地址,后面是高位地址,我们可以通过cp15配置,使cpu选择高位地址还是低位地址,通常我们选用低位的。有了前面这些概念,我们现在再来看异常向量表就非常简单了:图2值得注意的是,我们在编写编译器脚本时里面有一句.=ALIGN(4),这就说明我们接下来的代码是4字节对齐的,所以我们可以看到每一行代码跳4个字节,另外由于中间确实了一部分,所以我们用一个无用的函数名not_used补全,这样就方便了许多。这样就结束了,不懂的可以自己在看一遍或查资料。2.2 设置svc模式我们前面说过普通的应用程序是在usr下运行的,而内核和bootloader是在svc模式下运行,所以要运行bootloader,我们必须先将处理器设置为svc模式。我们之前也提过模式的设置是在CPSR的0-4位,这样我们就能找到设置的方向。参照2.1里的图1和图3,我们可以清楚的看到svc模式是将CPSR0-4位设置为10011。另外还有一点也要说明,我们制作的是相对简单的bootloader,所以irq和fiq最好也设置为不可用,之前在讲CPSR时,也同样提到I位和F位的作用,在这里我们就可以设置了,我们的目的是将第6,7位设为1,第0-4位设为10011,而其他位不变。编程如下:mrs r0, cpsrbic r0, r0, 0x1forr r0, r0, 0b11010011msr r0, cpsrmov pc, lr2.3 关闭看门狗首先我们先来介绍一下关门狗是什么,起到什么作用。Watchdog也就是我们所称的看门狗,一般是一个硬件模块,在长期无人值守的地方,电子器件可能会出现死机的情况,这是无人干预,就需要系统自己带有一个自动重启的机制,它在硬件上实现了计时功能,启动计时后,需要用户(软件)来在其计时结束前重新开始计时,俗称“喂狗”,否则watchdog就会认为死机了,就会重启系统。说白了,它的作用就是在死机时使系统自动重启。很多人看到这里,可能会想这看门狗好像很有用,那我们为什么要关闭它?这个结论是我们之前分析U-BOOT时得到的,我们认为bootloader很简单,一般不会死机,而不关闭它反而在程序运行时要不断喂狗,这样很消耗资源,所以我们就把它直接关闭了。这里我先给一张看门狗的原理图:图1这里的话,我就不对这个原理图多加赘述了。我们直接看如何关闭看门狗吧。我们在这里就得看看门狗的控制寄存器(WTCON)了,我们要关注一下第0,2位,分别是控制了看门狗超时后重启和中断的功能,我们都将其设置为0就行。编程如下:#define WTCON 0x7e004000ldr r0, =WTCONmov r1, 0x0str r1, r0mov pc. Lr2.4 关闭中断关闭中断说白了就是关闭外部中断(irq)和快速中断(fiq),我们先给一张图:图1我们从左到右可以在图中清楚的看到一个中断源会经过SRCPND,接下来要达到真正的中断还需要MODE和MASK的支持,我们需要做两件事才能真正地关闭中断,分别是设置CPSR和设置中断屏蔽寄存器。第一件事我们在前面进入svc模式时已经做过,忘了的可以回头看看,第二件就是我们现在将要做的。再给几张图(基于6410):图2图3图4图2我并没有截全,只截了重要的部分,我们可以看到一个description是Interrupt Enable Clear Register(中断使能寄存器)的寄存器,我们把那个寄存器找到,描述看图3,后面的备注告诉我们,这个寄存器只能用以设置中断使能,如果要关闭中断,需要一个叫INTENCLEAR的寄存器,我们继续找这个寄存器,如图4,这个就是我们要找的寄存器。我们需要把VIC0,VIC1都设置为1。这样编程就简单了。编程如下:#define INTCLR_VIC0 0x71200014#define INTCLR_VIC1 0x71300014ldr r0, =INTCLR_VIC0mvn r1, 0x0str r1, r0ldr r0, =INTCLR_VIC1str r1, r0mov pc, lr2.5 关闭mmu和cache 我们在编程前,必须要知道mmu是什么,起什么作用且为什么要关闭他。但是由于各种考虑,这些东西我觉得应该大家自己查阅资料,我这里只做简单介绍。 我们先给出百度对mmu给出的定义。图1说白了,mmu就是将虚拟地址处理成内存中的物理地址,它与虚拟内存是紧密相关的。另外cache,也就是高速缓冲存储器,或许根本不需要解释。我们这里只给ARM11核的几张图,大家意会一下,不懂可以去查资料。图2图2是计算机存储体系的一张非常有名的金字塔模型,同样适用于嵌入式系统,它反映了不同存储器与系统的关系紧密程度,存储器容量与速度大小与级别高低。图3图3在给出各种需要了解的重要概念的定义的同时也反映虚拟地址的作用,用它可以再继续深入到mmu的作用,方便易记。图4图4反映了MMU和cache在虚拟地址转物理地址时与cpu和主存之间的关系,上图是ARM11之前的系统,而下图则是ARM11之后(包括ARM11)的系统。 看完这些,自己再查阅一些资料以后,相信会对一些基础知识有所了解,我们在来说为什么要关闭mmu和cache,其实这两件东西都是好东西,我们智慧需要的时候会在打开,但现在由于系统还未配置好,所以现在打开它,可能会造成内核取址(mmu)和内核数据往内存的下载(cache)上的错误,所以现在先关闭它。我们现在来编程吧。我们需要ARM11的核手册,因为要配置mmu和cache需要设置cp15。我们先给几张图:图5图6我们需要做两件事,第一件时使D-cache里的数据失效,见图5,已经给出了明确的说明,我们选择第3行。第二件就是彻底使mmu和cache关闭,见图6,我们需要配置0位和2位,1位我们也顺便配置了,其实1位配不配置都无伤大雅。编程如下:mcr p15, 0, r0, c7, c7, 0mrc p15, 0, r0, c1, c0, 0bic r0, r0, #0x00000007mcr p15, 0, r0, c1, c0, 0mov pc, lr2.6 点亮LED 先不说技术上的问题,我们先来谈谈技术上的问题。在我们编程时,我们可能会因为各种原因而犯错,但此时由于是bootloader初期,我们并未对我们串口等硬件初始化,我们的调试手段相当有限,而我们又不知道哪里犯了错,所以我们必须使用一个可视化的检查机制来告诉我们我们之前的程序是否出错,这样每添加一段程序,我们就可以使用此机制来验证,这样效率会提高很多。然后我们来谈一下技术上的事,毕竟LED大家都懂,不需要我来特地浪费篇幅解释。我们要做点亮LED需要做两件事,不过在此之前,我们需要了解一些概念。我先给几张图: 图1图2图3图1是6410底板LED的原理图,图2是核心板cpu上有关LED的GPIO引脚图,图3是图2所指区域的放大图。我们先看图1,可以看出我们板上有4个用户使用的LED,他们所对应的GPIO引脚分别是NLED1,2,3,4。另外我们知道要使LED亮,我们需要在引脚上设置为输出低电平。图2位核心板cpu GPIO的示意图。在讲解这些之前,我们先了解一下什么叫GPIO。 GPIO(General-Perpose Input/Output Ports)也被称为通用输入输出端口,在嵌入式系统中,cpu通常需要控制一些简单的外部设备和电路,这些设备或电路通常只有开关两种状态,控制这些用USB或串口就显得复杂,所以嵌入式微处理器上通常提供了“通用可编程I/O端口”,也就是GPIO。 看完这些我们再来梳理一下思路,要使LED亮需要使线路输出低电平,也就是要控制LED的GPIO输出低电平,而图3告诉我们,控制LED的GPIO分别是GPM0,1,2,3。 现在我们我们的思路就清楚了,然而我们还需要了解一个关于GPIO寄存器的知识,GPIO一般是由至少2个寄存器控制,6410应该是3个,我不确定,第3个我们暂时不需要了解。第一个是控制寄存器,控制引脚的输入输出,第二个是数据寄存器,控制高低电平。了解了这些我们就可以编程了。图4我们需要就GPM0,1,2,3都设置为输出,再把它们设为低电平。编程如下:#define GPMCON 0x7f008820#define GPMDAT 0x7f008824ldr r0, =GPMCONldr r1, =0x1111str r1, r0ldr r0, =GPMDATmov r1, #0xfstr r1, r02.7 时钟初始化这个章节基础的知识很多,我们先解析一些概念。我们先来了解一下时钟脉冲信号,时钟频率和时钟源这三个概念。时钟脉冲信号按一定的电压幅度,一定的时间间隔连续发出的脉冲信号。时钟脉冲信号是时序逻辑的基础,它用于决定逻辑单元中的状态何时更新。数字芯片中众多的晶体管都工作在开关状态,它们的导通和关断动作无不是按照时钟信号的节奏进行的。说白了他们就是一个时钟,告诉系统何时该做什么事而何时又结束。时钟脉冲频率就是单位时间产生的时钟脉冲个数。时钟源这个可以分成两类,一种是晶振,另一种是PLL(锁相环)。第一种晶振,全称晶体振荡器,是将石英进行精密切磨然后通电产生,其振动频率与它们的材料,形状与切割方向密切相关。是一种简单的典型的系统时钟振荡器源。PLL(锁相环)合成器是一种更加复杂的系统时钟源,它需要一个外部晶体并包含一个能对特定频率加倍或分频的PLL(锁相环)集成电路。PLL比较晶振所需的晶体振动频率更低,但是他能合成符合各种需求的振动频率。它的成本更低,精密程度不落于晶振,是一种优秀的系统时钟源。现在,我们需要了解一些关于6410开发板的时钟体系,首先6410的晶振频率是12MHZ,然后我们需要知道它有哪些PLL,PLL又产生出了哪些时钟,这些时钟又有些什么用。图1从这张图上我们了解到6410有APLL,MPLL和EPLL三种PLL,而这三种PLL又分别产生ARMCLK,HCLK,PCLK和SCLK。这四种时钟有什么用呢?我们来看看。图2图3图2大家了解一下就行,图3使我们各种时钟的作用。图4我们可以从图中看出,我们在初始化时钟时配置完后会出现Lock time,而在这之中SYSCLK的时钟频率会归零,之后会按照分频的频率运行,SYSCLK也就是我们这里的ACLK,毕竟系统时钟,会和内核联系在一起。现在我们来看看初始化时钟需要哪些步骤。第一步是设置Lock Time第二步是设置分频系数。第三步是设置cpu到异步工作模式。最后是设置PCLK和MCLK(见图5) 有人可能会对上面的步骤抱有异议,那我们现在来看看为什么要这样设置。第一步设置Lock Time,大家应该是不会说什么的,但是我们这里不设置,我们保持它的默认值不动。第二步,我们之前说过PLL可以通过分频来满足一个系统中不同时钟体系的需求,很显然我们要用它,所以我们需要设置分频系数。第三步,当ARMCLK(核的时钟)和HCLK(系统总线时钟)分频系数不同时,需要设置为异步模式。第四步,分完頻,至少我们需要设置其中某个量为基准值。而图5也告诉我们APLL和MPLL似乎是基准值。这样似乎就合理了,下面我们来编程吧。图5图6图7图8图9图10这里我已经给出了所有信息,但是这里我不讲(其实是偷懒),我希望大家能根据我的编程来理清自己的思路,另外大家要注意的是图5中很多选择器,它所需的寄存器(CLK_SRC,OTHERS等)甚至已在图中列出,大家也需要去设置。就这样,我们直接来编程。编程如下:#define CLK_DIV0 0x7e00f020#define OTHERS 0x7e00f900#define MPLL_CON 0x7e00f010#define APLL_CON 0x7e00f00c#define CLK_SRC 0x7e00f01c#define DIV_VAL (0x00)|(0x19)|(0x18)|(0x312)#define PLL_VAL (131)|(26616)|(38)|(10)ldr r0, =CLK_DIV0ldr r1, =DIV_VALstr r1, r0ldr r0, =OTHERSldr r1, r0bic r1,r1,#0xc0str r1, r0ldr r0, =APLL_CONldr r1, =PLL_VALstr r1, r0ldr r0, =MPLL_CONldr r1, =PLL_VALstr r1, r0ldr r0, =CLK_SRCmov r1, #0x3str r1, r0mov pc,lr2.8 内存初始化 既然讲到内存初始化,那就必须先讲与内存相关的一些知识。 我们先来谈谈内存的分类,内存一般分为SRAM和DRAM,SRAM即静态随机存储器,它是具有静止存取功能的内存,它不需要定期刷新就可保存内部数据,因此存取速度较快,但是成本较高,一般用在存储容量要求不高,但速度要求很快的场合,比如stepping stone。 而DRAM(动态随机存储器)是由许许多多个小电容组成,电容可以在两个极板上保存电荷,它不具备静止存取数据的功能,它需要不停地刷新(充能),才能保存数据,因此它的速度较慢。DRAM有几种需要分成几类讲:1.SDRAM 2.DDR 3.DDR2图1图2图1和图2讲的很好,这里需要补充一下,SDRAM和DDR的传输速度理论是1:2的关系,是因为在一个时钟周期内SDRAM只能传输或接收一次数据,而DDR则2次。这里就引出了时钟周期,可以联想到我们之前所说的时钟脉冲信号,这个和那个有些关系,大家可以去引申一下,时钟周期是一个时钟的量,它反映了SDRAM所能运行的最高速率,更小的周期代表更高的运行速率。大家有兴趣可以去查阅一下资料。 现在我们再说一下内存的内部结构。 实际上我们可以把内存的内部当成一个表结构,如图3,当我们存取数据时我们先指定行地址,再指定列地址,这样我们就能准确地找到我们所需的数据。而这张表我们称为Logical Bank(L-Bank)。图3然而由于技术等各种原因,我们的一块内存不可能只用一个L-Bank,我们一般把它分成4个L-Bank,这样我们的寻址信息就变成先指定L-Bank,再指定行地址,最后确定列地址,而我们内存大小就等于4*行*列*一个单元格所能容纳的数据大小。现在就该讲到编程了,我们决定先从2440讲起,这样在原理上深入会比较简单。图4 从图4我们可以看出2440的芯片一共27根地址线,27根地址线对应了128M的内存,然而我们说内存不可能只有128M,那生产厂商用了什么方法使它的外设空间变为1G呢?在这里我们需要引出片选信号这种说法。 片选信号,也就是说不止这一块内存芯片,片选信号可以指定从不同的芯片中存取数据。看图5图5其实细心一点可以在图4中观察到8个片选信号nGCS0-7,现在我们来看一张更加早期的图:大家都应该知道2440的内存是从0x30000000开始的,为什么他要从这地方开始,现在我们应该有答案,内存是处于bank6和bank7的,bank6的起始地址就是0x30000000。 我们转而看6410的内存地址0x50000000,这个比2440要大,为什么呢?我们来看看6410的地址分布。图6保留区我们就不说了,外设区说白了就是我们之前那些寄存器的放置空间,而主存储区似乎我们应该更深入的去看一下。图7这样,我们就能明白为什么6410内存是从0x50000000开始了,因为内存是在Dynamic memory里的。另外还有一点要提:图8我们在之前可以看到2440cpu有32根地址线,而内存的两块芯片每块只有16根地址线,这要怎么连呢,很简单,就是16+16=32的问题,存取数据时,两块芯片个存取一半数据。6410在这方面也是同样的原理。 最后我们还需要了解一个非常重要的东西-存储控制器,当我们访问某一块内存空间时,我们往往就是输入地址,我们并没有用到之前学的寻址方式,先L-Bank啊,行列地址之类的,这完全归因于存储控制器,当cpu拿到我们的地址时,他并不知道该去哪找数据,这是存储控制器就会进行转化,使cpu能找到数据。如图9:图9所以,我们要控制内存,要初始化内存,实际上就是要对我们的存储控制器进行初始化,2440只要初始化存储控制器就可以了,但6410还须对我们的DDR进行初始化。不过也很简单,它已经把所有的步骤列出来了,我们只要照做就行。图10照着步骤一步步做就行,有些东西参照一下U-BOOT,具体的寄存器大家请参照6410的芯片手册,这里由于篇幅原因我就不列了。另外由于此程序篇幅很长,所以我们另起一个汇编文件,用.global定义一下全局符号。编程如下:.text.global mem_initmem_init: ldr r0, =0x7e00f120 mov r1, #0x8 str r1, r0 ldr r0, =0x7e001004 mov r1, #0x4 str r1, r0 ldr r0, =0x7e001010 ldr r1, =( ( 7800 / ( 1000000000/133000000 ) + 1 ) ) str r1, r0 ldr r0, =0x7e001014 mov r1, #(3 1) str r1, r0 ldr r0, =0x7e001018 mov r1, #0x1 str r1, r0 ldr r0, =0x7e00101c mov r1, #0x2 str r1, r0 ldr r0, =0x7e001020 ldr r1, =( ( 45 / ( 1000000000 / 133000000 ) + 1 ) ) str r1, r0 ldr r0, =0x7e001024 ldr r1, =( ( 68 / ( 1000000000 / 133000000 ) + 1 ) ) str r1, r0 ldr r0, =0x7e001028 ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) ) str r1, r0 ldr r0, =0x7e00102c ldr r1, =( ( 80 / ( 1000000000 / 133000000 ) + 1 ) ) str r1, r0 ldr r0, =0x7e001030 ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) ) str r1, r0 ldr r0, =0x7e001034 ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) ) str r1, r0 ldr r0, =0x7e001038 ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) ) ldr r2, r0 str r1, r0 ldr r0, =0x7e00103c mov r1, #0x07 str r1, r0 ldr r0, =0x7e001040 mov r1, #0x02 str r1, r0 ldr r0, =0x7e001044 ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) ) str r1, r0 ldr r0, =0x7e001048 ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) ) str r1, r0 ldr r0, =0x7e00100c ldr r1, =0x00010012 str r1, r0 ldr r0, =0x7e00104c ldr r1, =0x0b45 str r1, r0 ldr r0, =0x7e001200 ldr r1, =0x150f8 str r1, r0 ldr r0, =0x7e001304 mov r1, #0x0 str r1, r0 ldr r0, =0x7e001008 ldr r1, =0x000c0000 str r1, r0 ldr r1, =0x00000000 str r1, r0 ldr r1, =0x00040000 str r1, r0 ldr r1, =0x000a0000 str r1, r0 ldr r1, =0x00080032 str r1, r0 ldr r0, =0x7e001004 mov r1, #0x0 str r1, r0check_dmc1_ready: ldr r0, =0x7e001000 ldr r1, r0 mov r2, #0x3 and r1, r1, r2 cmp r1, #0x1 bne check_dmc1_ready nop mov pc, lr最后我们还得了解一点,第一段汇编中的寄存器0x7e00f120,那个是什么寄存器呢?我们在芯片手册搜一下看看。图11图12图11和图12我们可以看到这个寄存器各位的描述都不短,但我们现在只研究其中的第七位,我们应该设成0还是1。描述中Xm1是什么?其实他对应的是6410的Dynamic memory的数据线,也就是我们的DRAM的数据线,我们选0,是将他设为数据传输,选1是将他用于SROMC,明显应该选0。最后再附上6410的两块内存的图,以免有人看不清楚。图132.9 代码搬移(基于6410)事先说明一下,因为我们还没接触到nand flash,所以我们现在编写的代码只是先热个身,日后等我们了解到了nand flash,会在回头看这段代码。在前面讲到bootloader的工作原理时,我们提到了代码的搬移,即当上电后,bootloader的前几K(6410为8K,2440为4K)会被放入垫脚石中运行,这个我们不去管它,他是自动的,但是接下来整段代码从nand flash搬移到内存中,这个我们就需要进行干预了,我们需要通过代码来完成它。但有一点我们要注意,我们现在还没学到nand flash,而且我们现在的bootloader还远未达到4k或8k,所以我们现在不从nand flash搬移,而从我们的垫脚石中搬移代码。等日后学习了nand flash,我们再回头改这段代码。要搬移代码,我们需要注意3点:1. 搬移起点2. 搬移终点3. 搬移方式先说搬移起点,既然我们是从垫脚石搬移的,那我们就看垫脚石的起始地址。图1从图1中,我们可以看出垫脚石的起始地址是0x0c000000,这样我们第一个问题就解决了。第二个问题是搬移终点的问题,这个其实不是问题,我们之前编写过了编译器脚本文件里就有答案,我们在其中设置过程需的起始地址,也就是链接地址-. = 0x50008000。那个
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 山东省公积金征缴课件
- 2025年高强度及低松驰预应力钢绞线项目规划申请报告
- 山东化妆品护肤知识培训课件
- 2025年新型铝基轴瓦材料项目提案报告
- 2025年敏感元件项目提案报告模范
- 展馆规划讲解知识培训课件
- 2025年翡翠金融项目规划申请报告
- 2024年临沂平邑县县直城镇公益性岗位招聘真题
- 屏障受损知识培训内容总结
- 屏蔽门培训知识课件
- 火锅店股东协议合同范本
- 村流动人口管理办法细则
- HY/T0305-2024养殖大型藻类和双壳贝类碳汇计量方法碳储量变化法
- 中式婚礼知识培训课件
- 2025年4月安全生产会议记录
- 2025年试题辅警面考试练习题目及答案
- 2025年江苏省苏豪控股集团有限公司校园招聘笔试备考试题及答案详解(各地真题)
- 存款保险宣传培训
- 质量检查员基础知识培训
- 燃气施工安全培训课件
- 具有履行合同所必需的设备和专业技术能力的承诺书完整版
评论
0/150
提交评论