u(boot中NANDflash的MTD驱动移植)-
- 格式:doc
- 大小:29.50 KB
- 文档页数:8
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 }。
u-boot的norflash驱动分析,以及一些调试信息Flash 存储器接口还有两个标准:CFI和JEDEC。
CFI为公共Flash接口[Common Flash Interface],用来帮助程序从Flash芯片中获取操作方式信息,而不用在程序中硬编码Flash的ID。
JEDEC用来帮助程序读取Flash的制造商ID和设备ID,以确定Flash的大小和算法,如果芯片不支持CFI,就需使用JEDEC了。
CFI Flash自从Intel公司于1988年推出了可快速擦写的非易失性存储器Flash Memory以来,快速擦写存储器Flash Memory技术就得到了非常迅速的发展。
这主要是由于Flash Memory具有不需要存储电容器、集成度更高、制造成本低于DRAM、使用方便,读写灵活、访问速度快、断电后不丢失信息等特点。
虽然Flash Memory应用越来越广泛,但由于生产Flash Memory的半导体制造商众多,不同厂商Flash Memory产品的操作命令集和电气参数又千差万别,这给Flash Memory的开发设计人员和OEM制造商带来许多不便。
为了对现有的Flash Memory的产品进行升级或使用其它公司的Flash Memory 产品替换,必须对原有的程序代码和硬件结构进行修改。
为解决上述原因所引发的问题,迫切需要Flash Memory制造商提出一个公共的标准解决方案,在这样的背景下,公共闪存接口(Common Flash Interface),简称CFI 诞生了,CFI是一个公开的标准的从Flash Memory器件中读取数据的接口。
它可以使系统软件查询已安装的Flash Memory器件的各种参数,包括器件阵列结构参数、电气和时间参数以及器件支持的功能等。
利用CFI可以不用修改系统软件就可以用新型的和改进的产品代替旧版本的产品。
例如:如果新型的Flash Memory的擦除时间只有旧版本的一半,系统软件只要通过CFI读取新器件的擦除时间等参数,修改一下定时器的时间参数即可。
uboot移植与源码分析总结(6)-Nand驱动uboot移植与源码分析总结(6)-Nand驱动2013-06-29 11:32:17分享:有关nand flash的特性描述,可以见我之前写的这篇文章《NandFlash结构与分析》。
从功能上来说,nand flash与norflash 并无太大差异,主要区别在于操作接口和方式。
Nand基于非sram总线接口,使用nand接口,所以一般需要mcu具有nand控制器才可与其连接。
在读取时,以页为单位;擦除和写入时,以块为单位。
将nand视作一个MTD设备uboot将nand视作一个mtd设备,所以使用mtd机制对nand 设备进行管理。
单个nand设备用nand_info_t来描述。
而nand_info_t实际上就是mtd结构。
最多支持的nand设备数CONFIG_SYS_MAX_NAND_DEVICE可由开发者自行配置。
不过一般目标板上只有一块Nand设备,所以取值通常为1。
但是仅使用mtd结构来描述不够,因为MTD只是一个通用的存储描述结构,而Nand设备特定的某些属性,如ECC布局等不能简单的添加到mtd结构中。
所以,uboot定义了nand_chip结构。
int (*verify_buf)(struct mtd_info *mtd, const uint8_t *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 (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);int (*init_size)(struct mtd_info *mtd, struct nand_chip *this, u8 *id_data);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);void (*erase_cmd)(struct mtd_info *mtd, int page);int (*scan_bbt)(struct mtd_info *mtd);int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,int status, int page);int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,const uint8_t *buf, int page, int cached, int raw);int chip_delay;unsigned int options;int page_shift;int phys_erase_shift;int bbt_erase_shift;int chip_shift;int numchips;uint64_t chipsize;然后,分配了CONFIG_SYS_MAX_NAND_DEVICE个nand_chip 结构。
u-boot使用mtdparts提示Devicenand0wasnotfound的解决方法tekkaman修改版uboot使用config_mtd_device后不能正常访问nand的种原因原创作者:桃核(peachstone,又名sixiangzhe)背景:我使用的是tekkaman修改版本的u-boot源代码,使用其中的make mini2440_congfig进行编译当mini2440.h中不加入 #define config_mtd_device 时,可以正常的访问nand flash,正常的烧写内核加入config_mtd_device后,发现nand0不可用,即在执行nand命令和mtdparts命令时,都提示Device nand0 was not found原因:经过1天的时间阅读nand命令和mtdparts命令相关的代码,我发现,driver s/mtd/nand/nand.c中static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,ulong base_addr)函数中调用了/drivers/mtd/mtdcore.c 中的int add_mtd_device(struct mtd_info *mtd),并传递了struct mtd_info *mtd中mtd的值在两个函数中分别加入printf("nand_init_chip:mtd->name:value:%ld/n",mtd->name );printf("nand_init_chip:mtd->name:addr:%ld/n",&(mtd->na me));printf("nand_init_chip:mtd->name:%s/n",mtd->name);printf("nand_init_chip:mtd:%ld/n",mtd);和printf("add_mtd_device,mtd%ld/n",mtd);printf("add_mtd_device,mtd->name,value:%ld/n",mtd->na me);printf("add_mtd_device,mtd->name,add:%ld/n",&(mtd->na me));printf("add_mtd_device,mtd->name:%s/n",mtd->name);printf("add_mtd_device,mtd->name:%s/n",mtd_table[i]->na me);发现在系统启动时,会打印如下信息NAND: devname[0]:nand0nand_init_chip:mtd->name:value:872204104nand_init_chip:mtd->name:addr:872203676nand_init_chip:mtd->name:nand0nand_init_chip:mtd:872203640add_mtd_device,mtd872203640add_mtd_device,mtd->name,value:38add_mtd_device,mtd->name,add:872203672add_mtd_device,mtd->name:? ?€@?`?锞add_mtd_device,mtd->name:? ?€@?`?锞1024 MiBIn: serialOut: serialErr: serialUSB slave is enable!Net: dm9000Hit any key to stop autoboot: 1可见在两个函数中,,mtd的值相同,但是mtd->name的值却不同,所以我们怀疑两个函数中两个mtd的类型不同查找mtd_info结构体的定义,发现nand.c 和mtdcore.c中的mtd_info都是在/include/linux/mtd/mtd.h中定义的,同时我们发现在mtd_info的定义中,有以下几句话#if defined(ENABLE_CMD_NAND_YAFFS)/*Thanks for hugerat's code*/u_char rw_oob;u_char skipfirstblk;#endif在nand.c和mtdcore.c的编译过程中,不是都包含了mini2440.h(nand.c调用了,mtdcore没有调用),而我们在mini2440.h中定义了ENABLE_CMD_NAND_YAFFS,所以对mtd_info的定义就出现了不同修改办法:方法一:去掉#if defined(ENABLE_CMD_NAND_YAFFS)#endif方法二://在mtdcore.c开头加入#include"config.h"//(config.h中包含mini2440.h)(我在u-boot-2010-06中移植时发现方法二不行,最后采用方法一,或者在include/linux/mtd/mtd.h中加上#include "config.h",也可以达到相同效果)备注:我发现u_boot官方代码2010.12中并没有类似#if defined(ENABLE_CMD_NAND_YAFFS)/*Thanks for hugerat's code*/u_char rw_oob;u_char skipfirstblk;#endif的代码,应该出现mtd_device不能正常运行的问题。
uboot 传统led驱动写法
传统的U-Boot LED驱动通常是通过对硬件寄存器的直接操作来实现的。
在U-Boot中,LED驱动通常包括以下几个方面的内容:
1. 硬件初始化,在U-Boot启动过程中,需要对与LED相关的硬件进行初始化,包括设置相应的寄存器、引脚复用等操作。
2. LED控制接口,U-Boot通常会提供一些API或者函数接口,用于控制LED的开关、亮度和闪烁等操作。
这些接口通常会直接操作硬件寄存器来实现对LED的控制。
3. 设备树配置,在一些新的U-Boot版本中,设备树已经成为了描述硬件信息的标准方式。
因此,针对一些新的硬件平台,需要在设备树中添加LED相关的描述信息,以便U-Boot能够正确识别和初始化LED硬件。
4. 编译配置,在配置U-Boot编译选项时,需要确保使能了LED驱动相关的配置选项,以便将LED驱动代码编译进U-Boot镜像中。
总的来说,传统的U-Boot LED驱动编写涉及到硬件初始化、驱动代码编写、设备树配置和编译选项配置等多个方面。
针对具体的硬件平台和LED驱动需求,具体的编写方式会有所不同,但通常都会涉及到上述几个方面。
UBI文件系统的移植作者:piaozhiye86@首次做UBIFS的移植,不足之处欢迎批评指正。
2010-7-15自从linux2.6.27以后的内核版本都支持UBI文件系统了,新版本的uboot已经支持UBIFS了。
软件平台VMwareFedora-10使用源码:linux-2.6.30.4.tar.bz2u-boot-2010.06-rc1.tar.bz2硬件环境mini2440—64M NAND关于uboot的移植可以参考《嵌入式Linux之我行》中uboot的移植,那里写得比较详细。
我也是参考了其中的文章。
1、uboot的UBI的移植关于uboot的UBI的移植几乎没有说明介绍,移植首先要保证你的flash驱动能够跑起来,我是在nand flash 上跑的UBI。
刚开始的时候我也没有什么头绪,只能够从uboot的readme开始查找一些蛛丝马迹。
- MTD Support (mtdparts command, UBI support)CONFIG_MTD_DEVICEAdds the MTD device infrastructure from the Linux kernel.Needed for mtdparts command support.CONFIG_MTD_PARTITIONSAdds the MTD partitioning infrastructure from the Linuxkernel. Needed for UBI support.因此呢,要UBI支持首先得要MTD支持,因此在配置文件中要添加以上两项的定义。
要移植UBI还要添加:#define CONFIG_CMD_UBIFS#define CONFIG_CMD_UBI总的关于UBI的部分是以下几个宏/****MTD Support (mtdparts command, UBI support)****/#if 1#define CONFIG_MTD_DEVICE 1#define CONFIG_MTD_PARTITIONS 1#define CONFIG_CMD_MTDPARTS#define CONFIG_CMD_UBIFS#define CONFIG_CMD_UBI#define CONFIG_LZO 1#define CONFIG_RBTREE 1#endif同时呢要给NAND建立个默认的分区。
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中。
在U-Boot中,NAND write操作通常用于将数据写入NAND闪存设备。
NAND闪存是一种非易失性存储器,可以存储大量数据,并且具有较高的写入速度。
在U-Boot中,NAND write操作通常通过调用相应的NAND驱动程序函数来实现。
这些函数提供了与NAND设备进行通信的接口,以便将数据写入设备。
要执行NAND write操作,您需要提供要写入的数据、目标地址和选项等参数。
在U-Boot中,这些参数通常以结构体的形式提供。
然后,您可以通过调用相应的NAND驱动程序函数来执行写操作。
请注意,NAND闪存设备的写入操作可能受到一些限制,例如页大小、块大小和擦除周期等。
因此,在执行NAND write操作之前,您需要了解设备的规格和限制,并确保您的写操作符合设备的规范。
总之,U-Boot中的NAND write操作是通过调用相应的NAND驱动程序函数来实现的,您需要提供正确的参数并遵守设备的规范来执行写操作。
u-boot中分区和内核MTD分区关系⼀、u-boot中环境变量与uImage中MTD的分区关系分区只是内核的概念,就是说A~B地址放内核,C~D地址放⽂件系统,(也就是规定哪个地址区间放内核或者⽂件系统)等等。
⼀般我们只需要分3-4个区,第⼀个为boot区,⼀个为boot参数区(传递给内核的参数),⼀个为内核区,⼀个为⽂件系统区。
(但是有的内核就会有很多分区,⽐如内核参数会有两个,还有会Logo的地址)⽽对于bootloader中只要能将内核下载到A~B区的A地址开始处就可以,C~D区的C起始地址下载⽂件系统…….这些起始地址在MTD的分区信息中能找到。
所以bootloader对分区的概念不重要,只要它能把内核烧到A位置,把⽂件系统烧到C位置即可。
所以,在bootloader对Flash进⾏操作时,哪块区域放什么是以内核为主(内核中MTD的分区信息可以从内核的代码中看到)。
传递给u-boot 的参数只要和内核中MTD分区信息⼀致即可。
⽽为了⽅便操作,bootloader类似也引⼊分区的概念。
例如,可以使⽤“nandwrite 0x3000000 kernel 200000”命令将uImage烧到kernel分区,⽽不必写那么长:nand write 3000000 A 200000,也就是⽤分区名来代替具体的地址。
这要对bootloader对内核重新分区:这需要重新设置⼀下bootloader环境参数,就可以同步更新内核分区信息如:setenv bootargs 'noinitrd console=ttySAC0root=/dev/mtdblock3 rootfstype=jffs2 mtdparts=nand_flash:128k(u-boot)ro,64k(u-bootenvs),3m(kernel),30m(root.jffs2),30m(root.yaffs)'解析:在这⾥的挂载⽂件系统的地⽅mtdblock3,可以从mtdparts中看出来,第⼀个⽂件系统(jffs2格式)在第四个分区,所以使⽤mtdblock3,关于分区和⽂件系统的挂载在下⾯有解释。
u(boot中NANDflash的MTD驱动移植)-u-bootu-boot中的“与非”闪存的MTD驱动程序迁移移植了linux中的MTD 驱动程序源代码,以支持“与非”闪存擦除、刻录写入和读取驱动程序内存技术设备内存技术设备是Linux的一个子系统,用于访问闪存设备MTD的主要目的是简化新存储设备的驱动,并提供通用接口功能。
MTD驱动可以支持CFI接口的非闪存驱动和非闪存驱动。
众所周知,“与非”闪存的访问接口不像“非”闪存那样提供标准的CFI访问接口,但“与非”闪存制造商已经对不同品牌和型号的“与非”闪存芯片的访问接口制定了一些常规规定,如命令字、地址序列、命令序列、坏块标记位置、oob区域格式等。
值得注意的是,在工艺方面有两种类型的“与非”闪存:MLC和SLCMLC和SLC属于两种不同类型的NAND闪存SLC的全称是单级单元,即单级单元闪存,而MLC的全称是多级单元,即多级单元闪存。
它们的区别在于,SLC的每个单元只能存储一位数据,而MLC 的每个单元只能存储两位数据,MLC的数据密度是SLC的两倍。
就页容量而言,还有两种类型的与非:大页与非闪存(例如HY27UF082G2B)和小页与非闪存(例如K9F1G08U0A)这两种类型在页面容量、命令序列、地址序列、页面内访问和坏块识别方面非常不同,并且遵循不同的约定,因此在移植驱动程序时应该特别注意。
在下,以大页面NAND flash: HY27UF082G2B为例,介绍NAND flash 的一些基本情况,然后介绍MTD驱动程序的基本结构和流程分析。
最后,介绍了在u-boot中迁移MTD驱动程序的详细步骤:3 .4 . 1)nandflash的一些基本信息fl2400开发板上的NAND Flash芯片型号是现代HY27UF082G2B。
英特尔于1988年首次开发了或非闪存技术。
它最重要的特点是支持片上执行,彻底改变了EPROM和EEPROM主宰非易失性闪存世界的局面。
然后,在1989年,东芝发布了NAND闪存结构,它具有较低的单位成本、较高的容量,并且可以像磁盘一样通过接口轻松升级。
“或非”闪存更适合存储少量的关键代码和数据,而“与非”闪存更适合存储大量的高密度数据。
下表说明了非闪存与非闪存的区别:非闪存非闪存性能项目的容量通常为1~4MB,片上支持的最大容量为32MB 8MB~512MB。
它可以直接在芯片上启动。
它不受支持,需要驱动读取。
只有三星芯片支持步进式引导加载器技术,其他芯片必须配备norflash以启动具有较高可靠性、较低位反转概率、常见位反转的引导加载器,并且必须采取验证措施。
ECC椭圆曲线算法被推荐用于错误检查和恢复,这导致1/10的非闪存使得非闪存的管理和驱动程序写入更加复杂。
存取接口与随机存取存储器和可编程只读存储器相同。
地址线地址、数据和命令通过每个使能引脚区和输入/输出线与数据线分开。
访问接口可分为地址、数据和命令以及串行访问。
随机存取8K-64K块大小(擦除64K~128K单位)必须按顺序存取。
擦除时间为5S,慢3毫秒,快速读写速度慢。
快速读取,快速读取,刻录和写入可以快速擦除10 ~ 100,000次和100 ~ 100万次。
主要用途保存代码和关键数据保存大量高密度数据Jffs2 yaffs文件系统支持价格高低下面我们将根据HY27UF082G2B数据表从以下几个方面详细说明:3..)HY27UF082G2B概述HY27UF082G2B,48引脚TSOP1封装,2G位(256MB)容量,8位宽,地址、数据和命令多路复用输入/输出0~7芯片封装图如下(HY27UF082G2B数据手册截图):从上图可以看出,48个引脚大部分是无用的(NC)。
由于数据线路复用,hy27uf082g2b没有太多真正需要的连接引脚下表是HY27UF082G2B连接引脚功能表:引脚名称引脚功能输入/输出0 ~输入/输出7数据输入/输出CLE命令锁存使能ALE数据锁存使能CE芯片选择使能WE写使能RE读使能WP写保护R/B就绪/繁忙信号输出的NC VCC电源VSS未连接到。
从上表可以看出,HY27UF082G2B和S3C2440之间的连接相对较小:8个输入/输出引脚、5个使能引脚(CLE、ALE、CE、we、RE)、1个写保护引脚(WP)和1个状态引脚(R/B)地址、数据和命令通过8个输入/输出引脚与这些使能信号协同传输。
当写入地址、数据和命令时,CE和WE信号必须为低电平,并在WE信号的上升沿锁存命令锁存使能信号CLE和(总数据锁存信号ALE用于区分命令或地址是否在输入/输出引脚上传输其它总线操作线操作)在数据表的第11页有详细描述,在此不再重复。
从上面可以看出,芯片的总线操作必须有各种使能信号的配合,但是这些使能信号的控制不需要用户驱动器的干预。
S3C2440中的“与非”闪存控制器将根据用户对“与非”闪存控制寄存器(写命令寄存器NFCMD、地址寄存器NFADDR、读数据寄存器NFDATA等)的读写,在“与非”闪存控制相关的引脚上自动输出正确的使能信号。
)。
用户只需将S3C2440上的与非门闪光控制相关引脚正确连接到HY27UF082G2B的使能引脚。
S3C2440上的与非闪存控制相关引脚见下图:除了5个使能信号外,HY27UF082G2B的状态引脚也应连接到s3c2440上的与非闪存控制相关引脚FRnB“与非”闪存芯片与S3C2440之间的硬件连接如下图所示。
凌飞提供的官方硬件连接示意图如下:。
这里,还介绍了与S3C2440的与非门闪存控制器相关的寄存器:1。
NFCONF:与非门闪存配置寄存器1设置时序参数TACLS、TWRPH0、TWRPH0;2.ONT:与非门闪存配置寄存器2使能禁用与非门控制器,使能禁用引脚信号nFCE,初始化纠错码;;3.写寄存器时,“与非”闪存命令寄存器向“与非”闪存芯片发送命令信号;4.写该寄存器时,“与非”闪存地址寄存器向“与非”闪存芯片发送地址信号;5.nfdata:当读取和写入寄存器时,与非门闪存数据寄存器读取或写入数据信号到与非门闪存芯片;6.NFS状态:与非门闪存状态寄存器仅用于位0,0:忙碌,1:读取。
这里只简要介绍一些重要的寄存器,而没有介绍许多其他寄存器例如,与非闪存控制器提供的纠错码硬件生产功能相关的寄存器,请参考S3C2440数据表了解详情。
3..HY27UF082G2B的存储单元与非闪存的组织结构不同于非闪存,因为与非闪存是基于页来读取和烧录的,而非基于字节或字。
擦除以块为单位与非门闪存由块组成,块的基本单位是页每页还包含一个数据区和一个备用区。
小页NAND闪存设备在每页中包含512字节的数据区和16字节的备用区。
大页面NAND闪存设备在每页中包含2048字节的数据区和64字节的备用区。
HY27UF082G2B是一个大页面的nandfast。
下图显示了HY27UF082G2B存储单元的组织结构:HY27UF082G2B存储单元的组织结构在图中的红线处为8位宽。
可以看出,一个芯片包含2048个块,一个块包含64个页面,一个页面包含2048字节的数据存储区和64字节的备用区下图以图形方式显示了HY27UF082G2B的存储单元的组织结构(注意:此图中只有1024个块):可以看出,HY27UF082G2B芯片包括1gb(256 MB)的数据存储区和256Mbit(32MB)的备用区。
1,HY27UF082G2B访问地址序列HY27UF082G2B总容量为288MB(256MB+32MB),8位宽,需要29位访问地址然而,该芯片仅提供8条地址线(多路复用),这显然是不够的。
因此,当访问HY27UF082G2B时,访问地址被分成五个地址序列,其中前两个是页内地址,后三个是页地址。
两个页内地址序列的有效地址位是12位,以满足对页中2048+64字节空间的访问;最后三个地址序列的有效地址是17位,以满足对芯片中2048(块)*64(页)页的访问。
HY27UF082G2B地址序列表如下图所示:上图中的l表示无效地址设置为低电平在编程实际驱动程序时,用户必须严格按照这五个地址序列将每个序列的地址写入NFADDR寄存器。
换句话说,用户必须写5次NFADDR寄存器才能发出完整的访问地址。
值得注意的是,小页与非门闪存仅提供一个地址序列和八个访问地址位来访问512+16字节的页内空间,这显然是足够的因此,小页面NAND闪存将页面中的地址分为a、b和c三个区域,分别用不同的读取命令进行访问,以弥补页面中访问地址序列中地址位不足的缺陷相比之下,大页面与非闪存为页面内地址访问提供了足够的地址序列和访问地址位(12位地址访问2048+64字节空间就足够了),因此大页面与非闪存对页面内地址的访问也更加简洁。
2,HY27UF082G2B操作命令序列和前面提到的操作实现:与非门闪存在页面基础上被读取和烧录,并在块基础上被擦除然后,在“与非”闪存上有三个基本操作:读取页面、刻录页面和擦除块。
这三个基本操作有它们自己的命令序列。
事实上,除了这三个基本操作之外,大多数与非门闪存还提供许多其他操作和操作命令序列。
例如,HY27UF082G2B提供多平面程序(多层预烧)、多平面擦除(多层擦除)、回写程序(同层页面拷贝)、多平面回写程序(多层同层页面拷贝)、多平面擦除、edc操作、复位等上面提到的涉及到层的概念,什么是层?层是将每个芯片块平均分成块组,例如,块号为奇数的芯片块被分成一组,块号为偶数的芯片块被分成一组。
这种块组称为层。
图层具有这样的特性,用户可以同时擦除、刻录甚至复制不同图层中的块。
HY27UF082G2B中的块分为2层,一些NAND闪存分为4层显然,分层操作可以使写入和擦除的速度加倍。
下图是HY27UF082G2B每次操作的命令顺序:红线是HY27UF 082G2 B的五个基本操作以下是五种基本操作中的页面读取操作的顺序号。