跟着韦老师学Linux学习笔记(四)-Nand Flash
之前我们学习涉及的外设,一般都是有数据总线、地址总线以及便旋信号,但是今天我们使用的Nand Flash是只有数据总线和控制信号,没有地址总线,那我们该如何使用它呢?
(1)、硬件部分
首先我们先了解一下,Nand Flash的存储结构,如下图:
NandFlash在存储时,最小单位是一页(2k存储空间+64Bytes的OOB空间),64页组成一块(128K存储空间+4k的OOB空间),设备总共有2048个块,总容量是(128K+4K)*2048=2112Mbits。并且,我们在对Nand进行寻址时,一般情况下,我们只对每一页的前2k进行连续寻址,而忽略OOB的寻址空间。
正如开始时说的Nand Flash是没有地址总线,但是,他是有很多条控制信号线的如下图。
其中: RnB:检测当前设备是否忙的信号,如果不忙则我们可以使用它。
CLE:命令信号控制线,表示我们发出的是命令。
nFCE: 片选信号线。
ALE:地址信号线,表示我们发出的信号是地址。
nFEW:写使能信号,表示我们要对Nand进行写数据、地址或命令。
NFRE:读使能信号,表示我们要对Nand进行读数据
因此,我们只要控制上述信号线,通过I/o0~I/O7,进行命令、地址和数据的读写,就可以操作Nand Flash了。
那么如何对Nand Flash进行寻址呢?如下图:
我们要想访问一个地址,需要连续5个地址信号给Nand Flash,其中两个列信号,三个行信号。*L:低电平。
控制信号有了,地址也有了,我们还需要发送命令,才能设置进行操作。如下图:
操作Nand Flash时,我们首先需要传输命令(读、写、擦除或者其他),然后发送相应的地址,最后是数据的读写,中间还要检查Flash的状态是否繁忙。
相应的控制寄存器介绍:
a、 NFCONF:Nand Flash的配置寄存器
主要用来设置Nand Flash的时序参数TACLS、TWRPH0、TWRPH1,设置数据位宽,还有一些只读位,用来指示是否支持其他大小的页。
b、 NFCONT:Nand Flash控制寄存器
用于使能/禁止Nand Flash,使能/禁止控制引脚信号nFCE、初始化ECC。
c、 NFCMD:Nand Flash命令寄存器
d、 NFADDR:Nand Flash地址寄存器
e、 NFDATA:Nand Flash数据寄存器
f、 NFSTAT:Nand Flash状态寄存器
(二)程序设计:
本节程序只是对Nand Flash进行数据的读操作。流程图如下:
程序代码:
1 firtst 0x00000000 : { head.o init.o nand.o} 2 second 0x30000000 : AT(4096) { main.o }
首先为了方便测试程序,我们把要执行的主函数放在了地址空间4096以后了,程序的运行地址在0x30000000。
基于本节内容,主要对Nand Flash部分的程序进行分析:
首先我们要初始化Nand Flash,
1 nand_chip.nand_reset = s3c2440_nand_reset; 2 nand_chip.wait_idle = s3c2440_wait_idle; 3 nand_chip.nand_select_chip = s3c2440_nand_select_chip; 4 nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip; 5 nand_chip.write_cmd = s3c2440_write_cmd; 6 nand_chip.write_addr = s3c2440_write_addr; 7 nand_chip.read_data = s3c2440_read_data; 8 /* 设置时序 */ 9 s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); 10 /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ 11 s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
主要实现了Nand Flash的片选、复位、等待、读写的操作。
然后就是按照流程图进行多Nand Flash的读操作了
1 /* 读函数 */ 2 void nand_read(unsigned char *buf, unsigned long start_addr, int size) 3 { 4 int i, j; 5 6 #ifdef LARGER_NAND_PAGE 7 if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) { 8 return ; /* 地址或长度不对齐 */ 9 } 10 #else 11 if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { 12 return ; /* 地址或长度不对齐 */ 13 } 14 #endif 15 16 /* 选中芯片 */ 17 nand_select_chip(); 18 19 for(i=start_addr; i < (start_addr + size);) { 20 /* 发出READ0命令 */ 21 write_cmd(0); 22 23 /* Write Address */ 24 write_addr(i); 25 #ifdef LARGER_NAND_PAGE 26 write_cmd(0x30); 27 #endif 28 wait_idle(); 29 30 #ifdef LARGER_NAND_PAGE 31 for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) { 32 #else 33 for(j=0; j < NAND_SECTOR_SIZE; j++, i++) { 34 #endif 35 *buf = read_data(); 36 buf++; 37 } 38 } 39 40 /* 取消片选信号 */ 41 nand_deselect_chip(); 42 43 return ; 44 }
最后,下载调试。