学习uboot前奏之hardware-nand flash[s3c2440]

好久没有更新博文了,最近确实懒惰了,哎,不说了。开始今天的学习吧,今天让我们来学习下嵌入式开发中不可缺少的模块-NAND FLASH。


FLASH主要分为两类: NAND FLASH 和NOR FLASH

两者的主要区别和适用场合如下

参数NANDNOR
容量1-32MBNAND:16-512MB 甚至更大
XIP不可以可以直接在其上运行代码
接口IO接口RAM接口
访问方法顺序访问随机访问
可靠性比较低,位反转比较常见比较高
可擦写次数10000-100000100000-1000000
主要用途保存数据和代码保存代码

总结下的话就是NOR FLASH可以支持XIP,可靠性高,但是读写速度相对于NAND FLASH来说慢一些
NAND 不支持XIP,但是它的性价比比较高,但是也有一个比较严重的问题就是发生位翻转的概率比较大,因此NAND FLASH 在使用的时候都配备软件的ECC或者硬件的ECC。

在本人接触的有限的产品中,NAND FLASH用的比较多,功能类似PC的硬件,本文以三星公司生产的K9F1208U0M为例进行介绍NAND FLASH

K9F1208U0M的主要引脚如下:
这里写图片描述

对于NAND FLASH访问的命令、地址、数据都是通过I/O输入/输出,这种形式减少了
芯片的引脚个数,并使得系统很容易升级到更大的容量。

写入命令、地址或者数据时,都需要将WE#、CE#、信号同时拉低。数据在WE#信号的
上升沿被NAND FLASH锁存;命令锁存信号CLE、地址锁存信号ALE用来分辨、锁存命令命令或者地址

地址序列
这里写图片描述

K9F1208U0M一页大小为528字节,而列地址A0~A7可以寻址的范围是256字节,所以必须辅以其他手段才能完全寻址这528字节。将一页分为A、B、C、三个区;A区为0~255字节,B区为256~511字节,C区为512~527字节。访问某页,需要选定特定的区,这成为“使地址指针指向特定的区”。通过三个命令实现:命令00h让地址指针指向A区、命令01h让地址指针指向B区、命令50h让地址指针指向C区。命令00h和50h会使得访问FLASH的地址指针一直从A区或C区开始,除非发出了其他的修改地址的命令。命令01h的效果只能维持一次,当前的读、写、擦除、复位或者上电操作完成后,地址指针重新指向A区。写A区或C区的数据时,必须在发出命令80h之前发出00h或者50h;写B区的数据,发出命令01h后必须紧接就发出命令80h

下面讲下NAND FLASH的读写操作次序:

  1. 设置NFCONF(对于S3C2440还要设置NFCONT)寄存器,配置NAND Flash
  2. 向NFCMD寄存器写入命令,命令字参考具体的FLASH手册
  3. 向NFADDR寄存器写入地址
  4. 读/写数据:通过寄存器NFSTAT检测NAND Flash的状态,在启动某个操作后,应该检测R/nB信号以确定该操作是否完成、成功

举个读操作的例子:

  1. 设置NFCONF,NFCONT
    NFCONF=0x300(TACLS=0,TWRPH0=3,TWRPH1=0)
 设置NFCONT寄存器如下,表示使能NAND FlASH控制器、禁止控制引脚信号nFCE、初始化ECC
    NFCONT = (1<<4)|(1<<1)|(1<<0)

2.在第一次操作NAND Flash前,通常复位一下NAND flash

    NFCONT &= ~(1<<1) (发出片选信号)
    NFCMD = 0xff      (reset信号)

然后循环查询NFSTAT位0,直到它等于1。
最后禁止片选信号,在实际使用NAND Flash时再使能

    NFCONT |= 0X2

3.发出读命令
先使能NAND Flash,然后发出读命令

    NFCONT &= ~(1<<1)(发出片选信号)
    NFCMD   = 0 (读命令)

4 发出地址信号
在上面的表中列举出了地址的操作步骤和对应的以及对应的地址线,地址线A8不需要直接设置由A8设置,当读命令为0时,A8=0;当读命令为1时,A8=0,具体地址设置如下。

    NFADDR =  addr & 0xff
    NFADDR = (addr>>9)&0xff
    NFADDR =  (addr>>17)&0xff
    NFADDR =  (addr>>25)&0xff

5 循环查询NFSTAT位0,直到它等于1,这时就能读取数据了
6 连续读NFDATA既存器512次,得到一页数据
7 最后,禁止 NAND Flash的片选信号

下面以实际代码讲解NAND Flash操作。nand实验的源文件为head.s、init.c和main.c。程序的功能是将点灯的程序放在NAND flash地址4096后,当程序启动后通过NAND flash控制器将它们读出来执行。
连接脚本nand.lds把所有的源程序分为两部分,nand.lds代码如下:

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

其中链接脚本的第二行表示head.o、init.o、nand、这3个文件的运行地址为0,它们在生成的映像文件中的偏移地址也为0(从0开始存放)

第3行表示main.o,它在生成的映像文件中的偏移地址为4096

下面开始分析源代码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)
            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

head.S中调用init.c中的函数来管WATCH DOG、初始化SDRAM;调用nand.c中函数来初始化NAND Flash,然后将main.c中的代码从NAND Flash地址4096开始处复制到SDRAM中,最后跳到main.c中的main函数继续执行。

下面再仔细分析nand_read函数

/* 读函数 */
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;

    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
        return ;    /* 地址或长度不对齐 */
    }

    /* 选中芯片 */
    nand_select_chip();

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

      /* Write Address */
      write_addr(i);

      wait_idle();


      for(j=0; j < NAND_SECTOR_SIZE; j++, i++) 
      {

          *buf = read_data();
          buf++;
      }
    }

    /* 取消片选信号 */
    nand_deselect_chip();

    return ;
}

函数功能为从NAND flash中将起始地址为start_addr开始的size大小的数据拷贝到buf对应的地址处。从上面的程序可以看出读Flash数据的过程如下:

  1. 选择芯片
  2. 发出读命令
  3. 发出地址
  4. 等待数据就绪
  5. 读取数据
  6. 结束后,取消片选信号

好的,本节到此为止了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值