转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/25240909

一.框架总结

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcnVveXVubGl1ZmVuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

二.硬件原理

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcnVveXVubGl1ZmVuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

相比于nor flash。我们能够清楚的看出引脚少了非常多,主要是输入输出引脚进行了复用。如今我说下各引脚的用途。

a.LDATA0~LDATA7这8个引脚为输入输出引脚。

命令、地址、数据的传输都是由这8个引脚实现的(引脚复用,节约引脚)。

b.RnB:此引脚用来判忙。由于命令、数据、地址发出去和收到时候不能立马就完毕。须要一个时间。

此引脚为高电平时表示就绪,低电平时候表示正忙。

c.nFCE、nFWE、nFCE各自是芯片使能、写使能、和读使能。举个样例,就是说假如你想读数据、命令、地址时候。

必须先使能nFCE、nFCE(就是这两个引脚为低电平)。

d.CLE、ALE两个引脚是指令锁时能和数据锁使能。

使用方法:当ALE为高电平时传输的是地址,当CLE为高电平时传输的是命令。当ALE和CLE都为低电平时传输的是数据。

三.驱动程序

/* 參考
* drivers\mtd\nand\s3c2410.c
* drivers\mtd\nand\at91_nand.c
*/ #include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h> #include <asm/io.h> #include <asm/arch/regs-nand.h>
#include <asm/arch/nand.h> /*用到的寄存器*/
struct s3c_nand_regs {
unsigned long nfconf ;
unsigned long nfcont ;
unsigned long nfcmd ;
unsigned long nfaddr ;
unsigned long nfdata ;
unsigned long nfeccd0 ;
unsigned long nfeccd1 ;
unsigned long nfeccd ;
unsigned long nfstat ;
unsigned long nfestat0;
unsigned long nfestat1;
unsigned long nfmecc0 ;
unsigned long nfmecc1 ;
unsigned long nfsecc ;
unsigned long nfsblk ;
unsigned long nfeblk ;
}; static struct nand_chip *s3c_nand; //nand_chip结构体
static struct mtd_info *s3c_mtd;
static struct s3c_nand_regs *s3c_nand_regs; static struct mtd_partition s3c_nand_parts[] = {
[0] = {
.name = "bootloader", //名字
.size = 0x00040000, //大小
.offset = 0, //偏移值
},
[1] = {
.name = "params",
.offset = MTDPART_OFS_APPEND, //紧跟上面分区
.size = 0x00020000,
},
[2] = {
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = 0x00200000,
},
[3] = {
.name = "root",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
}
}; /*推断是否选中*/
static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
{
if (chipnr == -1)
{
/* 取消选中: NFCONT[1]设为1 */
s3c_nand_regs->nfcont |= (1<<1);
}
else
{
/* 选中: NFCONT[1]设为0 */
s3c_nand_regs->nfcont &= ~(1<<1);
}
}
/*推断发命令,还是地址*/
static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
if (ctrl & NAND_CLE)
{
/* 发命令: NFCMMD=dat */
s3c_nand_regs->nfcmd = dat;
}
else
{
/* 发地址: NFADDR=dat */
s3c_nand_regs->nfaddr = dat;
}
}
/*推断状态*/
static int s3c2440_dev_ready(struct mtd_info *mtd)
{
return (s3c_nand_regs->nfstat & (1<<0));
} static int s3c_nand_init(void) //入口函数
{
struct clk *clk; /* 1. 分配一个nand_chip结构体 */
s3c_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs)); //映射寄存器 /* 2. 设置nand_chip */
/* 设置nand_chip是给nand_scan函数使用的, 假设不知道怎么设置, 先看nand_scan怎么使用
* 它应该提供:选中,发命令,发地址,发数据,读数据,推断状态的功能
*/
s3c_nand->select_chip = s3c2440_select_chip; //推断选中
s3c_nand->cmd_ctrl = s3c2440_cmd_ctrl; //发命令。还是地址
s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata; //读数据
s3c_nand->IO_ADDR_W = &s3c_nand_regs->nfdata; //写数据
s3c_nand->dev_ready = s3c2440_dev_ready; //推断状态
s3c_nand->ecc.mode = NAND_ECC_SOFT; //设置ECC /* 3. 硬件相关的设置: 依据NAND FLASH的手冊设置时间參数 */
/* 使能NAND FLASH控制器的时钟 */
clk = clk_get(NULL, "nand");
clk_enable(clk); /* CLKCON'bit[4] */ /* HCLK=100MHz
* TACLS: 发出CLE/ALE之后多长时间才发出nWE信号, 从NAND手冊可知CLE/ALE与nWE能够同一时候发出,所以TACLS=0
* TWRPH0: nWE的脉冲宽度, HCLK x ( TWRPH0 + 1 ), 从NAND手冊可知它要>=12ns, 所以TWRPH0>=1
* TWRPH1: nWE变为高电平后多长时间CLE/ALE才干变为低电平, 从NAND手冊可知它要>=5ns, 所以TWRPH1>=0
*/
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4); /* NFCONT:
* BIT1-设为1, 取消片选
* BIT0-设为1, 使能NAND FLASH控制器
*/
s3c_nand_regs->nfcont = (1<<1) | (1<<0); /* 4. 使用: nand_scan */
s3c_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
s3c_mtd->owner = THIS_MODULE;
s3c_mtd->priv = s3c_nand; //设置私有数据 nand_scan(s3c_mtd, 1); /* 识别NAND FLASH, 构造mtd_info */ /* 5. add_mtd_partitions 加入分区*/
add_mtd_partitions(s3c_mtd, s3c_nand_parts, 4); //add_mtd_device(s3c_mtd); 整个flash仅仅有一个分区
return 0;
} static void s3c_nand_exit(void) //出口函数
{
del_mtd_partitions(s3c_mtd);
kfree(s3c_mtd);
iounmap(s3c_nand_regs);
kfree(s3c_nand);
} module_init(s3c_nand_init);
module_exit(s3c_nand_exit); MODULE_LICENSE("GPL");

四.驱动分析

1.总体分析

1.1分配一个nand_chip结构体并映射相关寄存器

1.2设置nand_chip(设置nand_chip是给nand_scan函数使用的, 假设不知道怎么设置,
先看nand_scan怎么使用。它应该提供:选中,发命令,发地址,发数据,读数据,推断状态的功能)

1.3硬件相关的设置: 依据NAND FLASH的手冊设置时间參数

1.4使用: nand_scan

1.5add_mtd_partitions 加入分区(分区在s3c_nand_parts结构体中进行设置)

2.寄存器介绍

2.1 NFSTAT(状态寄存器。主要判忙)

	s3c_nand->dev_ready   = s3c2440_dev_ready;         //推断状态

2.2 NFCMMD(命令寄存器)和NFADDR(地址寄存器)

static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
if (ctrl & NAND_CLE)
{
/* 发命令: NFCMMD=dat */
s3c_nand_regs->nfcmd = dat;
}
else
{
/* 发地址: NFADDR=dat */
s3c_nand_regs->nfaddr = dat;
}
}

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcnVveXVubGl1ZmVuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

2.3 NFCONT(控制寄存器)

	/* NFCONT: BIT1-设为1, 取消片选。  BIT0-设为1, 使能NAND FLASH控制器*/
s3c_nand_regs->nfcont = (1<<1) | (1<<0);

2.4 NFCONF(配置寄存器)

	/* HCLK=100MHz
* TACLS: 发出CLE/ALE之后多长时间才发出nWE信号, 从NAND手冊可知CLE/ALE与nWE能够同一时候发出,所以TACLS=0
* TWRPH0: nWE的脉冲宽度, HCLK x ( TWRPH0 + 1 ), 从NAND手冊可知它要>=12ns, 所以TWRPH0>=1
* TWRPH1: nWE变为高电平后多长时间CLE/ALE才干变为低电平, 从NAND手冊可知它要>=5ns, 所以TWRPH1>=0
*/
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcnVveXVubGl1ZmVuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

左图为2440nand时序。右面为nand手冊要求时序。最后一个图为详细数值。

以下这三个图计算最小值。

TACLS    =  tCLS-tWP=12-12=0

TWRPH0= tWP        =12

TWRPH1=  tCLH        =5

3.ECC校验

因为Nand flash的工艺特性。所以nand flash有一个缺点就是位反转。所以增加了ECC校验。

详细怎么实现呢?

nand flash的存储是以页为单位的。它在每页的后面增加了OOB(16字节),这里面存的就是ECC的值。怎样工作?

a.写每页的时候生成ECC,将ECC写入OBB

b.当读每页的时候先算出ECC,然后读OBB的ECC。两个ECC进行比較。

详细的算法实现比較复杂,我在这里仅仅是简单的说一下,有兴趣的能够深入研究。

參考:韦东山视频第二期

块设备驱动之NAND FLASH驱动程序的更多相关文章

  1. 块设备驱动之NOR FLASH驱动

    转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/25240947 一.硬件原理 从原理图中我们能看到NOR FLASH有地址线,有 ...

  2. 【驱动】linux系统下nand flash驱动程序框架

    linux操作系统下nand flash驱动框架 当我们需要在操作系统上读写普通文件的时候,总是需要一层层往下,最终到达硬件相关操作,当然底层设备大多数都是块设备 NAND FLASH就作为一个最底层 ...

  3. 嵌入式Linux驱动学习之路(二十三)NAND FLASH驱动程序

    NAND FLASH是一个存储芯片. 在芯片上的DATA0-DATA7上既能传输数据也能传输地址. 当ALE为高电平时传输的是地址. 当CLE为高电平时传输的是命令. 当ALE和CLE都为低电平时传输 ...

  4. FLASH驱动之-块设备驱动系统构架

    一.  块设备是只能以块为单位进行访问的设备,块的大小一般是512个字节的整数倍,常见的块设备包括硬件,SD卡,光盘,flash等.驱动程序是块的整数倍从设备读写得到数据.块设备的最小访单位为块,不同 ...

  5. NAND FLASH驱动程序

    NAND FLASH是一个存储芯片那么: 这样的操作很合理"读地址A的数据,把数据B写到地址A" 问1. 原理图上NAND FLASH和S3C2440之间只有数据线,     怎么 ...

  6. 15、NAND FLASH驱动程序框架

    驱动可以参考At91_nand.c,这个比S3c2410.c (drivers\mtd\nand)简单多了 NAND FLASH是一个存储芯片那么: 这样的操作很合理"读地址A的数据,把数据 ...

  7. 驱动09.nand flash

    1 nand flash的操作 目的:读地址A的数据,把数据B写到地址A. 问1. 原理图上NAND FLASH和S3C2440之间只有数据线,怎么传输地址?答1.在DATA0-DATA7上既传输数据 ...

  8. Linux块设备驱动(一) _驱动模型

    块设备是Linux三大设备之一,其驱动模型主要针对磁盘,Flash等存储类设备,本文以3.14为蓝本,探讨内核中的块设备驱动模型 框架 下图是Linux中的块设备模型示意图,应用层程序有两种方式访问一 ...

  9. Linux块设备驱动(二) _MTD驱动及其用户空间编程

    MTD(Memory Technology Device)即常说的Flash等使用存储芯片的存储设备,MTD子系统对应的是块设备驱动框架中的设备驱动层,可以说,MTD就是针对Flash设备设计的标准化 ...

随机推荐

  1. The Impact of Garbage Collection on Application Performance

    As we’ve seen, the performance of the garbage collector is not determined by the number of dead obje ...

  2. MYI 文件内容

    参考 http://blog.itpub.net/703656/viewspace-1018470/ 创建表结构 create table test(name char(20), age int, c ...

  3. poj2192

    初看这道题,以为是先用SA和SC求LCS,再从SC中把SA剔除,看剩下来的是不是SB(……) 显然不对;因为SC与SA的公共子串不止一种,判断不一定正确. 于是考虑SC中每一个字符,如果能够匹配,那么 ...

  4. Erlang入门(四)——错误处理和鲁棒性

    去了趟福州,事情没搞定,托给同学帮忙处理了,回家休息了两天就来上班了.回家这几天最大的收获是第四次重读<深入Java虚拟机>,以前不大明了的章节豁然开朗,有种开窍的感觉,水到渠成,看来技术 ...

  5. oracle server配置:监听程序未启动或数据库服务未注册到该监听程序

    第一次安装oracle时,时完全没有任何问题的, 但是当我去配置oracle_home时,误按之下进入了Database Configuration Assistant, 然后配置已有的一个数据库,就 ...

  6. Asp.Net 高性能框架 SqlSugar.ORM 2.3

    一.前言 SqlSugar从去年到现在已经一年了,版本从1.0升到了现在的2.3 ,这是一个稳定版本 ,有数家公司已经项目上线,在这里我将SqlSugar的功能重新整理成一篇新的贴子,希望大家喜欢. ...

  7. 法律网站分类 ­zt

    法律网站分类 ­ ­一.北大类 ­ 中国法律信息网(北大法学院)www.Chinalawinfo.com ­ ­北大金融法研究中心  www.pkufli.net ­ ­宪政知识网(北大法学院)www ...

  8. MFC定时器使用

    MFC定时器实现方法 方法一:CWnd类提供的成员函数SetTimer实现定时器功能,只能在CWnd类或其派生类中调用. 方法二:Windows API函数SetTimer来实现. MFC定时器 启动 ...

  9. TCP服务端和客户端的框架

    提供一个框架服务器端: 创建一个Socket sFd=socket(AF_INET,SOCK_STREAM,0) 把Socket和本机的IP,TCP口绑定 bind(sFd,(structsockad ...

  10. SQL Server 用表中已有数据造数据

    从表中选择数据再插入到表中(select XXX into 与insert into XXX select的结合) 在做性能测试时需要大量的业务数据.完全从画面造数据比较费时间,使用SQL文批量插入数 ...