“第012课 内存控制器与SDRAM”的版本间的差异
Baiwen root(讨论 | 贡献) |
Zhouyuebiao(讨论 | 贡献) (综上所述,本开发板中BANKCON6设为0x017001。---(修改为)---> 综上所述,本开发板中BANKCON6设为0x018001。) 标签:visualeditor |
||
(未显示3个用户的9个中间版本) | |||
第1行: | 第1行: | ||
+ | <div style="width:800px;" body> | ||
=第001节_辅线1_硬件知识_内存接口概念 = | =第001节_辅线1_硬件知识_内存接口概念 = | ||
首先来分析下操作GPIO控制器和操作UART控制器两者的区别。 | 首先来分析下操作GPIO控制器和操作UART控制器两者的区别。 | ||
+ | |||
如图是S3C2440是个片上系统,有GPIO控制器(接有GPIO管脚),有串口控制器 (接有TXD RXD引脚)。<br> | 如图是S3C2440是个片上系统,有GPIO控制器(接有GPIO管脚),有串口控制器 (接有TXD RXD引脚)。<br> | ||
− | [[File:chapter12_lesson1_001.jpg| | + | [[File:chapter12_lesson1_001.jpg|600px]]<br> |
配置GPIO控制器相应的寄存器,即可让引脚输出高低电平;配置UART控制器相应的寄存器,即可让引脚输出波形。前者相对简单,类似门电路,后者相对复杂,属于协议类接口。类似的协议类接口还有iic、iis、spi等。 | 配置GPIO控制器相应的寄存器,即可让引脚输出高低电平;配置UART控制器相应的寄存器,即可让引脚输出波形。前者相对简单,类似门电路,后者相对复杂,属于协议类接口。类似的协议类接口还有iic、iis、spi等。 | ||
对于CPU是不管什么接口的,它只写相应的寄存器,由控制器根据寄存器的配置去控制具体的引脚。 | 对于CPU是不管什么接口的,它只写相应的寄存器,由控制器根据寄存器的配置去控制具体的引脚。 | ||
+ | |||
那么CPU是如何访问各个不同的寄存器的呢? | 那么CPU是如何访问各个不同的寄存器的呢? | ||
+ | |||
CPU只管发出一个地址,内存控制器根据该地址选择不同的模块,然后从模块中得到数据或者发送数据到模块中。 | CPU只管发出一个地址,内存控制器根据该地址选择不同的模块,然后从模块中得到数据或者发送数据到模块中。 | ||
+ | |||
前面的GPIO/门电路接口、协议类接口,都不会把地址输出到外部,接下来的内存类接口,会把地址输出到外部,比如Nor Flash、网卡、SDRAM。 | 前面的GPIO/门电路接口、协议类接口,都不会把地址输出到外部,接下来的内存类接口,会把地址输出到外部,比如Nor Flash、网卡、SDRAM。 | ||
+ | |||
如图,SDRAM、DM9000网卡、Nor Flash都接在JZ2440的数据总线和地址总线上,CPU把数据和地址发送出去,然后内存控制器根据片选信号选择相应的设备接收地址和数据信号,互不干扰。<br> | 如图,SDRAM、DM9000网卡、Nor Flash都接在JZ2440的数据总线和地址总线上,CPU把数据和地址发送出去,然后内存控制器根据片选信号选择相应的设备接收地址和数据信号,互不干扰。<br> | ||
− | [[File:chapter12_lesson1_002.jpg| | + | [[File:chapter12_lesson1_002.jpg|600px]] |
+ | |||
+ | |||
+ | |||
+ | 片选信号和地址的关系怎么确定? | ||
+ | |||
+ | 这个是由2440芯片特性决定的。<br> | ||
+ | [[File:chapter12_lesson1_003.png|600px]]<br> | ||
− | |||
− | |||
* 当选择Nor Flash启动时,CPU发出的指令的地址范围处于0x0000000 - 0x08000000,内存控制器就会使nGCS0处于低电平(片选引脚被选中),Nor Flash被选中。 | * 当选择Nor Flash启动时,CPU发出的指令的地址范围处于0x0000000 - 0x08000000,内存控制器就会使nGCS0处于低电平(片选引脚被选中),Nor Flash被选中。 | ||
* 当CPU发出的指令的地址范围处于0x20000000 - 0x28000000,内存控制器就会使nGCS4处于低电平(片选引脚被选中),网卡被选中。 | * 当CPU发出的指令的地址范围处于0x20000000 - 0x28000000,内存控制器就会使nGCS4处于低电平(片选引脚被选中),网卡被选中。 | ||
第20行: | 第31行: | ||
GPIO/门电路接口、协议类接口、内存类接口都属于CPU的统一编址。对于Nand Flash,在原理图上它的地址线并没有连接到CPU,因此它不参与CPU的统一编址。但它的数据线也接到了数据总线上,为了防止干扰,它也有一个片选信号(CE)。当CPU访问Nand Flash时,Nand Flash控制器才会片选Nand Flash,让其接收数据总线上的数据。<br> | GPIO/门电路接口、协议类接口、内存类接口都属于CPU的统一编址。对于Nand Flash,在原理图上它的地址线并没有连接到CPU,因此它不参与CPU的统一编址。但它的数据线也接到了数据总线上,为了防止干扰,它也有一个片选信号(CE)。当CPU访问Nand Flash时,Nand Flash控制器才会片选Nand Flash,让其接收数据总线上的数据。<br> | ||
− | [[File:chapter12_lesson1_004.jpg| | + | [[File:chapter12_lesson1_004.jpg|600px]] |
再来看下Nor Flash的空间,0x00000000 * 0x08000000,为128M,即每一个片选信号可以选择的空间是128M=2^27,也就需要A0、A1……A26,共27根地址线。CPU发出的32位地址线,内存控制器根据地址范围,片选上相应的bank,并将地址转化为27位。<br> | 再来看下Nor Flash的空间,0x00000000 * 0x08000000,为128M,即每一个片选信号可以选择的空间是128M=2^27,也就需要A0、A1……A26,共27根地址线。CPU发出的32位地址线,内存控制器根据地址范围,片选上相应的bank,并将地址转化为27位。<br> | ||
− | [[File:chapter12_lesson1_005.jpg| | + | [[File:chapter12_lesson1_005.jpg|600px]] |
=第002节_辅线1_硬件知识_不同位宽设备的连接= | =第002节_辅线1_硬件知识_不同位宽设备的连接= | ||
参考2440芯片手册,可以看到内存接口与8-bit ROM连接时,2440的A0与外部芯片的A0相连。<br> | 参考2440芯片手册,可以看到内存接口与8-bit ROM连接时,2440的A0与外部芯片的A0相连。<br> | ||
− | [[File:chapter12_lesson2_001.png| | + | [[File:chapter12_lesson2_001.png|400px]]<br> |
当与两个8-bit ROM拼接成的一个16-bit ROM连接时,2440的A1与外部芯片的A0相连。<br> | 当与两个8-bit ROM拼接成的一个16-bit ROM连接时,2440的A1与外部芯片的A0相连。<br> | ||
− | [[File:chapter12_lesson2_002.png| | + | [[File:chapter12_lesson2_002.png|600px]]<br> |
当与四个8-bit ROM拼接成的一个32-bit ROM连接时,2440的A2与外部芯片的A0相连。<br> | 当与四个8-bit ROM拼接成的一个32-bit ROM连接时,2440的A2与外部芯片的A0相连。<br> | ||
− | [[File:chapter12_lesson2_003.png| | + | [[File:chapter12_lesson2_003.png|600px]]<br> |
当与一个16-bit ROM连接时,2440的A1与外部芯片的A0相连。<br> | 当与一个16-bit ROM连接时,2440的A1与外部芯片的A0相连。<br> | ||
− | [[File:chapter12_lesson2_004.png| | + | [[File:chapter12_lesson2_004.png|400px]]<br> |
可以看出外接芯片的位宽有变化时,地址线的接法也会有变化。那这个变化有什么规律呢? | 可以看出外接芯片的位宽有变化时,地址线的接法也会有变化。那这个变化有什么规律呢? | ||
第43行: | 第54行: | ||
MOV R0, #3 @去地址为3的内存上 | MOV R0, #3 @去地址为3的内存上 | ||
LDRB R1, [R0] @ 从内存为3的地址上,读出一个字节 | LDRB R1, [R0] @ 从内存为3的地址上,读出一个字节 | ||
− | + | ||
如图有8bitROM、16bitROM、32bitROM。<br> | 如图有8bitROM、16bitROM、32bitROM。<br> | ||
− | [[File:chapter12_lesson2_005. | + | [[File:chapter12_lesson2_005.jpg|600px]] |
8个bit组成一个字节,字节是计算机的最小的存储单位,因此我们读取数据肯定都是8bit的倍数。 | 8个bit组成一个字节,字节是计算机的最小的存储单位,因此我们读取数据肯定都是8bit的倍数。 | ||
第70行: | 第81行: | ||
MOV R0, #4 | MOV R0, #4 | ||
LDR R1, [R0] @去地址4,读取4字节数据 | LDR R1, [R0] @去地址4,读取4字节数据 | ||
− | |||
执行过程如下: | 执行过程如下: | ||
第98行: | 第108行: | ||
这节我们分析一下我们了解时序图,信号之间是怎样一起工作的,以Nor Flash 为例。 | 这节我们分析一下我们了解时序图,信号之间是怎样一起工作的,以Nor Flash 为例。 | ||
+ | |||
2440和Nor Flash 之间有地址线,数据线,还有各种数据线连接。<br> | 2440和Nor Flash 之间有地址线,数据线,还有各种数据线连接。<br> | ||
− | [[File:chapter12_lesson3_001.jpg| | + | [[File:chapter12_lesson3_001.jpg|600px]]<br> |
以Nor Flash为例,分析下如何设置它的时序。 | 以Nor Flash为例,分析下如何设置它的时序。 | ||
+ | |||
如图是S3C2440的Nor Flash控制器的读时序图,里面很多参数都需要根据外接芯片的性能进行设置,有的芯片性能好、响应时间快,就可以把参数时间设置小一点,释放更好的性能。 | 如图是S3C2440的Nor Flash控制器的读时序图,里面很多参数都需要根据外接芯片的性能进行设置,有的芯片性能好、响应时间快,就可以把参数时间设置小一点,释放更好的性能。 | ||
− | [[File:chapter12_lesson3_002.png| | + | |
+ | [[File:chapter12_lesson3_002.png|600px]]<br> | ||
如图是Nor Flash芯片的读时序。<br> | 如图是Nor Flash芯片的读时序。<br> | ||
− | [[File:chapter12_lesson3_003.png| | + | [[File:chapter12_lesson3_003.png|600px]]<br> |
− | 我们需要做的就是设置S3C2440的Nor Flash控制器时序去满足Nor | + | 我们需要做的就是设置S3C2440的Nor Flash控制器时序去满足Nor Flash芯片的时序。每个参数的参考范围可以通过AC CHARACTERISTICS得到。<br> |
− | [[File:chapter12_lesson3_004.png| | + | [[File:chapter12_lesson3_004.png|600px]] |
结合Nor Flash芯片的两张图,可以得到如下信息: | 结合Nor Flash芯片的两张图,可以得到如下信息: | ||
第117行: | 第130行: | ||
查阅S3C2240的参考手册,Nor Flash是接在BANKCON0上的,因此只需要设置BANKCON0即可。<br> | 查阅S3C2240的参考手册,Nor Flash是接在BANKCON0上的,因此只需要设置BANKCON0即可。<br> | ||
− | [[File:chapter12_lesson3_005.png| | + | [[File:chapter12_lesson3_005.png|600px]]<br> |
可以看到Tacc上电初始值是111,对应14个clocks。系统上电采用12MHz的晶振,HCLK=12MHz,Tacc=(1000/12*14)≈1166ns,这个值很大,几乎可以满足所有Nor Flash的要求。 | 可以看到Tacc上电初始值是111,对应14个clocks。系统上电采用12MHz的晶振,HCLK=12MHz,Tacc=(1000/12*14)≈1166ns,这个值很大,几乎可以满足所有Nor Flash的要求。 | ||
+ | |||
启动后,将HCLK设置为100MHz,T=1000/100=10ns,Tacc需要大于等于70ns,因此设置Tacc等于101,8个clocks即可。 | 启动后,将HCLK设置为100MHz,T=1000/100=10ns,Tacc需要大于等于70ns,因此设置Tacc等于101,8个clocks即可。 | ||
在前面uart实验的源码基础上,新建init.c和init.h两个文件。 | 在前面uart实验的源码基础上,新建init.c和init.h两个文件。 | ||
+ | |||
在init.c里面只需要设置BANKCON0寄存器即可。 | 在init.c里面只需要设置BANKCON0寄存器即可。 | ||
− | + | <syntaxhighlight lang="c"> | |
#include "s3c2440_soc.h" | #include "s3c2440_soc.h" | ||
第132行: | 第147行: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
init.h进行函数声明。 | init.h进行函数声明。 | ||
− | + | <syntaxhighlight lang="c"> | |
#ifndef _INIT_H | #ifndef _INIT_H | ||
#define _INIT_H | #define _INIT_H | ||
第142行: | 第157行: | ||
最后在主函数里面,通过串口获取输入的值,传入bank0_tacc_set()函数里,设置Tacc,然后再读取Nor Flash上的闪灯程序。 | 最后在主函数里面,通过串口获取输入的值,传入bank0_tacc_set()函数里,设置Tacc,然后再读取Nor Flash上的闪灯程序。 | ||
− | <syntaxhighlight lang="c" > | + | <syntaxhighlight lang="c"> |
#include "s3c2440_soc.h" | #include "s3c2440_soc.h" | ||
第175行: | 第190行: | ||
实验效果: | 实验效果: | ||
+ | |||
输入0~4,Tacc小于70ns,无法读取Nor Flash上数据,LED不能闪烁。 | 输入0~4,Tacc小于70ns,无法读取Nor Flash上数据,LED不能闪烁。 | ||
+ | |||
输入4~7,Tacc大于70ns,可以读取Nor Flash上数据,LED不断闪烁,且值越小越快(区别不明显)。 | 输入4~7,Tacc大于70ns,可以读取Nor Flash上数据,LED不断闪烁,且值越小越快(区别不明显)。 | ||
第185行: | 第202行: | ||
如图是SDRAM存储结构逻辑图:<br> | 如图是SDRAM存储结构逻辑图:<br> | ||
− | [[File:chapter12_lesson4_001.jpg| | + | [[File:chapter12_lesson4_001.jpg|700px]]<br> |
SDRAM总共有4个块(Banks),可以认为每个块就是一个表格,里面的每个格子表示的是16bit数据。 | SDRAM总共有4个块(Banks),可以认为每个块就是一个表格,里面的每个格子表示的是16bit数据。 | ||
− | 问题1:怎样访问里面的某个格子呢? | + | * 问题1:怎样访问里面的某个格子呢? |
+ | |||
1. 首先发出一个片选信号,选中整个芯片; | 1. 首先发出一个片选信号,选中整个芯片; | ||
+ | |||
2. 发出Bank地址,选择是哪一个Bank(块,即表格); | 2. 发出Bank地址,选择是哪一个Bank(块,即表格); | ||
+ | |||
3. 发出行地址; | 3. 发出行地址; | ||
+ | |||
4. 最后发出列地址,才能选中是个格子; | 4. 最后发出列地址,才能选中是个格子; | ||
− | 问题2:那么多的信号有谁发出呢? | + | |
+ | *问题2:那么多的信号有谁发出呢? | ||
+ | |||
由内存控制器发出,所以我们需要设置内存控制器,CPU只是简单的执行读写内存的命令,其他的都交给内存控制起来处理。 | 由内存控制器发出,所以我们需要设置内存控制器,CPU只是简单的执行读写内存的命令,其他的都交给内存控制起来处理。 | ||
例如 | 例如 | ||
第200行: | 第223行: | ||
LDR R0,=0x30000000 | LDR R0,=0x30000000 | ||
LDR R1,[R0] | LDR R1,[R0] | ||
− | + | ||
1. CPU把0x30000000这个地址发给内存控制器,内存控制器根据这个地址,判断属于哪个范围,然后发出相应的片选信号。 | 1. CPU把0x30000000这个地址发给内存控制器,内存控制器根据这个地址,判断属于哪个范围,然后发出相应的片选信号。 | ||
+ | |||
2. 根据类型(比如SDRAM)拆分成三部分:发出Bank地址、发出行地址、发出列地址。 | 2. 根据类型(比如SDRAM)拆分成三部分:发出Bank地址、发出行地址、发出列地址。 | ||
+ | |||
对于上面的三个,怎样拆分呢? | 对于上面的三个,怎样拆分呢? | ||
+ | |||
行地址线有几条,列地址线有几条,都要设置内存控制器里面相关寄存器。 | 行地址线有几条,列地址线有几条,都要设置内存控制器里面相关寄存器。 | ||
+ | |||
3. 读数据 | 3. 读数据 | ||
− | + | ||
+ | 综上所述:对SDRAM的访问可以分为如下步: | ||
+ | |||
1. CPU发出的片选信号nSCS6有效,它选中SDRAM芯片。 | 1. CPU发出的片选信号nSCS6有效,它选中SDRAM芯片。 | ||
+ | |||
2. SDRAM中有4个L-Bank,需要两根地址信号来选中其中之一,根据原理图,可知使用ADDR24,ADDR25作为L-Bank的选择信号。 | 2. SDRAM中有4个L-Bank,需要两根地址信号来选中其中之一,根据原理图,可知使用ADDR24,ADDR25作为L-Bank的选择信号。 | ||
+ | |||
3. 对被选中的芯片进行统一的行/列(存储单元)寻址。 | 3. 对被选中的芯片进行统一的行/列(存储单元)寻址。 | ||
+ | |||
根据SDRAM芯片的列地址线数目设置CPU的相关寄存器后,CPU就会从32位的地址中自动分出L_Bank片选信号,行地址信号,列地址信号,然后先后发出行地址信号,列地址信号。L_Bank选择信号在发出行地址信号的同时发出,并维持到列地址信号结束。 | 根据SDRAM芯片的列地址线数目设置CPU的相关寄存器后,CPU就会从32位的地址中自动分出L_Bank片选信号,行地址信号,列地址信号,然后先后发出行地址信号,列地址信号。L_Bank选择信号在发出行地址信号的同时发出,并维持到列地址信号结束。 | ||
− | + | ||
− | 4. | + | |
+ | 根据原理图可知: | ||
+ | |||
+ | 地址、列地址共用地线ADDR2—ADDRI4(BANK6位宽为32,ADDRO/I没有使用),使用nSRAS、nSCAS两个信号来区分它们。 | ||
+ | |||
+ | 比如本开发板中,使用两根地址线ADDR24、ADDR25作为L-Bank的选择信号:SDRAM芯片K4s5m632的行地址数为13,列地址数为9,所以当nSRAS信号有时,ADDR2—ADDR14上发出是行地址信号,它对应32位地址空间的b可23m]:当nSCAS信号有效时,ADDR2—ADDR10上发出的是列地址信号,它对应32位地址空间的bit[0:2];由于BANK6以32位的宽度外接DRAM,ADDR0、ADDR1恒为0,不参与译码。 | ||
+ | |||
+ | 4. 找到了存储单元后,被选中的芯片就要进行统一的数据传输了。 | ||
+ | |||
开发板中使用两片16位的SDRAM芯片并联组成32位的位宽,与CPU的32根数据线(DATA0—DATA31)相连。 | 开发板中使用两片16位的SDRAM芯片并联组成32位的位宽,与CPU的32根数据线(DATA0—DATA31)相连。 | ||
BANK6的起始地址为0x30000000,所以SDRAM的访问地址为0x30000000~低0x33FFFFFF,共64MB。 | BANK6的起始地址为0x30000000,所以SDRAM的访问地址为0x30000000~低0x33FFFFFF,共64MB。 | ||
− | 2440内存控制器设置: | + | |
+ | '''2440内存控制器设置:''' | ||
+ | |||
内存控制器共有13个寄存器, | 内存控制器共有13个寄存器, | ||
+ | |||
BANK0--BANK5只需要设置BWSCON和BANKCONx(x为0~5)两个寄存器; | BANK0--BANK5只需要设置BWSCON和BANKCONx(x为0~5)两个寄存器; | ||
+ | |||
BANK6、BANK7外接SDRAM时,除BWSCON和BANKCONx(x为6、7)外,还要设置REFRESH、BANKSIZE、MRSRB6、MRSRB7等4个寄存器。 | BANK6、BANK7外接SDRAM时,除BWSCON和BANKCONx(x为6、7)外,还要设置REFRESH、BANKSIZE、MRSRB6、MRSRB7等4个寄存器。 | ||
+ | |||
下面分类说明各个寄存起的设置。 | 下面分类说明各个寄存起的设置。 | ||
− | 1. 位宽和等待控制寄存器BWSCON(BUSWIDTH&WAITCONTROLREGISTER)<br> | + | |
− | [[File:chapter12_lesson4_002.png| | + | * 1. 位宽和等待控制寄存器BWSCON(BUSWIDTH&WAITCONTROLREGISTER)<br> |
+ | [[File:chapter12_lesson4_002.png|700px]] | ||
BWSCON中每4位控制一个BANK,最高4位对应BANK7(没有使用)、接下来4位对应BANK6。 | BWSCON中每4位控制一个BANK,最高4位对应BANK7(没有使用)、接下来4位对应BANK6。 | ||
+ | |||
(1)ST6[27]: 启动/禁止SDRAM的数据掩码引脚,对于SDRAM,此位为0:对于SRAM此位为1。 | (1)ST6[27]: 启动/禁止SDRAM的数据掩码引脚,对于SDRAM,此位为0:对于SRAM此位为1。 | ||
+ | |||
(2)WS6[26]:是否使用存储器的WAIT信号,通常设为0。 | (2)WS6[26]:是否使用存储器的WAIT信号,通常设为0。 | ||
+ | |||
(3)DW6[25:24]:使用两位来设置相应BANK的位宽,0b00对应8位,0b01对应16位,0b10对应32位(开发板用的就是32位的),0b11表示保留。 | (3)DW6[25:24]:使用两位来设置相应BANK的位宽,0b00对应8位,0b01对应16位,0b10对应32位(开发板用的就是32位的),0b11表示保留。 | ||
+ | |||
因此BWSCON寄存器的值为:0x22000000。 | 因此BWSCON寄存器的值为:0x22000000。 | ||
− | 2. BANK控制寄存器BANKCON6(BANKCONTROLREGISTER) | + | |
+ | * 2. BANK控制寄存器BANKCON6(BANKCONTROLREGISTER) | ||
在8个BANK中,只有BANK6和BANK7可以外接SRAM或SDRAM。<br> | 在8个BANK中,只有BANK6和BANK7可以外接SRAM或SDRAM。<br> | ||
− | [[File:chapter12_lesson4_003.png| | + | [[File:chapter12_lesson4_003.png|700px]]<br> |
− | + | (1)MT[16:15]:用于设置本BANK外接的是ROM/SRAM还是SDRAM,SRAM:0b00,SDRAM:0b11(开发板使用的是SDRAM)。 | |
− | + | ||
− | + | 当MT[16:15]设置为00时,此寄存器与BANKC0N0、BANKCON5类似,不再赘述。 | |
− | [[File:chapter12_lesson4_004.png| | + | |
+ | 当MT[16:15]设置为11时,此寄存器其他值如下设置。<br> | ||
+ | [[File:chapter12_lesson4_004.png|700px]] | ||
(2)Trcd[3:2]:行地址和列地址间隔多长时间,看芯片手册时间间隔是20ns,本来开发板的HCLK是100MHZ,clocks为10ns,所以设置为推荐值0b00(2clocks)。 | (2)Trcd[3:2]:行地址和列地址间隔多长时间,看芯片手册时间间隔是20ns,本来开发板的HCLK是100MHZ,clocks为10ns,所以设置为推荐值0b00(2clocks)。 | ||
+ | |||
(3)SCAN[1:0]:SDRAM的列地址位数,对于本开发板使用的SDRAMK4S561632。列地址位数为9,所以SCAN=0b010如果使用其他型号的SDRAM,需要查看其数据手册。来决定SCAN的取值。0b00表示8位,0b01表示9位,0b10表示10位。 | (3)SCAN[1:0]:SDRAM的列地址位数,对于本开发板使用的SDRAMK4S561632。列地址位数为9,所以SCAN=0b010如果使用其他型号的SDRAM,需要查看其数据手册。来决定SCAN的取值。0b00表示8位,0b01表示9位,0b10表示10位。 | ||
− | |||
− | + | 综上所述,本开发板中BANKCON6设为0x018001。 | |
− | [[File:chapter12_lesson4_005.png| | + | * 3. 刷新控制寄存器REFRESH(REFRESHCONTROLREGISTER)<br> |
+ | |||
+ | [[File:chapter12_lesson4_005.png|700px]] | ||
(1)REFEN[23]:0=禁止SDRAM的刷新功能,1:开启SDRAM的刷新功能(设置开启SDRAM的刷新功能)。 | (1)REFEN[23]:0=禁止SDRAM的刷新功能,1:开启SDRAM的刷新功能(设置开启SDRAM的刷新功能)。 | ||
+ | |||
(2)TREFMD[22]:SDRAM的刷新模式,0=CBR/AutoRefresh,1=SelfRefresh(一般在系统休眠时使用),我们设置默认值。 | (2)TREFMD[22]:SDRAM的刷新模式,0=CBR/AutoRefresh,1=SelfRefresh(一般在系统休眠时使用),我们设置默认值。 | ||
+ | |||
(3)Trp[21:20):根据芯片手册设为0即可。 | (3)Trp[21:20):根据芯片手册设为0即可。 | ||
+ | |||
(4)Tsrc[19:18]:根据芯片手册设为默认值0b01即可。 | (4)Tsrc[19:18]:根据芯片手册设为默认值0b01即可。 | ||
+ | |||
(5)RefreshCounter[10:0]:即R_CNT | (5)RefreshCounter[10:0]:即R_CNT | ||
+ | |||
R_CNT可如下汁算(SDRAM时钟频率就是HCLK): | R_CNT可如下汁算(SDRAM时钟频率就是HCLK): | ||
− | R_CNT=2^11+1-SDRAM时钟频率(MZ)*SDRAM刷新周期(us) | + | R_CNT=2^11+1-SDRAM时钟频率(MZ)*SDRAM刷新周期(us) |
− | SDRAM的刷新周期在SDRAM的数据手册上有标明,在本开发板使用的SDRAM | + | |
− | K4S561632的数据手册上,可看见这么一行“64msrefreshpenod(8KCycle)所以,刷新周期=64ms/8192=7.8125us。 | + | SDRAM的刷新周期在SDRAM的数据手册上有标明,在本开发板使用的SDRAM:K4S561632的数据手册上,可看见这么一行“64msrefreshpenod(8KCycle)所以,刷新周期=64ms/8192=7.8125us。 |
− | Refreshcount=2^11+1-100x7.8=1269=0x4F5。 | + | Refreshcount=2^11+1-100x7.8=1269=0x4F5。 |
+ | |||
因此,本开发板中REFRESH设为0x8404F5。 | 因此,本开发板中REFRESH设为0x8404F5。 | ||
− | |||
− | |||
− | + | * 4. BANKSIZE寄存器REFRESH(BANKSIZEREG ISTER)<br> | |
− | + | [[File:chapter12_lesson4_006.png|700px]]<br> | |
− | + | ||
− | + | (1)BURST_EN[7]:0=ARM核禁上突发传输,1=ARM核支持突发传输(推荐); | |
+ | |||
+ | (2)SCKEEN[5]:0=不使用SCKE信号令SDRAM进入省电模式,1=使用SCKE信号令SDRAM进入省电模式(推荐); | ||
+ | |||
+ | (3)SCLK-EN[4]:0=时刻发出SCLK信号,1=仅在访问SDRAM期间发出SCLK信号(推荐); | ||
+ | |||
+ | (4)BK76MAP[2:0]:设置BANK6的大小。本开发板BANK6外接64MB的SDRAM,令[2:0]=b001(64M/64M),表示BANK6/7的容量都是64MB,虽然BANK7没有使用。 | ||
+ | |||
因此,本开发板中BANKSIZE设为0xB1。 | 因此,本开发板中BANKSIZE设为0xB1。 | ||
− | 5. SDRAM模式设置寄存器MRSRBx6(SDRAM MODE REGISTER SET REGISTER)<br> | + | |
− | [[File:chapter12_lesson4_007.png| | + | * 5. SDRAM模式设置寄存器MRSRBx6(SDRAM MODE REGISTER SET REGISTER)<br> |
+ | [[File:chapter12_lesson4_007.png|700px]] | ||
能修改的只有位CL[6:4],这是SDRAM时序的一个时间参数,表示发出行、列地址后,等多久才返回收到数据, | 能修改的只有位CL[6:4],这是SDRAM时序的一个时间参数,表示发出行、列地址后,等多久才返回收到数据, | ||
CL可以取值为0b0l0(2 clocks)或0b011(3 clocks)。 | CL可以取值为0b0l0(2 clocks)或0b011(3 clocks)。 | ||
+ | |||
本开发板取最保守的值0b010,所以MRSRB6的值为0x20。 | 本开发板取最保守的值0b010,所以MRSRB6的值为0x20。 | ||
+ | |||
下面开始写程序: | 下面开始写程序: | ||
+ | |||
在init.c里面进行对内存控制器的寄存器依次进行设置: | 在init.c里面进行对内存控制器的寄存器依次进行设置: | ||
− | + | <syntaxhighlight lang="c"> | |
void sdram_init(void) | void sdram_init(void) | ||
{ | { | ||
BWSCON = 0x22000000; | BWSCON = 0x22000000; | ||
− | BANKCON6 = | + | BANKCON6 = 0x17001; |
− | BANKCON7 = | + | BANKCON7 = 0x17001; |
REFRESH = 0x8404f5; | REFRESH = 0x8404f5; | ||
第296行: | 第366行: | ||
再写一个测试函数,向SDRAM里面连续写1000个数,再读出数据对比是否是设置的数,返回对比结果: | 再写一个测试函数,向SDRAM里面连续写1000个数,再读出数据对比是否是设置的数,返回对比结果: | ||
− | <syntaxhighlight lang="c" > | + | <syntaxhighlight lang="c"> |
int sdram_test(void) | int sdram_test(void) | ||
{ | { | ||
第317行: | 第387行: | ||
在主函数里调用sdram_test()测试函数,如果测试成功,LED闪烁: | 在主函数里调用sdram_test()测试函数,如果测试成功,LED闪烁: | ||
− | + | <syntaxhighlight lang="c"> | |
int main(void) | int main(void) | ||
{ | { | ||
第331行: | 第401行: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
实验结果: | 实验结果: | ||
+ | |||
LED按预期闪烁,屏蔽掉sdram_init()后,LED不闪烁。 | LED按预期闪烁,屏蔽掉sdram_init()后,LED不闪烁。 | ||
− | + | </div> | |
='''《《所有章节目录》》'''= | ='''《《所有章节目录》》'''= | ||
− | <categorytree mode=all background*color:white;">ARM裸机加强版</categorytree> | + | <categorytree mode="all" background*color:white;"="">ARM裸机加强版</categorytree> |
[[Category:ARM裸机加强版 ]] | [[Category:ARM裸机加强版 ]] | ||
+ | [[Category:Jz2440 ]] | ||
+ | [[Category:SDRAM]] |
2019年12月20日 (五) 15:39的最新版本
目录
第001节_辅线1_硬件知识_内存接口概念
首先来分析下操作GPIO控制器和操作UART控制器两者的区别。
如图是S3C2440是个片上系统,有GPIO控制器(接有GPIO管脚),有串口控制器 (接有TXD RXD引脚)。
配置GPIO控制器相应的寄存器,即可让引脚输出高低电平;配置UART控制器相应的寄存器,即可让引脚输出波形。前者相对简单,类似门电路,后者相对复杂,属于协议类接口。类似的协议类接口还有iic、iis、spi等。
对于CPU是不管什么接口的,它只写相应的寄存器,由控制器根据寄存器的配置去控制具体的引脚。
那么CPU是如何访问各个不同的寄存器的呢?
CPU只管发出一个地址,内存控制器根据该地址选择不同的模块,然后从模块中得到数据或者发送数据到模块中。
前面的GPIO/门电路接口、协议类接口,都不会把地址输出到外部,接下来的内存类接口,会把地址输出到外部,比如Nor Flash、网卡、SDRAM。
如图,SDRAM、DM9000网卡、Nor Flash都接在JZ2440的数据总线和地址总线上,CPU把数据和地址发送出去,然后内存控制器根据片选信号选择相应的设备接收地址和数据信号,互不干扰。
片选信号和地址的关系怎么确定?
- 当选择Nor Flash启动时,CPU发出的指令的地址范围处于0x0000000 - 0x08000000,内存控制器就会使nGCS0处于低电平(片选引脚被选中),Nor Flash被选中。
- 当CPU发出的指令的地址范围处于0x20000000 - 0x28000000,内存控制器就会使nGCS4处于低电平(片选引脚被选中),网卡被选中。
- 当CPU发出的指令的地址范围处于0x30000000 - 0x38000000,内存控制器就会使nGCS6处于低电平(片选引脚被选中),SDRAM被选中。
内存控制器根据不同的地址地址范围,发出不同的片选引脚,只有被片选引脚选中的芯片才能正常工作,不被选中的芯片就像不存在一样,不工作。
GPIO/门电路接口、协议类接口、内存类接口都属于CPU的统一编址。对于Nand Flash,在原理图上它的地址线并没有连接到CPU,因此它不参与CPU的统一编址。但它的数据线也接到了数据总线上,为了防止干扰,它也有一个片选信号(CE)。当CPU访问Nand Flash时,Nand Flash控制器才会片选Nand Flash,让其接收数据总线上的数据。
再来看下Nor Flash的空间,0x00000000 * 0x08000000,为128M,即每一个片选信号可以选择的空间是128M=2^27,也就需要A0、A1……A26,共27根地址线。CPU发出的32位地址线,内存控制器根据地址范围,片选上相应的bank,并将地址转化为27位。
第002节_辅线1_硬件知识_不同位宽设备的连接
参考2440芯片手册,可以看到内存接口与8-bit ROM连接时,2440的A0与外部芯片的A0相连。
当与两个8-bit ROM拼接成的一个16-bit ROM连接时,2440的A1与外部芯片的A0相连。
当与四个8-bit ROM拼接成的一个32-bit ROM连接时,2440的A2与外部芯片的A0相连。
当与一个16-bit ROM连接时,2440的A1与外部芯片的A0相连。
可以看出外接芯片的位宽有变化时,地址线的接法也会有变化。那这个变化有什么规律呢?
假设CUP执行:
MOV R0, #3 @去地址为3的内存上 LDRB R1, [R0] @ 从内存为3的地址上,读出一个字节
8个bit组成一个字节,字节是计算机的最小的存储单位,因此我们读取数据肯定都是8bit的倍数。
- 对于8bitROM ,8bit是一次读写的最小单位,即0地址是第一个8bit,1地址是第二个8bit;CPU发出的命令是读取地址为3上的数据,即A0和A1都为1,8bitROM的A0和A1收到的也都是1,于是找到了ROM上地址为3的8bit数据,包含了我们需要的数据。
- 对于16bitROM ,16bit是一次读写的最小单位,即0地址是第一个16bit,里面有两个8bit数据;CPU发出的命令是读取地址为3上的数据,即A0和A1都为1,16bitROM的A0和A1分别收到的是1和0,于是找到了ROM上地址为1的16bit数据,包含了我们需要的数据,最后内存控制器再帮我们挑选出所需的8bit数据。
- 对于32bitROM ,32bit是一次读写的最小单位,即0地址是第一个32bit,里面有四个8bit数据;CPU发出的命令是读取地址为3上的数据,即A0和A1都为0,32bitROM的A0和A1收到的都是0,于是找到了ROM上地址为0的32bit数据,包含了我们需要的数据,最后内存控制器再帮我们挑选出所需的8bit数据。
ROM/bit | CPU发出地址 | ROM收到地址 | ROM返回数据 | 内存控制器挑选出数据给CPU |
---|---|---|---|---|
8bit(ROM) | 000011 | 000011 | 编号3的存储单元中的8数据 | 编号3的存储单元中的8bit数据 |
16bit(ROM) | 000011 | 000001 | 编号1的存储单元中的16数据 | 根据”A0=1”,挑出低8bit数据 |
32bit(ROM) | 000011 | 000000 | 编号0的存储单元中的32数据 | 根据“A0A1=11”,挑出最低8bit数据 |
接到芯片上的引脚用来确定读取芯片上的哪一个单元的数据,把这个单元的数据返回给内存控制器,内存控制器会根据没有连接芯片的引脚,来确定返回哪一个单元的数据给CPU,
再举一个例子: 假如传递一个32位的数据时
MOV R0, #4 LDR R1, [R0] @去地址4,读取4字节数据
执行过程如下:
- 8bitROM: 当CPU发出地址(000100),内存控制器会把000100,000101,000110,000111处的地址转发给ROM,ROM会把得到的地址000100,000101,000110,000111,上的数据返回给内存控制器,内存控制器会把得到的4个8bit的数据组装成一个32位的数据返回给CPU。
- 16bitROM: 当CPU发出地址(000100),内存控制器会把00010,00011处的地址转发给ROM,ROM会把得到的地址00010,00011,上的数据返回给内存控制器,内存控制器会把得到的2个16bit的数据组装成一个32位的数据返回给CPU。
- 32bitROM: 当CPU发出地址(000100),内存控制器会把0001处的地址发送给ROM,ROM会把得到的地址0001上的数据返回给内存控制器,内存控制器会把得到的1个32bit数据返回给CPU。
怎样确定芯片的访问地址: 1. 根据片选信号确定基地址, 2. 根据芯片所接地址线确定范围
实例: Nor Flash 使用的是片选0(nGCS0),基地址为0,用到A20,A19......A1,A0共21条地址线,所以地址范围为0x00000000 ~ 0x1FFFFF也就是2M的空间大小。 网卡(Net)使用的是片选4(nGCS4),基地址为0x20000000,用到A2,A0共2根地址线,所以地址范围为0x20000000 ~ 0x20000005。 SDRAM使用的是片选6(nGCS6),基地址为0x30000000。
- | Nor Flash | Net | |
---|---|---|---|
基地址(base) | 0x00000000 | 0x20000000 | 0x30000000 |
取址范围 | 0x00000000~0x1FFFFF | 0x20000000~0x20000005 | 比较特殊,后面讲解 |
第003节_辅线1_硬件知识_时序图分析示例
这节我们分析一下我们了解时序图,信号之间是怎样一起工作的,以Nor Flash 为例。
2440和Nor Flash 之间有地址线,数据线,还有各种数据线连接。
如图是S3C2440的Nor Flash控制器的读时序图,里面很多参数都需要根据外接芯片的性能进行设置,有的芯片性能好、响应时间快,就可以把参数时间设置小一点,释放更好的性能。
如图是Nor Flash芯片的读时序。
我们需要做的就是设置S3C2440的Nor Flash控制器时序去满足Nor Flash芯片的时序。每个参数的参考范围可以通过AC CHARACTERISTICS得到。
结合Nor Flash芯片的两张图,可以得到如下信息:
- 发出地址数据(Addresses)后,要等待Taa(要求大于等于70ns)时间,地址数据才有效;
- 发出片选信号(CE#)后,要等待Tce(要求大于等于70ns)时间,片选信号才有效;
- 发出读信号(OE#)后要等待Toe(要求大于等于30ns)时间,读信号才有效;
为了简单我们把地址数据(Addresses),片选信号(CE#),读信号(OE#),同时发出,然后让它们都等待70ns(等待信号有效)。对应S3C2440的Nor Flash控制器的读时序图,需要让地址信号A[24:0]、片选信号nGCS、读信号nOE同时发出,保持Tacc大于等于70ns。
查阅S3C2240的参考手册,Nor Flash是接在BANKCON0上的,因此只需要设置BANKCON0即可。
可以看到Tacc上电初始值是111,对应14个clocks。系统上电采用12MHz的晶振,HCLK=12MHz,Tacc=(1000/12*14)≈1166ns,这个值很大,几乎可以满足所有Nor Flash的要求。
启动后,将HCLK设置为100MHz,T=1000/100=10ns,Tacc需要大于等于70ns,因此设置Tacc等于101,8个clocks即可。
在前面uart实验的源码基础上,新建init.c和init.h两个文件。
在init.c里面只需要设置BANKCON0寄存器即可。
#include "s3c2440_soc.h"
void bank0_tacc_set(int val)
{
BANKCON0 = val << 8;
}
init.h进行函数声明。
#ifndef _INIT_H
#define _INIT_H
void bank0_tacc_set(int val);
#endif
最后在主函数里面,通过串口获取输入的值,传入bank0_tacc_set()函数里,设置Tacc,然后再读取Nor Flash上的闪灯程序。
#include "s3c2440_soc.h"
#include "uart.h"
#include "init.h"
int main(void)
{
unsigned char c;
uart0_init();
puts("Enter the Tacc val: \n\r");
while(1)
{
c = getchar();
putchar(c);
if (c >= '0' && c <= '7')
{
bank0_tacc_set(c - '0');
led_test();
}
else
{
puts("Error, val should between 0~7\n\r");
puts("Enter the Tacc val: \n\r");
}
}
return 0;
}
实验效果:
输入0~4,Tacc小于70ns,无法读取Nor Flash上数据,LED不能闪烁。
输入4~7,Tacc大于70ns,可以读取Nor Flash上数据,LED不断闪烁,且值越小越快(区别不明显)。
第004节_辅线1_硬件知识_SDRAM的设置
本节将讲解如何设置SDRAM,如果想对内存有更多的了解,可以在网上搜索看下这篇文档“高手进阶_终极内存技术指南——完整/进阶版”。
在JZ2440上接有64M的SDRAM,如果想要使用SDRAM,需要对内存控制器做一些设置。 在前面第一节讲到,CPU将数据或地址发给内存控制器,内存控制器再去访问外部的SDRAM,因此设置内存控制器就说本节的核心。
如图是SDRAM存储结构逻辑图:
SDRAM总共有4个块(Banks),可以认为每个块就是一个表格,里面的每个格子表示的是16bit数据。
- 问题1:怎样访问里面的某个格子呢?
1. 首先发出一个片选信号,选中整个芯片;
2. 发出Bank地址,选择是哪一个Bank(块,即表格);
3. 发出行地址;
4. 最后发出列地址,才能选中是个格子;
- 问题2:那么多的信号有谁发出呢?
由内存控制器发出,所以我们需要设置内存控制器,CPU只是简单的执行读写内存的命令,其他的都交给内存控制起来处理。 例如
LDR R0,=0x30000000 LDR R1,[R0]
1. CPU把0x30000000这个地址发给内存控制器,内存控制器根据这个地址,判断属于哪个范围,然后发出相应的片选信号。
2. 根据类型(比如SDRAM)拆分成三部分:发出Bank地址、发出行地址、发出列地址。
对于上面的三个,怎样拆分呢?
行地址线有几条,列地址线有几条,都要设置内存控制器里面相关寄存器。
3. 读数据
综上所述:对SDRAM的访问可以分为如下步:
1. CPU发出的片选信号nSCS6有效,它选中SDRAM芯片。
2. SDRAM中有4个L-Bank,需要两根地址信号来选中其中之一,根据原理图,可知使用ADDR24,ADDR25作为L-Bank的选择信号。
3. 对被选中的芯片进行统一的行/列(存储单元)寻址。
根据SDRAM芯片的列地址线数目设置CPU的相关寄存器后,CPU就会从32位的地址中自动分出L_Bank片选信号,行地址信号,列地址信号,然后先后发出行地址信号,列地址信号。L_Bank选择信号在发出行地址信号的同时发出,并维持到列地址信号结束。
根据原理图可知:
地址、列地址共用地线ADDR2—ADDRI4(BANK6位宽为32,ADDRO/I没有使用),使用nSRAS、nSCAS两个信号来区分它们。
比如本开发板中,使用两根地址线ADDR24、ADDR25作为L-Bank的选择信号:SDRAM芯片K4s5m632的行地址数为13,列地址数为9,所以当nSRAS信号有时,ADDR2—ADDR14上发出是行地址信号,它对应32位地址空间的b可23m]:当nSCAS信号有效时,ADDR2—ADDR10上发出的是列地址信号,它对应32位地址空间的bit[0:2];由于BANK6以32位的宽度外接DRAM,ADDR0、ADDR1恒为0,不参与译码。
4. 找到了存储单元后,被选中的芯片就要进行统一的数据传输了。
开发板中使用两片16位的SDRAM芯片并联组成32位的位宽,与CPU的32根数据线(DATA0—DATA31)相连。 BANK6的起始地址为0x30000000,所以SDRAM的访问地址为0x30000000~低0x33FFFFFF,共64MB。
2440内存控制器设置:
内存控制器共有13个寄存器,
BANK0--BANK5只需要设置BWSCON和BANKCONx(x为0~5)两个寄存器;
BANK6、BANK7外接SDRAM时,除BWSCON和BANKCONx(x为6、7)外,还要设置REFRESH、BANKSIZE、MRSRB6、MRSRB7等4个寄存器。
下面分类说明各个寄存起的设置。
- 1. 位宽和等待控制寄存器BWSCON(BUSWIDTH&WAITCONTROLREGISTER)
BWSCON中每4位控制一个BANK,最高4位对应BANK7(没有使用)、接下来4位对应BANK6。
(1)ST6[27]: 启动/禁止SDRAM的数据掩码引脚,对于SDRAM,此位为0:对于SRAM此位为1。
(2)WS6[26]:是否使用存储器的WAIT信号,通常设为0。
(3)DW6[25:24]:使用两位来设置相应BANK的位宽,0b00对应8位,0b01对应16位,0b10对应32位(开发板用的就是32位的),0b11表示保留。
因此BWSCON寄存器的值为:0x22000000。
- 2. BANK控制寄存器BANKCON6(BANKCONTROLREGISTER)
在8个BANK中,只有BANK6和BANK7可以外接SRAM或SDRAM。
(1)MT[16:15]:用于设置本BANK外接的是ROM/SRAM还是SDRAM,SRAM:0b00,SDRAM:0b11(开发板使用的是SDRAM)。
当MT[16:15]设置为00时,此寄存器与BANKC0N0、BANKCON5类似,不再赘述。
(2)Trcd[3:2]:行地址和列地址间隔多长时间,看芯片手册时间间隔是20ns,本来开发板的HCLK是100MHZ,clocks为10ns,所以设置为推荐值0b00(2clocks)。
(3)SCAN[1:0]:SDRAM的列地址位数,对于本开发板使用的SDRAMK4S561632。列地址位数为9,所以SCAN=0b010如果使用其他型号的SDRAM,需要查看其数据手册。来决定SCAN的取值。0b00表示8位,0b01表示9位,0b10表示10位。
综上所述,本开发板中BANKCON6设为0x018001。
- 3. 刷新控制寄存器REFRESH(REFRESHCONTROLREGISTER)
(1)REFEN[23]:0=禁止SDRAM的刷新功能,1:开启SDRAM的刷新功能(设置开启SDRAM的刷新功能)。
(2)TREFMD[22]:SDRAM的刷新模式,0=CBR/AutoRefresh,1=SelfRefresh(一般在系统休眠时使用),我们设置默认值。
(3)Trp[21:20):根据芯片手册设为0即可。
(4)Tsrc[19:18]:根据芯片手册设为默认值0b01即可。
(5)RefreshCounter[10:0]:即R_CNT
R_CNT可如下汁算(SDRAM时钟频率就是HCLK):
R_CNT=2^11+1-SDRAM时钟频率(MZ)*SDRAM刷新周期(us)
SDRAM的刷新周期在SDRAM的数据手册上有标明,在本开发板使用的SDRAM:K4S561632的数据手册上,可看见这么一行“64msrefreshpenod(8KCycle)所以,刷新周期=64ms/8192=7.8125us。
Refreshcount=2^11+1-100x7.8=1269=0x4F5。
因此,本开发板中REFRESH设为0x8404F5。
- 4. BANKSIZE寄存器REFRESH(BANKSIZEREG ISTER)
(1)BURST_EN[7]:0=ARM核禁上突发传输,1=ARM核支持突发传输(推荐);
(2)SCKEEN[5]:0=不使用SCKE信号令SDRAM进入省电模式,1=使用SCKE信号令SDRAM进入省电模式(推荐);
(3)SCLK-EN[4]:0=时刻发出SCLK信号,1=仅在访问SDRAM期间发出SCLK信号(推荐);
(4)BK76MAP[2:0]:设置BANK6的大小。本开发板BANK6外接64MB的SDRAM,令[2:0]=b001(64M/64M),表示BANK6/7的容量都是64MB,虽然BANK7没有使用。
因此,本开发板中BANKSIZE设为0xB1。
- 5. SDRAM模式设置寄存器MRSRBx6(SDRAM MODE REGISTER SET REGISTER)
能修改的只有位CL[6:4],这是SDRAM时序的一个时间参数,表示发出行、列地址后,等多久才返回收到数据, CL可以取值为0b0l0(2 clocks)或0b011(3 clocks)。
本开发板取最保守的值0b010,所以MRSRB6的值为0x20。
下面开始写程序:
在init.c里面进行对内存控制器的寄存器依次进行设置:
void sdram_init(void)
{
BWSCON = 0x22000000;
BANKCON6 = 0x17001;
BANKCON7 = 0x17001;
REFRESH = 0x8404f5;
BANKSIZE = 0xb1;
MRSRB6 = 0x20;
MRSRB7 = 0x20;
}
再写一个测试函数,向SDRAM里面连续写1000个数,再读出数据对比是否是设置的数,返回对比结果:
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;
}
在主函数里调用sdram_test()测试函数,如果测试成功,LED闪烁:
int main(void)
{
uart0_init();
sdram_init();
if (sdram_test() == 0)
led_test();
return 0;
}
实验结果:
LED按预期闪烁,屏蔽掉sdram_init()后,LED不闪烁。