前面我们使用过uart来打印输出信息。
今天我们来学习一下sdram的使用。
sdram的功能相当我们在使用PC机的时候里面插的ram,当然我们S3C2440在芯片内部会有一个自带的SRAM(大小为4K),
当这个自带的sram不够用的时候,就会需要使用我们外接的sdram了。
缺点是sdram在使用的时候,需要先把数据搬进去,处理好以后再搬出来给到cpu使用,与内部sram相比降低了运行速度。
但我们在配置的时候,把性能配置好,依然很快。
这里建议大家看一篇关于sdram的文章,讲的很深很好。
《SDRAM参考文档: 高手进阶,终极内存技术指南——完整/进阶版》百度一下这篇文章即可。
然后我们来学习一下本节sdram的一些知识和使用。不足之处希望大家指出,谢谢。
首先我们了解一下原理图,看下硬件构成。
我们使用的是16bits * 2 两块sdram。
那么我们由原理图可以看出,addr线是并接的,且从addr2开始接sdram的addr0线。
其原因有二:
1、并接的原因是因为我们s3c2440是32bit,所以把两个16bit的sdram组合成32bit来处理cpu的一个带宽数据。
2、addr2接sdram的addr0是因为如下图:
当我们cpu想访问的地址为A0A1A2A3 = 0010时,则sdram收到的地址是A2A3也就是SDRAM(A0A1)=10。
也就是我们两块sdram的第二个word。然后把两个sdram的③④组装成一个32bit的数据data,返回给内存控制器,再由内存控制器根据上s3c2440的A0A1地址数据,取出data中对应的那个byte数据给到cpu。
这里的原理和2440的spec写的一样:
接下来我们要看cpu是如何选中sdram的。原理图中可以看到,有一个片选引脚LnGS6, 由2440 spec可以看到这块内存接口是专门用来外接sdram的。
我们可以看到sdram是可编程内存空间的,2MB~128MB,我们用的是2个32MB的sdram组成一个64MB的sdram供cpu使用。
接下来我们讲一下sdram的内部结构和寻址方式:
目前我们的sdram内部采用的是逻辑分区为4个,然后是行列地址。
比如要写一个数据到sdram,那么我们需要先选中L_BANKx,然后行地址,再列地址。找到对应地址后再把数据写入目的地址。
再bank中的寻址方式类似于excel的单元格查找。
由原理图可以看到我们使用LADDR24/25来选中逻辑bank,再由laddr2~laddr14来写入行列地址。
行地址为laddr2~laddr14,列地址为9bit, laddr2~laddr1(sdram spec得到)
2440和sdram之间的通信时序如下图:
要注意的地方是,要根据sdram的时间要求来修改地址和数据之间的时间差。
到这里我们原理分析完毕。然后配置寄存器。
我们直接借用韦东山老师的讲课图。
上面说那么多原理,其实就是这几个寄存器的配置。我们只使用了基本的功能。一些busrt等等模式还没有使用。
上代码:
/*
* brief: init sdram registers config.
* param: none
* return: none
* notice: none
*/
void sdram_init(void)
{
/* not using UB/LB, wait disble, data bus width 32bits */
BWSCON = 0x22000000;
/* memory type sdram, RAS to CAS time 2clocks, column address 9bits */
BANKCON6 = 0x18001;
BANKCON7 = 0x18001; //bank7 config same param also.
/* enable auto refresh... */
REFRESH = 0x8404F5;
/* Enable burst operation, SDRAM power down mode enable,
* SCLK is active only during the access (recommended),
* 64MB SDRAM */
BANKSIZE = 0xB1;
/* CAS latency 2clocks */
MRSRB6 = 0x20;
MRSRB7 = 0x20; //bank7 config same param also.
}
到这里我们就可以使用sdram了。
下面加了一段sdram测试。
int sdram_test(void)
{
volatile unsigned char *p = (volatile unsigned char *)0x30000000;
int i;
//write sdram
for(i = 0; i < 1000; i++)
{
p[i] = 0x55;
}
//read sdram
for(i = 0; i < 1000; i++)
{
//printf("write data to sdram p[%d] = %d \r\n", i, p[i]);
if(p[i] != 0x55)
return -1;
}
return 0;
}
最后再做这个实验的时候,有两个问题捣鼓了一下午没解开?
1、添加uart的时候,使用了printf函数,Makefile中把-Tdata段设置在0xe80和0xee0之间都可以正常打印。但是设置到0xef0以后就不能正常输出%d %x等这些格式,都是空白输出。 我查了代码段和只读数据段最后地址都没有覆盖到-Tdata。
2、printf函数放到sdram.c里面就打印不出来。根源未知。