注:以下内容学习于韦东山老师arm裸机第一期视频教程
一.内存接口介绍
1.1 内存控制器的引入
2440是一个SOC,其中外设分为多种类型
1. 门电路类:GPIO
2. 协议类接口: UART I2C SPI
但是对于CPU来说只需要将值写给寄存器,CPU通过地址来区分不同的寄存器,因此就会引入另一个控制单元->内存控制器
1.2 内存控制器的作用
1.2.1 根据CPU发出的地址来选择不同的模块,把数据发送给模块,或者取出数据并且返回给CPU
1.3 内存接口
1.3.1 CPU发出的信号并不会直接输出到外部电路去,但是凡事都有例外,例如内存接口
1.3.2 对于内存接口,CPU发出的地址可以直接传给内存类设备(NOR,网卡,内存)
1.3.3 在内存芯片上有地址总线,数据总线,可以直接接收CPU发出的地址,数据
1.3.4 对于内存类设备会共用地址总线,因此引入片选引脚cs
只有当某个片选引脚输出低电平是对应的设备才被选中,可以向CPU提供数据
1.3.5 谁来控制片选引脚?(CPU只发出地址信号)
内存控制器根据CPU发出的地址来决定发出不同的片选信号.
地址与片选信号关系如下图:
1.3.6 如何确定数据传输方向
对于SDRAM、DM9000、NOR芯片上都有读写信号来表示数据传输方向
1.3.7 关于32位CPU的疑惑
其中每块地址范围为128M=2^27,因此至少需要A0,A1-A26,共27条地址线
但是cpu是32位的,却只用了27条地址线?
如下:
ldr r0, =addr ldr r1, =val str r1, [r0]
会让CPU发出32位的addr给内存控制器,内存控制器再来发出片选信号和addr0-addr26的地址信号
CPU确实发出了32位的地址,但是内存控制器只用到了0-26
1.3.8 特殊的NAND
对于GPIO、UART、I2C、SDRAM、DM9000、NOR都是CPU统一编制的,但是对于NAND原理图如下:
并没有地址总线,不属于CPU的统一编址,
但是Nand的数据信号仍然接到总线上,因此肯定会有片选信号,NAND的片选信号来自于NAND FLASH控制器发出
二.不同位宽设备的连接
2.1 SDRAM,NOR,DM9000网卡地址总线的连接如下图
SDRAM:
A0接ADDR2
A1接ADDR3...
NOR:
A0接ADDR1
A1接ADDR2...
DM9000:
只接了ADDR2
在2440芯片手册中提供了如下示例:
当使用一个8位的芯片时,CPU的A0接芯片的A0
当使用两个8位的芯片拼接(DATA0-7接一个芯片,DATA8-15接一个芯片,也就是组成了一个16位的芯片)的时候,CPU的A1接芯片的A0
当使用四个8位的芯片拼接(也就是组成了一个32位的芯片)的时候,CPU的A2接芯片的A0
2.2 不同位宽设备不同接法的详解
对于8位的ROM,里面的数据以8位为最小数据保存
对于16位的ROM,里面的数据以16位为最小数据保存,可以拆分为2个字节
对于32位的ROM,里面的数据以32位为最小数据保存,可以拆分为4个字节
2.2.1 假设CPU执行
mov R0, #3
ldrb R1, [R0] /* 读地址3的一个字节 */
CPU会将地址3发送出去,使得A0 = 1, A1 = 1, A2 = 0....
对于8bit的ROM,由于A0-A0,A1-A1,因此收到了0x3地址,就会去第三个最小单元读取,成功的读到了第三个byte
对于16位的ROM,由于A1-A0,A2-A1,因此收到了0x1地址,就会去第一个最小单元读取,读取到了16bit的数据,里面包含了我们想要的数据(芯片收到的地址 = CPU发出的地址 >> 1,即除以2, 16 / 2 = 8)
对于32位的ROM,由于A2-A0,A3-A1,因此收到了0x0地址,就回去第0个最小单元读取,读到了32bit的数据,里面包含了我们想要的数据(芯片收到的地址 = CPU发出的地址 >> 2,即除以4,32 / 4 = 8)
然后将数据发送给内存控制器,由内存控制器帮助跳出来需要得到的数据(根据未接的数据线来挑选).
对于16位,根据A0=1,从得到的数据中挑出第一个字节
对于32位,根据A0=1,A1=1,从得到的数据中挑出第三个字节
2.2.2 假设CPU执行
mov R0, #4
ldr R1, [R0] /* 读地址4的4个字节 */
CPU会将地址4发送出去,使得A0 = 0,A1 = 0,A2 = 1,A3 = 0....
对于8bit的ROM,发现需要读取4个字节,因此会发送4个地址给ROM,收到了0x4,0x5,0x6,0x7地址,将第4,5,6,7单元的数据发送给内存控制器,内存控制器进行组装发送给CPU
对于16bit的ROM,发现需要读取4个字节,因此会发送2个地址给ROM,收到了0x2,0x3地址,将第2,3单元的数据(也对应第4,5,6,7字节)发送给内存控制器,内存控制器进行组装发送给CPU
对于32bit的ROM,发现需要读取4个字节,因此会发送1个地址给ROM,收到了0x1地址,将第1单元的数据(也对应第4,5,6,7字节)发送给内存控制器,内存控制器直接发送给CPU
注意:在发送多个地址的时候是内存控制器来发送多个地址,CPU只会发出一个地址0001
2.3 怎么确定芯片的访问地址?
2.3.1 根据片选信号来确定基地址
2.3.2 根据连接的地址线来确定范围
NOR使用片选0,因此基地址等于0,会使用A0-A20,因此范围为 0-2^21 = 2M
网卡使用片选4,因此基地址等于0x20000000,只接了ADDR2,会用A0来分辨数据是低8位还是高8位(16位芯片),使用了A0 A2,因此范围 0x20000000 - 0x20000005
SDRAM使用片选6,因此基地址等于0x400000001,接了A2-A14,A24,A25,A0,A1只有17跟,大小为128K
但是SDRAM比较特殊,在访问的时候发出的地址信号分为列地址和行地址,也就是在访问的时候先发出行地址/列地址,在发出列地址/行地址(具体以后再讲)
三.时序图分析示例
3.1 以NOR为例,分析各种信号时如何工作的,NOR的原理图如下:
有地址信号,数据信号,片选信号,读信号,写信号,这些信号如何协同工作?
3.2 2440读时序图如下:
3.2.1 首先发出地址信号,经过Tacs时间发出片选信号,再经过Tcos时间发出读信号,过一会数据有效,然后释放掉读信号,片选信号
3.2.2 Tacs,Tcos,Tacc,Tacp等等的时间需要根据不同的芯片来进行不同的设置
3.3 NOR读操作时序图如下
3.4 NOR时序要求图
3.4.1 Taa->发出地址信号后经过多长时间能够访问数据,最大设置为70ns
(不同型号可能经过不同的时间才能够访问数据,但是经过70ns之后都可以访问,这就是"最大"的含义)
3.4.2 Tce->片选信号后经过多长时间数据有效,最大设置为70ns
3.4.3 Toe->数据在读信号之后多长时间数据有效,最大设置为30ns
3.4.4 Toh->数据保持时间,最小设置为0
3.4.5 Tdf->在这段时间,不能访问其他芯片,如果访问NOR会影响你的数据,最大设置为30ns
3.4.6 Trc->读周期时间(NOR每读一次消耗的时间),最小设置为70ns,对应2440手册上的Tacc
3.5 结合2440的读时序图与NOR读操作时序图对参数进行设置
为简单,设置地址信号,片选信号,读信号同时发出,设置Tacc >= 70ns
3.6 NOR使用片选0,因此我们要设置BANKCON0寄存器
3.6.1 设置BANKCON0
注意上电时Tacc的默认值是111,代表14个clocks,刚上电使用12M晶振,因此Tacc = 14 * 12000000 = 116ns,可以兼容各种类型的NOR
在设置完时钟之后,HCLK=100MHZ = 10ns,Tacc >= 70ns = 7个clock,因此可以设置为8个clock即101
3.6.2 设置BWSCON,如下
NOR接在BANK0上面,只需要设置bit[2:1],bit[2:1]是只读的表示外接的NOR是多少位的,因此不需要设置.
四.设置NOR的Tacc来提高性能
/* main.c */ #include "my_printf.h" #include "uart.h" #include "SetTacc.h" int main() { char c; Uart0Init(); puts("Enter the value of tacc:"); while (1) { c = getchar(); if(c == '\n') putchar('\r'); if(c == '\r') putchar('\n'); putchar(c); /* 回显输入语句 */ if (c >= '0' && c <= '7') SetTacc(c - '0'); /* 根据输入设置Tacc的值,当输入0-4时Tacc<8clock,程序无法工作 */ else printf("Error val,tacc should betwen 0-7"); } return 0; } /* SetTacc.c */ #include "s3c2440_soc.h" void SetTacc(int val) { BANKCON0 = val << 8; }