Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Nand Flash驱动(实现初始化以及读操作)

Nand Flash驱动(实现初始化以及读操作)

作者头像
呆呆
修改于 2021-05-27 06:30:03
修改于 2021-05-27 06:30:03
1.4K00
代码可运行
举报
文章被收录于专栏:centosDaicentosDai
运行总次数:0
代码可运行

本节来学习裸机下的Nand Flash驱动,本节学完后,再来学习Linux下如何使用Nand Flash驱动

Linux中的Nand Flash驱动,链接如下:

(分析MTD层以及制作Nand Flash驱动链接:http://www.cnblogs.com/lifexy/p/7701181.html)


本节简单制作一个Nand Flash驱动(只需要初始化Flash以及读Flash)

打开2440芯片手册,K9F2G08U0M芯片手册(因为2440中Nand Flash是用的256MB(2Gb)内存,8个数据引脚)

在芯片手册中得到K9F2G08U0M=2048块Block=128K页Pages=256MB=2Gb            

1个设备=2048块Block

1块Block=64页Pages

1页=(2K+64)B            (因为每个地址里都存放了一个字节,所以用B表示)

其中64B是存放ECC的OOB地址,(ECC:存放判断位反转的校验码)

Nand Flash 缺点:

读数据容易位反转

可以通过ECC编码器值来判断读数据是否位反转,若位反转则重新读数据

写过程:

  • 1)写页数据
  • 2)然后生成ECC
  • 3)将ECC写入到OBB页地址里(写数据是不会出现位反转)

读过程:

  • 1)读出页数据,然后生成临时ECC(此时ECC可能有错)
  • 2)然后读出OOB页地址里的ECC
  • 3)比较两个ECC,判断是否出现位反转

读OOB方法:

读整个Nand Flash时,是读不出页里面的OBB地址,比如读2049这个地址数据时,是读的第二页上的第2个地址:

只有读某一页时,才能读出这个页里面的OOB地址, 比如读第0页的2049这个地址数据时,才是读的第0页OOB的第2个地址:

Nand Flash芯片硬件引脚图:

  • RnB:就绪(ready)/忙(busy)输出信号,需要采用上拉电阻(1:表示写入数据成功,0:表示正在写入)
  • CLE:命令(command)锁存(latch)使能,(1:表示当前传的是命令值)
  • ALE:地址锁存使能,(1:表示当前传的是地址值,当CLE=0和ALE=0,表示传的是数据)
  • nCE:芯片使能(低电平使能)               (n:表示低电平有效)
  • nWE:写使能 ,比如写命令时,当CLE=1,ALE=0时,当nWE来个上升沿,则会将IO数据写入flash中
  • nRE:读使能,和we类似
  • nWP:写保护(protect) (1:不保护,0:只能读不能写),默认接高电平.

1.编写nand_init()函数

1.1设置通信时序 

 图1(nandflash时序表):

图2(nandflash时序图):

通过图2和图1可以看出:

tCS是等待芯片使能CE的时间, tCS=20nS

tCLS和tALS是等待WE(写信号)结束的时间, tCLS=tALS=15nS

tWP是WE(写信号)维持时间,  tWP=15nS

 tALH是等待命令写入成功的时间, tALH=5nS

tCLH是等待地址写入成功的时间, tCLH=5nS

图3(2440-nandflash时序图):

首先查看2440芯片手册里nandflash时序图,如上图,可以看出需要设置TACLS,TWRPH0和TWRPH1,这三个参数

TACLS:属于等待WE(写信号)就绪的时间,对比图2得出TACLS= tCLS- tWP=0nS

TWRPH0:属于WE(写信号)的时间, 对比图2得出TWRPH0= tWP=15nS

TWRPH1:属于等待命令写入成功的时间,对比图2得出TWRPH1=tALH=tCLH=5nS

最后,在NFCONF寄存器中设置这三个参数

TACLS[13:12] 

表示Duration(持续时间)=HCLK*TACLS,由于Duration=0nS,所以TACLS=0

TWRPH0 [10:8] 

表示Duration(持续时间)=HCLK*( TWRPH0+1),由于Duration=15nS,HCLK=10nS(100Mhz),所以TWRPH0 =1.

TWRPH1 [6:4] 

表示Duration(持续时间)= HCLK*( TWRPH1 +1),由于Duration=5nS,HCLK=10nS(100Mhz),所以TWRPH1 =0

1.2然后定义全局变量,并实现nand_init()初始化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* nand flash  时序 */
#define TACLS      0
#define TWRPH0     1
#define TWRPH1     0

 
/*     nand  flash  寄存器       */
#define   NFCONF     *((unsigend int *)0X4E000000); //配置寄存器(用来设置时序)
#define   NFCONT     *((unsigend int *)0X4E000000); //控制寄存器(用来使能nandflash控制器以及ECC编码器,还有控制芯片使能CE脚)
#define   NFCMMD    *((unsigend char *)0X4E000000);//发送命令寄存器(命令只有8位)
#define   NFADDR     *((unsigend char *)0X4E000000);//发送地址寄存器(地址只有8位)
#define   NFDATA      *((unsigend int *)0X4E000000);//读/写数据寄存器(数据只有8位)
#define   NFSTAT      *((unsigend int *)0X4E000000);//运行状态寄存器(用于判断RnB脚)

/*因为Nand Flash只有8位I/O脚,所以NFCMMD/ NFADDR/ NFDATA三个寄存器值都是unsigend char型  */

1.3 nand_init()函数初始化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void nand_init(void)
{

 /* 设置时序 */
NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

/* bit4=1:初始化ECC,  bit1=1:禁止片选  bit0=1:启动nandflash控制器*/    
NFCONT = (1<<4)|(1<<1)|(1<<0);

}

2编写nand_read()函数

2.1编写nand_read()函数需要以下几个子函数:

2.1.1片选使能函数(在读写FLASH之前都要选中片选)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nand_select()               //使能片选
{
int i;
NFCONT&=~(1<<1);        // NFCONT控制器位1置0
for(i=0;i<10;i++);           //等待芯片使能成功
}

2.1.2取消片选函数(退出读写FLASH时需要取消片选)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nand_deselect()                 //取消片选
{
int i;
NFCONT&=~(1<<1);        // NFCONT控制器位1置0
for(i=0;i<10;i++);           //等待芯片使能成功
}

2.1.3读命令函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nand_cmd(unsigned char cmd)                 
{
int i;
NFCMMD= cmd;        // 向NFCMMD寄存器写入命令
for(i=0;i<10;i++);        //等待写入命令成功
}

2.1.4判断RnB状态函数(在写入所有命令后都要判断RnB脚是否为高电平就绪)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nand_waite_idle()                 
{
int i;
while(!(NFSTAT&0X01))       // 等待NFSTAT寄存器位0置1
for(i=0;i<10;i++);         
}

2.1.5读数据函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nand_read_data()                 
{
 unsigend char  p=NFDATA;    //读取NFDATA寄存器
 return p;                   //返回
}

2.1.6 编写写入地址函数 (分5个周期)

首先Nand Flash引脚只有8位,然而地址共有2048(块)*64(页)*2KB,为了读出多个地址,如下图,所以需要分5个周期来实现发送地址

如上图,其中  A10~A0对应页大小(列),由于nandflash每页2048B,所以只用到A10~A0

A28~A11对应页目录(行),表示共有2048块*64(每块有64页)个目录

例如,4097 地址就是:

  A10~A0=4097%2048= 1(A0=1,其余为0)

 A28~A11=4097/2048=2(A13=1,其余为0)

所以nand_write_nand()函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void nand_read_addr(unsigned int addr)
{

   unsigned int col  = addr % 2048;
   unsigned int page = addr / 2048;
volatile int i;

   NFADDR=(col>>0)&0xff;           //A7~A0,第1周期
for(i=0;i<10;i++);

   NFADDR=(col>>8)&0x0f;           //A10~A8,第2周期
   for(i=0;i<10;i++);

   NFADDR=(page>>0)&0xff;          //A18~A11,第3周期
   for(i=0;i<10;i++);

   NFADDR=(page>>8)&0xff;          //A26~A19,第4周期
   for(i=0;i<10;i++);

   NFADDR=(page>>16)&0xff;         //A27~A28,第5周期
   for(i=0;i<10;i++);  
}

2.2Nand Flash命令图:

如上图,例如:当要reset复位nand flash时


1)      使能片选nand_select();

2)      发送0XFF复位命令nand_cmd(0xFF);

3)      等待RnB状态是否就绪 nand_wait_idle();

4)      取消片选 nand_deselect();


2.3Nand Flash读数据时序图:

从上图可以看出nand flash 读数据分为了以下几个步骤:


(1)      使能片选CE,将CLE置1,等待发送命令

(2)      将WE置低,将IO置为0X00,然后拉高WE,触发一次上升沿,则将把0x00写入flash中

(3)      将CLE置0,表示发送地址(分为5个周期)

(4)      发送读命令0X30

(5)     等待RnB信号为高电平

(6)     读数据

(在同一页里,数据可以连续读,读下一页时,需要重新发送新的地址才行例如:读1000地址到2050地址时,

1.发出1000地址,到达页0的1000地址上,然后再连续读(2048-1000)次,直到读到页0的2047处.

2.再发出2048地址,到达页1的0地址上,然后连续读(2051-2048)次,直到读到2050为止)

(7)     取消片选nCE


2.4 所以nand_read()函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void nand_read(unsigned int  src,unsigned char  *dest,unsigned int  len)
/* src:源地址,为32位地址,所以用unsigend int表示
*dest:目的地址内容,由于这里是将数据读出到目的地址内容中,所以需要用到*指针,因为每个地址里存的是一个字节,所以用unsigend char 型    */
{

int col=src%2048;      //第一次读,可能不是读的页首地址,所以需要记录当前页的位置

int i=0;                //当前读了0次

nand_select();           //1使能片选nCE     

while(i<len)

 { nand_cmd(0X00);        //2发送读命令0X00  

   nand_write_addr(src);     // 3发送yuan地址(分为5个周期)

   nand_cmd(0X30);        //4发送读命令0X30    

   nand_wait_idle();       //5等待RnB信号为高电平

   for(;(col<2048)&&(i<len);col++)      //连续读页内数据

   {dest[i]=nand_read_data();            //6.读数据

    i++;            
    src++;}

    col=0;}

    nand_deselect();                // 取消片选nCE
 
}

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Nand Flash驱动(实现初始化以及读操作)
本节来学习裸机下的Nand Flash驱动,本节学完后,再来学习Linux下如何使用Nand Flash驱动 Linux中的Nand Flash驱动,链接如下: (分析MTD层以及制作Nand Fla
诺谦
2018/01/03
2K0
Nand Flash驱动(实现初始化以及读操作)
第016课 Nand Flash操作原理及裸机程序分析
NAND FLASH原理图 NAND FLASH是一个存储芯片 那么: 这样的操作很合理”读地址A的数据,把数据B写到地址A”
韦东山
2020/09/30
8920
第016课 Nand Flash操作原理及裸机程序分析
24.Linux-Nand Flash驱动(分析MTD层并制作NAND驱动)
1.本节使用的nand flash型号为K9F2G08U0M,它的命令如下: 1.1我们以上图的read id(读ID)为例,它的时序图如下: 首先需要使能CE片选 1)使能CLE 2)发送0X90命
诺谦
2018/01/03
5.1K0
24.Linux-Nand Flash驱动(分析MTD层并制作NAND驱动)
最简 bootloader
bootloader 是什么?如果你看到了这篇文章,肯定已经知道答案了,所以这里就不赘述了。这篇文章主要是根据韦东山老师的视频,从零开始写一个最简单的 bootloader,每一行代码都是手动输入。虽然直接看一遍视频,也能够理解其中的步骤或者原理,但是根据视频敲一遍之后,印象才是最深刻的。
IOT物联网小镇
2021/05/13
8940
嵌入式开发常见的3个C语言技巧
在嵌入式开发中,常常要操作寄存器,对寄存器进行写入,读出等等操作。每个寄存器都有自己固有的地址,通过C语言访问这些地址就变得尤为重要。
C语言中文社区
2024/01/04
3310
嵌入式开发常见的3个C语言技巧
S3C2440移植uboot之支持NANDFLASH操作
  之前由于nand部分报错,直接注释了 u-boot- 2012.04.01\include\configs\smdk2440.h 中的#define CONFIG_CMD_NAND。现在我们去掉注释,重新编译。报错如下
嵌入式与Linux那些事
2021/05/20
7620
S3C2440移植uboot之支持NANDFLASH操作
3.移植uboot-使板卡支持nor、nand
上面的Flash: *** failed *** 是属于uboot第二阶段函数board_init_r()里的代码, 代码如下所示(位于arch/arm/lib/board.c):
诺谦
2019/05/24
1.1K0
超详细分析Bootloader(Uboot)到内核的启动流程(万字长文!)
  Bootloader的启动过程可以分为单阶段、多阶段两种。通常多阶段的 Bootloader能提供更为复杂的功能以及更好的可移植性。从固态存储设备上启动的 Bootloader大多都是两阶段的启动过程。第一阶段使用汇编来实现,它完成一些依赖于CPU体系结构的初始化,并调用第二阶段的代码;第二阶段则通常使用C语言来实现,这样可以实现更复杂的功能,而且代码会有更好的可读性和可移植性。   一般而言,这两个阶段完成的功能可以如下分类:
嵌入式与Linux那些事
2021/05/20
14.2K0
超详细分析Bootloader(Uboot)到内核的启动流程(万字长文!)
镁光256Gb NAND Flash芯片介绍
该芯片是一款典型的大容量NAND Flash存储颗粒,支持Open NAND Flash Interface (ONFI) 2.1的接口标准,采用ONFI NANDFlash的操作协议。该芯片采用Multiple-level Cell (MLC)技术,根据不同的容量,一个芯片内部封装了多个DIE(LUN),每个DIE由两个Plane构成,一个Plane可以分成2048个Block,每个Block由256页组成,一个页的大小为8KB+448B的组织结构方式。
全栈程序员站长
2022/06/25
3.4K1
镁光256Gb NAND Flash芯片介绍
S3C2440移植uboot之支持NAND启动「建议收藏」
  上一节S3C2440移植uboot之新建单板_时钟_SDRAM_串口移植uboot初始化了时钟,配置了支持串口,这一节我们继续修改uboot支持NAND启动。
全栈程序员站长
2022/07/01
5410
S3C2440移植uboot之支持NAND启动「建议收藏」
第2阶段——编写uboot之编译测试以及改进(3)
该文介绍了如何通过修改配置、开启ICAHE等方法来加快内核启动速度,并给出了具体的代码示例。
诺谦
2018/01/03
7490
第2阶段——编写uboot之编译测试以及改进(3)
嵌入式开发中常见3个的C语言技巧
今天我来说几个在嵌入式开发中常用的C语言技巧吧。也许你曾经用过,也许你只是见到过但是没有深入理解。那么今天好好补充下吧^_^
用户7515259
2020/08/04
5660
S3C2440移植uboot之支持NAND启动
  参考之前uboot使用的start.S, init.c来修改uboot代码新的uboot链接地址位于0,且在arm-linux-ld时加了"-pie"选项, 使得u-boot.bin里多了"*(.rel*)", "*(.dynsym)",从而程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K).   所以接下来修改代码,并取消"-pie"选项.   使用grep “-pie” * -nR找到:
嵌入式与Linux那些事
2021/05/20
7930
S3C2440移植uboot之支持NAND启动
嵌入式:ARM最小系统设计详解
嵌入式微处理器芯片自己是不能独立工作的,需要一些必要的外围元器件给它提供基本的工作条件。
timerring
2023/01/04
2.5K0
嵌入式:ARM最小系统设计详解
NAND FLASH_Flash下载
本文介绍了DM368 NAND Flash启动的原理,并且以DM368 IPNC参考设计软件为例,介绍软件是如何配合硬件实现启动的。
全栈程序员站长
2022/09/21
3.1K0
NAND FLASH_Flash下载
U-BOOT 移植到友善之臂mini2440
编译器:友善之臂mini2440光盘自带arm-linux-gcc 4.4.3
全栈程序员站长
2022/07/11
7190
Flash中XIP模式
XIP:eXecute In Place,即芯片内执行,指应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中。所谓片内执行并不是说程序在存储器内执行,CPU的基本功能是取指、译码、执行,存储器访问,写回。Nor Flash能在芯片内执行,指的是CPU能够直接从Nor flash中取指令,供后面的译码器和执行器来使用。
数字IC小站
2020/08/17
5.1K0
第012课 内存控制器与SDRAM
如图是S3C2440是个片上系统,有GPIO控制器(接有GPIO管脚),有串口控制器 (接有TXD RXD引脚)。
韦东山
2020/09/30
1.2K0
第012课 内存控制器与SDRAM
第2阶段——编写uboot之硬件初始化和制作链接脚本lds(1)
本文主要介绍了如何制作一个简单的U-Boot启动加载程序。首先介绍了U-Boot的架构和主要功能,然后详细描述了如何制作U-Boot的启动加载程序。最后,给出了一个示例代码和相关的工具链。
诺谦
2018/01/03
8620
S3C2440从NAND Flash启动和NOR FLASH启动的问题
    NAND FLASH本身是连接到了控制器上而不是系统总线上。CPU运行机制为:CPU启动后是要取指令执行的,如果是SROM、NOR FLASH 等之类的,CPU 通过地址线发个地址就可以取得指令并执行,NAND FLASH不行,因为NAND FLASH 是管脚复用,它有自己的一套时序,这样CPU无法取得可以执行的代码,也就不能初始化系统了。
嵌入式与Linux那些事
2021/05/20
8510
S3C2440从NAND Flash启动和NOR FLASH启动的问题
推荐阅读
相关推荐
Nand Flash驱动(实现初始化以及读操作)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验