NandFlash驱动超详细分析
u-boot_2010.6nandflash驱动彻底分析

u-boot_2010.6nandflash驱动彻底分析2017年11⽉13⽇15:37:34最近公司⼤裁员,闹的⼈⼼惶惶,不管怎么样,武装好⾃⼰才是硬道理,坚持学习,学会那些还没学会的。
今天虚拟机突然打不开了,吓了我⼀跳,因为代码都还没备份,⼀定得养成备份代码的习惯!好了,下⾯开始进⼊正题吧,nandflash驱动彻底分析底层驱动移植完后,执⾏nand 命令:nand read 0x30000000 0 0x2000nand read 的命令格式是 nand read addr off | partition size ,总结起来就是读到哪去?从哪读?读多⼤?返回的结果是:NAND read: device 0 offset 0x0, size 0x2000file is nand_util.c,fun is nand_read_skip_bad,line is 599,NAND read from offset 2000 failed -740 bytes read: ERROR读失败,给出读失败错误码 -74要分析失败原因,先分析函数执⾏流程执⾏nand read 命令后,其实是执⾏了nand_read_skip_bad(nand, off, &size,(u_char *)addr);跳过坏块读函数的参数简单明了,从哪读,读到哪去,读多少,以及⼀个公共句柄(包含nand的信息,例如有多少个块,块⼤⼩等) 1int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,2 u_char *buffer)3 {4int rval;5 size_t left_to_read = *length;6 size_t len_incl_bad;7 u_char *p_buffer = buffer;89 len_incl_bad = get_len_incl_bad (nand, offset, *length); /* 函数分析见2017.11.14笔记(往下翻) */1011if ((offset + len_incl_bad) > nand->size) {12 printf ("Attempt to read outside the flash area\n");13return -EINVAL;14 }1516if (len_incl_bad == *length) {17 rval = nand_read (nand, offset, length, buffer);18if (!rval || rval == -EUCLEAN)19return0;20 printf ("NAND read from offset %llx failed %d\n",21 offset, rval);22return rval;23 }2425while (left_to_read > 0) {26 size_t block_offset = offset & (nand->erasesize - 1);27 size_t read_length;2829 WATCHDOG_RESET ();3031if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {32 printf ("Skipping bad block 0x%08llx\n",33 offset & ~(nand->erasesize - 1));34 offset += nand->erasesize - block_offset;35continue;36 }3738if (left_to_read < (nand->erasesize - block_offset))39 read_length = left_to_read;40else41 read_length = nand->erasesize - block_offset;42/* read_length 最⼤不会超过 nand->erasesize (128K) */43/* nand_read 函数是⼀个按块读函数 */44 rval = nand_read (nand, offset, &read_length, p_buffer);45if (rval && rval != -EUCLEAN) {46 printf ("NAND read from offset %llx failed %d\n",47 offset, rval);48 *length -= left_to_read;49return rval;50 }5152 left_to_read -= read_length;53 offset += read_length;54 p_buffer += read_length;55 }5657return0;58 }先看get_len_incl_bad1static size_t get_len_incl_bad (nand_info_t *nand, loff_t offset,2const size_t length)3 {4 size_t len_incl_bad = 0;5 size_t len_excl_bad = 0;6 size_t block_len;78while (len_excl_bad < length) {9 block_len = nand->erasesize - (offset & (nand->erasesize - 1));1011if (!nand_block_isbad (nand, offset & ~(nand->erasesize - 1)))12 len_excl_bad += block_len;1314 len_incl_bad += block_len;15 offset += block_len;1617if (offset >= nand->size)18break;19 }2021return len_incl_bad;22 }想要看懂这个函数,先要理解offset的构成2017年11⽉14⽇10:00:40每天进步⼀点点nand->erasesize = 128K = 0x20000nand->erasesize - 1 = 0x1FFFFoffset & (nand->erasesize - 1) 保留低17位,清⾼位,因为nand的特性,所以是按块来统计长度block_len = nand->erasesize - offset & (nand->erasesize - 1) 作⽤是统计当前块要读的长度然后判断当前块是不是坏块,如果不是坏块,则让len_excl_bad += block_len,判断是否循环的标准是len_excl_bad < length 不论当前块是不是坏块,都让len_incl_bad += block_len,len_incl_bad 得到的是包含坏块的长度总结get_len_incl_bad函数的作⽤为:①如果偏移offset是从整块开始的,返回的结果是块的整数倍(不⽤看length,⽐如length是0x20001,则读两块)②如果偏移offset不是从整块开始的,返回的结果是块的整数倍+第⼀块要读的长度总之,返回的结果是按块补齐的再继续分析nand_read_skip_bad1if (len_incl_bad == *length) {2 rval = nand_read (nand, offset, length, buffer);3if (!rval || rval == -EUCLEAN)4return0;56return rval;7 }什么情况下,len_incl_bad == *length ?要读的内容⾥,没有坏块,且长度最后按块对齐(例如,从0x400开始读,读的长度为0x40000-0x400)如果不满⾜,则进⼊while循环读,在while⾥,按块读,先判断当前块是不是坏块,如果是则跳过,不是则读下⾯分析nand_read函数1/* 1.从哪读 2.读多少 3.读到哪去 */2static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,3 size_t *retlen, uint8_t *buf)4 {5struct nand_chip *chip = mtd->priv;6int ret;78/* Do not allow reads past end of device */9if ((from + len) > mtd->size)10return -EINVAL;11if (!len)12return0;13/* 选中芯⽚ */14 nand_get_device(chip, mtd, FL_READING);1516 chip->ops.len = len;17 chip->ops.datbuf = buf;18 chip->ops.oobbuf = NULL;1920 ret = nand_do_read_ops(mtd, from, &chip->ops);2122 *retlen = chip->ops.retlen;23/* 取消选中芯⽚ */24 nand_release_device(mtd);2526return ret;27 }其实真正的读函数是nand_do_read_ops,从哪去,读多少,读到哪去都被装载在chip->ops结构体中再看nand_do_read_ops函数1/**2 * nand_do_read_ops - [Internal] Read data with ECC3 *4 * @mtd: MTD device structure5 * @from: offset to read from6 * @ops: oob ops structure7 *8 * Internal function. Called with chip held.9*/10static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,11struct mtd_oob_ops *ops)12 {13int chipnr, page, realpage, col, bytes, aligned;14struct nand_chip *chip = mtd->priv;15struct mtd_ecc_stats stats;16int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;17int sndcmd = 1;18int ret = 0;19 uint32_t readlen = ops->len;//128K 0x20000 根据输⼊的长度决定20 uint32_t oobreadlen = ops->ooblen; // oobreadlen = 021 uint8_t *bufpoi, *oob, *buf;2223 stats = mtd->ecc_stats;2425 chipnr = (int)(from >> chip->chip_shift);26 chip->select_chip(mtd, chipnr);27/* realpage 总页地址(⾼17位) */28 realpage = (int)(from >> chip->page_shift);//pageshift is 1129 page = realpage & chip->pagemask;//pagemask = 1ffff30/* col 低11位 */31 col = (int)(from & (mtd->writesize - 1));//writesize = 2048, 2047 = 0x7ff32/* 得到页地址和列地址 */33 buf = ops->datbuf;34 oob = ops->oobbuf;3536while(1) {37 bytes = min(mtd->writesize - col, readlen); //128K 0x20000 根据输⼊的长度决定38 aligned = (bytes == mtd->writesize); //aligned = 1;3940/* Is the current page in the buffer ? */41if (realpage != chip->pagebuf || oob) {42 bufpoi = aligned ? buf : chip->buffers->databuf;43/* 对齐与不对齐读到的缓冲是不⼀样的 */44if (likely(sndcmd)) {45 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);46 sndcmd = 0;47 }4849/* Now read the page into the buffer */50if (unlikely(ops->mode == MTD_OOB_RAW))51 ret = chip->ecc.read_page_raw(mtd, chip,//nand_read_page_raw52 bufpoi, page);//从哪⾥读,读到哪⾥去,读多少53else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)54 ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);55/* nand_read_subpage */56else57 ret = chip->ecc.read_page(mtd, chip, bufpoi,//整页读 bufpoi = buf58 page); //nand_read_page_swecc59if (ret < 0)60break;6162/* Transfer not aligned data */63if (!aligned) {64if (!NAND_SUBPAGE_READ(chip) && !oob)65 chip->pagebuf = realpage;66 memcpy(buf, chip->buffers->databuf + col, bytes);67 }6869 buf += bytes;7071if (unlikely(oob)) {72/* Raw mode does data:oob:data:oob */73if (ops->mode != MTD_OOB_RAW) {74int toread = min(oobreadlen,75 chip->yout->oobavail);76if (toread) {77 oob = nand_transfer_oob(chip,78 oob, ops, toread);79 oobreadlen -= toread;80 }81 } else82 buf = nand_transfer_oob(chip,83 buf, ops, mtd->oobsize);84 }8586if (!(chip->options & NAND_NO_READRDY)) {87/*88 * Apply delay or wait for ready/busy pin. Do89 * this before the AUTOINCR check, so no90 * problems arise if a chip which does auto91 * increment is marked as NOAUTOINCR by the92 * board driver.93*/94if (!chip->dev_ready)95 udelay(chip->chip_delay);96else97 nand_wait_ready(mtd);98 }99 } else {100 memcpy(buf, chip->buffers->databuf + col, bytes);101 buf += bytes;102 }103104 readlen -= bytes;105106if (!readlen)107break;108109/* For subsequent reads align to page boundary. */110 col = 0;111/* Increment page address */112 realpage++;113114 page = realpage & chip->pagemask;115/* Check, if we cross a chip boundary */116if (!page) {117 chipnr++;118 chip->select_chip(mtd, -1);119 chip->select_chip(mtd, chipnr);120 }121122/* Check, if the chip supports auto page increment123 * or if we have hit a block boundary.124*/125if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))126 sndcmd = 1;127 }128129 ops->retlen = ops->len - (size_t) readlen;130if (oob)131 ops->oobretlen = ops->ooblen - oobreadlen;132133if (ret)134return ret;135136if (mtd->ecc_stats.failed - stats.failed)137return -EBADMSG;138139return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; 140 }。
NandFlash驱动编写知识详解与坏块管理

【Nand Flash驱动编写之前要了解的知识】1.硬件特性:【Flash的硬件实现机制】Flash全名叫做Flash Memory,属于非易失性存储设备(Non-volatile Memory Device),与此相对应的是易失性存储设备(Volatile Memory Device)。
关于什么是非易失性/易失性,从名字中就可以看出,非易失性就是不容易丢失,数据存储在这类设备中,即使断电了,也不会丢失,这类设备,除了Flash,还有其他比较常见的入硬盘,ROM等,与此相对的,易失性就是断电了,数据就丢失了,比如大家常用的内存,不论是以前的SDRAM,DDR SDRAM,还是现在的DDR2,DDR3等,都是断电后,数据就没了。
Flash的内部存储是MOSFET,里面有个悬浮门(Floating Gate),是真正存储数据的单元。
在Flash之前,紫外线可擦除(uv-erasable)的EPROM,就已经采用用Floating Gate存储数据这一技术了。
图1.典型的Flash内存单元的物理结构数据在Flash内存单元中是以电荷(electrical charge) 形式存储的。
存储电荷的多少,取决于图中的外部门(external gate)所被施加的电压,其控制了是向存储单元中冲入电荷还是使其释放电荷。
而数据的表示,以所存储的电荷的电压是否超过一个特定的阈值Vth来表示。
【SLC和MLC的实现机制】Nand Flash按照内部存储数据单元的电压的不同层次,也就是单个内存单元中,是存储1位数据,还是多位数据,可以分为SLC和MLC:1.SLC,Single Level Cell:单个存储单元,只存储一位数据,表示成1或0.就是上面介绍的,对于数据的表示,单个存储单元中内部所存储电荷的电压,和某个特定的阈值电压Vth,相比,如果大于此Vth值,就是表示1,反之,小于Vth,就表示0.对于nand Flash的数据的写入1,就是控制External Gate去充电,使得存储的电荷够多,超过阈值Vth,就表示1了。
NAND_Flash结构与驱动分析

一、NANDflash的物理组成NANDFlash的数据是以bit的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。
这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。
这些Line会再组成Page,(NANDFlash有多种结构,我使用的NANDFlash是K9F1208,下面内容针对三星的K9F1208U0M),每页528Bytes(512byte(MainArea)+16byte(SpareArea)),每32个page形成一个Block(32*528B)。
具体一片flash上有多少个Block视需要所定。
我所使用的三星k9f1208U0M具有4096个block,故总容量为4096*(32*528B)=66MB,但是其中的2MB是用来保存ECC校验码等额外数据的,故实际中可使用的为64MB。
NANDflash以页为单位读写数据,而以块为单位擦除数据。
按照这样的组织方式可以形成所谓的三类地址:ColumnAddress:StartingAddressoftheRegister.翻成中文为列地址,地址的低8位PageAddress:页地址BlockAddress:块地址对于NANDFlash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8位。
二、NANDFlash地址的表示512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1sthalfPageRegister和2ndhalfPageRegister,各自的访问由地址指针命令来选择,A[7:0]就是所谓的columnaddress(列地址),在进行擦除操作时不需要它,why?因为以块为单位擦除。
32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。
A8这一位地址被用来设置512byte的1sthalfpage还是2ndhalfpage,0表示1st,1表示2nd。
NANDFlash的驱动程序设计

NANDFlash的驱动程序设计NAND Flash是一种非常常见的闪存存储器技术,被广泛应用于各种存储设备中,如固态硬盘(SSD)、智能手机、平板电脑等。
在NAND Flash的使用中,驱动程序的设计起到了至关重要的作用,它负责管理NAND Flash的读写操作、错误校验和坏块管理等功能,下面将详细介绍NAND Flash驱动程序的设计要点。
一、硬件初始化NAND Flash驱动程序的第一个任务是对底层硬件进行初始化。
这包括将NAND Flash的外设进行初始化,初始化NAND Flash控制器、时钟、引脚状态等。
除此之外,还需要读取存储设备的ID信息,根据ID信息识别NAND Flash的型号和芯片的特性。
二、坏块管理坏块是NAND Flash存储器中的一种常见问题,这会对数据的读写造成很大的影响。
因此,驱动程序需要实现坏块管理功能,通过检测和标记坏块,确保数据的可靠性。
具体操作包括读取坏块表、标记坏块、零填充和迁移数据等。
三、页擦除和写入在进行数据读写操作之前,需要先进行页擦除操作。
页擦除是将整个NAND Flash页面的数据擦除为全0,以便写入新的数据。
驱动程序需要实现页擦除操作,并确保擦除的正确性。
写入操作是将数据写入NAND Flash的页面中,包括数据的写入和校验。
驱动程序需要实现数据的写入功能,并对写入的数据进行校验,确保数据的正确性。
同时,还需要考虑到写入性能的优化,如批量写入、异步写入等方式。
四、数据读取驱动程序需要实现数据的读取功能,包括读取数据和校验读取的数据。
在读取过程中,需要注意读取的数据是否与写入的数据相符,以及是否发生了错误。
如果发现数据错误,驱动程序需要进行纠错处理,如使用错误检测与纠正(ECC)算法。
五、垃圾回收和回收管理垃圾回收是回收已经无法再写入的块,以便将来新数据的存储。
驱动程序需要实现垃圾回收功能,定时扫描并标记需要回收的块,并进行擦除。
回收管理包括垃圾回收策略的选择、回收操作的优化等。
linux2.6nandflash驱动说明

linux2.6nandflash驱动说明linux2.6.14移植---nandflash--by farsight 一、实验目的本实验是在前面网络芯片驱动实验的基础上,加入了对nandflash的支持,从而进一步完善系统结构,通过移植的过程来了解nandflash的移植方法。
二、实验设备1、虚拟机ubuntu7.042、优龙公司开发板fs2410以及开发板中移植好的u-boot1.1.43、串口线和网线、电源各一根三、实验步骤1、指明分区信息在arch/arm/mach-s3c2410/decs.c文件中:root@farsight:/source/kernel/linux-2.6.14# vim arch/arm/mach-s3c2410/devs.c在文件中添加以下信息:1、建立分区表:#include#include#includestatic struct mtd_partition partition_info[]={{name: "kernel",size: 0x001c0000,offset: 0x00040000,},{name: "root",size: 0x02300000,offset: 0x00200000,},{name: "yaffs",size: 0x01B00000,offset: 0x02500000,}};2、加入nandflash分区struct s3c2410_nand_set nandset={nr_partitions: 4,partitions:partition_info,};3、建立nandflash文件支持:struct s3c2410_platform_nand superlpplatform={tacls:0,twrph0:30,twrph1:0,sets:&nandset,nr_sets:1,};2、加入nand flash芯片支持到nand flash驱动修改此文件中的s3c_device_nand结构体变量,添加对dev成员的赋值:struct platform_device s3c_device_nand = {.name = "s3c2410-nand",.id = -1,.num_resources = ARRAY_SIZE(s3c_nand_resource),.resource = s3c_nand_resource,.dev={.platform_data=&superlpplatform}};3、指定启动时初始化kernel启动时依据我们对分区的设置进行初始配置,修改arch/arm/mach-s3c2410/mach-smdk2410.c文件root@farsight:/source/kernel/linux-2.6.14#vim arch/arm/mach-s3c2410/mach-smdk2410.c 修改smdk2410_devices[].指明初始化时包括我们在前面所设置的flash信息static struct platform_device *smdk2410_devices[] __initdata = {&s3c_device_usb,&s3c_device_lcd,&s3c_device_wdt,&s3c_device_i2c,&s3c_device_iis,&s3c_device_nand, /*added*/};4、配置MTDDevice Drivers --->Memory Technology Devices (MTD) --->[*] MTD partitioning supportNAND Flash Device Drivers ---><*> NAND Device Support<*> NAND Flash support for S3C2410/S3C2440 SoC5、编译内核root@farsight:/source/kernel/linux-2.6.14# make zImageroot@farsight:/source/kernel/linux-2.6.14# cp arch/arm/boot/zImage /tftpboot 启动开发板进行下载。
NandFLash分析与总结

友善之臂K9F1208U0C PCB04-5位,12代表512M位,也就是64M字节熟悉一下NandFlash的硬件:1主要的引脚:I/O0 —I/O7:数据输入输出端,命令,数据,地址复用端口(LDATA0-LDATA7)R/B: 准备忙输出(RnB)CE:芯片使能(nFCE)CLE: 命令锁存使能(CLE)ALE:地址锁存使能(ALE)WE:写使能(nFWE)RE:读使能(nFRE)2Mini2440的一些引脚设置:和寄存器设置:(NCON(Advflash), GPG13(页大小), GPG14(地址周期), GPG15(总线宽度)–参考引脚配置)#define rGSTATUS0 (*(volatile unsigned *)0x560000ac) //External pin status3NandFlash启动时,代码小于4k与大于4k的情况:在三星的NAND Flash 中,当CPU从NAND Flash开始启动时,CPU会通过内部的硬件将NAND Flash开始的4KB数据复制到称为“Steppingstone”的4KB 的内部RAM中,起始地址为0,然后跳到地址0处开始执行。
这也就是我们为什么可以把小于4KB的程序烧到NAND Flash中,可以运行,而当大于4KB时,却没有办法运行,必须借助于NAND Flash的读操作,读取4KB以后的程序到内存中。
4NandFlash的存储结构以及读写原理:4.1NandFlash中的块,页,位宽:●NAND Flash的数据是以bit的方式保存在memory cell(存储单元)一般情况下,一个cell中只能存储一个bit。
这些cell以8个或者16个为单位,连成bit line ,形成所谓的byte(x8)/word(x16),这就是NAND Flash的位宽。
这些Line会再组成Pape(页)。
然后是每32个page形成一个Block,所以一个Block(块)大小是16k.Block是NAND Flash中最大的操作单元。
Nandflash原理与启动详解

NandFlash原理与启动详解一、Nandflash内部是怎么工作的:1片Nandflash=1设备;1设备=4096块;1块=32页;1页=528字节=数据大小(512字节)+oob块大小(16字节)(oob用于Nandflash命令执行完成后设置状态)可以通过NAND Flash命令00h/01h/50h分别对前半部、后半部、OOB进行定位,通过NAND Flash内置的指针指向各自的首地址。
存储操作特点有:擦除操作的最小单位是块;NAND Flash芯片每一位只能从1变为0,而不能从0变为1,所以在对其进行写入操作之前一定要将相应块擦除(擦除即是将相应块的位全部变为1);OOB部分的第6字节(即517字节)标志是否是坏块,值为FF时不是坏块,否则为坏块。
除OOB第6字节外,通常至少把OOB的前3字节用来存放NAND Flash硬件ECC码。
(ECC:"Error Correcting Code" "错误检查纠正",带有奇偶校验的内存的主要功能。
)1.Nand flash以page为单位进行读写,以block为单位进行擦除,没页分为main区和spare区,main区用于存放正常的数据,spare区用于存放一些附加信息2.S3c2440 支持从Nand 启动是因为内部有一个叫做Steppingstone的SRAM buffer,当启动的时候,nand 的前4k的将会代码将被拷贝到steppingstone中执行,注意前4k代码是不会经过ECC校验的,所以必须确保这些代码的准确3.对nand的操作都是通过使用命令来实现,有的操作只要一个命令就可以完成,而有的需要两个命令才能完成,下面是K9F1G08U0B的命令表:4 Flash烧写程序原理及结构基本原理:将在SDRAM中的一段存储区域中的数据写到NAND Flash存储空间中。
烧写程序在纵向上分三层完成。
Nand Flash 驱动

Nand Flash 驱动详解1 nand_chip 结构位于\include\linux\mtd\nand.h,是NandFlash 驱动的一个核心数据结构。
IO_ADDR_R/IO_ADDR_W:读写Flash的地址,本系统中,该地址为0x40000000(CS3)read_byte / write_byte :读写字节的函数,根据数据总线的不同,可分别使用nand_read_byte16或nand_read_byte / nand_write_byte16或nand_write_byteread_word / write_word :读写字的函数,具体使用nand_read_word / nand_write_word实现read_buf / write_buf :读写缓存的函数,根据数据总线的不同,可分别使用nand_read_buf16或nand_read_buf / nand_write_buf16 或nand_write_buf 实现verify_buf:缓存校验,验证从Flash中读取的内容是否与缓存中一致,根据数据总线的不同,可分别使用nand_verify_buf16 或nand_verify_buf 实现 select_chip:选择芯片,当参数为0时,置CS3为低,当参数为-1时,置CS3为高。
具体由nand_select_chip实现,其实是通过调用hwcontrol实现的。
block_bad:读取指定页的Bad标记(badblockpos处,在使用小块NandFlash 时,该变量为5,使用大块的NandFlash时,该变量为0),如果读到的内容为0xFF,则认为该Block未坏。
具体由nand_block_bad实现。
函数中用到nand_get_device,该函数用于处理多线程同时访问NandFlash的互锁。
block_markbad:具体由nand_default_block_markbad实现,该函数在bbt 中将指定偏移所属块标志为坏块,并利用write_bbt函数将其存储到Flash中。
WinCE中nandflash驱动开发介绍

WinCE中nandflash驱动开发介绍+WinCE中地Flash分区和Check Sum+ NAND和NOR的比较收藏摘录下来,用来学习,呵呵文章一:一.NAND和NOR的比较NOR和NAND是现在市场上两种主要的非易失闪存技术。
Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM 和EEPROM一统天下的局面。
紧接着,1989年,东芝公司发表了NAND flash结构,强调降低每比特的成本,更高的性能,并且象磁盘一样可以通过接口轻松升级。
但是经过了十多年之后,仍然有相当多的硬件工程师分不清NOR和NAND闪存。
相"flash存储器"经常可以与相"NOR存储器"互换使用。
许多业内人士也搞不清楚NAND闪存技术相对于NOR技术的优越之处,因为大多数情况下闪存只是用来存储少量的代码,这时NOR闪存更适合一些。
而NAND则是高数据存储密度的理想解决方案。
NOR的特点是芯片内执行(XIP, eXecut e In Place),这样应用程序可以直接在 flash闪存内运行,不必再把代码读到系统RAM中。
NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。
NAND结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快。
应用NAND的困难在于flash的管理和需要特殊的系统接口。
二.性能比较flash闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编程。
任何flash器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。
NAND器件执行擦除操作是十分简单的,而NOR则要求在进行擦除前先要将目标块内所有的位都写为0。
由于擦除NOR器件时是以64~128KB 的块进行的,执行一个写入/擦除操作的时间为5s,与此相反,擦除NAND器件是以8~32KB的块进行的,执行相同的操作最多只需要4ms。
NAND Flash驱动程序结构

NAND Flash驱动程序1、NAND Flash驱动程序框架FAT文件系统下的NAND Flash驱动程序采用了分层结构。
驱动程序的上层是Flash抽象层,是物理操作无关层,该层对NAND Flash的操作进行抽象,并采用一定的策略平衡了NAND Flash的擦写。
NAND Flash驱动程序的结构如图5.5所示。
图5.5 FAT下NAND Flash驱动结构在图中:File System即文件系统。
在这里,采用的是FAT文件系统。
FAT文件系统是一种采用链式分配方式的文件系统。
并没有对NAND Flash的特点优化,因此需要在下层的驱动程序做优化。
Flash Driver即NAND Flash驱动程序。
对上层的文件系统提供以DSK为前缀的流驱动接口。
该层驱动程序本身分为两层:FAL层、F MD层。
(1)、FAL层即Flash Abstraction Layer,Flash抽象层。
该层主要提供三个功能:A、将物理的Flash抽象成统一的接口提供给上层的文件系统。
B、将逻辑扇区地址转换成物理扇区地址。
上层的FAT文件系统使用的是逻辑扇区地址,并不是真正的物理扇区,其转换由FAL实现。
C、对Flash实现损耗平衡("Wear-level")。
为了避免反复的擦写Flash的同一个块,需要一种策略来减少反复的擦写块。
(2)、FMD层即Flash Media Driver,Flash介质驱动层。
该层实现FAL层的请求,对Flash物理扇区进行操作。
Flash Hardware即NAND Flash物理芯片。
2、FAL层(Flash Abstraction Layer)1)函数接口定义FAL层对上的函数接口也就是整个NAND Flash驱动程序的对外接口,由于NAND Flash 是块设备,Windows CE中块设备采用的是流驱动接口,流驱动接口是一个标准的统一接口,只是各个驱动的前缀不同,在这里NAND Flash函数接口的前缀为“DSK”,这个前缀也使得Windows CE将“DSKxx:”的文件名看作为设备,使得我们能够通过Windows CE标准的Win32 API,如CreateFile、DeviceIOControl等来对设备进行打开、读写等操作。
mtdnandflash分析

mtd nandflash 分析一、MTD 的概念和层次MTD(memory technology device 存储技术设备) 是用于访问memory 设备(ROM 、flash )的Linux 的子系统。
MTD 的主要目的是为了使新的memory 设备的驱动更加简单,为此它在硬件和上层之间提供了一个抽象的接口。
MTD 的所有源代码在/drivers/mtd 子目录下。
[1]传统上,UNIX 只认识块设备和字符设备。
字符设备是类似键盘或者鼠标的这类设备,你必须从它读取当前数据,但是不可以定位也没有大小。
块设备有固定的大小并且可以定位,它们恰好组织成许多字节的块,通常为512字节。
闪存既不满足块设备描述也不满足字符设备的描述。
它们表现的类似块设备,但又有所不同。
比如,块设备不区分写和擦除操作。
因此,一种符合闪存特性的特殊设备类型诞生了,就是MTD 设备。
所以MTD 既不是块设备,也不是字符设备。
[2]关于MTD 的层次,网络上有一张流传盛广的图片,如下所示,但是最初我看了这幅图根本是一点概念都没有的,不过通过看代码和网上查阅资料,知道了详细一点的分层结构,也纠正了一些前期对这张图的误解。
( 以下这部分纯属个人理解,如果有误,请高人拍砖!)为了方便理解,先声明两点:1. xxx 层(MTD 原始设备层,MTD 块设备层) ,实现封装的代码。
2. xxx 设备(MTD 原始设备,MTD 块设备) ,是xxx 层向下封装后呈现给上层的表象就是一个xxx 设备。
Flash 硬件驱动层:该层的基于特定处理器和特定flash 芯片,这里以pxa935 和Hynix NAND 512MB 1.8V 16-bit 为例。
使用类型为nand_chip, pxa3xx_nand_info, dfc_context, pxa3xx_bbm 这几个结构体来实现硬件驱动。
代码位于drivers/mtd/nand 目录下。
S3C6410 NAND Flash驱动分析

S3C6410NAND Flash驱动分析文档单位名称:无锡东集电子公司部门名称:SOC系统研发部系统I组文档修订记录版本时间修订者备注1.0 2009-3-30 张纪艳010zjy 完成初稿每次修改需说明修改内容1.目的意义通过对6410下NAND Flash驱动的分析,了解以ARM11为内核的处理器下NAND Flash驱动的实现方式,并为SEP0718处理器中NAND Flash驱动的实现做准备。
2.背景该文档中的分析的NAND FLash驱动由华恒提供,其软硬件平台分别为:硬件平台:S3C6410软件平台:WinCE 6.03.硬件原理3.1NAND Flash分类从存储容量方面,NAND Flash包括两种:大容量NAND Flash和小容量NAND Flash,大容量为每页(2048+64)Byte,小容量为每页(512+16)Byte。
从组成存储单元的类型方面NAND Flash也包括两种:SLC(Single Level Cell)与MLC(Multi Level Cell)。
SLC技术与EEPROM原理类似,只是在浮置闸极(Floating gate)与源极(Source gate)之中的氧化薄膜更薄,其数据的写入是透过对浮置闸极的电荷加电压,然后可以透过源极,即可将所储存的电荷消除,采用这样的方式便可储存每1个信息位,这种技术的单一位方式能提供快速的程序编程与读取。
MLC原理是将两个位的信息存入一个浮动栅(Floating Gate,闪存存储单元中存放电荷的部分),然后利用不同电位的电荷,透过内存储存格的电压控制精准读写。
即一个Cell存放多个bit,现在常见的MLC架构闪存每Cell可存放2bit,容量是同等SLC架构芯片的2倍。
这也使得MLC NAND Flash的存取速度较慢。
MLC因较大容量和价格优势,具有较好的应用前景。
3.2NAND Flash硬件结构NandFlash用来保存大容量的数据,该系统中采用三星公司的K9G8G08,其要求电压范围为2.7~3.6V,总容量为(1G+32M)*8bit,其中1GB为数据区的容量,32MB为信息区的总容量,内部数据寄存器容量为(2K+64)Byte。
NANDflash详解

NANDflash详解NAND flash和NOR flash的区别详解[导读]我们使⽤的智能⼿机除了有⼀个可⽤的空间(如苹果8G、16G等),还有⼀个RAM容量,很多⼈都不是很清楚,为什么需要⼆个这样的芯⽚做存储呢,这就是我们下⾯要讲到的这⼆种存储.关键词:NOR flashNand flashFlaSh我们使⽤的智能⼿机除了有⼀个可⽤的空间(如苹果8G、16G等),还有⼀个RAM容量,很多⼈都不是很清楚,为什么需要⼆个这样的芯⽚做存储呢,这就是我们下⾯要讲到的。
这⼆种存储设备我们都统称为“FLASH”,FLASH是⼀种存储芯⽚,全名叫Flash EEPROM Memory,通地过程序可以修改数据,即平时所说的“闪存”。
Flash⼜分为NAND flash和NOR flash⼆种。
U盘和MP3⾥⽤的就是这种存储器。
相“flash存储器”经常可以与相“NOR存储器”互换使⽤。
许多业内⼈⼠也搞不清楚NAND闪存技术相对于NOR技术的优越之处,因为⼤多数情况下闪存只是⽤来存储少量的代码,这时NOR闪存更适合⼀些。
⽽NAND则是⾼数据存储密度的理想解决⽅案。
NOR Flash 的读取和我们常见的 SDRAM 的读取是⼀样,⽤户可以直接运⾏装载在 NOR FLASH ⾥⾯的代码,这样可以减少 SRAM 的容量从⽽节约了成本。
NAND Flash 没有采取内存的随机读取技术,它的读取是以⼀次读取⼀块的形式来进⾏的,通常是⼀次读取 512 个字节,采⽤这种技术的 Flash ⽐较廉价。
⽤户不能直接运⾏ NAND Flash 上的代码,因此好多使⽤ NAND Flash 的开发板除了使⽤ NAND Flah以外,还作上了⼀块⼩的 NOR Flash 来运⾏启动代码。
NOR flash是intel公司1988年开发出了NOR flash技术。
NOR的特点是芯⽚内执⾏(XIP, eXecute In Place),这样应⽤程序可以直接在flash 闪存内运⾏,不必再把代码读到系统RAM中。
NandFlash驱动(实现初始化以及读操作)

NandFlash驱动(实现初始化以及读操作)本节来学习裸机下的Nand Flash驱动,本节学完后,再来学习Linux下如何使⽤Nand Flash驱动Linux中的Nand Flash驱动,链接如下:(只需要初始化Flash以及读Flash)打开2440芯⽚⼿册,K9F2G08U0M芯⽚⼿册(因为2440中Nand Flash是⽤的256MB(2Gb)内存,8个数据引脚)在芯⽚⼿册中得到K9F2G08U0M=2048块Block=128K页Pages=256MB=2Gb1个设备=2048块Block1块Block=64页Pages1页=(2K+64)B (因为每个地址⾥都存放了⼀个字节,所以⽤B表⽰)其中64B是存放ECC的OOB地址,(ECC:存放判断位反转的校验码)Nand Flash 缺点:读数据容易位反转可以通过ECC编码器值来判断读数据是否位反转,若位反转则重新读数据写过程:1)写页数据2)然后⽣成ECC3)将ECC写⼊到OBB页地址⾥(写数据是不会出现位反转)读过程:1)读出页数据,然后⽣成临时ECC(此时ECC可能有错)2)然后读出OOB页地址⾥的ECC3)⽐较两个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=20nStCLS和tALS是等待WE(写信号)结束的时间, tCLS=tALS=15nStWP是WE(写信号)维持时间, tWP=15nStALH是等待命令写⼊成功的时间, tALH=5nStCLH是等待地址写⼊成功的时间, tCLH=5nS图3(2440-nandflash时序图):⾸先查看2440芯⽚⼿册⾥nandflash时序图,如上图,可以看出需要设置TACLS,TWRPH0和TWRPH1,这三个参数TACLS:属于等待WE(写信号)就绪的时间,对⽐图2得出TACLS= tCLS- tWP=0nSTWRPH0:属于WE(写信号)的时间, 对⽐图2得出TWRPH0= tWP=15nSTWRPH1:属于等待命令写⼊成功的时间,对⽐图2得出TWRPH1=tALH=tCLH=5nS最后,在NFCONF寄存器中设置这三个参数TACLS[13:12]表⽰Duration(持续时间)=HCLK*TACLS,由于Duration=0nS,所以TACLS=0TWRPH0 [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()初始化:/* 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()函数初始化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之前都要选中⽚选)nand_select() //使能⽚选{int i;NFCONT&=~(1<<1); // NFCONT控制器位1置0for(i=0;i<10;i++); //等待芯⽚使能成功}2.1.2取消⽚选函数(退出读写FLASH时需要取消⽚选)nand_deselect() //取消⽚选{int i;NFCONT&=~(1<<1); // NFCONT控制器位1置0for(i=0;i<10;i++); //等待芯⽚使能成功}2.1.3读命令函数nand_cmd(unsigned char cmd){int i;NFCMMD= cmd; // 向NFCMMD寄存器写⼊命令for(i=0;i<10;i++); //等待写⼊命令成功}2.1.4判断RnB状态函数(在写⼊所有命令后都要判断RnB脚是否为⾼电平就绪)nand_waite_idle(){int i;while(!(NFSTAT&0X01)) // 等待NFSTAT寄存器位0置1for(i=0;i<10;i++);}2.1.5读数据函数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()函数如下: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) 取消⽚选nCE2.4 所以nand_read()函数如下: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使能⽚选nCEwhile(i<len){ nand_cmd(0X00); //2发送读命令0X00nand_write_addr(src); // 3发送yuan地址(分为5个周期)nand_cmd(0X30); //4发送读命令0X30nand_wait_idle(); //5等待RnB信号为⾼电平for(;(col<2048)&&(i<len);col++) //连续读页内数据{dest[i]=nand_read_data(); //6.读数据i++;src++;}col=0;}nand_deselect(); // 取消⽚选nCE }。
NANDFLASH驱动框架以及程序实现

NANDFLASH驱动框架以及程序实现1、NAND FLASH的硬件连接:实验⽤的NAND FLASH芯⽚为K9F2G08U0C,它是三星公司的存储芯⽚,它的⼤⼩为256M。
它的接线图如下所⽰:它的每个引脚的分别为LDATA0-LDATA7为数据引脚、CLE为发送命令使能引脚、ALE为发送地址使能引脚、CE为芯⽚使能引脚、WE为写使能引脚、WP为写保护引脚、R/B为芯⽚是否繁忙的状态指⽰引脚,如下图所⽰:2、NAND FLASH的操作:根据NAND FLASH的芯⽚⼿册可以知道需要操作NAND FLASH⼀般的流程是发出命令、发出地址、发出数据/读数据,下⾯依次分析。
a、发命令,对于NAND FLASH芯⽚来说需要1、选中芯⽚(CE为低电平);2、CLE设为⾼电平、ALE设为低电平;3、在DATA0-DATA7上输出命令数据;4、在WE上发出⼀个上升沿的信号。
这样命令数据就会被写⼊命令的命令寄存器。
⽽对于S3C2440来说,只要简单的令NFCMD寄存器为命令值S3C2440的NAND控制器就可以完成1-4的操作。
b、发地址,对于NAND FLASH芯⽚来说需要1、选中芯⽚(CE为低电平);2、ALE设为⾼电平、CLE设为低电平;3、在DATA0-DATA7上输出地址数据;4、在WE上发出⼀个上升沿的信号。
这样地址数据就会被写⼊地址寄存器。
分析图中可知需要5个字节的地址。
⽽对于S3C2440来说,只要简单的令NFADDR寄存器为地址值S3C2440的NAND控制器就可以完成1-4的操作。
c、发数据/读数据,对于NAND FLASH芯⽚来说需要1、选中芯⽚(CE为低电平);2、ALE设为低电平、CLE设为低电平;3、在DATA0-DATA7上输出数据或读⼊数据;4、在WE上发出⼀个上升沿的信号,这样数据就会被写⼊、在RE上发出⼀个上升沿信号,这样数据就会被读出。
⽽对于S3C2440来说,只要简单的令NFDATA寄存器为数据值或读NFDATA寄存器,S3C2440的NAND控制器就可以完成1-4的操作。
NandFlash驱动超详细分析

今天学习了NandFlash的驱动,硬件操作非常简单,就是这个linux下的驱动比较复杂,主要还是MTD层的问题,用了一下午时间整理出来一份详细的分析,只是分析函数结构和调用关系,具体代码实现就不看了,里面有N个结构体,搞得我头大。
我用内核,2440板子,先从启动信息入手。
内核启动信息,NAND部分:S3C24XX NAND Driver, (c) 2004 Simtec Electronicss3c2440-nand s3c2440-nand: Tacls=2, 20ns Twrph0=3 30ns, Twrph1=2 20ns NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)Scanning device for bad blocksCreating 3 MTD partitions on "NAND 64MiB 3,3V 8-bit":0x00000000-0x00040000 : "boot"0x0004c000-0x0024c000 : "kernel"0x0024c000-0x03ffc000 : "yaffs2"第一行,在driver/mtd/nand/中第910行,s3c2410_nand_init函数:printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");行二行,同一文件,第212行,s3c2410_nand_inithw函数:dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));第三行,在driver/mtd/nand/中第2346行,printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID:0x%02x (%s %s)\n", *maf_id, dev_id, nand_manuf_ids[maf_idx].name,type->name);第四行,在driver/mtd/nand/中第380行,creat_bbt函数:Printk(KERN INFO " Scanning device for bad blocks \n");第五行,在driver/mtd/中第340行,add_mtd_partitions函数:printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);下面三行,是flash分区表,也在同一函数中,第430行:printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,slave->offset + slave->, slave->;MTD体系结构:在linux中提供了MTD(Memory Technology Device,内存技术设备)系统来建立Flash针对linux的统一、抽象的接口引入MTD后,linux系统中的Flash设备驱动及接口可分为4层:设备节点MTD设备层MTD原始设备层硬件驱动层硬件驱动层:Flash硬件驱动层负责底层硬件设备实际的读、写、擦除,Linux MTD 设备的NAND型Flash驱动位于driver/mtd/nand子目录下s3c2410对应的nand Flash驱动为MTD原始设备层:MTD原始设备层由两部分构成,一部分是MTD原始设备的通用代码,另一部分是各个特定Flash的数据,比如分区主要构成的文件有:drivers/mtd/ 支持mtd字符设备driver/mtd/ 支持mtd块设备MTD设备层:基于MTD原始设备,Linux系统可以定义出MTD的块设备(主设备号31) 和字符设备(设备号90),构成MTD设备层简单的说就是:使用一个mtd层来作为具体的硬件设备驱动和上层文件系统的桥梁。
基于MTD的NANDFLASH设备驱动底层实现原理分析

基于MTD的NANDFLASH设备驱动底层实现原理分析经过UBOOT初步的移植,Linux内核初步的移植,Linux内核总线设备模型的分析,等一系列痛苦的折腾,目的就是想更好的来分析下NANDFLASH的驱动。
大概一共历经了半个月的时间,慢慢的对NANDFLASH驱动程序有感觉了。
一、MTD体系结构:Linux内核提供MTD子系统来建立FLASH针对Linux的统一、抽象接口。
MTD将文件系统与底层的FLASH存储器进行隔离。
引入MTD后Linux系统中对FLASH的设备驱动分为4层设备节点:用户在/dev目录下使用mknod命令建立MTD字符设备节点(主设备号为90),或者MTD块设备节点(主设备号为31),使用该设备节点即可访问MTD设备。
MTD设备层:基于MTD原始设备层,系统将MTD设备可以定义为MTD字符(在/mtd/mtdchar.c中实现,设备号90)和MTD块设备(在/mtd/mtdblock.c中实现,设备号31)。
MTD原始设备层:MTD原始设备层由两部分构成,一部分是MTD原始设备的通用代码,另一部分是各个特定Flash的数据,如分区。
主要构成的文件有:drivers/mtd/mtdcore.c支持mtd字符设备driver/mtd/mtdpart.c支持mtd块设备Flash硬件驱动层:Flash硬件驱动层负责对Flash硬件的读、写和擦除操作。
MTD设备的Nor Flash芯片驱动位于drivers/mtd/chips/子目录下,Nand Flash芯片的驱动则位于drivers/mtd/nand/子目录下。
二、Linux内核中基于MTD的NANDFLASH驱动代码布局:在Linux2.6.35内核中,MTD源代码放在driver/mtd目录中,该目录中包含chips、devices、maps、nand、onenand、lpdrr、tests和ubi八个子目录。
其中只有nand和onenand目录中的代码才与NAND驱动相关,不过nand目录中的代码比较通用,而onenand目录中的代码相对于nand中的代码而言则简化了很多,它是针对三星公司开发的另一类Flash芯片,即OneNAND Flash。
Nand Flash 介绍及高通nand flash驱动

Nand Flash 介绍及高通nand flash驱动1. Nand Flash 相关概念1.1 NOR flash与nand flash1) Nor flash 写速度要比Nand flash 慢得多,Nor flash的读速度比Nand flash快得多。
2.)Nor flash 可以挂上CPU 芯片的地址线,不需要额外的sdram 就可直接在Nor flash 中直接运行,而Nand flash 需要代码搬运到Ram中运行,所以需要Boot loader,需要额外的sdram 的开销。
3)Nandflash需要做badblock检测和ecc校验;每个page中需有一块区域标识坏块信息,而 Nor flash 没有badblock 和ecc 校验的概念。
4)Nand flash最小的program单位为page,而Nor flash 可以对bit进行1.2 什么是SLC和MLCSLC,Single Level Cell:单个存储单元,只存储一位数据,表示成1或0.对于数据的表示,单个存储单元中内部所存储电荷的电压,和某个特定的阈值电压Vth,相比,如果大于此Vth值,就是表示1,反之,小于Vth,就表示0.MLC,Multi Level Cell:与SLC相对应,就是单个存储单元,可以存储多个位,比如2位,4位等。
其实现机制,就是,通过控制内部电荷的多少,分成多个阈值,通过控制里面的电荷多少,而达到我们所需要的存储成不同的数据。
比如,假设输入电压是Vin=4V那么,可以设计出2的2次方=4个阈值, 1/4 的Vin=1V,2/4的Vin=2V,3/4的Vin=3V,Vin=4V,分别表示2位数据00,01,10,11。
对于写入数据,就是充电,通过控制内部的电荷的多少,对应表示不同的数据。
另,nand flash:页大小是512+16=528的称为small page页大小是2048+64=2112的称为large page1.3 Nand flash的组成结构图2 Nand flash 物理存储单元的阵列组织结构NAND Flash 的数据是以bit 的方式保存在memory cell,一般来说,一个cell 中只能存储一个bit。
NandFlash驱动超详细分析报告报告材料

今天学习了NandFlash的驱动,硬件操作非常简单,就是这个linux下的驱动比较复杂,主要还是MTD层的问题,用了一下午时间整理出来一份详细的分析,只是分析函数结构和调用关系,具体代码实现就不看了,里面有N个结构体,搞得我头大。
我用linux2.6.25内核,2440板子,先从启动信息入手。
内核启动信息,NAND部分:S3C24XX NAND Driver, (c) 2004 Simtec Electronicss3c2440-nand s3c2440-nand: Tacls=2, 20ns Twrph0=3 30ns, Twrph1=2 20nsNAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND64MiB 3,3V 8-bit)Scanning device for bad blocksCreating 3 MTD partitions on "NAND 64MiB 3,3V 8-bit":0x00000000-0x00040000 : "boot"0x0004c000-0x0024c000 : "kernel"0x0024c000-0x03ffc000 : "yaffs2"第一行,在driver/mtd/nand/s3c2410.c中第910行,s3c2410_nand_init函数:printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");行二行,同一文件,第212行,s3c2410_nand_inithw函数:dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns,Twrph1=%d %dns\n", tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));第三行,在driver/mtd/nand/nand_base.c中第2346行,printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, nand_manuf_ids[maf_idx].name, type->name);第四行,在driver/mtd/nand/nand_bbt.c中第380行,creat_bbt函数:Printk(KERN INFO " Scanning device for bad blocks \n");第五行,在driver/mtd/mtdpart.c中第340行,add_mtd_partitions函数:printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);下面三行,是flash分区表,也在mtdpart.c同一函数中,第430行:printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, slave->offset + slave->mtd.size, slave->);MTD体系结构:在linux中提供了MTD(Memory Technology Device,内存技术设备)系统来建立Flash针对linux的统一、抽象的接口引入MTD后,linux系统中的Flash设备驱动及接口可分为4层:设备节点MTD设备层MTD原始设备层硬件驱动层硬件驱动层:Flash硬件驱动层负责底层硬件设备实际的读、写、擦除,Linux MTD设备的NAND型Flash驱动位于driver/mtd/nand子目录下s3c2410对应的nand Flash驱动为s3c2410.cMTD原始设备层:MTD原始设备层由两部分构成,一部分是MTD原始设备的通用代码,另一部分是各个特定Flash的数据,比如分区主要构成的文件有:drivers/mtd/mtdcore.c 支持mtd字符设备driver/mtd/mtdpart.c 支持mtd块设备MTD设备层:基于MTD原始设备,Linux系统可以定义出MTD的块设备(主设备号31) 和字符设备(设备号90),构成MTD设备层简单的说就是:使用一个mtd层来作为具体的硬件设备驱动和上层文件系统的桥梁。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
今天学习了NandFlash的驱动,硬件操作非常简单,就是这个linux下的驱动比较复杂,主要还是MTD层的问题,用了一下午时间整理出来一份详细的分析,只是分析函数结构和调用关系,具体代码实现就不看了,里面有N个结构体,搞得我头大。
我用linux2.6.25内核,2440板子,先从启动信息入手。
内核启动信息,NAND部分:S3C24XX NAND Driver, (c) 2004 Simtec Electronicss3c2440-nand s3c2440-nand: Tacls=2, 20ns Twrph0=3 30ns, Twrph1=2 20ns NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)Scanning device for bad blocksCreating 3 MTD partitions on "NAND 64MiB 3,3V 8-bit":0x00000000-0x00040000 : "boot"0x0004c000-0x0024c000 : "kernel"0x0024c000-0x03ffc000 : "yaffs2"第一行,在driver/mtd/nand/s3c2410.c中第910行,s3c2410_nand_init函数:printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");行二行,同一文件,第212行,s3c2410_nand_inithw函数:dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));第三行,在driver/mtd/nand/nand_base.c中第2346行,printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID:0x%02x (%s %s)\n", *maf_id, dev_id, nand_manuf_ids[maf_idx].name,type->name);第四行,在driver/mtd/nand/nand_bbt.c中第380行,creat_bbt函数:Printk(KERN INFO " Scanning device for bad blocks \n");第五行,在driver/mtd/mtdpart.c中第340行,add_mtd_partitions函数:printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);下面三行,是flash分区表,也在mtdpart.c同一函数中,第430行:printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,slave->offset + slave->mtd.size, slave->);MTD体系结构:在linux中提供了MTD(Memory Technology Device,内存技术设备)系统来建立Flash针对linux的统一、抽象的接口引入MTD后,linux系统中的Flash设备驱动及接口可分为4层:设备节点MTD设备层MTD原始设备层硬件驱动层硬件驱动层:Flash硬件驱动层负责底层硬件设备实际的读、写、擦除,Linux MTD 设备的NAND型Flash驱动位于driver/mtd/nand子目录下s3c2410对应的nand Flash驱动为s3c2410.cMTD原始设备层:MTD原始设备层由两部分构成,一部分是MTD原始设备的通用代码,另一部分是各个特定Flash的数据,比如分区主要构成的文件有:drivers/mtd/mtdcore.c 支持mtd字符设备driver/mtd/mtdpart.c 支持mtd块设备MTD设备层:基于MTD原始设备,Linux系统可以定义出MTD的块设备(主设备号31) 和字符设备(设备号90),构成MTD设备层简单的说就是:使用一个mtd层来作为具体的硬件设备驱动和上层文件系统的桥梁。
mtd给出了系统中所有mtd设备(nand,nor,diskonchip)的统一组织方式。
mtd层用一个数组struct mtd_info *mtd_table[MAX_MTD_DEVICES]保存系统中所有的设备,mtd设备利用struct mtd_info 这个结构来描述,该结构中描述了存储设备的基本信息和具体操作所需要的内核函数,mtd系统的那个机制主要就是围绕这个结构来实现的。
结构体在include/linux/mtd/mtd.h中定义:struct mtd_info {u_char type; //MTD 设备类型u_int32_t flags; //MTD设备属性标志u_int32_t size; //标示了这个mtd设备的大小u_int32_t erasesize; //MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小u_int32_t oobblock; //oob区在页内的位置,对于512字节一页的nand 来说是512u_int32_t oobsize; //oob区的大小,对于512字节一页的nand来说是16u_int32_t ecctype; //ecc校验类型u_int32_t eccsize; //ecc的大小char *name; //设备的名字int index; //设备在MTD列表中的位置struct nand_oobinfo oobinfo; //oob区的信息,包括是否使用ecc,ecc的大小//以下是关于mtd的一些读写函数,将在nand_base中的nand_scan中重载int (*erase)int (*read)int (*write)int (*read_ecc)int (*write_ecc)int (*read_oob)int (*read_oob)void *priv;//设备私有数据指针,对于NandFlash来说指nand芯片的结构下面看nand_chip结构,在include/linux/mtd/nand.h中定义:struct nand_chip {void __iomem *IO_ADDR_R; //这是nandflash的读写寄存器void __iomem *IO_ADDR_W;//以下都是nandflash的操作函数,这些函数将根据相应的配置进行重载u_char (*read_byte)(struct mtd_info *mtd);void (*write_byte)(struct mtd_info *mtd, u_char byte);u16 (*read_word)(struct mtd_info *mtd);void (*write_word)(struct mtd_info *mtd, u16 word);void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); void (*select_chip)(struct mtd_info *mtd, int chip);int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);void (*hwcontrol)(struct mtd_info *mtd, int cmd);int (*dev_ready)(struct mtd_info *mtd);void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char*read_ecc, u_char *calc_ecc);void (*enable_hwecc)(struct mtd_info *mtd, int mode);void (*erase_cmd)(struct mtd_info *mtd, int page);int (*scan_bbt)(struct mtd_info *mtd);int eccmode; //ecc的校验模式(软件,硬件)int chip_delay; //芯片时序延迟参数int page_shift; //页偏移,对于512B/页的,一般是9u_char *data_buf; //数据缓存区跟NAND操作相关的函数:1、 nand_base.c:定义了NAND驱动中对NAND芯片最基本的操作函数和操作流程,如擦除、读写page、读写oob等。
当然这些函数都只是进行一些常规的操作,若你的系统在对NAND操作时有一些特殊的动作,则需要在你自己的驱动代码中进行定义。