本博客的参考文章及相关资料下载 :
DRAM 简介 :
SRAM 简介 :
DRAM 分为 SDRAM, DDR, DDR2 三种类型;
SDRAM 简介 :
DDR 和 DDR2 简介 :
L-Bank 简介 :
内存容量 = L-Bank 个数 * L-Bank 容量 L-Bank 个数 一般 是 4 个 L-Bank 容量 = 单元格数目 * 单元格容量 内存容量 = 4 * L-Bank 单元格数目 * 单元格容量
计算如下内存大小 : 下面 截图 是 一款 内存芯片说明
2440 芯片地址线 :
计算其访问的字节数 : 2^27 = 134217728 字节 ( Byte ) , 将 Byte 转为 MB : 134217728 / 1024 / 1024 = 128 MB ;
片选信号 :
片选信号 与 内存地址 :
存储控制器 简介 :
芯片 与 内存 芯片 连接方式 :
存储控制器 设置 :
BWSCON 寄存器 :
0x22000000
BANKCON 0~ 5 寄存器 :
0x00000700 0x00000700 0x00000700 0x00000700 0x00000700 0x00000700
BANKCON 6~ 7 寄存器 :
0x00018001 0x00018001
刷新控制寄存器 : 管理 SRAM 刷新 , SRAM 工作原理是需要不断的 定期 的 进行刷新 ;
BANK SIZE 寄存器设置 :
SDRAM MODE REGISTER SET REGISTER : BANK6 和 BANK7 分别对应一个寄存器 MRSRB6 和 MRSRB7 , 这两个寄存器内容 和 意义 是一样的 ;
内存相关寄存器总结 :
汇编循环方法设计 :
#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 存储的地址 指向的内存中
实现的汇编代码 : 详细请看注释 :
#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 模式
6410 地址空间分布 :
S3C6410 主存储区 ( 0x00000000 ~ 0x6FFFFFFF ) 划分 :
S3C6410 开发板内存芯片介绍 :
回顾 : 2440 开发板内存容量是 64MB , 是由 2 个 32MB 的芯片并联起来 , 形成的 64MB 的容量 ;
S3C2440 开发板 内存初始化 , 只需要设置 13 个寄存器的值即可 , 对于设置的顺序 是没有要求的 ; 但是 S3C 6440 开发板 的内存初始化 , 需要按照指定的流程 来进行操作 ;
S3C6410 内存初始化流程 : 文档位置 : S3C6410X.pdf , Page 192 , 5.4.1 DRAM CONTROLLER INITIALIZATION SEQUENCE ;
u-boot 内存初始化相关 源码 解析 :
#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
前期准备 : 将 内存初始化代码 单独写在一个文件中 , mem.S , 然后在 start.S 中进行调用 ;
@****************************
@File:mem.S
@
@内存 初始化代码
@****************************
.text @ 宏 指明代码段
.global mem_init @ 伪指令 mem.S 可以理解成一个函数 , 该函数由 start.S 进行调用 , 它必须是一个全局的
mem_init: @ 定义内存初始化的标号 , 在 start.S 中进行调用
reset: @ reset 地址存放要执行的内容
...
bl init_clock @ 跳转到 init_clock 标号, 执行时钟初始化操作
bl mem_init @ 跳转到 mem_init 标号 , 执行内存初始化操作 , 该段代码定义在 mem.S 文件中
bl light_led @ 打开开发板上的 LED 发光二极管
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
S3C6410 内存控制器初始化 ( DRAM CONTROLLER INITIALIZATION SEQUENCE ) :
@ 设置 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 所指向的内存地址对应的空间中
@ 步骤五 : 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 所指向的内存地址对应的空间中
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
S3C6410 内存初始化 ( DDR/MOBILE DDR SDRAM INITIALIZATION SEQUENCE ) : 这里需要注意的是 , 初始化序列 和 表格 中的指令不准确, 图2 中 下半部分的 文字截图是准确的 ;
@ 步骤四 : 内存初始化 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 所指向的内存地址对应的空间中
@ 步骤四 : 内存初始化 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 所指向的内存地址对应的空间中
@ 步骤四 : 内存初始化 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 所指向的内存地址对应的空间中
@ 步骤四 : 内存初始化 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 所指向的内存地址对应的空间中
@ 步骤四 : 内存初始化 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 所指向的内存地址对应的空间中
@****************************
@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
@****************************
@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
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 = .;
}
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
编译过程 :
make
;OK6410 开发板启动切换方式 : 通过控制 开发板右侧的 8个开关来设置启动来源;
制作 SD 卡启动盘 :
参考资料 : OK6410烧写裸板程序方法 这是之前写过的博客, 仅作为参考;
SecureCRT 连接开发板并烧写程序 步骤 :