zoukankan      html  css  js  c++  java
  • 【嵌入式开发】裸机引导操作系统和ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 )

    【嵌入式开发】ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 )

     

    一. 内存 简介



    1. 两大内存分类


    ( 1 ) DRAM 简介 ( 定期刷新 | 速度慢 | 成本低 )


    DRAM 简介 :

    • 1.硬件描述 : DRAM 基本由一个个小电容基本原件组成, 电容的两端保留电荷;
    • 2.优缺点描述 :
      • ① 优点 : 成本很低, 很便宜;
      • ② 缺点 : 需要 定期刷新数据速度较慢;
        • a.定期刷新 : DRAM 需要定期给其存储介质 ( 电容 ) 充电, 刷新数据, 否则数据会丢失;
        • b.速度慢 : 其存取速度比较慢;
    • 3.使用场景 : 一般开发板上使用的是 DRAM, 如 128M , 256 M 内存的 开发板 使用的就是 DRAM 内存 , 这些内存比较便宜 ;


    ( 2 ) SRAM 简介 ( 不需刷新 | 存取速度快 | 功耗大 | 成本高 )


    SRAM 简介 :

    • 1.使用特性 ( 不需刷新 ) : SRAM 具有 静止存取 的功能, 不需要定期刷新其存储介质, 就可以保存数据;
    • 2.优缺点介绍 :
      • ① 优点 : 访问存取速度很快;
      • ② 缺点 : a. 功耗比较大b. 成本很高;
    • 3.使用场景 : CPU 内部一般使用 SRAM, 一般只有 几KB 大小, 其访问速度非常快, 如 启动时的 stepping stone ( 垫脚石 ) ;



    2. DRAM 分类 ( SDRAM | DDR | DDR2 )


    DRAM 分为 SDRAM, DDR, DDR2 三种类型;


    (1) SDRAM 简介 ( 动态随机访问存储器 | 同步时钟 | 动态刷新 | 随机访问 )


    SDRAM 简介 :

    • 1.全称 : Synchronous Dynamic Random Access Memory, 即 同步 动态 随机访问 存储器;
    • 2.同步时钟 : 内存中的 数据传输 和 内部命令传输 都是以 同步时钟为准, 所有的工作都基于该同步时钟;
    • 3.动态刷新 : 内存的 存储单元 需要 不断的刷新 , 以 保证数据的存在 ;
    • 4.随机访问 : 数据访问可以 不按照 线性次序进行 , 可以 自由读写任意一个地址的数据 ;
    • 5.使用场景 : 2440 开发板 的 内存 一般是 SDRAM ;


    (2) DDR 和 DDR2 ( DDR 是 SDRAM 传输速率的 2 倍 | DDR2 是 DDR 传输速率的 2 倍 )


    DDR 和 DDR2 简介 :

    • 1.DDR ( Double Data Rate SDRAM ) : 即 双倍速率 同步动态随机存储器 , 与 上一节 介绍的 SDRAM 对比 ,:
      • ① SDRAM 传输数据 : SDRAM 只能在 时钟脉冲 的 上升沿 传输数据 , 不能再 下降沿 传输数据 ;
      • ② DDR 传输数据 : DDR 除了 在 时钟脉冲 的 上升沿 传输数据外 , 还能 在 时钟脉冲的 下降沿 传输数据 ;
      • ③ SDRAM 与 DDR 对比结果 : 如果 时钟脉冲 频率相同 , DDR 的数据传输速率 是 SDRAM 的 2 倍 ;
    • 2.DDR2 简介 : DDR2 在 DDR 的 基础上 进行了技术上的 改进 , DDR2 的数据传输速率是 DDR 的 2倍 ;
    • 4.使用场景 : 6410 开发板 使用 DDR 内存 , 210 开发板 的 内存 是 DDR2 类型的 ;



    3. 内存的内部结构


    ( 1 ) Logical Bank ( 行列表格 | L-Bank 4 个组成内存 | 内存寻址信息 ① L-Bank 选择信号 ② 行地址 ③ 列地址 )


    L-Bank 简介 :

    • 1.内部逻辑 ( 表格结构 ) : 内存 内部 逻辑 与 表格 类似 , 数据 存放在 单元格 中 , 这个 表格 有 行 和 列 , 可以根据 行号 和 列号 读取 对应单元格 中的数据 ;
    • 2.数据读写 : 读取 内存 表格 中的数据时 , 指定 行号 ( 行地址 ) 和 列号 ( 列地址 ) , 根据 两个地址值 , 就可以 准确的找到 存储数据的 单元格 ;
    • 3.L-Bank 引入 : 上面所描述的 表格 , 就是 Logical-Bank ( L-Bank ) ;
    • 4.L-Bank 数量 : 在 一个 内存中 , 将 所有的 内存单元 封装到一个 L-Bank 成本很高 , 一般情况下 会 在 一块内存 中 设置 4 个 L-Bank ;
    • 5.内存寻址信息 : 如果 要 到 内存中 存取数据 , 需要 三种数据 , 来寻找对应数据 ;
      • ① L-Bank 选择信号 : 选择 内存中 哪个 L-Bank , 一个内存有 4 个 L-Bank ;
      • ② 行地址 : L-Bank 的 行号 ;
      • ③ 列地址 : L-Bank 的 列号 ;



    4. 推导 内存 容量 计算公式


    ( 1 ) 内存 容量 计算公式 ( 内存容量 = 4 * L-Bank 单元格数目 * 单元格容量 )


    内存容量 = L-Bank 个数 * L-Bank 容量
    L-Bank 个数 一般 是 4 个
    L-Bank 容量 = 单元格数目 * 单元格容量
    内存容量 = 4 * L-Bank 单元格数目 * 单元格容量



    ( 2 ) 举例说明


    计算如下内存大小 : 下面 截图 是 一款 内存芯片说明
    在这里插入图片描述

    • 1.参数列举 : 该 SDRAM 有 4 个 L-Bank , 每个 L-Bank 有 4M 个 存储单元 , 每个存储单元 有 16 bit , 即 2 字节 ;
    • 2.计算结果 : 可以得到 4 * 4M * 2Byte = 32MB , 该内存大小为 32MB ;




    二. 2440 开发板 内存初始化



    1. 2440 地址空间


    ( 1 ) S3C2440 芯片地址线 ( ADDR0 ~ ADDR26 27根地址线 )


    2440 芯片地址线 :

    • 1.地址线 : 查询 mini2440 原理图 , 可以看到 2440 芯片 对外提供的 引脚 , 在 左侧 的有 27 根地址线 ADDR0 ~ ADDR26 ; 该手册 在 博客提供的下载文件中 的 2440 手册目录下 ;
      在这里插入图片描述
    • 2.可访问外设空间大小 : 有 27 根 地址线 , 说明 它能 访问 2 的 27 次方 大小的空间 , 即 128M 的内存空间 ;

    计算其访问的字节数 : 2^27 = 134217728 字节 ( Byte ) , 将 Byte 转为 MB : 134217728 / 1024 / 1024 = 128 MB ;

    • 3.内存太小 : 如果只有 128M 内存 , 这个内存太小了 , 需要使用下面的方法 扩大内存 , 如 片选信号 ;


    ( 2 ) 片选信号 ( nGCS0 ~ nGCS7 8 个片选信号 | 8 * 128MB = 1024MB = 1GB 内存 )


    片选信号 :

    • 1.片选信号引入 : 2440 芯片 有 27 根 地址线 , 能访问 128MB 的内存 , 为了 扩大 访问范围 , 这里 提供 多个芯片 , 即 27 根地址线 , 可以 访问 不同的 内存芯片 , 这样 就实现了 扩大内存的 目的 ; 转换芯片 就需要用到 片选信号 ;
    • 2.2440 片选信号 : S3C2440 芯片 , 提供了 8 个片选信号 , 分别是 nGCS0 ~ nGCS7 信号 ;
    • 3.片选信号选中 : 当 nGC0 ~ 7 中的 某个信号 出现有效值 , 那么 S3C2440 芯片的 27 根地址线 , 就 访问 该信号对应的 128MB 内存空间 ;
    • 4.芯片内存空间计算 : S3C2440 芯片 有 8 * 128MB = 1024MB = 1GB 内存 ;


    ( 3 ) 片选信号 与 内存地址


    片选信号 与 内存地址 :

    • 1.查询 S3C2440 文档 : S3C2440.pdf , Page 194 , 展示了 S3C2440 芯片的 片选分布图 ;
      在这里插入图片描述
    • 2.两种启动方式 : 左侧 展示的是 NOR Flash 启动方式 , 右侧展示的是 Nand Flash 启动方式 , Nand Flash 中可以看到 0 区域是 4KB 的 SRAM 垫脚石 ;
    • 3.内存地址由来 : 一般情况下 , 内存是安排在 片选 6 和 片选 7 中 , 片选 6 的起始地址是 0x30000000 , 这也是 内存起始地址是 0x30000000 的原因 ;


    ( 4 ) 存储控制器 ( 转换 地址 -> L-Bank 行 列 | 初始化存储控制器 )


    存储控制器 简介 :

    • 1.片选安排 : 芯片 将 不同的 外设 安排在 不同的 片选地址中 , 如 将内存安排在 片选 6 和 片选 7, 将网卡芯片安排在片选 3 中 , 将 Nor Flash 安排在 片选 0 上 ;
    • 2.外设的地址值 : 处理器访问 外设 时 , 只会访问 一个地址 ;
    • 3.CPU 对地址值不知情 : CPU 对 地址值对应的什么外设 是不知情的 , 其访问对应的地址 , 还需要通过 存储控制器 将地址转换为 对应的 存储单元 ;
    • 4.存储控制器 : 通过 存储控制器 , 对 地址 进行相应处理 , 将地址分解为 ① 内存的 L-Bank 序号 , L-Bank 中的 ② 行地址 和 ③ 列地址 , 然后 才能 访问到 地址 对应的 数据存储单元 ;
    • 5.初始化内存操作 : 初始化内存 就是 对 存储控制器 进行初始化 , 不是初始化 内存芯片 ;



    2. S3C2440 芯片 与 内存芯片 的 硬件 连接


    ( 1 ) 芯片 与 内存芯片 连接方式 ( 4Banks * 4M * 16Bit = 32MB | 两个内存芯片 16位 并联到 2440 芯片的数据线上 32位 )


    芯片 与 内存 芯片 连接方式 :

    • 1.查询 S3C2440 对应的内存芯片手册 ( HY57V561620.pdf ) : 可以到到 其 内存芯片规格是 4Banks * 4M * 16Bit Synchronous DRAM , 可以得到 4 * 4M * 2Byte = 32MB , 该内存大小为 32MB , 每个内存芯片大小 32MB ;
      在这里插入图片描述
    • 2.规格解析 : 有 4 个 L-Bank , 每个 L-Bank 有 4M 个 存储单元 , 每个存储单元 有 16 bit , 两层含义 ① 单元格容量 2 字节 , ② 其数据宽度为 16 位 ;
    • 3.2440 芯片数据线个数 : 查询 mini2440 原理图可得 , 其 数据线有 32 位 , DATA 0 ~ DATA31 ;
      在这里插入图片描述
    • 4.将内存芯片 并联 与 数据线 连接 : 内存芯片宽度为 16位 , 2440 芯片 数据线有 32 位 ; 为了不出现资源浪费 , 这里采用 两个 内存芯片并联的方式 , 每个 16 位 , 并联后 32 位 , 对应 2440 芯片的 32位 数据线 ; 2440 芯片 高 16 位 数据线 接到 一个 内存芯片上 , 2440 芯片 低16 位 接到 另一个 内存芯片上 ;
    • 5.数据读取 : 2440 芯片 数据线 高 16位 从 第一个芯片上读取 16位数据 , 低 16 位数据线 从 第二个芯片上读取 16位数据 , 这样 一次可以读取 32 位 数据 ; 2440 开发板上采用的是 2 个 32MB 内存并联方式连接 , 其内存大小是 64MB ;



    3. 设置 2440 存储控制寄存器


    ( 1 ) 存储控制器设置 ( 作用 控制 CPU 对外设访问 | 配置 | 文档 S3C2440.pdf Page193 | )


    存储控制器 设置 :

    • 1.存储控制器作用 : 其 作用 是 控制 CPU 对外设的访问 , 如 内存 , 网卡芯片 , NOR Flash 等 ;
    • 2.存储控制器 配置 : 存储控制器 不是 完全智能的 , 需要我们 配置存储控制器 以 什么方式进行访问 ;
    • 3.参考文档位置 : 在 S3C2440.pdf 芯片手册中 , 第 5 章 , Memory Controller , Page193 , 介绍了 存储控制器 工作原理 , 以及 设置方法 ;


    ( 2 ) BWSCON 寄存器 ( BUS WIDTH & WAIT CONTROL REGISTER 总线宽度 和 等待控制寄存器 )


    BWSCON 寄存器 :
    在这里插入图片描述

    • 1.简介 :
      • ① 作用 : BWSCON 寄存器 是 设置总线宽度 和 等待状态 的 控制寄存器 ;
      • ② 寄存器地址 : 0x4800 0000 ;
      • ③ 寄存器初始值 : 0x000 000 ;
    • 2.寄存器位 与 Bank 的对应设置 : 32 位 的寄存器 , 分成 8 组 , 分别对应 一个 L-Bank 设置 ; 因此 下面 介绍 一组 值的设置即可 ;
      在这里插入图片描述
      在这里插入图片描述
    • 3.Bank7 设置 : ST7 , WS7 , DW7 设置 ;
      在这里插入图片描述
      • ① ST7 设置 : 对应 BWSCON 的 [31] 位 , 决定 SRAM 是否使用了 UB/LB pin 脚 ; 设置 0 是没有使用 UB/SB , 设置 1 是使用了 UB/SB pin 脚 ; 其 并 没有使用 UB/LB pin 脚 , 设置 0 ;
      • ② WS7 设置 : 对应 BWSCON 的 [30] 位 , 决定 Bank7 是否使用 等待状态 , 设置 0 不使用 , 设置 1 使用 ; 这里设置 0 , 不适用 等待状态 ;
      • ③ DW7 设置 : 对应 BWSCON 的 [29:28] 位 , 决定 Bank7 总线宽度 , 00 = 8位总线宽度 , 01 = 16位总线宽度 , 10 = 32位总线宽度 , 11 = 保留位 ; 查看芯片手册可以知道 , 2440 的总线宽度时 32 位的 , 这里设置 10 值 ;
      • ④ 寄存器值确定 : 这里 只配置 Bank6 和 Bank7 , 其它都配置成 0 , 因此 Bank7 配置 为 0b0010 , Bank6 与 Bank7 配置一样 , 也是 0b0010 , 其它位均使用 0 默认值 ; 最终 BWSCON 寄存器值为 0b 0010 0010 0000 0000 0000 0000 0000 0000 , 十六进制值 为 0x22000000 ;
    • 4.BWSCON 寄存器设置 :

    0x22000000



    ( 3 ) BANKCON 寄存器 ( BANK CONTROL REGISTER : Bank 0 ~ 5 控制寄存器 )


    BANKCON 0~ 5 寄存器 :
    在这里插入图片描述

    • 1.简介 : 该 寄存器 是 一组寄存器 , 共 6 个, 每个寄存器 都 控制 一个 Bank ;
    • 2.寄存器值设置 : 这一组寄存器是 控制 Bank 0 ~ Bank5 的, 内存是在 Bank6 和 Bank7 中, 因此这里 保持默认值 0x0700 不变即可;
    • 3.Bank0 ~ Bank5 控制寄存器设置 :

    0x00000700
    0x00000700
    0x00000700
    0x00000700
    0x00000700
    0x00000700



    ( 4 ) BANKCON 寄存器 ( BANK CONTROL REGISTER : Bank 6 ~ 7 控制寄存器 )


    BANKCON 6~ 7 寄存器 :
    在这里插入图片描述

    • 1.内存类型 MT ( Memory Type ) 设置 : [ 16:15 ] 位 , 决定 Bank6 或 Bank7 的 内存 的类型 , 2440 中 , 内存使用的是 SRAM , 这里取值 11 ;
      在这里插入图片描述

    • 2.设置其他参数 : 之后的 14 位 被分为 两种情况 , 当 MT 类型设置为 ROM 或 SRAM 时 , 即 [ 16:15 ] 取 00 值 , 需要设置 [ 14 : 0 ] 位 ; 当 MT 类型设置为 SDRAM 时 , 即 [16:15] 取 11 值 , 只需要设置 [ 3 : 0 ] 位 即可 ; 2440 芯片 使用的是 SDRAM , 这里只需要设置 [ 3 : 0 ] 位 即可 , 此时 [ 14 : 4 ] 位 全部取值 0 ;
      在这里插入图片描述

      • ① Trcd 设置 : [ 3 : 2 ] 表示的是 行列地址选择 信号的转换延时 , 00 代表 2 个时钟 , 01 代表 3 个时钟 , 10 代表 4 个时钟 , 该值在 时序图中 明确指出 , Trcd 取值 是 2 个时钟 , 这里设置该值为 00 ;
        在这里插入图片描述
      • ② SCAN 域设置 : [ 1 : 0 ] 位 设置 , 表示 列地址 数目 , 00 表示 8 位 , 01 表示 9 位 , 10 表示 10 位 ; 行地址 和 列地址 信息需要去查询 SRAM 内存芯片文档 HY57V561620F(L)T§Series_(Rev1.1).pdf , 其中可以查到 Column Address : CA0 ~ CA8 , 有 9列 , 该 SCAN 域 取值为 01 ;
        在这里插入图片描述
    • 3.BANKCON 寄存器值 : 0b 11 ( 内存类型设置 ) 00000000000 ( SRAM 时设置 0 , ROM 时 设置其它 ) 00 ( 行列地址信号转换延迟 2 时钟 ) 01 ( 设置列地址有 9 位 ) , 二进制值 0b11000000000000001 , 转为 16 进制 为 0x18001 ;

    • 4.Bank6 和 Bank7 控制寄存器设置为 :

    0x00018001
    0x00018001



    ( 5 ) REFRESH CONTROL REGISTER 刷新控制寄存器 ( 负责控制 SDRAM 刷新 )


    刷新控制寄存器 : 管理 SRAM 刷新 , SRAM 工作原理是需要不断的 定期 的 进行刷新 ;
    在这里插入图片描述

    • 1.REFEN 域 ( Refresh Enable ) : [ 23 ] 位 ; 设置 SDRAM 是否需要刷新 ; 0 = 不刷新 , 1 = 刷新 ; 这里选择 1 , 要进行刷新 ;
    • 2.TREFMD 域 ( Refresh Mod ) : [ 22 ] 位 ; 设置 SDRAM 的刷新模式 ; 0 = CBR/Auto Refresh 自动刷新 , 1 = Self Refresh 自己刷新 ; 这里我们选择 0 自动刷新 ;
    • 3.Trp 域 : [ 21 : 20 ] 位 ; 设置 SDRAM 的准备充电时间 ; 00 = 2 个时钟 , 01 = 3 个时钟 ; 10 = 4 个时钟 , 11 = 不准备充电 ; 翻到 205 页 的时序图中 , 可以看到 Trp 预充电时间是 2 个时钟 , 这里设置 00 即可 ;
      在这里插入图片描述
    • 4.Tsrc 域 : [ 19 : 18 ] 位 ; 设置 一行 需要 刷新的时间 ; 该值通常是 7 个时钟 , 这里使用默认值 11 , 代表刷新一行需要 7 个时钟时间 ;
    • 5.不支持的域 : [ 17 : 16 ] 和 [ 15 : 11 ] 位 不支持 , 暂时没有使用 , 前者取值 00 , 后者取值 00000 ;
    • 6.Refresh Counter 域 : [ 10 : 0 ] 位 ; 刷新计数值 , SDRAM 每隔一段时间就需要刷新 , 这个时间间隔由该域进行设定 ;
      • ① 计算公式 : 刷新时间 与 刷新计数 公式 : refresh_period = ( 2^11 - refresh_count + 1 ) / HCLK , HCLK 是提供给内存使用的时钟 , 其内存时钟是核时钟的 1/4 即 100MHz, 推导出 refresh_count = 2 ^ 11 + 1 - refresh_peroid * HCLK ;
      • ② 计算案例 : 这里文档中给出一个示例 , 如果 refresh_period 为 7.8us , HCLK 为 100MHz , 计算出 refresh_count = 2 ^ 11 + 1 - 100 * 7.8 = 1269 ;
      • ③ 最终取值 : 这里我们取值 1269 , 转为二进制 10011110101 ;
    • 7.SDRAM 刷新控制寄存器取值 : REFEN = 1 ; TREFMD = 0 ; Trp = 00 ; Tsrc = 11 ; 不支持域 [ 17 : 11 ] = 00 00000 ; Refresh Counter = 10011110101 ; 整合为 0b100011000000010011110101 , 转为十六进制 0x8C04F5 ;


    ( 6 ) BANK SIZE 寄存器 ( 设置 BANK 的大小 )


    BANK SIZE 寄存器设置 :
    在这里插入图片描述

    • 1.BURST_EN :

      • ① 位数 : 寄存器位数 [ 7 ] ;
      • ② 作用 : 设置 ARM 核 的 突发模式 ( burst operation ) 是否使能 ;
      • ③ 突发模式 : 突发模式 是 访问内存时 , 一次性可以使用 批量数据 , 使用突发模式后 , 可以提高内存访问效率 ;
      • ④ 取值 : 一般情况下 , 打开 突发模式 , 这里设置 1 ;
    • 2.Reserved : 寄存器位数 [ 6 ] , 没有使用该位 ; 使用默认值 0 ;

    • 3.SCKE_EN : 寄存器位数 [ 5 ] ; 是否使用节电模式 ; 0 = 不使用 , 1 = 使用 ; 这里 我们 设置 1 , 打开节电模式 ;

    • 4.SCLK_EN : : 寄存器位数 [ 4 ] ; 这里文档中推荐设置成 1 , 直接设置 1 即可 ;

    • 5.Reserved : 寄存器位数 [ 3 ] , 没有使用该位 ; 使用默认值 0 ;

    • 6.BK76MAP : 寄存器位数 [ 2 : 0 ] ; 设置 BANK 6 / 7 容量大小 , 之前讲到过 内存芯片 与 硬件的连接方式是 两块 32M 的内存连接 , 形成 64 M 容量 , 这里设置 001 代表其 容量是 64MB ;

    • 7.寄存器值 : BURST_EN [ 7 ] = 1 ; Reserved [ 6 ] = 0 ; SCKE_EN [ 5 ] = 1 ; SCLK_EN [ 4 ] = 1 ; Reserved [ 3 ] = 0 ; BK76MAP [ 2 : 0 ] = 001 ; 其二进制值为 0b10110001 , 转为 16 进制 为 0xB1 ;



    ( 7 ) SDRAM MOD REGISTER SET REGISTER ( 设置 BANK6 和 BANK7 模式的寄存器 )


    SDRAM MODE REGISTER SET REGISTER : BANK6 和 BANK7 分别对应一个寄存器 MRSRB6 和 MRSRB7 , 这两个寄存器内容 和 意义 是一样的 ;
    在这里插入图片描述

    • 1.CL : 寄存器位 [ 8 : 7 ] ; 设置 CAS 潜伏期 ; 在下面 时序图 中 , 找到 CAS 信号 , 潜伏期指的是 RAS 变为低电平 到 CAS 变为 低电平 之间的时钟 , 在 时序图中可以看到 这期间 持续了 3 个时钟 ; 因此 这里 取 011 值 , 代表 3 个时钟 ;
    • 2.其它域设置 : 该寄存器的 TM , BT , BL 域 的 值是固定的 , 文档中已经写了 Fixed , 因此不用设置 , 该寄存器只需要设置 CL 即可 ;
    • 3.寄存器取值 : Reserved [ 11 : 10 ] = 00 ; WBL [ 9 ] = 0; TM [ 8 : 7 ] = 00 ; CL[ 6 : 4 ] = 011 ; BT [ 3 ] = 0; BL [ 2 : 0 ] = 000 ; 最终二进制值为 0b000000110000 , 转为 16 进制为 0x30 ;


    ( 8 ) 内存相关寄存器总结 ( 13 个寄存器 )


    内存相关寄存器总结 :

    • 1.BWSCON ( 总线宽度 和 等待控制寄存器 ) : 0x22000000 ;



    4. 编写汇编指令设置上述寄存器值


    ( 1 ) 汇编循环方法设计


    汇编循环方法设计 :

    • 1.设置寄存器值方法 : 参考一下 设置 其它寄存器的代码 , ① 首先将地址 装在到 r0 寄存器中 , ② 然后 将 要设置的 寄存器值 装载到 r1 寄存器中 , ③ 最后将 r1 寄存器中的值 设置 到 r0 寄存器地址对应的内存中 ;
    #define CLK_DIV0 0x7E00F020							@ 定义 CLK_DIV0 寄存器地址, 时钟的分频参数都是通过该寄存器进行设置的 
    #define OTHERS 0x7E00F900							@ 定义 OTHERS 寄存器地址, 用于设置 CPU 异步工作模式
    #define CLK_VAL ( (0x0 << 0) | (0x1 << 9) | (0x1 << 8) | (0x3 << 12) ) @ 设置 CLK_DIV0 寄存器的值, 即 各个时钟分频器的参数
    
    ldr r0, =CLK_DIV0								@ 将 CLK_DIV0 的地址装载到 r0 通用寄存器中
    ldr r1, =CLK_VAL 								@ 将 要设置给 CLK_DIV0 寄存器的值 CLK_VAL 立即数 装载到 r1 通用寄存器中; 
    str r1, [r0]									@ 将 r1 寄存器中的内容 存储到 r0 存储的地址 指向的内存中
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 2.引入循环 : 在上面的方法中 , 每设置一个寄存器 , 需要 3 行代码 , 如果设置 内存的 13 个寄存器 , 需要 39 行代码 , 代码量略高 , 这里可以使用循环来进行设置 ;
    • 3.循环方案 :
      • ① 值处理 : 将 13 个寄存器值 , 用数组存储起来 , 用指针指向首地址 即可 , 之后指针递增即可 ;
      • ② 寄存器地址处理 : 13 寄存器 的 地址都是递增的 , 只要记录 第一个寄存器 BWSCON 地址 0x48000000 即可 , 之后递增就行 ; 最后一个寄存器 MRSRB7 地址为 0x48000030 作为循环退出条件 ;


    ( 2 ) 汇编实现


    实现的汇编代码 : 详细请看注释 :

    #define mem_contrl 0x48000000		@ 定义 13 个寄存器中第一个寄存器 BWSCON 内存地址 0x48000000
    init_sdram:							@ 标号, 执行该段代码的入口
    	ldr r0, =mem_contrl 			@ 将寄存器内存地址装在到 r0 寄存器中		
    	add r3, r0, #4*13               @ 计算出结束循环的寄存器地址 , r0 中存储的地址 加上 4字节 * 13个寄存器, 是 0x48000034, 即 MRSRB7 寄存器的结束地址
    	adrl r1, mem_data               @ 将 13 个寄存器数字的首地址 装载到 r1 寄存器中, 之后每次使用完 地址 加 4 即可
    
    0:									@ 0 作为循环跳转用的标号
    	ldr r2, [r1], #4				@ 从 r1 指针指向的地址中取出数据 , 将该数据 存储到 r2 中 , 取出数据后 , r1 指针 加 4 
    	str r2, [r0], #4  				@ 将 r2 寄存器中的数据 写出到 r0 指针指向的内存地址中 ( 即实际的内存控制寄存器中 ) , 之后 r2 指针 加 4
    	cmp r0, r3  					@ 循环控制 : 对比 r0 指针 与 最后一个 ( 第 13 个 ) 寄存器 末地址进行对比
    	bne 0b							@ 如果不相等 , 跳转 , 0b 代表向前跳转到 0 标号处 
    	mov pc, lr						@ 如果相等 , 那么整个方法执行完毕, 13 个寄存器都设置完毕
    
    mem_data:							@ 13 个寄存器值 数组, .long 是伪指令 , 指明每个数据的长度
    	.long 0x22000000 				@ BWSCON 寄存器值 , 设置 总线宽度 和 等待状态
    	.long 0x00000700  				@ BANKCON0 寄存器 , 设置 BANK0 的寄存器
    	.long 0x00000700				@ BANKCON1 寄存器 , 设置 BANK1 的寄存器
    	.long 0x00000700				@ BANKCON2 寄存器 , 设置 BANK2 的寄存器
    	.long 0x00000700				@ BANKCON3 寄存器 , 设置 BANK3 的寄存器
    	.long 0x00000700				@ BANKCON4 寄存器 , 设置 BANK4 的寄存器
    	.long 0x00000700				@ BANKCON5 寄存器 , 设置 BANK5 的寄存器
    	.long 0x00018001				@ BANKCON6 寄存器 , 设置 BANK6 的寄存器
    	.long 0x00018001				@ BANKCON7 寄存器 , 设置 BANK7 的寄存器
    	.long 0x008c04f5				@ REFRESH 寄存器 , 刷新控制寄存器
    	.long 0x000000b1				@ BANKSIZE 寄存器 , 设置 BANK 大小 ; 
    	.long 0x00000030				@ MRSRB6 寄存器, 设置 BANK6 模式
    	.long 0x00000030				@ MRSRB7 寄存器, 设置 BANK7 模式
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27




    三. 6410 开发板 内存初始化



    1. S3C6410 地址空间


    ( 1 ) 6410 地址空间分布 ( 保留区 2GB | 外设区 256MB | 主存储区 2GB )


    6410 地址空间分布 :

    • 1.地址总线与空间大小 : S3C6410 的 处理器 有 32 位 地址总线 , 因此其寻址空间 为 4GB , 与 2440 相同 ;
    • 2.空间分布 : S3C6410 的 4GB 空间被分为 3 个区域 , 分别是 ① 保留区 , ② 外设区 , ③ 主存储区 ;
    • 3.保留区 ( 0x80000000 ~ 0xFFFFFFFF ) : 2G ~ 4G 的空间 , 占 2G 空间 , 没有使用 , 暂时保留 ;
    • 4.外设区 ( 0x70000000 ~ 0x7FFFFFFF ) : 占 256MB 空间 , 该段地址主要存放 6410 芯片的各种寄存器 , 之前进行的 看门狗 , 时钟 , 内存初始化 等操作 , 相关寄存器的地址都处于该 内存段 ; 如 下 举例 :
      在这里插入图片描述
    • 5.主存储区 ( 0x00000000 ~ 0x6FFFFFFF ) : 占 1972 MB 空间 , 下面小节详细展开讲解 ;
    • 6.与 2440 对比 :
      • ① 2440 内存空间分布 : 从大的角度来说 , 2440 的地址空间 分为 ① 内部空间 和 ② 外设空间 , 加起来 共 4GB 大小 ;
      • ② 2440 内存外设空间 : 大小 1GB, 分为了 8个 Bank, 每个 Bank 128MB ;


    ( 2 ) 6410 主存储区划分 ( 保留区 2GB | 外设区 256MB | 主存储区 2GB )


    S3C6410 主存储区 ( 0x00000000 ~ 0x6FFFFFFF ) 划分 :
    在这里插入图片描述

    • 1.Boot 镜像区 :
      • ① 大小 范围 : 128MB , 地址范围 0x0000 0000 ~ 0x07FF FFFF ;
      • ② 作用 : 启动映射 , 该区域 不会 固定地 关联 某个 硬件 , 当选中某硬件作为启动设备时 , 如 SD卡驱动 , NandFlash ( I-ROM ) 启动 , 会将该硬件 映射到该区域中 ;
      • ③ 举例 : 将 I-ROM 设置为启动设备 , 即 将其 映射到 Boot Image 中 , ARM 处理器一旦上电 , 就会运行 第一条指令 , 即 运行的是 I-ROM 中的指令 ;
    • 2.内部存储区 :
      • ① 大小 和 范围 : 128MB 大小 , 地址范围 0x0800 0000 ~ 0x0FFF FFFF ;
      • ② 分为两部分 :
        • a. I_ROM : 64MB , 地址范围 : 0x0800 0000 ~ 0x0BFF FFFF ;
        • b. I_SRAM : 64MB , 地址范围 : 0x0C00 0000 ~ 0x0FFF FFFF ;
      • ③ S3C6410 的 I_ROM 和 I_SRAM : 6410 中 I_ROM 只有 32KB , I_SRAM ( 垫脚石 ) 只有 8KB , 这两个区域使用时都没有占满 ;
    • 3.静态存储区 : 6 * 128MB , 地址范围 0x1000 0000 ~ 0x3FFF FFFF ; 可以用于外接设备 , 如 NorFlash ; 该区域 被 分为 6 个 Bank , 每个 Bank 分为 128MB 大小 ;
    • 4.保留区 : 2 * 128 MB , 地址范围 0x4000 0000 ~ 0x4FFF FFFF ;
    • 5.动态存储区 : 2 * 256MB , 地址范围 0x5000 0000 ~ 0x6FFF FFFF ;
      • ① 内存描述 : 将程序下载到 6410 开发板内存中 , 其内存地址就是 0x5000 0000 , 即 动态存储区 ;
      • ② 与 2440 的内存首地址 对比 : 2440 开发板 芯片内存是 0x3000 0000 , 这是因为 芯片 将 内存放在了 Bank6 位置 , 这个 Bank 6 的起始地址就是 0x3000 0000 ; 在 6410 中 , 将内存放在了 动态存储区中 , 因此 6410 开发板上的内存地址是从 0x5000 0000 开始的 ;



    2. S3C6410 内存芯片硬件连接方式


    S3C6410 开发板内存芯片介绍 :

    • 1.内存芯片容量及连接方式 : 6410 开发板 内存容量是 256MB , 是由 2 片 128MB 内存芯片并联起来的 ;
    • 2.芯片地址线和数据线 : 两个 芯片 的 地址线 和 数据线 都是 16 位 , 其 16 位的地址线是相同的 , 但是 其数据线不同 , 即 有 32 位 的数据线用于输出 , 如下图 :
      在这里插入图片描述

    回顾 : 2440 开发板内存容量是 64MB , 是由 2 个 32MB 的芯片并联起来 , 形成的 64MB 的容量 ;




    3. S3C6410 内存初始化



    ( 1 ) 6410 内存初始化流程 ( Config 状态 | 寄存器设置 | 电压时钟稳定 | 内存初始化 | Ready 状态 | 检查 Ready 状态 )


    S3C2440 开发板 内存初始化 , 只需要设置 13 个寄存器的值即可 , 对于设置的顺序 是没有要求的 ; 但是 S3C 6440 开发板 的内存初始化 , 需要按照指定的流程 来进行操作 ;

    S3C6410 内存初始化流程 : 文档位置 : S3C6410X.pdf , Page 192 , 5.4.1 DRAM CONTROLLER INITIALIZATION SEQUENCE ;

    • 1.存储控制器进入配置 ( Config ) 状态 : memc_cmd 写入3位二进制数字 0b100 , 设置 DRAM 存储控制器 进入 Config 状态 ;
      • ① Memc_cmd 介绍 : Memc_cmd 是 DRAM CONTROLLER COMMAND REGISTER 寄存器中的 [ 2 : 0 ] 位 ;
      • ② 文档位置 : S3C6410X.pdf , Page 193 , 5.5.2 DRAM CONTROLLER COMMAND REGISTER ;
      • ③ Memc_cmd 作用 : 设置 DRAM 存储控制器进入不同的状态 ;
        在这里插入图片描述
    • 2.向一系列相关寄存器中写入参数 : 内存时序参数寄存器 , 芯片配置寄存器 , id 配置寄存器 中 写入指定的参数 ;
    • 3.等待电压时钟稳定 : 等待 200 微秒 , 等待 SDRAM 电压 和 时钟 稳定 ; 但是 当 CPU 处理器工作时 , 其电压和时钟就已经稳定了 , 该步骤可以不执行 ;
    • 4.执行初始化 : 除了要初始化 内存控制器外, 还要 对内存 进行初始化操作 ;
      • ① 内存初始化 : 文档中给出了两种内存的初始化步骤 , 5.4.2 是 SDRAM 类型的内存初始化序列 ( 5.4.2 SDR/MOBILE SDR SDRAM INITIALIZATION SEQUENCE ) ; 5.4.3 是 DDR 类型的内存初始化序列 ( 5.4.3 DDR/MOBILE DDR SDRAM INITIALIZATION SEQUENCE ) ; 6410 开发板中使用的是 DDR 类型的内存 , 因此这里参考 5.4.3 中的内存初始化顺序 ;
    • 5.存储控制器设置 Ready 状态 : 将 DRAM 存储控制器设置成 Ready 状态 , 设置 Memc_cmd 为 0b000 ;
    • 6.检查存储控制器状态 : 检查存储控制器是否是 Ready 状态 , 检查 memc_stat 域 直到该值成为 0b01 ;


    ( 2 ) u-boot 内存初始化源码阅读 ( Config 状态 | 寄存器设置 | 电压时钟稳定 | 内存初始化 | Ready 状态 | 检查 Ready 状态 )


    u-boot 内存初始化相关 源码 解析 :

    • 1.源码位置 :
      • ① 源码路径 : ARM内存操作9.u-boot源代码uboot_6410cpus3c64xxs3c6410cpu_init.S , 其中 ARM内存操作9.u-boot源代码 是博客附件的路径 , uboot_6410cpus3c64xxs3c6410 是 u-boot 源码路径 ;
      • ② 下载地址 : 直接下载该博客附件即可 , 其中有 u-boot 源码 ;
    • 2.源码注释解析 : ( 仅做参考 )
    #include <config.h>
    #include <s3c6410.h>
    
    	.globl mem_ctrl_asm_init
    mem_ctrl_asm_init:
    	ldr	r0, =ELFIN_MEM_SYS_CFG			@Memory sussystem address 0x7e00f120
    	mov	r1, #0xd						@ Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1
    	str	r1, [r0]
    
    	ldr	r0, =ELFIN_DMC1_BASE			@DMC1 base address 0x7e001000
    
    	ldr	r1, =0x04									@ 第一步操作 : 0x4 转成二进制 0b100 , 设置 存储控制寄存器 Config 状态
    	str	r1, [r0, #INDEX_DMC_MEMC_CMD]				@ 将 0b100 设置到 memc_cmd 域 中
    
    	ldr	r1, =DMC_DDR_REFRESH_PRD					@ 第二部操作 : 设置一系列寄存器 ; 
    	str	r1, [r0, #INDEX_DMC_REFRESH_PRD]
    
    	ldr	r1, =DMC_DDR_CAS_LATENCY
    	str	r1, [r0, #INDEX_DMC_CAS_LATENCY]
    
    	ldr	r1, =DMC_DDR_t_DQSS
    	str	r1, [r0, #INDEX_DMC_T_DQSS]
    
    	ldr	r1, =DMC_DDR_t_MRD
    	str	r1, [r0, #INDEX_DMC_T_MRD]
    
    	ldr	r1, =DMC_DDR_t_RAS
    	str	r1, [r0, #INDEX_DMC_T_RAS]
    
    	ldr	r1, =DMC_DDR_t_RC
    	str	r1, [r0, #INDEX_DMC_T_RC]
    
    	ldr	r1, =DMC_DDR_t_RCD
    	ldr	r2, =DMC_DDR_schedule_RCD
    	orr	r1, r1, r2
    	str	r1, [r0, #INDEX_DMC_T_RCD]
    
    	ldr	r1, =DMC_DDR_t_RFC
    	ldr	r2, =DMC_DDR_schedule_RFC
    	orr	r1, r1, r2
    	str	r1, [r0, #INDEX_DMC_T_RFC]
    
    	ldr	r1, =DMC_DDR_t_RP
    	ldr	r2, =DMC_DDR_schedule_RP
    	orr	r1, r1, r2
    	str	r1, [r0, #INDEX_DMC_T_RP]
    
    	ldr	r1, =DMC_DDR_t_RRD
    	str	r1, [r0, #INDEX_DMC_T_RRD]
    
    	ldr	r1, =DMC_DDR_t_WR
    	str	r1, [r0, #INDEX_DMC_T_WR]
    
    	ldr	r1, =DMC_DDR_t_WTR
    	str	r1, [r0, #INDEX_DMC_T_WTR]
    
    	ldr	r1, =DMC_DDR_t_XP
    	str	r1, [r0, #INDEX_DMC_T_XP]
    
    	ldr	r1, =DMC_DDR_t_XSR
    	str	r1, [r0, #INDEX_DMC_T_XSR]
    
    	ldr	r1, =DMC_DDR_t_ESR
    	str	r1, [r0, #INDEX_DMC_T_ESR]
    
    	ldr	r1, =DMC1_MEM_CFG
    	str	r1, [r0, #INDEX_DMC_MEMORY_CFG]
    
    	ldr	r1, =DMC1_MEM_CFG2
    	str	r1, [r0, #INDEX_DMC_MEMORY_CFG2]
    
    	ldr	r1, =DMC1_CHIP0_CFG
    	str	r1, [r0, #INDEX_DMC_CHIP_0_CFG]
    
    	ldr	r1, =DMC_DDR_32_CFG
    	str	r1, [r0, #INDEX_DMC_USER_CONFIG]
    	
    														@ 第三部操作 : 等待 时钟 和 电压 稳定 , 文档中说明 该步骤可以省略
    														
    														
    														@ 第四步操作 : 内存初始化
    														
    	@DMC0 DDR Chip 0 configuration direct command reg	@ 内存初始化 1. 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b11 , 整体值为 0b11 0000 0000 0000 0000 , 转为 16 进制为 0xC0000
    	ldr	r1, =DMC_NOP0									@ 将 DMC_NOP0 值装载到 r1 中, 该值是 DMC_NOP0 = 0x0C0000
    	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]					
    
    	@Precharge All										@ 内存初始化 2. 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b00, DMC_PA0 = 0x000000
    	ldr	r1, =DMC_PA0
    	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]
    
    	@Auto Refresh	2 time								@ 内存初始化 3. 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b01, DMC_AR0 = 0x040000 , 连做两次
    	ldr	r1, =DMC_AR0
    	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]
    	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]
    
    	@MRS												@ 内存初始化 4. 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b10, 发出 MRS 命令 , 这里也是写出 2 次
    	ldr	r1, =DMC_mDDR_EMR0
    	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]
    
    	@Mode Reg
    	ldr	r1, =DMC_mDDR_MR0
    	str	r1, [r0, #INDEX_DMC_DIRECT_CMD]
    
    	@Enable DMC1										@ 第五步操作 : 设置存储控制器 Ready 状态 
    	mov	r1, #0x0
    	str	r1, [r0, #INDEX_DMC_MEMC_CMD]
    
    check_dmc1_ready:										@ 第六步操作 : 检查 memc_stat 域 是否 成为 0b01 , 
    	ldr	r1, [r0, #INDEX_DMC_MEMC_STATUS]				@ 即 代表 存储控制器是 Ready 状态, 如果不是, 继续跳转 循环 等待 , 直到到达 Ready 状态
    	mov	r2, #0x3
    	and	r1, r1, r2
    	cmp	r1, #0x1
    	bne	check_dmc1_ready
    	nop
            mov	pc, lr
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118

    ( 3 ) S3C 6410 内存初始化 相关编译文件 和 函数调用接口


    前期准备 : 将 内存初始化代码 单独写在一个文件中 , mem.S , 然后在 start.S 中进行调用 ;

    • 1.mem.S 代码内容 :
    @****************************  
    @File:mem.S  
    @  
    @内存 初始化代码 
    @****************************  
    
    .text                                   @ 宏 指明代码段  
    .global mem_init                        @ 伪指令  mem.S 可以理解成一个函数 , 该函数由 start.S 进行调用 , 它必须是一个全局的
    mem_init:								@ 定义内存初始化的标号 , 在 start.S 中进行调用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 2.start.S 中调用 :
    reset:                                              @ reset 地址存放要执行的内容  
    
            ...
    
    		bl init_clock								@ 跳转到 init_clock 标号, 执行时钟初始化操作
    		bl mem_init									@ 跳转到 mem_init 标号 , 执行内存初始化操作 , 该段代码定义在 mem.S 文件中
    		bl light_led								@ 打开开发板上的 LED 发光二极管
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 3.Makefile 文件修改 : 这里多了一个 mem.S 文件 , 因此需要修改 Makefile 文件, 编译该文件 ; 在 第一行 增加了 mem.o ;
    all: start.o mem.o
    	arm-linux-ld -Tu-boot.lds -o u-boot.elf $^		
    	arm-linux-objcopy -O binary u-boot.elf u-boot.bin 
    	
    %.o : %.S
    	arm-linux-gcc -g -c $^
    	
    %.o : %.c
    	arm-linux-gcc -g -c $^
    	
    .PHONY: clean	
    clean:
    	rm *.o *.elf *.bin
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13


    ( 4 ) S3C6410 内存控制器初始化 ( DRAM CONTROLLER INITIALIZATION SEQUENCE )


    S3C6410 内存控制器初始化 ( DRAM CONTROLLER INITIALIZATION SEQUENCE ) :
    在这里插入图片描述

    • 0.设置 MEM_SYS_CFG 寄存器 中的 数据线 pin 脚 : MEM_SYS_CFG 寄存器初始值 0x0000_0080 , 要设置的是 第 [ 7 ] 位 , 作用是 : 设置 XmlDATA [ 31 : 16 ] pin 脚的 作用 ; Xml 对应的区域是 动态存储区 ( Dynamic Memory , 2 * 256MB ) , 对应 下图3 中右侧框起来的 pin 脚 ; 0 = 这些 pin 脚用作 [ 31 : 16 ] 位的 数据线 , 1 = 这些 pin 脚 给 SROM 使用 ; 这里设置 0 , 作为数据线使用 ;
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    									@ 设置 MEM_SYS_CFG 寄存器中的 [ 7 ] 位 , 设置 XmlDATA [31 : 16] pin 脚作用
    									@ 这些 pin 脚 用于作为 内存输出的 数据线 的
    									@ 如果 该位 为 0 , 那么 就作为 [ 31 : 16 ] 位的数据线引脚 , 这里设置为 0 即可
        ldr r0, =0x7e00f120				
        mov r1, #0x0
        str r1, [r0]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 1.DRAM 控制命令寄存器 ( DRAM CONTROLLER COMMAND REGISTER ) 设置 Config 状态 : 设置 DRAM 存储控制寄存器的 memc_cmd 域 ( [ 2 : 0 ] ) 为 0b100 , 高位全部设置 0 ; DRAM 控制命令寄存器地址是 0x7E001004 , 设置的值是 0b100 , 转为16进制 0x4 ;
      在这里插入图片描述
    															@ 步骤一 : DRAM 控制器进入配置状态
    	ldr r0, =0x7e001004										@ 将 DRAM CONTROLLER COMMAND REGISTER 寄存器地址装在到 r0 中
        mov r1, 0x4												@ 设置 DRAM 控制命令寄存器 ( DRAM CONTROLLER COMMAND REGISTER  ) 值 0x4 进入配置 ( Config ) 状态
        str r1, [r0]											@ 将 r1 装载到 r0 所指向的内存地址对应的空间中
    
    • 1
    • 2
    • 3
    • 4
    • 2.设置一系列寄存器值 : 逐个参考文档分析 ;
    • 3.内存初始化 : 下面会有单个小节 S3C6410 内存初始化 ( DDR/MOBILE DDR SDRAM INITIALIZATION SEQUENCE ) 详细解析 ; 下面给出带注释源码 ;
    • 4.DRAM 控制命令寄存器 ( DRAM CONTROLLER COMMAND REGISTER ) 设置 Ready 状态 : 设置 DRAM 存储控制寄存器的 memc_cmd 域 ( [ 2 : 0 ] ) 为 0b000 , 高位全部设置 0 ; DRAM 控制命令寄存器地址是 0x7E001004 , 设置的值是 0b100 , 转为16进制 0x0 ;
      在这里插入图片描述
    									@ 步骤五 : DRAM 控制器进入 Ready 状态
    	ldr r0, =0x7e001004				@ 将 DRAM CONTROLLER COMMAND REGISTER 寄存器地址装在到 r0 中
        mov r1, 0x0						@ 设置 DRAM 控制命令寄存器 ( DRAM CONTROLLER COMMAND REGISTER  ) 值 0x0 进入配置 ( Ready ) 状态
        str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中
    
    • 1
    • 2
    • 3
    • 4
    • 5.检查是否进入 Ready 状态 : 在 DRAM 控制状态寄存器 ( DRAM CONTROLLER STATUS REGISTER ) 中的 Controller status 域 中的值 , 如果是 0b 01 就是 Ready 状态 ; 如果没有 进入 Ready 状态 , 继续等待 再次验证 ;
      在这里插入图片描述
    
    check_ready:
        
        ldr r0, =0x7e001000 			@ 将 DRAM CONTROLLER STATUS REGISTER 地址 装载到 r0 寄存器中
        ldr r1, [r0]					@ 将 r0 寄存器存储的地址对应的内存中的内容装载到 r1 寄存器中 , 这个 DRAM CONTROLLER STATUS REGISTER 寄存器的值就获取到了
        mov r2, #0x3					@ 将 立即数 3 设置给 r2 寄存器中, 用于 与操作 , 获取最后的 两位 二进制数值
        and r1, r1, r2					@ 将 r1 ( 第二个 ) 与 r2 进行 与 操作 , 将结果放入 r1 ( 第一个 ) 寄存器中
        cmp r1, #0x1					@ 将 与 结果 与 0x1 进行比较 , 如果相等 继续执行 , 如果不相等, 跳转到 check_ready 继续执行判定操作
    	
        bne check_ready					@ 如果不相等, 跳转到 check_ready 继续执行判定操作
        nop
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12


    ( 5 ) S3C6410 内存初始化 ( DDR/MOBILE DDR SDRAM INITIALIZATION SEQUENCE )


    S3C6410 内存初始化 ( DDR/MOBILE DDR SDRAM INITIALIZATION SEQUENCE ) : 这里需要注意的是 , 初始化序列 和 表格 中的指令不准确, 图2 中 下半部分的 文字截图是准确的 ;
    在这里插入图片描述

    在这里插入图片描述

    • 1.DIRECT COMMAND REGISTER 发出 Nop 内存指令 : DIRECT COMMAND REGISTER 寄存器 的 Memory command 域, 写入 NOP 指令 , 需要 设置 [ 19:18 ] 位 为 0b11 , 整个寄存器值为 0b 11 00 0000 0000 0000 0000 , 转为十六进制 0xC0000 ;
    									@ 步骤四 : 内存初始化 1. 发出 NOP 命令 :  
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b11 , 整体值为 0b11 0000 0000 0000 0000 , 转为 16 进制为 0xC0000	
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0xc0000				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 2.DIRECT COMMAND REGISTER 发出 Prechargeall 内存指令 : DIRECT COMMAND REGISTER 寄存器 的 Memory command 域, 写入 Prechargeall 指令 , 需要 设置 [ 19:18 ] 位 为 0b00 , 整个寄存器值为 0b 00 00 0000 0000 0000 0000 , 转为十六进制 0x0 ;
    									@ 步骤四 : 内存初始化 2. 写入 Precharge All 命令 : 
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b00
    									@ 整体值为 0b00 0000 0000 0000 0000 , 转为 16 进制为 0x0
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0x0					@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 3.DIRECT COMMAND REGISTER 发出 Autorefresh 内存指令 ( 执行两次 ) : DIRECT COMMAND REGISTER 寄存器 的 Memory command 域, 写入 Autorefresh 指令 , 需要 设置 [ 19:18 ] 位 为 0b01 , 整个寄存器值为 0b 01 00 0000 0000 0000 0000 , 转为十六进制 0x40000 ;
    									@ 步骤四 : 内存初始化 3. 写入 Autorefresh 命令 : 该步骤执行两次
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b01
    									@ 整体值为 0b 01 00 0000 0000 0000 0000 , 转为 16 进制为 0x40000
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0x40000				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中	
    
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0x40000				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中		
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 4.DIRECT COMMAND REGISTER 发出 MRS 内存指令 : DIRECT COMMAND REGISTER 寄存器 的 Memory command 域, 写入 MRS 指令 , 需要 设置 [ 19:18 ] 位 为 0b01 , 同时需要设置 EMRS 的 Bank Address , Bank Address 类型 在 [ 17 : 16 ] 位设置 , 地址值 在 Address_13_to_0 域 [ 13 : 0 ] 设置 , 整个寄存器值为 0xa0000 ;
    									@ 步骤四 : 内存初始化 5. 写入 MRS 命令 : 
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b10, 同时还需要设置 Bank Address
    									@ 整体值 转为 16 进制为 0xa0000
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0xa0000				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中		
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 5.DIRECT COMMAND REGISTER 发出 MRS 内存指令 ( RMRS ) : DIRECT COMMAND REGISTER 寄存器 的 Memory command 域, 写入 MRS 指令 , 需要 设置 [ 19:18 ] 位 为 0b01 , 同时需要设置 EMRS 的 Bank Address , Bank Address 类型 在 [ 17 : 16 ] 位设置 , 地址值 在 Address_13_to_0 域 [ 13 : 0 ] 设置 , 整个寄存器值为 0xa0000 ;
    									@ 步骤四 : 内存初始化 5. 写入 MRS 命令 : ( EMRS )
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b10
    									@ 同时还需要设置 Bank Address , 该步骤设置的是 EMRS 的 Bank Address
    									@ 整体值 转为 16 进制为 0xa0000
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0xa0000				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 6.DIRECT COMMAND REGISTER 发出 MRS 内存指令 ( MRS ) : DIRECT COMMAND REGISTER 寄存器 的 Memory command 域, 写入 MRS 指令 , 需要 设置 [ 19:18 ] 位 为 0b01 , 同时需要设置 EMRS 的 Bank Address , Bank Address 类型 在 [ 17 : 16 ] 位设置 , 地址值 在 Address_13_to_0 域 [ 13 : 0 ] 设置 , 整个寄存器值为 0x80032 ;
    									@ 步骤四 : 内存初始化 6. 写入 MRS 命令 : ( MRS )
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b10, 
    									@ 同时还需要设置 Bank Address , 该步骤设置的是 MRS 的 Bank Address
    									@ 整体值 转为 16 进制为 0x80032
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0x80032				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9



    4. S3C6410 内存初始化 完整代码



    ( 1 ) start.S ( 入口 )


    @****************************  
    @File:start.S  
    @  
    @BootLoader 初始化代码 
    @****************************  
    
    .text                                   @ 宏 指明代码段  
    .global _start                          @ 伪指令声明全局开始符号  
    _start:                                 @ 程序入口标志  
            b   reset                       @ reset 复位异常  
            ldr pc, _undefined_instruction  @ 未定义异常, 将 _undefined_instruction 值装载到 pc 指针中  
            ldr pc, _software_interrupt     @ 软中断异常  
            ldr pc, _prefetch_abort         @ 预取指令异常  
            ldr pc, _data_abort             @ 数据读取异常  
            ldr pc, _not_used               @ 占用 0x00000014 地址                            
            ldr pc, _irq                    @ 普通中断异常  
            ldr pc, _fiq                    @ 软中断异常  
    
    _undefined_instruction: .word undefined_instruction @ _undefined_instruction 标号存放了一个值, 该值是 32 位地址 undefined_instruction, undefined_instruction 是一个地址  
    _software_interrupt:    .word software_interrupt    @ 软中断异常  
    _prefetch_abort:    .word prefetch_abort            @ 预取指令异常 处理  
    _data_abort:        .word data_abort                @ 数据读取异常  
    _not_used:      .word not_used                      @ 空位处理  
    _irq:           .word irq                           @ 普通中断处理  
    _fiq:           .word fiq                           @ 快速中断处理  
    
    undefined_instruction:                              @ undefined_instruction 地址存放要执行的内容  
            nop  
    
    software_interrupt:                                 @ software_interrupt 地址存放要执行的内容  
            nop  
    
    prefetch_abort:                                     @ prefetch_abort 地址存放要执行的内容  
            nop  
    
    data_abort:                                         @ data_abort 地址存放要执行的内容  
            nop  
    
    not_used:                                           @ not_used 地址存放要执行的内容  
            nop  
    
    irq:                                                @ irq 地址存放要执行的内容  
            nop  
    
    fiq:                                                @ fiq 地址存放要执行的内容  
            nop  
    
    reset:                                              @ reset 地址存放要执行的内容  
    		bl set_svc                                  @ 跳转到 set_svc 标号处执行
    		bl set_serial_port							@ 设置外设基地址端口初始化
    		bl disable_watchdog                         @ 跳转到 disable_watchdog 标号执行, 关闭看门狗
    		bl disable_interrupt						@ 跳转到 disable_interrupt 标号执行, 关闭中断
    		bl disable_mmu								@ 跳转到 disable_mmu 标号执行, 关闭 MMU 
    		bl init_clock								@ 跳转到 init_clock 标号, 执行时钟初始化操作
    		bl mem_init									@ 跳转到 mem_init 标号 , 执行内存初始化操作 , 该段代码定义在 mem.S 文件中
    		bl light_led								@ 打开开发板上的 LED 发光二极管
    
    set_svc:
    		mrs r0, cpsr                                @ 将 CPSR 寄存器中的值 导出到 R0 寄存器中
    		bic r0, r0, #0x1f                           @ 将 R0 寄存器中的值 与 #0x1f 立即数 进行与操作, 并将结果保存到 R0 寄存器中, 实际是将寄存器的 0 ~ 4 位 置 0
    		orr r0, r0, #0xd3                           @ 将 R0 寄存器中的值 与 #0xd3 立即数 进行或操作, 并将结果保存到 R0 寄存器中, 实际是设置 0 ~ 4 位 寄存器值 的处理器工作模式代码
    		msr cpsr, r0                                @ 将 R0 寄存器中的值 保存到 CPSR 寄存器中
    		mov pc, lr									@ 返回到 返回点处 继续执行后面的代码
    		
    #define pWTCON 0x7e004000                           @ 定义看门狗控制寄存器 地址 ( 6410开发板 )
    disable_watchdog:                                 
    		ldr r0, =pWTCON                             @ 先将控制寄存器地址保存到通用寄存器中
    		mov r1, #0x0                                @ 准备一个 0 值, 看门狗控制寄存器都设置为0 , 即看门狗也关闭了
    		str r1, [r0]                                @ 将 0 值 设置到 看门狗控制寄存器中 
    		mov pc, lr									@ 返回到 返回点处 继续执行后面的代码
    		
    disable_interrupt:
    	mvn r1,#0x0										@ 将 0x0 按位取反, 获取 全 1 的数据, 设置到 R1 寄存器中
    	ldr r0,=0x71200014								@ 设置第一个中断屏蔽寄存器, 先将 寄存器 地址装载到 通用寄存器 R0 中 
    	str r1,[r0]										@ 再将 全 1 的值设置到 寄存器中, 该寄存器的内存地址已经装载到了 R0 通用寄存器中
    
    	ldr r0,=0x71300014								@ 设置第二个中断屏蔽寄存器, 先将 寄存器 地址装载到 通用寄存器 R0 中 
    	str r1,[r0]										@ 再将 全 1 的值设置到 寄存器中, 该寄存器的内存地址已经装载到了 R0 通用寄存器中
    	mov pc, lr										@ 返回到 返回点处 继续执行后面的代码
    	
    disable_mmu : 
    	mcr p15,0,r0,c7,c7,0							@ 设置 I-Cache 和 D-Cache 失效
    	mrc p15,0,r0,c1,c0,0							@ 将 c1 寄存器中的值 读取到 R0 通用寄存器中
    	bic r0, r0, #0x00000007							@ 使用 bic 位清除指令, 将 R0 寄存器中的 第 0, 1, 2 三位 设置成0, 代表 关闭 MMU 和 D-Cache
    	mcr p15,0,r0,c1,c0,0							@ 将 R0 寄存器中的值写回到 C1 寄存器中
    	mov pc, lr										@ 返回到 返回点处 继续执行后面的代码
    	
    set_serial_port : 
    	ldr r0, =0x70000000								@ 将基地址装载到 r0 寄存器中, 该基地址 在 arm 核 手册中定义
    	orr r0, r0, #0x13								@ 设置初始化基地址的范围, 将 r0 中的值 与 0x13 立即数 进行或操作, 将结果存放到 r0 中
    	mcr p15, 0, r0, c15, c2, 4						@ 将 r0 中的值设置给 c15 协处理器 
    	mov pc, lr
    
    #define CLK_DIV0 0x7E00F020							@ 定义 CLK_DIV0 寄存器地址, 时钟的分频参数都是通过该寄存器进行设置的 
    #define OTHERS 0x7E00F900							@ 定义 OTHERS 寄存器地址, 用于设置 CPU 异步工作模式
    #define CLK_VAL ( (0x0 << 0) | (0x1 << 9) | (0x1 << 8) | (0x3 << 12) ) @ 设置 CLK_DIV0 寄存器的值, 即 各个时钟分频器的参数
    #define MPLL_CON 0x7E00F010							@ 定义 MPLL_CON 寄存器地址常量
    #define APLL_CON 0x7E00F00C 						@ 定义 APLL_CON 寄存器地址常量
    #define PLL_VAL ( (0x1 << 31) | (266 << 16) | (3 << 8) | (1 << 0) )	@ 设置 PLL 控制寄存器的值
    #define CLK_SRC 0x7E00F01C							@ 定义 CLK_SRC 时钟源控制寄存器的地址常量
    init_clock : 
    	ldr r0, =CLK_DIV0								@ 将 CLK_DIV0 的地址装载到 r0 通用寄存器中
    	ldr r1, =CLK_VAL 								@ 将 要设置给 CLK_DIV0 寄存器的值 CLK_VAL 立即数 装载到 r1 通用寄存器中; 
    	str r1, [r0]									@ 将 r1 寄存器中的内容 存储到 r0 存储的地址 指向的内存中
    	
    	ldr r0, =OTHERS									@ 将 OTHERS 寄存器地址存到 r0 通用寄存器中
    	ldr r1, [r0]									@ 将 r0 寄存器存储的地址指向的寄存器中的值读取到 r1 通用寄存器中
    	bic r1, r1, #0xc0								@ 将 r1 寄存器中的值的 第 6 位 和 第 7 位 设置成 0
    	str r1, [r0]									@ 将 r1 寄存器中的值 写出到 r0 寄存器存储的地址指向的内存位置 即 OTHERS 寄存器
    	
    	ldr r0, =APLL_CON								@ 将 APLL_CON 寄存器地址存到 r0 通用寄存器中
    	ldr r1, =PLL_VAL								@ 将 要设置给 APLL_CON 寄存器的值 PLL_VAL 立即数 装载到 r1 通用寄存器中;
    	str r1, [r0]									@ 将 r1 寄存器中的内容 存储到 r0 存储的地址 指向的内存中, 即 将 PLL_VAL 的值 设置到 APLL_CON 寄存器中
    	
    	ldr r0, =MPLL_CON								@ 将 MPLL_CON 寄存器地址存到 r0 通用寄存器中
    	ldr r1, =PLL_VAL                                @ 将 要设置给 MPLL_CON 寄存器的值 PLL_VAL 立即数 装载到 r1 通用寄存器中;
    	str r1, [r0]                                    @ 将 r1 寄存器中的内容 存储到 r0 存储的地址 指向的内存中, 即 将 PLL_VAL 的值 设置到 MPLL_CON 寄存器中
    	
    	ldr r0, =CLK_SRC								@ 将 CLK_SRC 寄存器地址设置到 r0 通用寄存器中
    	mov r1, #0x3									@ 将 0x3 立即数设置给 r1 寄存器
    	str r1, [r0]									@ 将 r1 中存储的立即数设置给 r0 寄存器存储的地址指向的内存中, 即 CLK_SRC 寄存器中
    	
    	mov pc, lr
    
    	
    #define GPBCON 0x7F008820
    #define GPBDAT 0x7F008824
    light_led : 
    	ldr r0, =GPBCON								    @ 将 0x7F008820 GPM 控制寄存器的地址 0x7F008820 装载到 r0 寄存器中
    	ldr r1, =0x1111								 	@ 设置 GPM 控制寄存器的行为 为 Output 输出, 即每个对应引脚的设置为 0b0001 值
    	str r1, [r0]									@ 将 r1 中的值 存储到 r0 指向的 GPBCON 0x7F008820 地址的内存中
    	
    	ldr r0, =GPBDAT									@ 将 GPBDAT 0x7F008824 地址值 装载到 r0 寄存器中
    	ldr r1, =0b110101								@ 计算 GPM 数据寄存器中的值, 设置 0 为 低电平, 设置 1 为高电平, 这里设置 0 ~ 3 位为低电平, 其它为高电平
    	str r1, [r0]									@ 将 r1 中的值 存储到 r0 指向的 GPBDAT 0x7F008824 地址的内存中
    	mov pc, lr
    	
    
    
    
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141


    ( 2 ) mem.S ( 内存初始化 )


    @****************************  
    @File:mem.S  
    @  
    @内存 初始化代码 
    @****************************  
    
    .text                               @ 宏 指明代码段  
    .global mem_init                    @ 伪指令  mem.S 可以理解成一个函数 , 该函数由 start.S 进行调用 , 它必须是一个全局的
    mem_init:							@ 定义内存初始化的标号 , 在 start.S 中进行调用
    
    
    									@ 设置 MEM_SYS_CFG 寄存器中的 [ 7 ] 位 , 设置 XmlDATA [31 : 16] pin 脚作用
    									@ 这些 pin 脚 用于作为 内存输出的 数据线 的
    									@ 如果 该位 为 0 , 那么 就作为 [ 31 : 16 ] 位的数据线引脚 , 这里设置为 0 即可
        ldr r0, =0x7e00f120				
        mov r1, #0x0
        str r1, [r0]
    
    
    									@ 步骤一 : DRAM 控制器进入配置状态
    	ldr r0, =0x7e001004				@ 将 DRAM CONTROLLER COMMAND REGISTER 寄存器地址装在到 r0 中
        mov r1, #0x4						@ 设置 DRAM 控制命令寄存器 ( DRAM CONTROLLER COMMAND REGISTER  ) 值 0x4 进入配置 ( Config ) 状态
        str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中
    
    
    									@ 步骤二 : 设置一系列寄存器
    									
    									
        ldr r0, =0x7e001010  			@刷新寄存器地址
        ldr r1, =( ( 7800 / ( 1000000000/133000000 ) + 1 ) )      @设置刷新时间
        str r1, [r0]
    
        ldr r0, =0x7e001014  			@CAS latency寄存器
        mov r1, #(3 << 1)
        str r1, [r0]
    
        ldr r0, =0x7e001018  			@t_DQSS寄存器
        mov r1, #0x1
        str r1, [r0]
    
        ldr r0, =0x7e00101c  			@T_MRD寄存器
        mov r1, #0x2
        str r1, [r0]
    
        ldr r0, =0x7e001020   			@t_RAS寄存器
        ldr r1, =( ( 45 / ( 1000000000 / 133000000 ) + 1 ) )
        str r1, [r0]
    
        ldr r0, =0x7e001024   			@t_RC寄存器
        ldr r1, =( ( 68 / ( 1000000000 / 133000000 ) + 1 ) )
        str r1, [r0]
    
        ldr r0, =0x7e001028   			@t_RCD寄存器
        ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
        str r1, [r0]
    
        ldr r0, =0x7e00102c   			@t_RFC寄存器
        ldr r1, =( ( 80 / ( 1000000000 / 133000000 ) + 1 ) )
        str r1, [r0]
    
        ldr r0, =0x7e001030   			@t_RP寄存器
        ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
        str r1, [r0]
    
        ldr r0, =0x7e001034   			@t_rrd寄存器
        ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
        str r1, [r0]
    
        ldr r0, =0x7e001038   			@t_wr寄存器
        ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
     @  ldr r2, [r0]
        str r1, [r0]
    
        ldr r0, =0x7e00103c   			@t_wtr寄存器
        mov r1, #0x07
        str r1, [r0]
    
        ldr r0, =0x7e001040   			@t_xp寄存器
        mov r1, #0x02
        str r1, [r0]
    
        ldr r0, =0x7e001044   			@t_xsr寄存器
        ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
        str r1, [r0]
    
        ldr r0, =0x7e001048   			@t_esr寄存器
        ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
        str r1, [r0]
    
        ldr r0, =0x7e00100c   			@内存控制配置寄存器
        ldr r1, =0x00010012   			@配置控制器
        str r1, [r0]
    
        ldr r0, =0x7e00104c   			@32位DRAM配置控制寄存器
        ldr r1, =0x0b45
        str r1, [r0]
    
        ldr r0, =0x7e001200   			@片选寄存器
        ldr r1, =0x150f8
        str r1, [r0]
    
        ldr r0, =0x7e001304   			@用户配置寄存器
        mov r1, #0x0
        str r1, [r0]								
    									
    									
    									
    									@ 步骤三 : 可以不执行 , 等待 电压 和 时钟稳定下来 , 但是电压和时钟本来就是稳定的
    									
    
    	
    	
    									@ 步骤四 : 内存初始化
    									
    									
    									@ 步骤四 : 内存初始化 1. 写入 NOP 命令 : 
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b11
    									@ 整体值为 0b 11 00 0000 0000 0000 0000 , 转为 16 进制为 0xC0000
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0xc0000				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中
    	
    	
    									@ 步骤四 : 内存初始化 2. 写入 Precharge All 命令 : 
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b00
    									@ 整体值为 0b 00 00 0000 0000 0000 0000 , 转为 16 进制为 0x0
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0x0					@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中
    									 
    
    									@ 步骤四 : 内存初始化 3 , 4 . 写入 Autorefresh 命令 : 该步骤执行两次
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b01
    									@ 整体值为 0b 01 00 0000 0000 0000 0000 , 转为 16 进制为 0x40000
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0x40000				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中	
    
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0x40000				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中	
    
    
    									@ 步骤四 : 内存初始化 5. 写入 MRS 命令 : ( EMRS )
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b10
    									@ 同时还需要设置 Bank Address , 该步骤设置的是 EMRS 的 Bank Address
    									@ 整体值 转为 16 进制为 0xa0000
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0xa0000				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中	
    
    
    
    									@ 步骤四 : 内存初始化 6. 写入 MRS 命令 : ( MRS )
    									
    									@ 执行过程 : 向 Direct Command Register 的 Memory Command [19:18] 域中写入 0b10, 
    									@ 同时还需要设置 Bank Address , 该步骤设置的是 MRS 的 Bank Address
    									@ 整体值 转为 16 进制为 0x80032
    									
    	ldr r0, =0x7e001008				@ 装载 DIRECT COMMAND REGISTER 寄存器 地址到 r0 寄存器中
    	ldr r1, =0x80032				@ 装载 要写入的值 到 r1 寄存器中
    	str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中		
    									 
    
    
    									@ 步骤五 : DRAM 控制器进入 Ready 状态
    	ldr r0, =0x7e001004				@ 将 DRAM CONTROLLER COMMAND REGISTER 寄存器地址装在到 r0 中
        mov r1, #0x0						@ 设置 DRAM 控制命令寄存器 ( DRAM CONTROLLER COMMAND REGISTER  ) 值 0x0 进入配置 ( Ready ) 状态
        str r1, [r0]					@ 将 r1 装载到 r0 所指向的内存地址对应的空间中
    	
    					
    									@ 步骤六 : 检查 DRAM 控制器 是否 进入 Ready 状态
    
    check_ready:
        
        ldr r0, =0x7e001000 			@ 将 DRAM CONTROLLER STATUS REGISTER 地址 装载到 r0 寄存器中
        ldr r1, [r0]					@ 将 r0 寄存器存储的地址对应的内存中的内容装载到 r1 寄存器中 , 这个 DRAM CONTROLLER STATUS REGISTER 寄存器的值就获取到了
        mov r2, #0x3					@ 将 立即数 3 设置给 r2 寄存器中, 用于 与操作 , 获取最后的 两位 二进制数值
        and r1, r1, r2					@ 将 r1 ( 第二个 ) 与 r2 进行 与 操作 , 将结果放入 r1 ( 第一个 ) 寄存器中
        cmp r1, #0x1					@ 将 与 结果 与 0x1 进行比较 , 如果相等 继续执行 , 如果不相等, 跳转到 check_ready 继续执行判定操作
    	
        bne check_ready					@ 如果不相等, 跳转到 check_ready 继续执行判定操作
        nop
    									 
    									
        mov pc, lr
    
    		
    	
    
    
    
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201


    ( 3 ) u-boot.lds ( 链接器脚本 )


    OUTPUT_ARCH(arm)
    ENTRY(_start)
    SECTIONS {
    	. = 0x50008000;
    	
    	. = ALIGN(4);
    	.text :
    	{
    	start.o (.text)
    	*(.text)
    	}
    
    	. = ALIGN(4);
    	.data : 
    	{
    	*(.data)
    	}
    	
    	. = ALIGN(4);
    	bss_start = .;
    	.bss : 
    	{
    	*(.bss) 
    	}
    	bss_end = .;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27


    ( 4 ) Makefile ( 编译脚本 )


    all: start.o mem.o
    	arm-linux-ld -Tu-boot.lds -o u-boot.elf $^		
    	arm-linux-objcopy -O binary u-boot.elf u-boot.bin 
    	
    %.o : %.S
    	arm-linux-gcc -g -c $^
    	
    %.o : %.c
    	arm-linux-gcc -g -c $^
    	
    .PHONY: clean	
    clean:
    	rm *.o *.elf *.bin
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16



    5. 编译输出可执行文件


    编译过程 :

    • 1.文件准备 : 将 汇编代码 ( start.S ) 链接器脚本 ( gboot.lds ) makefile 文件 拷贝到编译目录 ;
    • 2.执行编译命令 : make ;
    • 3.编译结果 : 可以看到 生成了 编译目标文件 start.o, 链接文件 u-boot.elf, 可执行的二进制文件 u-boot.bin ;
      这里写图片描述



    6. 烧写代码到开发板并执行


    ( 1 ) OK6410 开发板启动切换方式


    OK6410 开发板启动切换方式 : 通过控制 开发板右侧的 8个开关来设置启动来源;

    • 1.sd 卡启动 : (1~8) 位置 : 0, 0, 0, 1, 1, 1, 1, 1;
    • 2.nand flash 启动 : (1~8) 位置 : x, x, x, 1, 1, 0, 0, 1;
    • 3.nor flash 启动 : (1~8) 位置 : x, x, x, 1, 0, 1, 0, x;


    ( 2 ) 制作 SD 卡启盘 并 准备程序


    制作 SD 卡启动盘 :

    • 1.找到开发板的烧写工具 : OK6410-A 开发板的烧写工具 在开发光盘 A 的 OK6410-A-1G用户光盘(A)-20160812Linux-3.0.1Linux烧写工具 目录下, 开发板光盘资料下载地址 ;
      这里写图片描述
    • 2.设置 SD_Writer.exe 属性 ( win10系统需要进行的设置 ) : 右键点击属性, 在兼容性一栏, 设置 以 Windows 7 兼容模式运行, 并设置 以管理员身份运行此程序 ; 注意 一定要 使用管理员身份 运行 , 否则报错 , 报错信息 Select Volume Error , 无法格式化SD卡 , 无法烧写 程序 ;
      这里写图片描述
    • 3.先格式化 SD 卡 : 注意这里要使用 SD_Writer 中的 format 功能进行格式化 , 按照下面的步骤, 一步一步点击确定执行 ;
      这里写图片描述
      这里写图片描述
      这里写图片描述
    • 4.选择要烧写的文件 : 这里选择 OK6410-A-1G用户光盘(A)-20160812Linux-3.0.1Linux烧写工具mmc_ram256.bin 文件;
    • 5.烧写文件到 SD 卡中 : 直接点击 Program 按钮, 就将启动程序烧写到了 SD 卡中;
      这里写图片描述
    • 6.准备 LED 灯程序 : 将编译出的 gboot.bin 文件名修改成 u-boot.bin, 必须修改成该文件名, 否则无法烧写上去;
    • 7.将程序拷贝到 SD 卡中 : 将程序直接拷贝到 SD 卡中即可;

    参考资料 : OK6410烧写裸板程序方法
    这是之前写过的博客, 仅作为参考;



    ( 3 ) SecureCRT 连接开发板并烧写程序


    SecureCRT 连接开发板并烧写程序 步骤 :

    • 1.硬件连接操作 : 使用 USB 转 串口工具 将电脑 与 开发板链接, USB 插在电脑端, 串口端插在 开发板上, 插上电源适配器, 但是不要打开电源开关;
    • 2.开发板设置 : 将开发板右侧的开关设置成 SD 卡启动, 即 (1~8) 位置 : 0, 0, 0, 1, 1, 1, 1, 1; 该步骤很重要;
    • 2.查询串口端口号 : 在设备管理器中查看串口端口号, 这里可以看到是 COM9;
      这里写图片描述
    • 3.SecureCRT 连接串口 : 打开 SecureCRT 软件, 点击快速连接, 然后在弹出的对话框中按照下面进行配置, ① 首先要选择 Serial 协议, ② 然后选择端口, 这个端口从设备管理器中查看, ③ 波特率选择 115200, ④ 取消 RTS/CTS 选项;
      这里写图片描述
    • 4.打开开发板 ( 很重要 ) : 选中 SecureCRT 软件, 然后按住空格键不放, 这个操作很重要, 打开开发板开关, ① 先按住空格键, ②再打开开关;
      这里写图片描述
    • 5.首先格式化 Nand Flash : 选择 [1] 选项, 格式化 Nand Flash;
      这里写图片描述
    • 6.选择从 SD 卡中烧写 : 选择 [2] Burn image from SD card 选项, 从 SD 卡中向开发板烧写程序;
      这里写图片描述
    • 7.选择烧写 u-boot : 选择 [2] Flash u-boot, 烧写 u-boot, 会从 SD 卡中查找 u-boot.bin 文件, 然后烧写到 nand flash 中, 如果 SD 卡中 没有 u-boot.bin 会报错;
      这里写图片描述
    • 8.设置从 Nand Flash 启动 : 设置开发板上的启动开关, (1~8) 位置 : x, x, x, 1, 1, 0, 0, 1; 此时 四个 LED 全亮;
    • 9.效果展示 : 设置的 GPBDAT 寄存器值为 0b110000, 四个 LED 灯都亮起来;
      这里写图片描述
    • 10.修改 LED 灯显示参数后显示结果 : 设置 GPBDAT 寄存器中值为 0b110101 是 第一个 和 第三个 LED 亮起来;
      这里写图片描述
  • 相关阅读:
    雅礼集训 Day6 T2 Equation 解题报告
    雅礼集训 Day6 T1 Merchant 解题报告
    雅礼集训 Day5 T3 题 解题报告
    雅礼集训 Day3 T2 u 解题报告
    雅礼集训 Day3 T2 v 解题报告
    set-begin
    set-constructors
    set-constructors
    list-unique
    list-unique
  • 原文地址:https://www.cnblogs.com/cfas/p/12032245.html
Copyright © 2011-2022 走看看