ARM裸机编程系列----nandflash

关于NAND Flash

S5PV210的NAND Flash控制器有如下特点:

  • 支持512byte,2k,4k,8k的页大小
  • 通过各种软件模式来进行NAND Flash的读写擦除等
  • 8bit的总线
  • 支持SLC和MCL的NAND Flash
  • 支持1/4/8/12/16bit的ECC
  • 支持以字节/半字/字为单位访问数据/ECC寄存器,以字为单位访问其他寄存器。

注意:在此使用的GEC210的NAND Flash类型为SLC,大小为512MB,型号为K9K8G08U0A。所以本章的内容是针对SLC类型的NAND Flash(包括256M/512M/1GB等),并不适用MLC类型的NAND Flash。

程序例子:

/*nand.c*/
// NAND Flash初始化函数nand_init(),代码如下
void nand_init(void)
{
  // 1. 配置NAND Flash
  NFCONF = (TACLS<<12)|(TWRPH0<<8)|(T    WRPH1<<4)|(0<<3)|(0<<2)|(1<<1)|(0<<0);
  NFCONT =(0<<18)|(0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(0<<7)|(0<<6)|(0x3<<1)|(1<<0);
  // 2. 配置引脚
  MP0_1CON = 0x22333322;
  MP0_2CON = 0x00002222;
  MP0_3CON = 0x22222222;
  // 3. 复位
  nand_reset();
} 

第一步 配置NAND Flash

主要是设置NFCONF和NFCONT两个寄存器步骤:

NFCONF寄存器

AddrCycle = 1,When page size is 2K or 4K, 1 = 5 address cycle,GEC210的NAND Flash的页大小为2k,所有是5个地址周期;

PageSize = 0,When MLCFlash is 0, the value of PageSize is as follows: 0 = 2048 Bytes/page,Mini210S使用的是SLC NAND Flash且每页大小为2k;

MLCFlash = 0,在此使用的是SLC NAND Flash;

TWRPH1/TWRPH0/TACLS是关于访问时序的设置,需对照NAND Flash芯片手册设置,这里不再详细解释,分别取TWRPH1=1,TWRPH0=4,TACLS=1;

ECCType0/MsgLength,我们的裸机代码没有使用到ECC,所有不用设置这两个标志。

MODE = 1,使能NAND Flash控制器;

Reg_nCE0 = 1,取消片选,需要操作NAND Flash时再发片选;

Reg_nCE1 = 1, 取消片选,需要操作NAND Flash时再发片选;

InitMECC/InitSECC/SECCLock/MECCLock,我们的裸机代码不涉及ECC,这4个标志位随便设置即可;

RnB_TransMode = 0,Detect rising edge,RnB是NAND Flash的状态探测引脚,我们使用上升沿触发;

EnbRnBINT = 0 ,禁止RnB中断;

EnbIllegalAccINT = 0,禁止Illegal access 中断 ;

EnbMLCDecInt/EnbMLCEncInt为MCL相关,不用设置;

LOCK = 0,我们没有用到Soft Lock,所以禁止Soft Lock;

LockTight = 0,我们没有用到Lock-tight,所有禁止Lock-tight;

MLCEccDirection,MLC相关,可不用设置

第二步 配置引脚

用于NAND Flash相关功能;

第三步 复位

复位函数nand_reset的相关代码如下:

static void nand_reset(void)
{
    nand_select_chip();
    nand_send_cmd(NAND_CMD_RES);
    nand_wait_idle();
    nand_deselect_chip();
} 

NAND Flash的复位操作共4个步骤:

1) 发片选,实质就是NFCONT &= ~(1<<1);往NFCONT的bit[1]写0;

2) 发命令复位命令NAND_CMD_RES (0xff);实质就是NFCMMD = cmd;将命令写到NFCMMD寄存器;完整的NAND Flash命令信息见下图:

3) 等待NAND Flash 就绪;实质就是while( !(NFSTAT & (BUSY<<4)) ),读NFSTAT的bit[4]检查NAND Flash是否就绪;

4) 取消片选,实质就是NFCONT |= (1<<1); 往NFCONT的bit[1]写1;

<2> NAND Flash读ID函数nand_read_id(),代码如下

void nand_read_id(void)
{
  nand_id_info nand_id;
  // 1. 发片选
  nand_select_chip();
  // 2. 读ID
  nand_send_cmd(NAND_CMD_READ_ID);
  nand_send_addr(0x00);
  nand_wait_idle();
  nand_id.IDm = nand_read();
  nand_id.IDd = nand_read();
  nand_id.ID3rd = nand_read();
  nand_id.ID4th = nand_read();
  nand_id.ID5th = nand_read();
  printf("NANDFlash: makercode = %x,devicec ode = %x\r\n",nand_id.IDm,nand_id.IDd);
  nand_deselect_chip();
}

NAND Flash 读ID操作

根据上图,NAND Flash的读ID操作共4个步骤:

第一步 发片选;

第二步 发读ID命令NAND_CMD_READ_ID(0x90);

第三步 发地址0x00;调用函数nand_send_addr();

第四步 等待NAND Flash 就绪;

第五步 读ID;调用了nand_read()函数,实质就是读NFDATA寄存器;

/*nand_send_addr()*/
{
  // 列地址,即页内地址
  col = addr % NAND_PAGE_SIZE;
  // 行地址,即页地址
  row = addr / NAND_PAGE_SIZE;
  // Column Address A0~A7
  NFADDR = col & 0xff;
  for(i=0; i<10; i++);
  // Column Address A8~A11
  NFADDR = (col >> 8) & 0x0f;
  for(i=0; i<10; i++);
  // Row Address A12~A19
  NFADDR = row & 0xff;
  for(i=0; i<10; i++);
  // Row Address A20~A27
  NFADDR = (row >> 8) & 0xff;
  for(i=0; i<10; i++);
  // Row Address A28~A30
  NFADDR = (row >> 16) & 0xff;
  for(i=0; i<10; i++);
} 

首先根据页大小来获取页地址和页内偏移地址,然后通过5个周期将地址发送出去,实质就是写NFADDR寄存器,具体每个周期如何发送,查阅NAND Flash芯片手册可知,见下图:

发送地址后,就可以连续读出5个ID了,其中第一个是MAKDER CODE, 第二个是DEVICE CODE。

NAND Flash擦除操作

NAND Flash擦除函数nand_erase(),核心代码如下:

nand_erase()
{
  // 获得row地址,即页地址
  unsigned long row = block_num * NAND_BLOCK_SIZE;
  // 1. 发出片选信号
  nand_select_chip();
  // 2. 擦除:第一个周期发命令0x60,第二个周期 发块地址,第三个周期发命令0xd0 nand_send_c    md(NAND_CMD_BLOCK_ERASE_1st);
  for(i=0; i<10; i++);
  // Row Address A12~A19
  NFADDR = row & 0xff;
  for(i=0; i<10; i++);
  // Row Address A20~A27
  NFADDR = (row >> 8) & 0xff;
  for(i=0; i<10; i++);
  // Row Address A28~A30
  NFADDR = (row >> 16) & 0xff;
  NFSTAT = (NFSTAT)|(1<<4);
  nand_send_cmd(NAND_CMD_BLOCK_ERASE_2st);
  for(i=0; i<10; i++);
  // 3. 等待就绪
  nand_wait_idle();
  // 4. 读状态
  unsigned char status = read_nand_status();
}

根据上图,NAND Flash的擦除操作共6个步骤:

第一步 发片选;

第二步 发擦除命令1 NAND_CMD_BLOCK_ERASE_1(0x60);

第三步 发页地址,只需发页地址;

第四步 发擦除命令2 NAND_CMD_BLOCK_ERASE_2st(0xD0);

第五步 等待NAND Flash就绪;

第六步 读状态,判断擦除是否成功。若擦除失败,则打印是坏块再取消片选;否则直接直接取消片选即可。读状态调用了函数read_nand_status(),它的实质就是nand_send_cmd(NAND_CMD_READ_STATUS);ch = nand_read();先发读状态命令NAND_CMD_READ_STATUS,然后再读状态值。

NAND Flash 读操作

<4> NAND Flash读函数copy_nand_to_sdram(),从NAND Flash中读数据到DRAM,核心代码如下:

copy_nand_to_sdram()
{
  // 1. 发出片选信号 nand_select_chip();
  // 2. 从nand读数据到sdram,第一周期发命令0x00,第二周期发地址nand_addr,第三个周期发命令0x30,可读一页(2k)的数据
  while(length)
 {
    nand_send_cmd(NAND_CMD_READ_1st);
    nand_send_addr(nand_addr);
    NFSTAT = (NFSTAT)|(1<<4);
    nand_send_cmd(NAND_CMD_READ_2st);
    nand_wait_idle();
    // 列地址,即页内地址
    unsigned long col = nand_addr % NAND_PAGE_SIZE;
    i = col;
    // 读一页数据,每次拷1byte,共拷2048次(2k),直到长度为length的数据拷贝完毕
    for(; i<NAND_PAGE_SIZE && length!=0; i++,length--)
    {
      *sdram_addr = nand_read();
      sdram_addr++; nand_addr++;
    }
  }
  // 3. 读状态
  unsigned char status = read_nand_status();
}

NAND Flash 读操作

根据上图,NAND Flash的读操作共7个步骤:

第一步 发片选;

第二步 发读命令1 NAND_CMD_READ_1st(0x00);

第三步 发地址,调用函数nand_send_cmd(),发5个地址周期;

第四步 发读命令2 NAND_CMD_READ_2st(0xD0);

第五步 等待NAND Flash就绪;

第六步 从页内偏移地址开始读,读到页结尾即结束,每次读1byte;

第七步 读状态,判断是否读成功。

NAND Flash写操作

NAND Flash写函数copy_sdram_to_nand (),从DRAM写数据到NAND Flash,核心代码如下:

copy_sdram_to_nand ()
{
  // 1. 发出片选信号
  nand_select_chip();
  // 2. 从sdram读数据到nand,第一周期发命令0x80,第二周期发地址nand_addr,第三个周期写一页(2k)数据,第四周期发0x10
  while(length)
  {
    nand_send_cmd(NAND_CMD_WRITE_PAGE_1st);
    nand_send_addr(nand_addr);
    // 列地址,即页内地址
    unsigned long col = nand_addr % NAND_PAGE_SIZE;
    i = col;
    // 写一页数据,每次拷1byte,共拷2048次(2k),直到长度为length的数据拷贝完毕
    for(; i<NAND_PAGE_SIZE && length!=0; i++,length--)
    {
      nand_write(*sdram_addr);
      sdram_addr++;
      nand_addr++;
    }
    NFSTAT = (NFSTAT)|(1<<4);
    nand_send_cmd(NAND_CMD_WRITE_PAGE_2st);
    nand_wait_idle();
  }
  // 3. 读状态
  unsigned char status = read_nand_status();
}

根据上图,NAND Flash的写操作共7个步骤:

第一步 发片选;

第二步 发写命令1 NAND_CMD_WRITE_PAGE_1st (0x80);

第三步 发地址地址,调用函数nand_send_cmd(),发5个地址周期;

第四步 发读命令2 NAND_CMD_WRITE_PAGE_2st (0x10);

第五步 等待NAND Flash就绪;

第六步 从页内偏移地址开始写,读到页结尾即结束,每次写1byte;

第七步 读状态,判断是否读成功。

2. main.c

在main.c中,首先会调用nand_init()来初始化NAND Flash,然后打印一个菜单,提供4种选择测试NAND Flash:

读ID功能(nand_read_id());

擦除功能(nand_erase());

读功能(copy_nand_to_sdram());

写功能(copy_sdram_to_nand());

完整代码地址:https://github.com/zhouhui321/gec210-nos/tree/master/nand

时间: 2024-10-09 06:58:51

ARM裸机编程系列----nandflash的相关文章

S3C2416裸机开发系列十四_GCC下UCGUI的移植(2)

S3C2416裸机开发系列十四 GCC下UCGUI的移植(2) 象棋小子    1048272975 现在主要讲解一下在GCC移植UCGUI,Makefile工程如何加入目录,加入源码,c标准库,编译选项的设置. 笔者的Makefile模板提取自uboot,工程中加入目录,加入源码都是很简单的,详细的介绍请参考前面章节" GCC启动代码工程应用实例".下面主要介绍UCGUI目录下很多的源码文件Makefile的编写,一种可行的方式就是把GUI目录上所有的c文件,不管有无用到,均加入工程

S5PV210(TQ210)裸机编程

本文很多其它的是教会大家怎样学习. 4.1    汇编学习 4.1.1 基础知识 4.1.2 ARM模拟器 4.2    S5PV210启动流程 4.3    点亮一个LED 4.4    串口 4.5    实现printf函数 4.6    时钟配置 4.7    重定位(BL1载入BL2到SRAM) 4.8    DDR 4.9    NAND FLASH读写 4.10 NAND读写之8位硬件ECC 4.11 NAND读写之8位硬件ECC(续) 4.12 LCD操作 裸机编程仅仅是我写的<

S3C2416裸机开发系列十七_GCC下Fatfs的移植

S3C2416裸机开发系列十七 GCC下Fatfs的移植 象棋小子    1048272975 对于固态存储器,其存储容量可以很大,往往需要一款文件系统对存储器用户数据进行组织文件的管理.它对文件存储器空间进行组织和分配,负责文件的存储并对存入的文件进行保护和检索.在嵌入式系统中,往往需要采用windows兼容的文件系统,像相机的照片.视频监控.语音产品等,很多都需要从windows计算机上提取资源或在windows计算机上进一步处理.Fatfs由于其开源免费,支持fat32,受到了广泛的应用,

ARM裸机之点亮LED

声明:本文由个人学习过程中整理而成,转载请注明出处 实验开发版:S5PV210 1.什么是GPIO? General Purpose Input Output (通用输入/输出)简称为GPIO,属于芯片引脚的一部分. 嵌入式系统中常常有数量众多,但是结构却比较简单的外部设备/电路,对这些设备/电路有的需要CPU为之提供控制手段,有的则需要被CPU用作输入信号.而且,许多这样的设备/电路只要求一位,即只要有开/关两种状态就够了,比如灯亮与灭.对这些设备/电路的控制,使用传统的串行口或并行口都不合适

裸机编程与OS环境编程的有关思考

这里的所谓的裸机编程指的是为“无OS支持的硬件系统编程”,而实际的编程工作肯定需要一个环境,通常这样的情况中,编程和编译的环境叫做“宿主机”,最终的程序在“目标机”上运行(交叉编译).而OS环境编程指的是最终运行的程序是在有操作系统支持的环境中运行,而编程和编译的环境,可能是运行程序的机器(本地编译),也可能不是(交叉编译). 裸机编程现在主要是正对低端的嵌入式系统,如SCM(single chip machine).各式MCU.DSP等.当然,编写PC的bootloader肯定也属于裸机编程.

【iOS与EV3混合机器人编程系列之一】iOS要干嘛?EV3可以更酷!

乐高Mindstorm EV3智能机器人(以下简称EV3)自从在2013年的CES(Consumer Electronics Show美国消费电子展)上展出之后,就吸引了全球广大机器人爱好者的眼球!EV3相比其上一代机器人NXT最大的提升就在于其硬件上.除了更强大的ARM处理器,并加载了Linux操作系统之外,EV3还配备了蓝牙,支持外接USB,外接WiFi.因为有了这么多的硬件提升,EV3最酷的特性在于EV3支持iOS设备!!!这使得我们可以使用iOS设备比如iPhone来控制EV3!乐高官方

S3C2416裸机开发系列十五_GCC下uCOS的移植(1)

S3C2416裸机开发系列十五 GCC下uCOS的移植(1) 象棋小子    1048272975 操作系统是用来管理系统硬件.软件及数据资源,控制程序运行,并为其它应用软件提供支持的一种系统软件.根据不同的种类,又可分为实时操作系统.桌面操作系统.服务器操作系统等.对于一些小型的应用,对系统实时性要求高,硬件资源有限等的情况下,应尽量避免使用复杂庞大的操作系统(如Linux),使用小型的实时操作系统(如uCOS)更能满足应用的需求.笔者此处就uCOS-II的移植作一个简单的介绍. 1. 代码准

S3C2416裸机开发系列十五_GCC下uCOS的移植(2)

S3C2416裸机开发系列十五 GCC下uCOS的移植(2) 象棋小子    1048272975 4. uCOS配置 uCOS是可裁减实时操作系统,可以根据实际的应用对内核未使用到的功能进行裁减,以进一步节省系统宝贵的硬件资源,通常可用的uCOS-II内核代码在6K~26K,这在uCOS-II配置文件os_cfg.h中进行配置,这个配置文件在源码目录为os_cfg_r.h,从目录中拷贝添加到uCOS/uCOS-II/Cfg目录中,并重命名为os_cfg.h. #ifndef OS_CFG_H

S3C2416裸机开发系列十八_音频驱动实现(1)

S3C2416裸机开发系列十八 音频驱动实现(1) 象棋小子    1048272975 在消费电子产品中,往往都会用到音频系统来播放音乐.进行通话等多媒体应用,此外,对于一些需语音提示的产品,音频部分都是不可或缺的功能.笔者此处就s3c2416的音频驱动实现作一个简单的介绍. 1. IIS音频总线 s3c2416支持IIS.PCM.AC97这三种音频接口,此处只分析IIS音频接口.IIS接口(Inter-IC Sound)在20世纪80年代首先被飞利浦公司用于消费音频,为数字音频设备之间的音频