嵌入式linux第五课之Nand Flash控制器

本节课的主要内容如下:
NAND Flash访问原理

  1. 地址空间概念
  2. NAND的编址
  3. NAND的命令
  4. 使用S3C2440的NAND Flash控制器访问NAND Flash

地址空间概念

NAND Flash有数据总线,没有地址总线。
内存的地址总线直接接2440发出来的地址总线上去。
网卡的地址总线也是跟2440的地址总线直接相连。

因此,SDRAM,DM9000(网卡)接到2440的地址总线上去了。
Nand Flash没有接到2440的地址总线。

结论:Nand Flash与其他两种的寻址方式是不一样的。另外两种的地址是CPU可见的或者成为CPU统一编址的。SDRAM的地址是0x30000000-0x34000000,片内RAM的内存是0-4094(4k),寄存器,DM9000,这些都有一块地址,这些是CPU统一的编址空间。
Nand Flash有256M,而Nand Flash的编址空间时独立于CPU之外的,与上面讲到的地址不同。

NAND的编址

NAND Flash的原理图如下图所示:
在这里插入图片描述
如果通过数据线来实现数据线和地址线的共用,这就需要用到控制信号。
我们用的是大页的空间,大页空间为2k,还有个OOB的区域,该区域有64字节,64页组成一块。故一页的大小为2048+64,64字节不参与寻址,即访问2049的地址时,访问的是第一页的第二个字节。
在这里插入图片描述
如何访问内存:
发出地址,传送数据
如何访问Nand:
先发出命令(命令有发送数据,读命令),再发出地址,在传输数据
命令代码如下:
在这里插入图片描述
控制信号的发出由寄存器开控制:

  1. 想发出命令时,只需要往NFCMMD寄存器写入值,2440就会自动控制命令引脚将命令发给NAND Flash。
  2. 想操作地址时,只需要将地址写入NFADDR寄存器就可以了。
  3. 读和写数据都是NFADATA寄存器来完成。

从硬件上访问Nand:

  1. 发出命令,涉及CLE引脚,还要将命令发送到数据总线上去
  2. 发出地址,发出ALE地址锁存信号,再将将地址发送到地址总线上去
  3. 传输数据,由引脚控制读写

2440精简了这些东西:

  1. 发出命令,把命令写进NFMMD寄存器就行
  2. 操作地址,NFADDR寄存器
  3. 读写数据,NFADATA寄存器
  4. 状态,NFSTA ,擦除之后才能写,擦除时要等一会才能写,这是就要涉及状态

下面为makefile的内容,依赖的文件是head.o init.o nand.o main.o


nand.bin : $(objs)
   arm-linux-ld -Tnand.lds	-o nand_elf $^
   arm-linux-objcopy -O binary -S nand_elf $@
   arm-linux-objdump -D -m arm  nand_elf > nand.dis

%.o:%.c
   arm-linux-gcc -Wall -c -O2 -o $@ $<

%.o:%.S
   arm-linux-gcc -Wall -c -O2 -o $@ $<

clean:
   rm -f  nand.dis nand.bin nand_elf *.o

再来看一下nand.lds这个链接脚本,该脚本的意思是从0地址开始分别写head.o init.o nand.o的程序,然后再4096的地方放main的函数。运行时,第一段的内容应该在0地址运行,而第二段的内容则应该在0x30000000的地址处执行,“应该”这字很关键,运行时应该把程序放在0x30000000的链接地址上去。

SECTIONS { 
  firtst  	0x00000000 : { head.o init.o nand.o}
  second 	0x30000000 : AT(4096) { main.o }
} 

该实验程序的过程以及目的(感觉和SDRAM的实验很像):

  1. Nand Flash里面的内容是:从0地址开始放head.o init.o nand.o,在4096地址放main.o。
  2. 上电时会自动把0-4k的内容,即head.o init.o nand.o的内容拷贝到片内RAM中。
  3. 运行片内RAM的内容,该内容有关看门狗,初始化SDRAM,其实地址为0x30000000。
  4. 片内RAM的代码还要将Nand Flash里面4096地址开始的main.o的内容拷贝到SDRAM里面去。
  5. 通过给pc赋值将运行地址转移到SDRAM里面去,main的函数是点灯函数,当灯亮是说明程序运行成功。

该实验过程与之前SDRAM实验的区别,之前没有对Nand Flash进行初始化,而且该实验中Nand Flash中4k内存之外还有程序,将4k之外的程序拷贝到SDRAM中就是其区别。

这个实验拷贝到SDRAM的内容和SDRAM实验、MMU实验拷贝内容的区别:
SDRAM拷贝过去的内容是完完全全原函数的内容,MMU拷贝的内容除了有一级页表,还有leds.o程序,而这些内容是在4k内存内的,就是说一上电就已经拷进片内RAM中,而该实验拷贝的是main.o 程序的内容,且该内容是在4k内存外。

head.s的内容如下:

.text
.global _start
_start:
                                            @函数disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定义
            ldr     sp, =4096               @设置堆栈 
            bl      disable_watch_dog       @关WATCH DOG
            bl      memsetup                @初始化SDRAM
            bl      nand_init               @初始化NAND Flash
             @将NAND Flash中地址4096开始的1024字节代码(main.c编译得到)复制到SDRAM中
                                            @nand_read_ll函数需要3个参数:
            ldr     r0,     =0x30000000     @1. 目标地址=0x30000000,这是SDRAM的起始地址
            mov     r1,     #4096           @2.  源地址   = 4096,连接的时候,main.c中的代码都存在NAND Flash地址4096开始处
            mov     r2,     #2048           @3.  复制长度= 2048(bytes),对于本实验的main.c,这是足够了
            bl      nand_read               @调用C函数nand_read

            ldr     sp, =0x34000000         @设置栈
            ldr     lr, =halt_loop          @设置返回地址
            ldr     pc, =main               @b指令和bl指令只能前后跳转32M的范围,所以这里使用向pc赋值的方法进行跳转
halt_loop:
            b       halt_loop

ldr sp, =4096 一开始设置栈的原因:关看门狗的功能是通过C函数实现的,因此需要设置栈。(为什么用C函数写的就要设置栈呢?)
Nand_init函数的内容挺复杂的。

初始化后接下来代码的目的将4k之外的内容读取到SDRAM里面去,那么就要知道:

  1. 从哪里读,4096
  2. 读到那里去,0x30000000
  3. 读多大,2k
    上面的程序中r0,r1,r2分别对应函数的第一个、第二个、第三个传递参数,nand_read的函数内容如下所示。nand_read(a, b, c)
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;

#ifdef LARGER_NAND_PAGE
    if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
        return ;    /* 地址或长度不对齐 */
    }
#else
    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
        return ;    /* 地址或长度不对齐 */
    }
#endif	
    /* 选中芯片 */
    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);) {
      /* 发出READ0命令 */
      write_cmd(0);

      /* Write Address */
      write_addr(i);
#ifdef LARGER_NAND_PAGE
      write_cmd(0x30);		
#endif
      wait_idle();

#ifdef LARGER_NAND_PAGE
      for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {
#else
	  for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
#endif
          *buf = read_data();
          buf++;
      }
    }
    /* 取消片选信号 */
    nand_deselect_chip();
    
    return ;
}

nand_init函数的程序

void nand_init(void)
{
#define TACLS   0
#define TWRPH0  3
#define TWRPH1  0

    /* 判断是S3C2410还是S3C2440 */
    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
    {
        nand_chip.nand_reset         = s3c2410_nand_reset;
        nand_chip.wait_idle          = s3c2410_wait_idle;
        nand_chip.nand_select_chip   = s3c2410_nand_select_chip;
        nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip;
        nand_chip.write_cmd          = s3c2410_write_cmd;
        nand_chip.write_addr         = s3c2410_write_addr;
        nand_chip.read_data          = s3c2410_read_data;

		/* 使能NAND Flash控制器, 初始化ECC, 禁止片选, 设置时序 */
        s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
    }
    else
    {
        nand_chip.nand_reset         = s3c2440_nand_reset;
        nand_chip.wait_idle          = s3c2440_wait_idle;
        nand_chip.nand_select_chip   = s3c2440_nand_select_chip;
        nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;
        nand_chip.write_cmd          = s3c2440_write_cmd;
#ifdef LARGER_NAND_PAGE
        nand_chip.write_addr         = s3c2440_write_addr_lp;
#else
		nand_chip.write_addr		 = s3c2440_write_addr;
#endif
        nand_chip.read_data          = s3c2440_read_data;

		/* 设置时序 */
        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
        /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
    }
    
    /* 复位NAND Flash */
    nand_reset();
}
移动电话的功能日益丰富,其对系统中数据存储容量的需求正在快速增长。 NAND Flash具有速度快、密度大、成本低等特点,在各种数码产品中得到了广泛 应用,在各种片上系统芯片中(SOC)集成NAND Flash控制器正成为一种趋势。 本文讨论了Flash Memory的两种主流实现技术即NAND Flash和NOR Flash 的特点和区别,分析了市场上存在的NAND Flash的典型规格及其存储结构特点, 阐述了不同NAND Flash器件一些通用的存取操作方式,近一步分析了进行这些 存取操作所必须满足的时序规范,在此基础上,结合某公司手机SOC芯片的设计 需求,提出了一种基于AMBA总线的NAND Flash控制器实现方案,对该实现方 案进行了充分的验证工作。 本文所提出的控制器的实现方式,可以支持市场上存在的两种典型规格的 NAND Flash器件,可同时外接1至4个Flash芯片,通过可配置的控制方式可灵 活的对不同存取速度的器件予以支持,具备良好的可扩展性。在控制器的主控逻 辑设计中,采取了“块读’’和“块写”方式实现对大页器件的读页和写页操作, 这种方式有效减小了控制器中用做数据缓存的buffer大小,降低了芯片面积。针 对NAND Flash在使用过程中可能出现的位反转现象,在控制器的设计中加入了错 误检测和纠错功能。论文深入分析了ECC(Error Checking and Correcting)算法,讨 论了ECC算法的硬件实现和优化方法。在不影响对存储器读写效率的前提下,实 现对数据的存取进行实时的高速检错和纠错,为提高NAND Flash的可靠性提供了 硬件上的支持。 对控制器的验证采用了模拟验证和FPGA验证两种方式。在模拟验证阶段对 控制器的所有功能点进行全面验证,结果正确后,在Xilinx公司的Vertex4开发板 上对控制器进行了FPGA验证。结果表明控制器能正确控制对于NAND Flash的各 种存取操作,工作完全正常。 本文设计验证的NAND Flash控制器即将应用于某公司的SOC手机芯片,提 出的控制器实现方案对NAND Flash控制系统的设计优化具有普遍适用性,论文研 究的工程实用价值大。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值