008NAND_FLASH驱动

一、 NAND_FALSH原理及硬件操作(第十九课/第一节)

A、 回顾块设备驱动

    应用程序读写一个普通文件,最终肯定会去操作到硬件上(比如Flash),这个普通的文件存在什么地方,文件系统会把对普通文件的读写转换为一项一项的对块设备的读写操作,然后会调用"ll_rw_block"这个函数,这个函数就会把这些一项一项的读写操作放入队列优化然后调用请求处理函数执行。

B、 回顾怎么写块设备驱动程序

    1. 分配gendisk结构:alloc_disk
    2. 设置:a.分配/设置队列;b.设置其它属性(比如容量等)
    3. 注册:add_disk

C、 NandFlash硬件原理图:


D、各引脚作用:

    问1:原理图上NAND_FLASH和S3C2440之间只有(DATA0~DATA7)数据线,怎么传输地址呢?
    答1:在DATA0~DATA7上既有传输数据,又传输地址,还传输命令。当ALE为高电平时传输的是地址;当ALE为低电平时传输的是数据。
    问2:从NAND_FLASH芯片手册可知,要操作NAND_FLASH需要先发出命令,怎么传入命令?
    答2:当ALE为高电平时传输的是地址;当CLE为高电平时传输的是命令;当ALE和CLE都为低电平时传输的是数据。
    问3:数据线既接到NAND_FLASH,也接到NOR_FLASH,还接到SDRAM,DM9000等等?
    答3:这些设备在访问之前必须"选中",没有选中的芯片相当没接一样。
    问4:假设烧写NAND_FLASH,把命令、地址、数据发给它之后,NAND_FLASH肯定不可能瞬间完成烧写,怎么判断烧写完成?
    答4:通过状态引脚RnB来判断:它为高电平表示就绪,它为低电平表示正忙。
    问5:怎么操作NAND_FLASH呢?
    答5:根据NAND_FLASH的芯片手册,一般过程是:a. 发出命令; b. 发出地址; c.发出数据/读取数据
    nFWE、nFRE分别表示读写信号。

以读ID操作为例


执行不同的操作,NAND_FLASH和S3C2440对应步骤



E、 用Uboot来体验NAND_FLASH的操作之读取ID


先看看md和mw如何操作



第一步:操作寄存器bit1设为0,选中


第二步:发出命令0x90,发出地址0x00



第三步:获取数据



第四步:退出读ID的状态


F、 用Uboot来体验NAND_FLASH的操作之读内容
读取NAND中0地址的数据:使用Uboot命令(nand dump 0)


(nand dump)实现了发命令,发地址、读数据的操作。若想通过操作寄存器,如何读出nand上的内容





Uboot上操作寄存器来模拟(nand dump)命令,最后读到的结果就和(nand dump)结果一样。

二、 NAND_FALSH驱动程序框架(第十九课/第二节)

NAND_FLASH驱动程序层次
看内核启动信息:


在内核里面搜索框中的内容


从入口函数开始



是否有同名的平台设备


查看(s3c24xx_nand_probe)函数




来看看(nand_scan)做了哪些事情


到nand_scan_ident看看做了什么


来看看获取flash类型的函数(nand_get_flash_type)



回到nand_scan函数,到nand_scan_tail函数看看


构造mtd_info


回到probe函数,看看(s3c2410_nand_add_partion)函数


跟着函数进去



看看这个(add_mtd_device)函数做了什么事情



搜索一下在哪儿设置的,这个函数就会把一个结构体放入链表里


这个函数又是在哪儿被调用的,搜索一下


当在add_mtd_device函数的链表中查询到有Nand设备的时候就会调用list_for_each中的add函数,来看看这个add函数



先看看字符设备的mtd_notify_add


只有在查询到nand之后才会调用add函数,从而创建设备结点

同理,再来看看块设备


当在add_mtd_device函数的链表中查询到有Nand设备的时候就会调用list_for_each中的add函数,来看看这个add函数



再来看看块设备的blktrans_notify_add


这个链表在哪儿设置的



这个(register_mtd_blktrans)函数又是在哪儿被调用的呢?搜索一下。



当在blktrans_notify_add函数的链表中查询到有mtd_blktrans_ops结构的时候就会调用list_for_each中的add_mtd函数,来看看这个add函数


来看看这个(mtdblock_add_mtd)函数内容


跟进函数




这个初始化队列在哪儿被设置的,搜索一下


框架:


nand驱动程序框架


我们可以把NAND_FLASH当做字符设备,也可以当做块设备。在启动后的内核里查看(ls /dev/mtd* -l)

三、 NAND_FALSH驱动程序之编写代码之1简单编写(第十九课/第三节)

参考(at91_nand.c)中的probe函数代码
分配内存



自己写程序,仿造一下


看看nand_scan函数需要什么,然后在设置
里面有一个设置默认函数,如果nand_chip结构中指向函数的指针都为空就调用默认的函数


1.首先来看看默认的选中是否适合我们使用


所以我们需要自己提供这个函数



2.再看看命令函数是否适用


看看别人的cmd_ctrl函数是怎么做的,来搜索一下



所以即使使用默认的命令函数最终也会调用(cmd_ctrl)函数,我们自己来实现这个函数。
仿造别人写这个函数



3.继续看看默认的读数据函数


4.写数据函数


5.判断状态函数



2440有一个状态寄存器,它的bit0就表示状态



四、 NAND_FALSH驱动程序之编写代码之2完善识别过程(第十九课/第三节)

1th、 现在开始来填充那些函数,这些函数要操作那些寄存器,所以要映射寄存器**

定义一个寄存器的结构体


映射寄存器地址


填充选中函数


填充发送命令地址函数


填充判断状态函数


填充nfdat寄存器虚拟地址


设置硬件相关的设置,比如nand的时间参数,发出一些信号应该维持一定的时钟才行,若时间太短可能nand_flash还没反应过来。
先看看2440芯片手册


  • TACLS:表示发出(CLE/ALE)信号多长时间才发出(nWE)信号。
  • TWRPH0:表示(nWE)信号脉冲维持的时间。
  • TWRPH1:表示(nWE)变为高电平后多长时间(CLE/ALE)才能变为低电平。
    查看nand_flash手册来设置这些值




    使能nand控制器



    使能nand时钟,为了省电内核一启动就会把用不到的模块都给关掉,实质上就是设置(CLKCOM)这个寄存器


    我们要使用就得把bit4设置为1,可以先(ioremap)这个寄存器然后在设置这个位,也可以使用内核提供的(clk_get)函数。
    在做硬件的设置之前就应该使能这个时钟



    写出口函数

测试1th:

现在还不用去掉原来的nand驱动程序,因为现在只是识别,等以后实现第五步添加分区了在把它去掉。
加载驱动:


等会儿只需要"add_mtd_partition"就能通知"字符设备"和"块设备",块设备里面最终会分配一个gendisk结构,然后"add_disk"注册这个gendisk结构。我们先来消除这个警告,ECC是什么呢?
先来看看NAND的结构:

一页一页(一页就是一个扇区)的结构,一页是2KB,,除了这2KB外还有64B的空间,这个64B的空间叫做"OOB"(out of bank在BANK之外的东西)。这个OOB区不参与统一的编址。
也就是说假如某一页的地址是"0-2047",那么2048这个地址不是在OOB区,而是在该页的下一页。

为什么会引入OOB区呢?

因为NAND天生有一个缺点:位反转。如读一页数据时,里面很有可能某一位发生了位反转,本来值是0,读出来是1;同理,写的时候也有可能发生位反转。所以就引入了ECC校验,在写操作的时候除了写这一页数据以外,还会用这一页数据生成ECC码,然后把ECC码烧写到OOB区。

解决位反转办法:
烧写时:


读取时:



这个ECC校验码可以用硬件生成,也可以用软件生成。
用软件生成只需要设置一项就好了。来看看别人怎么做的


仿造一下


继续测试:
重新编译然后加载驱动

五、 NAND_FALSH驱动程序之编写代码之3添加MTD设备及测试(第十九课/第三节)

现在继续来完善这个程序,当我们扫描识别出来以后,就会构造出"mtd_info"结构体,里面读写擦除各种函数就都有了。现在就剩下添加分区了。


来看看这个函数需要什么参数

  1. 参1,mtd_info结构体。
  2. 参2,mtd_partition结构体指针,传入的参数可能是一个数组,里面的每一个组员都是"mtd_partition"的结构体。
  3. 参3,表示使用参数2数组的组员个数。

可以来看看内核的分区信息,然后搜索一下




我们拷贝过来然后仿造一下


填充add_mtd_partition函数参数


在出口函数删除mtd分区,这个驱动程序就完善了

测试2th:

第一步:做实验之前需要把内核自带的NAND_FLASH驱动。



第二步:编译:make uImage v=1(v=1表示把命令更加详细的列出来)


第三步:使用没有nand驱动程序的新内核启动,并且设置启动参数使用NFS作为根文件系统。
看看以前的启动参数:


设置启动参数:


使用nfs加载新内核然后启动



从启动的信息可以看到没有关于nand的东西了
查看/dev/mtd,发现确实没有了


第四步:装载驱动


再次查看/dev/mtd,发现四个分区都出来了


挂接:mount /dev/mtdblock3 /mnt


可以进行操作了


第五步:格式化
A、 需要准备格式化工具

1.解压:

2.进入解压文件的util目录:

3.修改Makefile:把#CROSS=arm-linux-改为CROSS=arm-linux-(去掉#号)

4.make

5.拷贝文件到网络文件系统


flash_erase表示擦除一个扇区;flash_eraseall表示把这整块分区都给擦除。

B、 卸载挂接后擦除最后一个分区,擦除后本身就是yaffs文件了


第六步:挂接:(mount -t yaffs /dev/mtdblock3 /mnt)


第七部:在/mnt目录下创建文件
A、 vi 1.txt


B、 回到根目录,然后取消挂载,重启(reboot),使用nfs文件系统重启,重启后看看文件是否还在



C、 装载模块


D、 挂接:mount /dev/mtdblock3 /mnt


E、 查看文件是否还在

NAND_FLASH驱动程序源码

/*
 * 参考:linux-2.6.22.6\drivers\mtd\nand\s3c2410.c
 *         linux-2.6.22.6\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>

static struct nand_chip* s3c_nand_chip;
static struct mtd_info* s3c_mtd;
static struct clk* s3c_nand_clk;
static struct s3c_nand_regs* s3c_nand_regs;

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 mtd_partition s3c_nand_part[] = {
    [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 s3c_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 s3c_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
    if (cmd == NAND_CMD_NONE)
        return;

    if (ctrl & NAND_CLE)
    {
        /* 发命令:NFCMMD = cmd */
        s3c_nand_regs->nfcmd = cmd;
    }
    else
    {
        /* 发地址:NFADDR = cmd */
        s3c_nand_regs->nfaddr = cmd;
    }
}

static int s3c_dev_ready(struct mtd_info *mtd)
{
    return (s3c_nand_regs->nfstat & (1 << 0));
}

static int s3c_nand_init(void)
{
    /* 1. 分配一个nand_chip结构体 */
    s3c_nand_chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
    s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs));

    /* 2. 设置nand_chip是给nand_scan函数使用的 */
    /* 它应该提供:选中、发命令、发地址、发/读数据、判断状态的功能 */
    s3c_nand_chip->select_chip = s3c_select_chip;
    s3c_nand_chip->cmd_ctrl = s3c_cmd_ctrl;
    s3c_nand_chip->IO_ADDR_R = &s3c_nand_regs->nfdata;
    s3c_nand_chip->IO_ADDR_W = &s3c_nand_regs->nfdata;
    s3c_nand_chip->dev_ready = s3c_dev_ready;
    s3c_nand_chip->ecc.mode = NAND_ECC_SOFT;    /* enable ECC */

    /* 3. 硬件相关操作 */
    /* 使能NAND_FLASH控制器的时钟 */
    s3c_nand_clk = clk_get(NULL, "nand");
    clk_enable(s3c_nand_clk);        //CLKCON[4] = 1
    /* HCLK=100MHz
     * TACLS[12:13]:  发出CLE/ALE之后多长时间才发出nWE信号, 从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
     * TWRPH0[8:10]: nWE的脉冲宽度, HCLK x ( TWRPH0 + 1 ), 从NAND手册可知它要>=12ns, 所以TWRPH0>=1
     * TWRPH1[4:6]: 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_chip与mtd_info的联系,使用:nand_scan */
    s3c_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
    s3c_mtd->priv = s3c_nand_chip;
    s3c_mtd->owner = THIS_MODULE;

    /* 识别、构造mtd */
    nand_scan(s3c_mtd, 1);        //参2表示最多芯片个数,我们为一个芯片。

    /* 5. add_mtd_partitions */
    add_mtd_partitions(s3c_mtd, s3c_nand_part, 4);
    return 0;
}

static void s3c_nand_exit(void)
{
    del_mtd_partitions(s3c_mtd);
    kfree(s3c_mtd);
    iounmap(s3c_nand_regs);
    clk_disable(s3c_nand_clk);
    clk_put(s3c_nand_clk);
    kfree(s3c_nand_chip);
}

module_init(s3c_nand_init);
module_exit(s3c_nand_exit);

MODULE_LICENSE("GPL");

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

       

原文地址:https://www.cnblogs.com/luosir520/p/11458712.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


  译序:JWMediaPlayer是开源的网页使用的Flash播放器。本文采摘于JWPlayer的官方文档,讲解了JWPlayer对于RTMP的使用方法,我们可以从JWPlayer客户端的角度来了解RTMP协议。以下是官方原文:      简介    RTMP(RealTimeMessagingProtocol
    Flash编程原理都是只能将1写为0,而不能将0写成1.所以在Flash编程之前,必须将对应的块擦除,而擦除的过程就是将所有位都写为1的过程,块内的所有字节变为0xFF.因此可以说,编程是将相应位写0的过程,而擦除是将相应位写1的过程,两者的执行过程完全相反.一、Nor和NandFlash
 上传setenvgatewayip192.168.1.1;setenvserverip192.168.1.7;setenvipaddr192.168.1.156;mw.b0x820000000xff0x1000000sfprobe0sfread0x8200000000x1000000tftp0x82000000test.bin0x1000000 下载mw.b82000000ff1000000tftp82000000test.bi
Error:FlashDownloadFailed-"Cortex-M3"出现一般有两种情况:1.SWD模式下,Debug菜单中,Reset菜单选项(Autodetect/HWreset/sysresetReq/Vectreset)默认是AutoDetect,改成SysResetReq即可。2.Jtag模式下,主要是芯片大小选错。Flash->ConfigureFalshTools配置窗口,切换到“Utilities"
jPlayer是一个用于控制和播放mp3文件的jQuery插件。它在后台使用Flash来播放mp3文件,前台播放器外观完全可以使用XHML/CSS自定义。支持:有一点比较好的是,在支持html5的浏览器上会使用html5的标签audio或者video,而不支持的浏览器上使用swf来播放选择需要播放的Mp3文件。播放、暂停
#ifndef__FONTUPD_H__#define__FONTUPD_H__#include"sys.h" //字库信息结构体定义33字节__packedtypedefstruct{u8fontok;//字库存在标志,0XAA,字库正常;其他,字库不存在u32ugbkaddr;//unigbk的地址u32ugbksize;//unigbk的大小u32f12addr;//gbk12地址u32g
ROM(ReadOnlyMemory)和RAM(RandomAccessMemory)指的都是半导体存储器。ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是在掉电之后就丢失数据,但是访问速度快。典型的RAM就是计算机的内存。RAM有两大类,一种称为静态RAM(StaticRAM/SRAM),SRAM速度非常快,是目前读写最快的存储
JSpc端和移动端实现复制到剪贴板功能实现在网页上复制文本到剪切板,一般是使用JS+Flash结合的方法,网上有很多相关文章介绍。随着HTML5技术的发展,Flash已经在很多场合不适用了,甚至被屏蔽。本文介绍的一款JS插件,实现了纯JS方法复制文本到剪切板。插件名是Clipboard.js,该插件不依
例子:R0=1R1=1R2=10R3=e000ed10R12=0LR=fffffff9(中断返回值)PC=0PSR=60000013或60000016或60000036(Z、C、EXCEPT_NUM:RTC_WKUP_IRQn、EXTI0_IRQn、USART2_IRQn)BFAR=e000ed38(不关心)CFSR=20000(INVSTATE:Invalidstateusagefault thePCvaluestackedf
 内存接口概念首先来分析下操作GPIO控制器和操作UART控制器两者的区别如图是S3C2440是个片上系统,有GPIO控制器(接有GPIO管脚),有串口控制器(接有TXDRXD引脚)配置GPIO控制器相应的寄存器,即可让引脚输出高低电平;配置UART控制器相应的寄存器,即可让引脚输出波形。前者相对简单,类
小编导语:    近几年来,网页游戏成为了游戏界关注的焦点,由于其制作简单,成本低并且收益率较高,因此成为了众多游戏厂商追逐的对象,但是除了商家夸张的炒作宣传外,很少有页游佳作出现。然而,随着Unity3D游戏引擎的出现,网页游戏的3D化成了页游冲出重围的杀手锏,那么在flash网页游戏称
1.指定数组到特定的Flash单元#pragmalocation=0x000FFF00 __rootconstcharFlash_config[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0
继续研究发现,计算机的固件真的很有趣。参考了一些重要的资料,比如http://donovan6000.blogspot.com/2013/06/insyde-bios-modding-advanced-and-power-tabs.html等,对于IDA的使用也了解了一些。最后,总结一下目前看来可行性的方案:0.基础知识储备,包括UEFIBIOS的概念,InsydeBIOS的
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>navigator对象<itle></head><body><buttononclick="checkFlash()">检测</button>
修改网上流传的flash-marker.js(function(global,factory){typeofexports==='object'&&typeofmodule!=='undefined'?module.exports=factory():typeofdefine==='function'&&define.amd?define(factory
shareObject本地缓存存储位置:win7系统用户到C:\Users\[你的用户名]\AppData\Roaming\Macromedia\FlashPlayer\#SharedObjects\XP或2003用户到:C:\DocumentsandSettings\用户名\ApplicationData\Macromedia\FlashPlayer\#SharedObjects\ ---------------------作者:iteye_
安装谷歌浏览器之后经常遇到Flash崩溃或者浏览器在浏览Flash内容时卡死的情况。在网上查找资料大多都认为应该是浏览器自带的Flash插件工作模式引起的问题,解决方法如下:首先在地址栏输入chrome://plugins/显示浏览器使用的插件。点击右上角的详细信息,可以看到Flash插件为进程外
之前一直使用的W25Q16spiflash都没问题,换了一款W25Q80后发现工作不正常,经过测试,初步定位到问题在于初始化SPI后是否将CS拉高。于是又去查看了一下原厂代码:发现原厂的代码初始化SPI接口时是专门拉高CS的。结论:网上很多代码初始化SPI接口时没有专门拉高CS,对某些型号可能确实
======================================================NANDFlash最小存储单元:写数据操作:通过对控制闸(ControlGate)施加高电压,然后允许源极(SOURCE)和汲极(RRAIN)间的N信道(N-Channel)流入电子,等到电流够强,电子获得足够能量时,便会越过浮置闸(FloatingGate)底下的二氧化硅层(S
安装CnarioPlayer3.8.1.156或其他版本时,有时会出现如下提示:Warning4154.AdobeFlashPlayer13...notcorrectlyinstalled:请前往AdobeFlash网站,并选择下图示的版本下载安装: