原创 在21IC DIY U盘实验板上实现的128MB U盘(含坏块管理)

2009-6-15 18:32 7230 18 27 分类: MCU/ 嵌入式

修正程序中的一处小错误:
Usbcore.c中,
pSendData=(uint8)DeviceDescriptor;  //需要发送的数据
强制转换漏掉一个“*”号,应该修改为
pSendData=(uint8 *)DeviceDescriptor;  //需要发送的数据


下载地址2:rar


单击此处下载该实验的程序包:http://bbs.21ic.com/upfiles/img/20093/2009327134626795.rar

    本程序在21IC DIY U盘的实验板上实现“真”U盘的功能。
学习板上有一个128MB的NAND FLASH,只要实现扇区读、写以及
坏块管理,就可以在原来的“假”U盘的基础上做成真正的U盘了。

    由于NAND FLASH擦除时,只能按按块擦除,因此在写扇区时,
首先要擦除一个块。在擦除块前,必须将块内其他数据复制出来,
由于一个块比较大(128KB),无法在MCU内开辟如此大的缓冲区。
只好借助该NAND FLASH内的页复制命令,将原来的块暂时复制到
一个交换用的交换块中。但是如果仅用一个块作为交换的话,它
就会被频繁擦写,因而寿命会大大降低。所以在该系统中,保留了
10个块用来作为交换区,轮流使用。另外对扇区的连续写进行了
优化,当连续写扇区时,就不必每次重复上面的操作,只有当地址
跨块时,才需要重新擦除。连续写扇区的实现原理如下:当检测到
扇区地址跨块时,就把原来的整块数据复制到交换块中,然后将
该块内当前所写地址的前面部分页面复制到原来的块中,接着就从
交换块中取出当前扇区地址所在页(使用页复制-随机写入命令),
再把一个扇区的数据写入,并接着写入其他扇区,当扇区地址跨页
时,就把该页写入到原来的块中,直到扇区被写完(当然如果写
的过程中跨块了,还需要重复前面的块擦除以及复制过程)。接着
把交换块中剩余的页再复制回原来的块中,这样一个连续写过程就
完成了。

    因为NAND FLASH在生产和使用过程中,会产生坏块,所以必须
增加坏块管理。在该系统中,保留了50个块用做坏块管理。当上述
的擦、写过程中,如果发现坏块,那么就把该块的地址重新影射到
一个保留的块中。以后每次对该坏块地址操作时,都被重新定位到
新的块地址。使用一个二维数组来保存该影射关系。二维数组的前
半部分为坏块地址,后半部分为重新影射过后的块地址。每当发现
坏块时,就需要重建这张表(主要是增加新的影射并排序,方便地
址重新影射的二分查表法),并将其三份一样的写入到专门为此而
保留的三个块中。之所以使用三个备份保存,是考虑到这些数据的
重要性,因为一旦这个影射关系被破坏,后果将会是灾难性的。在
保存这个表格时,做了特殊处理,首先标志他们准备擦除,然后才
依次擦除并写入数据,这样即使在操作过程中突然断电,也至少有
两个块的备份数据是可以用的,在系统开机初始化时,可以将这些
数据恢复。数据使用了特殊标志(0x0055AAFF)以及累加和校验来
判断是否有效。对于新出厂的FALSH,在加载坏块表时,就会校验
失败,程序就会假设没有坏块并初始化该数组后保存。每个备用块
还由另外一个数组用来标志其状态(未用、已损坏、已用等)。
当需要使用新的备用块时,就从该数组中查找未用的,并标志为
已用。如果备用块本身是坏的,那么就标志它已损坏。该数组与
坏块重影射表一并保存。此外还保存了当前坏块的数量。

    地址的重新影射过程:当对一个地址进行读写操作时,首先要
对其进行重影射。首先判断是否有坏块,当坏块数量为0时,就直接
返回原来的地址即可。当坏块数量不为0时,先判断最后一次访问和
本次访问的地址是否属于同一页,如果属于,那么就直接影射到上
一次影射过的块地址。如果不属于,那么就需要去查坏块影射表了。
如果只有一个坏块,只要直接比较即可,不用查表。如果坏块数量
大于2,那么就需要查表。由于表中地址是按从小到大的顺序排列的,
所以可以先和第一个和最后一个判断,如果不在该范围内,那么也
不用重新影射,返回原来的地址即可。如果在该范围内,就使用二
分查表法查表,搜索它是否在坏块表中。如果是的话,就重新影射
地址,并将这个地址保存,以备下一次重影射时地址未跨块直接使用。
最大支持50个坏块,在最坏的情况下,该二分查表法需要判断6次。


                                    圈圈  2009-03-27  13:25

坏块表及FLASH存储空间划分如下图:
点击看大图



实验图片~~~~


点击开大图


点击开大图

文章评论13条评论)

登录后参与讨论

用户377235 2012-9-11 14:36

你好,圈圈,我现在在做STM32+NAND FLASH做U盘,先将NAND FLASH 格式化为FAT文件系统,格式化完成后,可以出现盘符但是U盘显示容量为0,双击显示需格式化,点确定后蹦出格式化无法完成,请问是什么原因,一直实验但是老是这样,急!急!急!

用户273733 2010-4-26 11:03

圈圈你好。有个问题向你请教 AT91SAM7S64的端点0大小是16字节,还是8字节啊,为什么设备描述符注释里写的是16字节,但是定义的时候写的是0x08呢??

用户273733 2010-4-2 15:44

nand flash 的读写到底是以什么为单位啊??怎么有页还有扇区啊???

用户232566 2010-4-2 10:42

为什么这个工程编译不过去呢? 开发环境是不是MDK? 如果是的话为什么编译不过去呢 ?提示如下的错Build target 'Target 1' assembling SAM7S.s... --- Error: failed to execute 'C:\KeilARM\ARM\BIN\AA' Target not created

用户273733 2010-4-1 10:23

圈圈,请问一下,对于优盘nandflash的读写擦除等操作,是否需要文件系统的干涉呢???例如对于坏块的管理等~~~~~~~ 如果文件系统可以管理这些操作的话,是不是固件就不用这么复杂了 ??????

computer00 2009-8-10 02:09

你自己再仔细想想,这种情况是不可能会出现的,i的值不可能会变得比j还大,那样就没办法查表了。

用户1278632 2009-7-28 14:32

圈圈的二分查表法有BUG 在代码flash.c 第331~352行处 假设有一种可能,i=2 j=1 程序将进入死循环

用户1278632 2009-7-28 14:30

else //属于坏块区间,使用二分查表法决定是否需要影射 { i=0; j=FlashBadBlocksCount-1; while(1) { if((Addr&(~(FLASH_BLOCK_SIZE-1)))==FlashBadBlockTable[0][(i+j)/2]) //如果相等,则影射 { CurrentRemapBlockAddr=FlashBadBlockTable[1][(i+j)/2]; return CurrentRemapBlockAddr+(Addr&(FLASH_BLOCK_SIZE-1)); //由当前块地址加上块内偏移得到完整地址 } if(i==j)break; //如果i和j相等,则退出查找 if((Addr&(~(FLASH_BLOCK_SIZE-1)))

computer00 2009-5-28 12:57

格式化时选择快速格式化就很快了。

用户1320233 2009-5-25 14:40

怎么实现的格式化功能啊?能格式化,但是去很慢,是什么原因?帮帮忙!
相关推荐阅读
computer00 2013-06-05 16:27
[招聘]Android系统开发工程师
任职要求: 1. 扎实的C/C++基础,熟悉嵌入式Linux和Android操作系统的软件开发; 2. 良好的沟通能力和逻辑思维能力; 3. 良好的英文文献阅读能力; 4. 具备...
computer00 2013-06-04 09:26
[招聘]Android应用开发工程师
任职要求: 1. 具备扎实的面向对象编程思想和JAVA编程基础; 2. 熟悉Eclipse+ADT开发环境,熟练掌握Android基本类库; 3. 熟悉网络应用和多媒体应用开发; ...
computer00 2012-09-26 13:15
圈圈的新浪官方围脖
http://weibo.com/computer00  ...
computer00 2012-09-26 13:12
欢迎大家去收听圈圈弹的曲子
http://www.tudou.com/home/_105209016  ...
computer00 2009-06-29 15:07
《圈圈教你玩USB》勘误(更新日期2009 年06月29日)
《圈圈教你玩USB》勘误(更新日期2009 年06月29日)下载地址1:下载地址2: 勘误.pdf...
computer00 2009-06-25 11:23
一块磐正845GE主板PS2接口的修复
圈圈有一部台式机,某天开机时,发现键盘用不了了,停留在输入BIOS密码那里。主机自检通过,但是蜂鸣器却发出很微弱的、连续的声音,同时键盘的三个LED也没有出现象往常一样的闪烁一下。圈圈以为多日未用,积...
我要评论
13
18
关闭 站长推荐上一条 /3 下一条