Part9:内存控制器与SDRAM硬件编程
程序员文章站
2022-07-14 09:38:26
...
Part9: 内存控制器与SDRAM硬件编程
1 内存接口的概念
以s3c2440为例,看下面该开发板的内存接口图
竟然Nor Flash、网卡、SDRAM(内存)、GPIO、UART这些是统一编址,那有没有“独立编址”的呢?
答:有的,nand flash就是一个典例,它不参与CPU的统一编址,看下图
此外,由第一张图可观察到,这些接口是由CPU发给内存控制器32位addr选择的
那问题来了,对于以上接口,内存控制器怎么根据32位的Addr选择不同的芯片/模块呢?
备注:片选名称、addr范围都是查S3C2440芯片手册和原理图获取的
由上图可观察注意到,一个片选信号选通的地址范围是0x0800,0000,即128M范围。128M=2^(27),即需要27根地址总线
但是S3C2440是32位的,有32根地址线,那为只用到了27根地址线呢?
答:CPU发出32位地址,而实际内存控制器只用27根地址线而已,其余地址线另有他用,
而这涉及到不同位宽芯片的连接问题,看下面的第2点分析
2 不同位宽芯片的地址连接
查看S3C2440的原理图,可发现像SDRAM/DM9000/Nor Flash它们并不是都有27根地址线,而只是其中一部分。
因此,这涉及到内存控制怎样寻址不同芯片,或者说,不同位宽的芯片/设备地址连接关系是怎样的?看下图
备注:上面8/16/32bit RAM芯片的连法可查看S3C2440芯片手册,里面有举例说明。限于篇幅,在此就不贴出了
但是,当读取4字节时,8bit/16bit的RAM怎么读取呢?
答:对应8bitRAM,需发出4次访问,如访问地址是0x4,第一次访问0x4,接着地址自动+1,访问0x5,依次类推
同理,对于16bitRAM,需要发出两次地址信号。第二次会在第一次地址基础上+1再访问,最终内存控制器
会组装好4字节数据给CPU。
可见,正如教程说的。CPU是大爷,不关心内存控制器怎么操作。大爷动动嘴,就让内存控制器跑断腿 :)
最后一个问题,怎么根据确定芯片访问地址
答:1)根据片选信号确定基址
2)根据芯片所接地址线确定范围
例如,SDRAM(内存)、DM900(网卡)、Nor Flash的访问地址范围如下表
备注一下:SDRAM的地址访问较复杂,下面第4点SDRAM原理和编程时才介绍
3 内存访问时序图
除了地址总线/数据总线,还有其它数据线。例如怎么确定是CPU向SDRAM读数据还是写数据呢?
答:这涉及内存控制时序的问题,还是看图,如下,以可编程访问周期——读时序图为例
补充:1)从左往右理解值,信号的发出顺序。如上面需要读数据时,先发出A[24:0]地址信号,再发出nGCS片选信号,
最后才发出nOE读使能信号,并等待Tacc时长数据方可读取,而释放信号顺序反过来理解即可。
2)s3c2440可接不同性能的芯片,这些时间参数就是为满足不同性能芯片可编程设置。
上面时间参数如何选择呢?以s3c2440所接的Nor Flash芯片的读时序为例讲解,如下所示
因此,结合Nor Flash和s3c2440的读时序图,可同时发出片选信号、地址信号和读信号,并等待Tacc=70ns即可满足
Nor Flash这款芯片的读要求。
基于前面文件HCLK=100mHZ,查询s3c2440手册,只需设置BANKCON0里的tacc(即[10:8])即可,如下所示
因为要>=70ns,且HCLK=100mHZ的周期为10ns,故BANKCON0的[10:8]最少为0b101,即5≤val≤7
实验效果:我这边测试时,在[4,7]范围内都是有效的,且流水灯速度越来越慢。至于为啥4时有效,不太清楚,
可能有些误差(我用的是S3C2440的V3版本,Nor Flash型号是MX29LV160DBTI-70G(NOR FLASH))
4 SDRAM原理及硬件编程
对于怎么根据addr访问SDRAM,可看下图的简要解释(注:这里偷个懒,直接截取自韦东山老师的课堂笔记,哈哈)
总的来说,要查看SDRAM芯片手册确定行列地址线数后,再配置s3c2440有关内存控制的寄存器以正确匹配地址拆分,
为此才能正确访问SDRAM,下面根据S3C2440接的EM63A165TS(SDRAM)这款芯片为例,讲解如何配置寄存器
对于EM63A165TS(SDRAM)这款芯片查询可知,列地址需9条列地址线(A0-A8),BANK地址2条(64M,需Bank0~Bank3)、
行地址线13条(A0-A12)
对于nGCS6这条SDRAM的片选信号,需要设置5个相关的内存控制寄存器,如下所示
OK,只需设置上面5个寄存器即可,代码如下
sdram_init函数
void sdram_init(void)
{
BWSCON = 0x22000000;
BANKCON6 = 0x18001;
BANKCON7 = 0x18001; //可不设置
REFRESH = 0x8404f5;
BANKSIZE = 0xb1;
MRSRB6 = 0x20;
MRSRB7 = 0x20; //可不设置
}
sdram_test函数
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++)
if (p[i] != 0x55)
return -1;
return 0;
}
main.c函数
int main(void)
{
uart0_init();
sdram_init();
if (sdram_test() == 0)//测试成功,才执行流水灯
led_test();
return 0;
}
备注:我并没有贴出完整代码,一方面官网有(www.100ask.net),没必要这里占据篇幅。
另一方面,重在理解即可。
实验效果:我这里演示是OK的,即测试成功,有流水灯。
总结:
以上就是这篇文章的所有内容,虽然篇幅有点长,但我尽量以图的方式展示了。
主要讲解了内存接口概念、不同位宽芯片的地址连接、内存访问时序图如何看、SDRAM地址拆分和硬件编程。
这些知识很重要,望重视 : )
说明一下,以上内容是基于韦东山老师新1期的“内存控制器及SDRAM”教程里的笔记。
我这里只是重新整理并加以注释总结。更详细的可查看**** (我不做广告,只是尊重版权: )
上一篇: 开发板刷系统
下一篇: Linux驱动之LCD框架介绍