OK6410DRAM存储器的初始化

在介绍OK6410的DRAM存储器的初始化之前,先把OK6410的存储资源搞清楚:

这部分内容摘于:点击打开链接


ROM是只读存储器,RAM是随机存储器。 
区别: 
1.ROM(Read Only Memory)掉电数据不丢失,但存储读取速度慢,所以常用作存放程序,存放bootloader,存放内核,存放文件系统;
2.RAM(Random Access Memory)掉电数据丢失,但存取速度快,常用作内存 ;
3.RAM还分为SRAM静态随机存储器(不用不断刷新就可以读取数据,速度快但是造价也高)和DRAM动态随机存储器(要不断刷新才能存储读取数据,造价相对较低) ;
4.DRAM还可以分为SDRAM、DDR、DDR2等,DDR的传输速率为SDRAM的2倍,而DDR2的传输速率为DDR的2倍。一般是2440板子用的SDRAM作为内存,6410板子用DDR作为内存,210板子用DDR2作为内存 ;
5.nandflash不能运行程序,只能存储数据、动引导系统,而在 SDRAM 上执行主程序代码。


明白以上的概念以后,就可以进行DRAM存储器的初始化了(也就是DDR的初始化),这部分学习分为以下几个内容:

一、背景知识

二、DRAM控制器初始化

三、SDRAM初始化

四、代码分析

五、结果验证


一、背景知识

1.OK6410内存映射


上图即为OK6410的内存空间说明,具体说明如下图


这部分比较长,我们把需要的东西提炼出来:从NandFlash启动的时候,6410会自动将NandFlash最前面的8K区域的的代码拷贝到“Stepping Stone”(英文直译为垫脚石,命运悲惨的一块SRAM,哈哈哈),拷贝完成后,会将Stepping Stone映射到0x00000000开始的8K区域,然后开始执行这8K代码,这些代码主要完成的工作包括:初始化硬件、设置中断向量表、设置堆栈,并把NandFlash中的执行代码拷贝到SDRAM中,所以,在这段代码不做SDRAM的初始化,你只能用8K的内存。

2.原理图


上图即为DDR原理图,可以看到芯片型号,同时可以看到DDR是由俩片该DDR并联得到的

3.DDR芯片


由上图可知,存储大小为32M*16位,即64MB,所以俩片总共为32M*16*2,即128MB存储空间


由上图,可知Bank2位,Row13位,Column10位,总共25位,即可以寻址32M,俩片组合为32位,所以32M*32=128MB,可以想一下为什么有这样的设定呢?


二、DRAM控制器初始化

1.DRAM控制器介绍

DRAM控制器相当于cpu控制DRAM的一个中介(如下图)


OK6410的控制器的特性如下图:


2.初始化操作顺序


1.设置P1MENCCMD为3'b100,使控制器进入配置状态

2.写存储器时间参数,芯片配置和ID配置寄存器(这些参数的设定要从芯片手册里找)

3.等待200us让SDRAM电源时钟稳定,cpu开始工作的时候,已经稳定下来了(就是说其实不用等)

4.执行存储器初始化

5.设置P1MEMCCMD的‘Memc_cmd’为0x'b000,让DRAM进入准备状态

6.检查P1MEMSTAT的‘Controller status’变为‘2'b01’


三、SDRAM初始化


1.设置P1DIRECTCMD控制器产生'NOP'存储器命令

2.设置P1DIRECTCMD为2b'00,使控制器产生'PrechargeAll'存储器命令

3.设置P1DIRECTCMD为2b'01,使控制器产生'Autorefresh'存储器命令

4.设置P1DIRECTCMD为2b'01,使控制器产生'Autorefresh'存储器命令

5.设置P1DIRECTCMD为2b'10,使控制器产生'MRS'存储器命令

6.如果存储器类型为移动SDR SDRAM,设置P1DIRECTCMD的'Memory command'为‘2b'10’(需要这一步,可以看之前的截图,芯片名那张,上面有写Mobile-DDR SDRAM )


四、代码分析

具体内容不会独立摘出来说了,可以看注释:

#include "common.h"

#define MEMCCMD	0x7e001004
#define P1REFRESH	0x7e001010
#define P1CASLAT	0x7e001014
#define MEM_SYS_CFG	0x7e00f120
#define P1MEMCFG	0x7e00100c
#define P1T_DQSS	0x7e001018
#define P1T_MRD		0x7e00101c
#define P1T_RAS		0x7e001020
#define P1T_RC		0x7e001024
#define P1T_RCD		0x7e001028
#define P1T_RFC		0x7e00102c
#define P1T_RP		0x7e001030
#define P1T_RRD		0x7e001034
#define P1T_WR		0x7e001038
#define P1T_WTR		0x7e00103c
#define P1T_XP		0x7e001040
#define P1T_XSR		0x7e001044
#define P1T_ESR		0x7e001048
#define P1MEMCFG2	0X7e00104c
#define P1_chip_0_cfg	0x7e001200

#define P1MEMSTAT	0x7e001000
#define P1MEMCCMD	0x7e001004
#define P1DIRECTCMD	0x7e001008

	
#define HCLK	133000000

#define nstoclk(ns)	(ns/( 1000000000/HCLK)+1)

int sdram_init( void )
{
	// 1.设置P1MENCCMD为3'b100,使控制器进入配置状态			
	set_val( MEMCCMD, 0x4 );

	// 2.刷新频率设置,可以在芯片手册里找到,refresh项
	set_val( P1REFRESH, nstoclk(7800) );

	// 时间参数的设定,这部分都要从芯片手册查,先在ok6410的手册查相应的	//寄存器作用,然后到存储器芯片手册找到相关的值
	set_val( P1CASLAT, ( 3 << 1 ) );  
	set_val( P1T_DQSS, 0x1 );	
	set_val( P1T_MRD, 0x2 );
	set_val( P1T_RAS, nstoclk(45) );
	set_val( P1T_RC, nstoclk(68) );		

	u32 trcd = nstoclk( 23 );
	set_val( P1T_RCD, trcd | (( trcd - 3 ) << 3 ) );
	u32 trfc = nstoclk( 80 );
	set_val( P1T_RFC, trfc | ( ( trfc-3 ) << 5 ) );   
	u32 trp = nstoclk( 23 );
	set_val( P1T_RP, trp | ( ( trp - 3 ) << 3 ) ); 
	set_val( P1T_RRD, nstoclk(15) );
	set_val( P1T_WR, nstoclk(15) );
	set_val( P1T_WTR, 0x7 );
	set_val( P1T_XP, 0x2 );
	set_val( P1T_XSR, nstoclk(120) );
	set_val( P1T_ESR, nstoclk(120) );
	
	// 这部分设置上边的截图有(Address  configuration)
	set_nbit( P1MEMCFG, 0, 3, 0x2 );  //10列
	set_nbit( P1MEMCFG, 3, 3, 0x2 );  //13行
	set_zero( P1MEMCFG, 6 );		  // A10/AP 
	set_nbit( P1MEMCFG, 15, 3, 0x2 ); // Burst 4 
	
	set_nbit( P1MEMCFG2, 0, 4, 0x5 );
	set_2bit( P1MEMCFG2, 6, 0x1 );		//俩片 32 bit
	set_nbit( P1MEMCFG2, 8, 3, 0x3 );	// Mobile DDR SDRAM
	set_2bit( P1MEMCFG2, 11, 0x1 );

	set_one( P1_chip_0_cfg, 16 );		//片外内存初始化

	// 4.执行存储器初始化
	set_val( P1DIRECTCMD, 0xc0000 ); // NOP
	set_val( P1DIRECTCMD, 0x000 );	// precharge
	set_val( P1DIRECTCMD, 0x40000 );// auto refresh
	set_val( P1DIRECTCMD, 0x40000 );// auto refresh
	set_val( P1DIRECTCMD, 0xa0000 ); // EMRS
	set_val( P1DIRECTCMD, 0x80032 ); // MRS

	set_val( MEM_SYS_CFG, 0x0 );
					
	// 5.设置P1MEMCCMD的‘Memc_cmd’为0x'b000,让DRAM进入准备状态	
	set_val( P1MEMCCMD, 0x000 );

	// 6.检查P1MEMSTAT的‘Controller status’变为‘2'b01’
	while( !(( read_val( P1MEMSTAT ) & 0x3 ) == 0x1));
}

五、结果验证

可以由反汇编代码看到,程序开始地址变为0x50000000了,如下图:



PS:关于上面问的,为什么设置Bank2位,Row13位,Column10位的解答:由原理图可以看到,地址线远远不够寻址128MB,通过设置这些东西,多次寻址,可以以更少的地址线寻址更大的范围。


最后,这部分内容涉及的寄存器特别多,没有单独摘出来讲(毕竟懒癌晚期……),以上内容仅供参考,如有错误多谢指正。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值