前面写完代码后,直接送到车间就可以运行。ARM是流水线工作,内存只是存放代码的场所,那么CPU是如何跟内存打交道的呢?(计算机组成原理知识)
组成原理很理论的描述了它们之间的关系。但是并没有针对ARM做分析。其实只需要搞懂下面几个问题:
① 内存如何存放程序(摆放)
② CPU如何访问内存(读写)
Ⅰ、CPU与外设的藕断丝连
芯片结构图:
CPU不会直接与外设打交道,它只管发指令,中间还隔了一个内存控制器(秘书),秘书会将CPU指令发到合适的控制器上,例如:GPIO控制器负责控制引脚的输入输出。SDRAM等由于是内存,所以直接接收内存控制器发出的命令。咦?会不会画错呢,为什么SDRAM等于nandflash不同呢,是的,nandflash虽然是存储器,但是它不参与CPU统一编址。
自问自答:
内存控制器如何管理这些接口呢?这个跟芯片特性有关。
图中分为程序使用nandflash和程序不使用nandflash的内存映射
当选择Nor Flash启动时,CPU发出的指令的地址范围处于0x0000000 - 0x06000000,内存控制器就会使nGCS0处于低电平(片选引脚被选中),Nor Flash被选中。
当CPU发出的指令的地址范围处于0x20000000 - 0x26000000,内存控制器就会使nGCS4处于低电平(片选引脚被选中),网卡被选中。
当CPU发出的指令的地址范围处于0x30000000 - 0x36000000,内存控制器就会使nGCS6处于低电平(片选引脚被选中),SDRAM被选中。
内存控制器根据不同的地址地址范围,发出不同的片选引脚,只有被片选引脚选中的芯片才能正常工作,不被选中的芯片就像不存在一样,不工作。
GPIO/门电路接口、协议类接口、内存类接口都属于CPU的统一编址。对于Nand Flash,在原理图上它的地址线并没有连接到CPU,因此它不参与CPU的统一编址。但它的数据线也接到了数据总线上,为了防止干扰,它也有一个片选信号(CE)。当CPU访问Nand Flash时,Nand Flash控制器才会片选Nand Flash,让其接收数据总线上的数据。
关于内存与CPU关系的理论知识就谈这么多,还是从实践中学习吧!!!
Ⅱ、原理图
内存与芯片之间又该如何连线呢?
看到没有,仅一个norflash就需要这么多地址线,这个地址线跟内存大小有关。还有其它的内存模块,它们也是需要地址线的。所以设置内存控制器不是没有道理的。
Ⅱ、芯片手册
光知道怎么连线时没有任何鸟用的,如何用起来才是关键。对于这种有芯片手册的,需要看外设本身的手册,还有看处理器的手册。
看外设本身的手册时为了确定命令时序,如何读写都是在这个里面规定的。
看处理器手册是确定哪些寄存器来控制时序。
norflash读时序
处理器时序产生图
这两个图怎样理解呢?
处理器给出的时序图是通用的时序图,具体要操作哪个外设需要根据外设给出的时间特性来设置其中对应的值。
表格描述了各个时间参数的意义。
trc表示在地址发出多长时间后数据有效,也就是说,发出地址数据后需要等待70ns以上
结合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即可。
Ⅲ、编程
代码很简单
#include "s3c2440_soc.h"
void bank0_tacc_set(int val)
{
BANKCON0 = val << 8;
}
#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;
}