|
测试平台:SK-1788开发板 CPU:Cortex-M3 LPC1788FBD208 SDRAM:H57V2562GTR-75C (两片)
H57V2562GTR-75C简介: 16位数据总线(D0-D15),13位地址总线(A0-A12),两片,构成32位数据总线,26位地址总线,每片4个bank,由BA0,BA1两个管脚选择寻址,CS为片选管脚。 存储器类型:动态 HY57V2562GTR大小: 2片32M组成的64MB的内存, 32*2=64MB 每一块SDRAM:8192行(2^13)*512列(2^9)*4个bank = 16M * 16位宽 = 256Mb = 32MB
连接方式 lpc1788 的封装是208PIN(所以ECC配置应该使用208的配置) HY57V2562GTR挂到LPC1788的EMC_DYCS0,起始地址为0xA0000000,片选管脚EMC_CS0 地址范围:0xA0000000-0xA3FFFFFF 连接图如下:
实现原理: 研究过SDRAM的人都知道,我们的sdram是动态的,它要保存数据,依靠的是里面一个一个的微小电容排成的电容阵列(姑且这么认为),数据在每次的读写都会让电容的电荷流失,即使不对数据操作,间隔一定的时间,电容上的电荷也会流失。因此,sdram需要不断的刷新数据,为电容充电,以保证上面的数据不丢失。 不少sdram芯片datasheet上都会标出
等字样,(有的是4096)这就是说:每隔64ms刷新8192行。Sdram刷新是以“行”进行的,我们的sdram是8192行,因此刷新一次需要64ms。如果刷新的这个值比64ms大,那么我们的数据将得不到保存。64ms也是晶体存储容量的极限。因此在配置寄存器的时候,需要注意。
时钟配置: 为了使整个系统运行流畅,有必要说一下该开发板对于时钟的配置。 ■ CPU上电复位,晶振稳定工作之后,通过配置CLKSRCSEL[0]=1,选择芯片的震荡源为外部12MHz晶振。 ■ 通过配置PLL0寄存器,将时钟倍频到108MHz输出,此时pll_clk为108MHz,sysclk为12MHz。(PLL1模块是单独一个给USB提供时钟的模块,占时不用管。) ■ 通过配置CCLKSEL[8]=1,选择输入为108MHz,将108MHz送到CPU模块,EMC(SDRAM)模块和外设模块。 ■ 通过配置CPU Clock Divider 来选择时钟分频(不分频,108MHz),即cclk=108MHz, ■ 通过配置EMC Clock Divider 来选择时钟(和CPU一致,108MHz),即emc_clk=108MHz, ■ 通过配置Peripheral Clock Divider 来配置外设时钟分频,暂时不涉及到。 该系统的时钟部分工作原理如下图
下图是sdram模块的原理框图。
这里有两个比较重要的地方: CMDDLY(EMCDLYCTL[4:0]),命令延迟模式下EMC 输出的可编程延迟值 FBCLKDLY(EMCDLYCTL[12:8]),控制输入数据采样的反馈时钟的可编程延迟值 这两个延时是非常重要的,1788芯片的SDRAM有一个很重要的寄存器, EMCDLYCTL 寄存器延时的设置,就算你和官方所使用芯片一样,只要电路板有差异,这个寄存器的设置将有可能导致SDRAM在使用过程中出现错误。 我在配置这两个寄存器的时候,花费了很长的时间才把延时配好。具体怎么配,下面再说。
初始化EMC模块和sdram 初始化SDRAM之后,就需要我们编写测试程序对sdram进行测试,具体实现为:按照8位,16位,32位数据写入,然后延时一段时间(也可以不作延时),将数据读出,看看与写入的值是否一致,如果一致,则sdram的驱动没有问题,可以使用。 下面是测试程序(返回值:0 测试通过;返回值1:测试失败) - #define SDRAM_BASE 0xA0000000
- #define EMC_BASE_ADDR 0x2009C000
- #define EMC_RS_BASE_ADDR 0x400FC1DC
- #define SDRAM_SIZE 0x4000000 // 512Mbit=64MB
-
- #define EMCControl_ENABLE (1<<0)
- #define EMCConfig_SMALL (0<<0)
- #define EMCConfig_PERC_OF_CCLK (0<<8)
- #define EMCDLYCTL_CMDDLY (0x0D<<0)
- #define EMCDLYCTL_FBCLKDLY (0x10<<8)
- #define EMCDLYCTL_CLKOUT0DLY (0<<16)
- #define EMCDLYCTL_CLKOUT1DLY (0<<24)
- #define EMC_DRC_CLKDELAY (1<<0)
- #define EMC_Ras_late_3 (3<<0)
- #define EMC_Cas_late_3 (3<<8)
-
- #define EMCDCF0_BUF_EN (1<<19)
- #define EMCDCF0_AM (1<<7)|(3<<9)|(1<<14)
- #define EMCDC_DIS_CE (0<<0)
- #define EMCDC_CE (1<<0)
- #define EMCDC_DIS_CS (0<<1)
- #define EMCDC_CS (1<<1)
- #define EMCDC_SDRAM_INIT_NOP (3<<7)
- #define EMCDC_SDRAM_INIT_PALL (2<<7)
- #define EMCDC_SDRAM_INIT_MODE (1<<7)
- #define EMCDC_SDRAM_INIT_NORMAL (0<<7)
-
- void EMC_Init(void)
- {
- // float SDRAM_PERIOD;
- int i;
- // volatile unsigned long Dummy;
- volatile unsigned int mhz = 0;
- volatile unsigned int nsPerClk = 0;
- unsigned int wtemp = wtemp;
- unsigned int dwtemp = dwtemp;
- // unsigned int j = 0;
- lpc178x_emc_typedef *emc = get_emc_addr(EMC_BASE_ADDR);
- lpc178x_emc_rs_typedef *emc_rs = get_emc_rs_addr(EMC_RS_BASE_ADDR);
- /*PCONP 开启EMC*/
- lpc178x_periph_enable(LPC178X_SCC_PCONP_PCEMC_MSK,ENABLE);
-
- /*配置延时寄存器,这个延时寄存器配置比较麻烦,后面还要讲到,先设置一个例程里面的初始值,CMD-DELAY:4.25ns,FBCLK-DELAY:4.25ns*/
- emc_rs->EMCDLYCTL = EMCDLYCTL_CMDDLY | EMCDLYCTL_FBCLKDLY | EMCDLYCTL_CLKOUT0DLY | EMCDLYCTL_CLKOUT1DLY;
-
- emc->EMCControl = EMCControl_ENABLE; /*ECC 使能*/
- /*配置sdram为小端模式,时钟和CPU一致,CCLK:CLKOUT = 1:1*/
- emc->EMCConfig = EMCConfig_SMALL | EMCConfig_PERC_OF_CCLK;
复制代码
后记:在调试sdram的过程中,遇到了很多问题,有些问题是网上出现的,但是没有具体的答案,自己摸索出来的,有些问题是网上没有遇到过的。 问题1: 开始调试1788,芯片硬件仿真时,调试SDRAM寄存器配置错误,导致1788芯片无法进入仿真状态,只能用Flash Magic才能擦除。
问题2: 设定sdram参数的时候,由于没有深入的研究datasheet,导致后来测试的时候,跑一万年,调死了也不正确,后来才发现原来芯片datasheet上的参数跟例程上面的不一样,改了之后,就可以了。(果然datasheet是王道啊,信datasheet,得永生) - #define EMC_NS2CLK(ns, nsPerClk) ((ns +nsPerClk - 1) / nsPerClk)
- #define SDRAM_REFRESH 7513
- #define SDRAM_TRP 20
- #define SDRAM_TRAS 42
- #define SDRAM_TRRD 15
- #define SDRAM_TMRD 2
- #define SDRAM_TDAL 22
- #define SDRAM_TRC 63
- #define SDRAM_SREX 1
- #define SDRAM_TAPR 1
- #define SDRAM_TXSR 0xF
- #define SDRAM_TWR 1
- #define SDRAM_TRFC 70
复制代码问题3: 配置芯片的管脚出错: sdram用到的芯片管脚为: - P2_16:列地址选通
- P2_17:行地址选通
- P2_18 :EMC_CLK0,sdram的时钟管脚0
- P2_20:EMC_DYCS0选通线(片选)
- P2_24: EMC_CKE0—SDRAM时钟使能0
- P2_28 - P2_31:数据屏蔽线0,1,2,3
- P3_0 - P3_31: 数据线D0-D31
- P4_0 - P4_12: 地址线A0-A12
- P4_13 – P4_14:BA0,BA1,bank选择管脚
- P4_25: EMC_WE,写使能,低电平有效写入使能信号
复制代码
管脚配置值为0x21
问题4: sdram的延时设置错误(即EMCDLYCTL),具体表现为:写入的数据和读出的数据有一位乃至更多位的数据出错,我的方法是通过官方的测试程序,将EMCDLYCTL的值调试到最优情况,可以使数据不出错。 下图是EMC的延时模块,从图中我们可以看出,EMC的延时可以以一个很小的尺度(0.25ns)增大和减小,范围在0.25-8ns之间变化,通过配置EMCDLYCTL的值可以配置延时。 下表有关延时详细的配置信息: 例如:如果我需要配置CMDDLY为5ns,根据下面的公式 Delay_time = (CMDDLY+1) * 250ps 即:5ns=(CMDDLY+1)*250ps => CMDDLY = 19=0x13 根据上面的原理,我们可以设计程序,来找到最佳的延时时间。不过网上有官方的调试的程序,我们可以参照着来调试。 具体做法是: 设置一个延时最小值,看看测试的时候是否出错; 逐渐增大延时,当测试成功时,记录这个值,然后继续增大, 当再次增大,测试数据出现错误的时候,记下最大值,然后通过最大值和最小值计算平均,得出比较稳定的延时。
|