OpenEdv-开源电子网

 找回密码
 立即注册

扫一扫,访问微社区

正点原子全套STM32开发资料,上千讲STM32视频教程,RT1052教程免费下载啦...

查看: 407|回复: 0

OK6410开发板学习之一步一步实现精简BootLoader(BL1部分)三

[复制链接]

  离线 

12

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
92
金钱
92
注册时间
2016-7-24
在线时间
13 小时
发表于 2018-4-18 21:00:22 | 显示全部楼层 |阅读模式
正点原子公众号
7.内存初始化:bl mem_init

内存由于具备访问速度快,访问方式简单等优点,成为了PC或者是嵌入式硬件平台上不可或缺的元件。在开始学习如何使用内存之前,非常有必要先了解一下内存的分类:

1.DRAM:它的基本原件是小电容,电容可以在两个极板上保留电荷,但是需要定期的充电(刷新),否则数据会丢失。缺点:由于要定期刷新存储介质,存取速度较慢。

2.SRAM:它是一种具有静止存取功能的内存,不需要定期刷新电路就能保存它内部存储的数据。其优点:存取速度快; 但是缺点是:功耗大,成本高。常用作存储容量不高,但存取速度快的场合,比如steppingstone。

在嵌入式硬件体系中,除了CPU内部的”垫脚石”采用SRAM外,板载内存一般会采用DRAM,而DRAM又可以分为SDRAM,DDR,DDR2等。

SDRAM(Synchronous Dynamic Random AccessMemory):同步动态随机存储器.
同步: 内存工作需要有同步时钟,内部的命令的发送与数据的传输都以该时钟为基准。
动态:存储阵列需要不断的刷新来保证数据不丢失。

随机:是指数据不是线性依次存储,而是自由指定地址进行数据读写。

DDR (Double Data Rate SDRAM),即“双倍速率同步动态随机存储器”。与早期的SDRAM相比,DDR 除了可以在时钟脉冲的上升沿传输数据,还可以在下降沿传输信号,这意味着在相同的工作频率下,DDR 的理论传输速率为SDRAM的两倍。DDR2 则在DDR 的基础上再次进行了改进,使得数据传输速率在DDR 的基础上再次翻倍。6410开发板通常采用DDR内存 。

内存的内部如同表格,数据就存放在每个单元格中。数据读写时,先指定行号(行地址),再指定列号(列地址) ,我们就可以准确地找到所需要的单元格。而这张表格的称为ogical Bank(L-Bank)。 如下图:


由于技术、成本等原因,一块内存不可能把所有的单元格都做到一个L-Bank,现在内存内部基本都会分割成4
个L-Bank。 S3C6410处理器拥32位地址总线,其寻址空间为4GB。其中高2GB为保留区,低2GB区域又可划分

为两部分:主存储区和外设区。如下左图:

            

主存储去又可以分为:Boot镜像区、内部存储区、静态存储区、保留区、动态存储区,如上右图 。

Boot镜像区:这个区域的作用正如它的名字所述,是用来启动ARM系统的。但是这个区域并没有固定的存储介质与之对应。而是通过修改启动选项,把不同的启动介质映射到该区域。比如说选择了IROM 启动方式后,就把IROM映射到该区域。

内部存储区:这个区域对应着内部的内存地址,iROM和SRAM都是分布在这个区间。0x08000000~0x0bffffff对应着内部ROM,但是IROM实际只有32KB,选择从IROM启动的时候,首先运行就是这里面的程序BL0,这部分代码由三星固化。0x0c000000~0x0fffffff对应内部SRAM,实际就是8KB的Steppingstone。

静态存储区:这个区域用于访问挂在外部总线上的设备,比如说NOR flash、oneNand等。这个区域被分割为6个bank,每个bank为128MB,数据宽度最大支持16bit,每个bank由片选Xm0CS[0]~Xm0CS[5] 选中。

动态存储区:该区域从0x50000000~0x6fffffff,又分为2个区间,分别占256MB,可以片选Xm1CS[0]~Xm1CS[1]来进行着2个区间的选择。我们6410开发板上256MB的DDR内存就安排在这个区域,这也就是为什么6410的内存地址是从0x50000000开始的原因。

OK6410内存芯片硬件连接如下:


从上图可以知道,它是通过两片内存芯片组合成32位数据的,分别使用s3c6410的前16位和后16位数据线。

查看s3c6410手册DRAM Controller 章节,可以发现有关于内存初始化操作步骤的说明,如下:


所以就可以参考上面的操作步骤来实现内存的初始化。

第1步:配置DRAM CONTROLLER COMMAND REGISTER为2b011及为0x4,让其进入配置模式,寄存器说明如下:


第2步:配置内存时序寄存器、片选配置寄存器、用户配置寄存器;内存时序寄存器比较多,这里不再一一列举,大家可以查看s3c6410手册,片选配置寄存器说明如下:


用户配置寄存器说明如下:


第3步:等待200us,让SDRAM电源和时钟稳定,但是,当cpu启动时电源和时钟已经稳定。呵呵,就是不需要了呗,绕这么大一圈,可能是三星公司有病吧;

第4步:执行内存初始化,说了半天才内存初始化,之前干啥啦?不要吵吵,之前是sdram的初始化,因为OK6410使用的是mobile DDR sdram,所以参考5.4.2的ddr/mobile DDR sdram初始化步骤,根据说明,其实就是重复设置P1DIRECTCMD寄存器(直接命令寄存器)的Memory command位,即[19:18]位。分别设置为2b11  2b00 2b01 2b01 2b10 2b10使其运行中nop、Prechargeall 、Autorefresh 、MRS、EMRS。直接命令寄存器说明如下:


第5步:设置P1MEMCCMD寄存器(内存控制命令寄存器)的Memc_cmd位位3b000,让DRAM控制器进入准备好模式,内存控制命令寄存器说明如下:


第6步:检测DRAM控制器是否进入准备模式,详见代码,如下:

.text.global mem_initmem_init:        ldr r0, =0x7e00f120  @配置内存系统子程序寄存器地址     mov r1, #0x8         @将0x8存入r1寄存器    str r1, [r0]         @将r1寄存器里的数据写入配置内存系统子程序寄存器中    ldr r0, =0x7e001004  @内存控制命令寄存器        mov r1, #0x4         @根据手册得知需要先进入配置模式    str r1, [r0]         @将寄存器r1内容写入内存控制命令寄存器中    ldr r0, =0x7e001010  @刷新寄存器地址    ldr r1, =( ( 7800 / ( 1000000000/133000000 ) + 1 ) )      @设置刷新时间    str r1, [r0]         @将寄存器r1内容写入刷新寄存器寄存器中    ldr r0, =0x7e001014  @CAS latency寄存器    mov r1, #(3 << 1)    @r1=0x6    str r1, [r0]         @将寄存器r1内容(0x06)写入CAS latency寄存器中    ldr r0, =0x7e001018  @t_DQSS寄存器    mov r1, #0x1         @r1=0x1    str r1, [r0]         @将寄存器r1内容(0x01)写入t_DQSS寄存器中    ldr r0, =0x7e00101c  @T_MRD寄存器    mov r1, #0x2         @r1=0x2    str r1, [r0]         @将寄存器r1内容(0x02)写入T_MRD寄存器中    ldr r0, =0x7e001020  @t_RAS寄存器    ldr r1, =( ( 45 / ( 1000000000 / 133000000 ) + 1 ) )   @r1=6.95    str r1, [r0]         @将寄存器r1内容(6.95)写入t_RAS寄存器中    ldr r0, =0x7e001024  @t_RC寄存器    ldr r1, =( ( 68 / ( 1000000000 / 133000000 ) + 1 ) )   @r1=10.044    str r1, [r0]         @将寄存器r1内容(10.044)写入t_RC寄存器中    ldr r0, =0x7e001028  @t_RCD寄存器    ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )   @r1=3.99    str r1, [r0]         @将寄存器r1内容(3.99)写入t_RCD寄存器中    ldr r0, =0x7e00102c  @t_RFC寄存器    ldr r1, =( ( 80 / ( 1000000000 / 133000000 ) + 1 ) )   @r1=11.64       str r1, [r0]         @将寄存器r1内容(11.64)写入t_RFC寄存器中    ldr r0, =0x7e001030  @t_RP寄存器    ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )   @r1=3.99    str r1, [r0]         @将寄存器r1内容(3.99)写入t_RP寄存器中    ldr r0, =0x7e001034  @t_rrd寄存器    ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )   @r1=2.995    str r1, [r0]         @将寄存器r1内容(2.995)写入t_rrd寄存器中    ldr r0, =0x7e001038  @t_wr寄存器    ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )   @r1=2.995 @  ldr r2, [r0]    str r1, [r0]         @将寄存器r1内容(2.995)写入T_MRD寄存器中    ldr r0, =0x7e00103c  @t_wtr寄存器    mov r1, #0x07        @r1=0x07    str r1, [r0]         @将寄存器r1内容(0x07)写入T_MRD寄存器中    ldr r0, =0x7e001040  @t_xp寄存器    mov r1, #0x02        @r1=0x02    str r1, [r0]         @将寄存器r1内容(0x02)写入t_xp寄存器中    ldr r0, =0x7e001044  @t_xsr寄存器    ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )   @r1=16.69    str r1, [r0]         @将寄存器r1内容(16.69)写入t_xsr寄存器中    ldr r0, =0x7e001048   @t_esr寄存器    ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )   @r1=16.69    str r1, [r0]         @将寄存器r1内容(16.69)写入t_esr寄存器中    ldr r0, =0x7e00100c  @内存控制配置寄存器 P1MEMCFC    ldr r1, =0x00010012  @配置控制器  r1=2b0000_0000_0000_0001_0000_0000_0001_0010    str r1, [r0]         @将寄存器r1内容(0x10012)写入P1MEMCFC寄存器中    ldr r0, =0x7e00104c  @32位DRAM配置控制寄存器    ldr r1, =0x0b45      @r1=2b0000_0000_0000_0000_0000_1011_0100_0101  选择Mobile DDR SDRAM    str r1, [r0]         @将寄存器r1内容(0x0b45)写入T寄存器中    ldr r0, =0x7e001200  @片选寄存器    ldr r1, =0x150f8     @r1=0x150f8  r1=2b0000_0000_0000_0001_0101_0000_1111_1000   Bank-Row-Column organization    str r1, [r0]         @将寄存器r1内容(0x02)写入T_MRD寄存器中    ldr r0, =0x7e001304  @用户配置寄存器    mov r1, #0x0         @r1=0x0    str r1, [r0]         @将寄存器r1内容(0x00)写入用户配置寄存器中    ldr r0, =0x7e001008  @直接命令寄存器    ldr r1, =0x000c0000  @r1=2b0000_0000_0000_1100_0000_0000_0000_0000   makes DRAM Controller issue ‘NOP’ memory    str r1, [r0]         @将寄存器r1内容(0xc0000)写入直接命令寄存器中    ldr r1, =0x00000000  @r1=0   makes DRAM Controller issue‘PrechargeAll’ memory command.     str r1, [r0]         @将寄存器r1内容(0x0)写入直接命令寄存器中    ldr r1, =0x00040000  @r1=2b0000_0000_0000_0100_0000_0000_0000_0000  makes DRAM Controller issue ‘Autorefresh’ memory command.    str r1, [r0]         @将寄存器r1内容(0x40000)写入直接命令寄存器中    ldr r1, =0x000a0000  @r1=2b0000_0000_0000_1010_0000_0000_0000_0000  makes DRAM Controller issue ‘MRS’ memory command.     str r1, [r0]         @将寄存器r1内容(0xa0000)写入直接命令寄存器中    ldr r1, =0x00080032  @r1=2b0000_0000_0000_1000_0000_0000_0011_0010    str r1, [r0]         @将寄存器r1内容(0x80032)写入直接命令寄存器中  makes DRAM Controller issue ‘EMRS’ memory command.    ldr r0, =0x7e001004  @内存控制命令寄存器    mov r1, #0x0         @根据手册得知需要进入ready模式    str r1, [r0]         @将寄存器r1内容写入内存控制命令寄存器中@检查内存初始化是否准备好check_dmc1_ready:        ldr r0, =0x7e001000  @DRAM控制状态寄存器    ldr r1, [r0]         @将DRAM控制状态寄存器中内容写入寄存器r1中    mov r2, #0x3         @将0x03写入寄存器r2中    and r1, r1, r2       @将r1和r2与运算后存在r1中,即只保持读出的值的[1:0]位    cmp r1, #0x1         @将读出的值与0x01比较    bne check_dmc1_ready @若不相等,跳转到标号check_dmc1_ready处继续执行,检查内存状态    nop    mov pc, lr           @返回调用处继续往下执行

8.拷贝bl到内存中:bl copy_to_arm

要想拷贝bl到内存中,我们首先的看一下s3c6410的启动流程图,如下:


解释如下:


整个流程如下:首先是执行芯片固化在iROM中的bl0代码,该段代码将Booting Device中的bl1搬移到Stepping stone中,但是Stepping stone只有8k,一个完整的代码代码量会超过8K,那样就没法运行了,所以bl1这段代码其中就有一个功能将大部分代码搬移到内存中去执行,这里要实现的就是这个功能,只不过是将从Booting device中bl1开始的的4K代码移过去。代码如下:

        @ 代码搬移,拷贝bl到内存中copy_to_ram:        ldr r0, =0x0c000000    @ Stepping Stone (Boot Loader)基地址,即要搬移的源地址存入r0   起点        ldr r1, =0x50008000    @ 内存地址,要搬移的目标地址存入r1   终点        add r3, r0, #1024*4    @ 将r0处的地址加4k大小存入r3,要搬移的内存Size 4k, 大小copy_loop:               @ 等待搬移完成        ldr r2, [r0], #4       @ 将地址0x0c000000增加4后(0x0c000004)地址数据存入r2        str r2, [r1], #4       @ 将r2的数据传送到r1+4地址处(0x500080004)        cmp r0, r3             @ 比较r0和r3处地址        bne copy_loop               @ 若不相等,跳到标号copy_loop处继续执行        mov pc, lr               @ 返回调用处继续往下执行

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则




关闭

必看:"原子哥”力荐上一条 /1 下一条

QQ|联系我们|手机版|官方淘宝店|微信公众平台|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2018-8-19 19:45

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表
/* */