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

[复制链接]
8995|37
 楼主| computer00 发表于 2009-3-27 13:49 | 显示全部楼层 |阅读模式
单击此处下载该实验的程序包:<a href="https://bbs.21ic.com/upfiles/img/20093/2009327134626795.rar" target=_blank>https://bbs.21ic.com/upfiles/img/20093/2009327134626795.rar</a><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;本程序在21IC&nbsp;DIY&nbsp;U盘的实验板上实现“真”U盘的功能。<br />学习板上有一个128MB的NAND&nbsp;FLASH,只要实现扇区读、写以及<br />坏块管理,就可以在原来的“假”U盘的基础上做成真正的U盘了。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;由于NAND&nbsp;FLASH擦除时,只能按按块擦除,因此在写扇区时,<br />首先要擦除一个块。在擦除块前,必须将块内其他数据复制出来,<br />由于一个块比较大(128KB),无法在MCU内开辟如此大的缓冲区。<br />只好借助该NAND&nbsp;FLASH内的页复制命令,将原来的块暂时复制到<br />一个交换用的交换块中。但是如果仅用一个块作为交换的话,它<br />就会被频繁擦写,因而寿命会大大降低。所以在该系统中,保留了<br />10个块用来作为交换区,轮流使用。另外对扇区的连续写进行了<br />优化,当连续写扇区时,就不必每次重复上面的操作,只有当地址<br />跨块时,才需要重新擦除。连续写扇区的实现原理如下:当检测到<br />扇区地址跨块时,就把原来的整块数据复制到交换块中,然后将<br />该块内当前所写地址的前面部分页面复制到原来的块中,接着就从<br />交换块中取出当前扇区地址所在页(使用页复制-随机写入命令),<br />再把一个扇区的数据写入,并接着写入其他扇区,当扇区地址跨页<br />时,就把该页写入到原来的块中,直到扇区被写完(当然如果写<br />的过程中跨块了,还需要重复前面的块擦除以及复制过程)。接着<br />把交换块中剩余的页再复制回原来的块中,这样一个连续写过程就<br />完成了。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;因为NAND&nbsp;FLASH在生产和使用过程中,会产生坏块,所以必须<br />增加坏块管理。在该系统中,保留了50个块用做坏块管理。当上述<br />的擦、写过程中,如果发现坏块,那么就把该块的地址重新影射到<br />一个保留的块中。以后每次对该坏块地址操作时,都被重新定位到<br />新的块地址。使用一个二维数组来保存该影射关系。二维数组的前<br />半部分为坏块地址,后半部分为重新影射过后的块地址。每当发现<br />坏块时,就需要重建这张表(主要是增加新的影射并排序,方便地<br />址重新影射的二分查表法),并将其三份一样的写入到专门为此而<br />保留的三个块中。之所以使用三个备份保存,是考虑到这些数据的<br />重要性,因为一旦这个影射关系被破坏,后果将会是灾难性的。在<br />保存这个表格时,做了特殊处理,首先标志他们准备擦除,然后才<br />依次擦除并写入数据,这样即使在操作过程中突然断电,也至少有<br />两个块的备份数据是可以用的,在系统开机初始化时,可以将这些<br />数据恢复。数据使用了特殊标志(0x0055AAFF)以及累加和校验来<br />判断是否有效。对于新出厂的FALSH,在加载坏块表时,就会校验<br />失败,程序就会假设没有坏块并初始化该数组后保存。每个备用块<br />还由另外一个数组用来标志其状态(未用、已损坏、已用等)。<br />当需要使用新的备用块时,就从该数组中查找未用的,并标志为<br />已用。如果备用块本身是坏的,那么就标志它已损坏。该数组与<br />坏块重影射表一并保存。此外还保存了当前坏块的数量。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;地址的重新影射过程:当对一个地址进行读写操作时,首先要<br />对其进行重影射。首先判断是否有坏块,当坏块数量为0时,就直接<br />返回原来的地址即可。当坏块数量不为0时,先判断最后一次访问和<br />本次访问的地址是否属于同一页,如果属于,那么就直接影射到上<br />一次影射过的块地址。如果不属于,那么就需要去查坏块影射表了。<br />如果只有一个坏块,只要直接比较即可,不用查表。如果坏块数量<br />大于2,那么就需要查表。由于表中地址是按从小到大的顺序排列的,<br />所以可以先和第一个和最后一个判断,如果不在该范围内,那么也<br />不用重新影射,返回原来的地址即可。如果在该范围内,就使用二<br />分查表法查表,搜索它是否在坏块表中。如果是的话,就重新影射<br />地址,并将这个地址保存,以备下一次重影射时地址未跨块直接使用。<br />最大支持50个坏块,在最坏的情况下,该二分查表法需要判断6次。<br /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;圈圈&nbsp;&nbsp;2009-03-27&nbsp;&nbsp;13:25<br /><br />坏块表及FLASH存储空间划分如下图:<br /><img src="https://bbs.21ic.com/upfiles/img/20093/2009327134450180.gif"><br /><br /><br /><br />实验图片~~~~<br /><img src="https://bbs.21ic.com/upfiles/img/20093/200932501925185.gif"><br /><br /><img src="https://bbs.21ic.com/upfiles/img/20093/200932721349861.gif"><br />
 楼主| computer00 发表于 2009-3-27 13:54 | 显示全部楼层

FLASH.c文件中读、写扇区以及管理坏块的主要部分代码

/********************************************************************<br />函数功能:获取下一个可用的备用块。<br />入口参数:无。<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:找到的块地址。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:在该函数中会先擦除,只有成功擦除的才被返回。<br />********************************************************************/<br />uint32&nbsp;FlashGetNewRemapBlock(void)<br />{<br />&nbsp;uint32&nbsp;i,Addr;<br />&nbsp;for(i=0;i&ltFLASH_BAD_BLOCKS_REMAP;i++)<br />&nbsp;{<br />&nbsp;&nbsp;if(FLASH_BLOCK_OK==FlashRemapBlockStatus)&nbsp;//如果该块还未用<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;Addr=FLASH_BAD_BLOCK_REMAP_ADDR+i*FLASH_BLOCK_SIZE;&nbsp;//计算地址<br />&nbsp;&nbsp;&nbsp;if(0x01==(FlashEraseBlock(Addr)&0x01))&nbsp;&nbsp;//如果擦除失败<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashRemapBlockStatus=FLASH_BLOCK_BAD;&nbsp;&nbsp;//标志该块为已经损坏<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;else&nbsp;//否则,擦除成功<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashRemapBlockStatus=FLASH_BLOCK_USED;&nbsp;//标志为该块已被使用&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Addr;&nbsp;//返回地址<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />&nbsp;}<br />&nbsp;return&nbsp;-1;&nbsp;//如果找不到,则返回-1。<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:标志当前重影射的块为坏块。<br />入口参数:Addr:要标志的块的地址。<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:无。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:无。<br />********************************************************************/<br />void&nbsp;FlashMarkRemapBlockBad(uint32&nbsp;Addr)<br />{<br />&nbsp;uint32&nbsp;i;<br />&nbsp;i=(Addr-FLASH_BAD_BLOCK_REMAP_ADDR)/FLASH_BLOCK_SIZE;&nbsp;&nbsp;//计算偏移量<br />&nbsp;if(i&gt=FLASH_BAD_BLOCKS_REMAP)return;&nbsp;//出错<br />&nbsp;FlashRemapBlockStatus=FLASH_BLOCK_BAD;&nbsp;&nbsp;//标志为已经损坏<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:地址重新影射,坏块管理用。<br />入口参数:Addr:需要影射的字节地址。<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:影射后的字节地址。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:无。<br />********************************************************************/<br />uint32&nbsp;FlashAddrRemap(uint32&nbsp;Addr)<br />{<br />&nbsp;static&nbsp;uint32&nbsp;CurrentRemapBlockAddr;<br />&nbsp;uint32&nbsp;i,j;<br />&nbsp;<br />&nbsp;if(0==FlashBadBlocksCount)&nbsp;&nbsp;//如果坏块数量为0,则不需要处理,直接返回地址<br />&nbsp;{<br />&nbsp;&nbsp;return&nbsp;Addr;<br />&nbsp;}<br />&nbsp;<br />&nbsp;//如果最后一次访问的地址和本次访问的地址属于同一个块地址,那么不需要重新影射<br />&nbsp;if(0==((Addr-FlashLastAccessAddr)&(FLASH_BLOCK_SIZE-1)))<br />&nbsp;{<br />&nbsp;&nbsp;return&nbsp;CurrentRemapBlockAddr+(Addr&(FLASH_BLOCK_SIZE-1));&nbsp;//由当前块地址加上块内偏移得到完整地址<br />&nbsp;}<br />&nbsp;<br />&nbsp;FlashLastAccessAddr=Addr;&nbsp;//保存最后一次访问过的地址<br />&nbsp;<br />&nbsp;if(1==FlashBadBlocksCount)&nbsp;//如果坏块数量为1,则直接影射<br />&nbsp;{<br />&nbsp;&nbsp;if((Addr&(~(FLASH_BLOCK_SIZE-1)))==FlashBadBlockTable[0][0])&nbsp;//如果块地址相等,则直接影射<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;CurrentRemapBlockAddr=FlashBadBlockTable[1][0];<br />&nbsp;&nbsp;&nbsp;return&nbsp;CurrentRemapBlockAddr+(Addr&(FLASH_BLOCK_SIZE-1));&nbsp;//由当前块地址加上块内偏移得到完整地址<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;else&nbsp;//不用影射<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;CurrentRemapBlockAddr=Addr&(~(FLASH_BLOCK_SIZE-1));&nbsp;&nbsp;//获取当前块地址<br />&nbsp;&nbsp;&nbsp;return&nbsp;Addr;&nbsp;&nbsp;//直接返回原来的地址<br />&nbsp;&nbsp;}<br />&nbsp;}<br />&nbsp;else&nbsp;//坏块数量大于1<br />&nbsp;{<br />&nbsp;&nbsp;//如果地址比第一个坏块的地址还小或者比最后一个坏块的地址还大,<br />&nbsp;&nbsp;//那么肯定不会是坏快,不需要重新影射<br />&nbsp;&nbsp;if((Addr&ltFlashBadBlockTable[0][0])<br />&nbsp;&nbsp;&nbsp;||((Addr&(FLASH_BLOCK_SIZE-1))&gtFlashBadBlockTable[0][FlashBadBlocksCount-1]))<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;CurrentRemapBlockAddr=Addr&(~(FLASH_BLOCK_SIZE-1));&nbsp;&nbsp;//获取当前块地址<br />&nbsp;&nbsp;&nbsp;return&nbsp;Addr;&nbsp;&nbsp;//直接返回原来的地址<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;else&nbsp;//属于坏块区间,使用二分查表法决定是否需要影射<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;i=0;<br />&nbsp;&nbsp;&nbsp;j=FlashBadBlocksCount-1;<br />&nbsp;&nbsp;&nbsp;while(1)<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;if((Addr&(~(FLASH_BLOCK_SIZE-1)))==FlashBadBlockTable[0][(i+j)/2])&nbsp;//如果相等,则影射<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CurrentRemapBlockAddr=FlashBadBlockTable[1][(i+j)/2];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;CurrentRemapBlockAddr+(Addr&(FLASH_BLOCK_SIZE-1));&nbsp;//由当前块地址加上块内偏移得到完整地址<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;if(i==j)break;&nbsp;//如果i和j相等,则退出查找<br />&nbsp;&nbsp;&nbsp;&nbsp;if((Addr&(~(FLASH_BLOCK_SIZE-1)))&ltFlashBadBlockTable[0][(i+j)/2])&nbsp;&nbsp;//如果小于<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j=(i+j)/2-1;&nbsp;//搜索前半段<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;//如果大于<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i=(i+j)/2+1;&nbsp;//搜索后半段<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />&nbsp;}<br />&nbsp;//没有在坏块表中找到,则说明不是坏块<br />&nbsp;CurrentRemapBlockAddr=Addr&(~(FLASH_BLOCK_SIZE-1));&nbsp;&nbsp;//获取当前块地址<br />&nbsp;return&nbsp;Addr;&nbsp;&nbsp;//直接返回原来的地址<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:从FLASH的特定位置加载坏块表。<br />入口参数:无。<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:无。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:无。<br />********************************************************************/<br />void&nbsp;FlashLoadBadBlockTable(void)<br />{<br />&nbsp;uint32&nbsp;i,j,k,Sum,Ok;<br />&nbsp;uint8&nbsp;Data;<br /><br />&nbsp;Ok=0;&nbsp;//设置为不成功<br />&nbsp;for(i=0;i&ltFLASH_BLOCKS_TABLE;i++)&nbsp;//查找没有准备擦除的块<br />&nbsp;{<br />&nbsp;&nbsp;//从该块中最后一页读回第一字节,看是否为0xFF,如果为0xFF,表示该块没有准备擦除<br />&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*(i+1)&nbsp;-&nbsp;FLASH_PAGE_SIZE);<br />&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;if(Data==0xFF)&nbsp;&nbsp;//表示该块数据还未准备擦除<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;//从该块中倒数第二页读回第一字节,看是否为0,如果为0,表示该块已经写入了数据<br />&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*(i+1)&nbsp;-&nbsp;2*FLASH_PAGE_SIZE);<br />&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;if(Data==0)&nbsp;//表示数据有效<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);&nbsp;//读出校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;Sum=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);&nbsp;//读出校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;Sum=(Sum&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);&nbsp;//读出校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;Sum=(Sum&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);&nbsp;//读出校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;Sum=(Sum&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;//从该块开始位置读<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;&nbsp;&nbsp;//检查第1字节是否为0<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;if(Data!=0)continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;//检查第2字节是否为0x55<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;if(Data!=0x55)continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;//检查第3字节是否为0xAA<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;if(Data!=0xAA)continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;//检查第4字节是否为0xFF<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;if(Data!=0xFF)continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;Sum+=0x1FE;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;//读坏块数量<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashBadBlocksCount=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashBadBlocksCount=(FlashBadBlocksCount&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashBadBlocksCount=(FlashBadBlocksCount&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashBadBlocksCount=(FlashBadBlocksCount&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;j=8;<br />&nbsp;&nbsp;&nbsp;&nbsp;//读回坏块表<br />&nbsp;&nbsp;&nbsp;&nbsp;for(k=0;k&ltsizeof(FlashBadBlockTable[0][0])*FLASH_BAD_BLOCKS_REMAP*2;k++)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(0==(j&(FLASH_PAGE_SIZE-1)))&nbsp;//如果超过了页,则需要重新读新页<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i+j);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;&nbsp;//求校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((uint8&nbsp;*)FlashBadBlockTable)[k]=Data;&nbsp;&nbsp;//读回一字节到坏块表中<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j++;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;//读回重影射区的状态表<br />&nbsp;&nbsp;&nbsp;&nbsp;for(k=0;k&ltsizeof(FlashRemapBlockStatus[0])*FLASH_BAD_BLOCKS_REMAP;k++)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(0==(j&(FLASH_PAGE_SIZE-1)))&nbsp;//如果超过了页,则需要重新读新页<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i+j);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;&nbsp;//求校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((uint8&nbsp;*)FlashRemapBlockStatus)[k]=Data;&nbsp;&nbsp;&nbsp;//读回一字节到重影射区状态表中<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j++;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;if(Sum==0)&nbsp;//如果校验成功,则说明数据正确<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ok=0xFF;&nbsp;//设置为成功<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;&nbsp;&nbsp;//并退出循环<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />&nbsp;}<br />&nbsp;<br />&nbsp;if(Ok==0)&nbsp;//如果在已写入的表中找不到好的坏块表,再去准备擦除的中去找<br />&nbsp;{<br />&nbsp;&nbsp;for(i=0;i&ltFLASH_BLOCKS_TABLE;i++)&nbsp;//查找准备擦除的块<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;//从该块中最后一页读回第一字节,看是否为0,如果为0,表示该块已经准备擦除了<br />&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*(i+1)&nbsp;-&nbsp;FLASH_PAGE_SIZE);<br />&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;if(Data==0x00)&nbsp;&nbsp;//表示该块数据准备擦除<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;//从该块中倒数第二页读回第一字节,看是否为0,如果为0,表示该块已经写入了数据<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*(i+1)&nbsp;-&nbsp;2*FLASH_PAGE_SIZE);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;if(Data==0)&nbsp;//表示数据有效<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);&nbsp;//读出校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);&nbsp;//读出校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum=(Sum&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);&nbsp;//读出校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum=(Sum&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);&nbsp;//读出校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum=(Sum&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//从该块开始位置读<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//检查第1字节是否为0<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Data!=0)continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//检查第2字节是否为0x55<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Data!=0x55)continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//检查第3字节是否为0xAA<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Data!=0xAA)continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//检查第4字节是否为0xFF<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Data!=0xFF)continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum+=0x1FE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//读坏块数量<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashBadBlocksCount=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashBadBlocksCount=(FlashBadBlocksCount&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashBadBlocksCount=(FlashBadBlocksCount&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashBadBlocksCount=(FlashBadBlocksCount&lt&lt8)+Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j=8;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//读回坏块表<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(k=0;k&ltsizeof(FlashBadBlockTable[0][0])*FLASH_BAD_BLOCKS_REMAP*2;k++)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(0==(j&(FLASH_PAGE_SIZE-1)))&nbsp;//如果超过了页,则需要重新读新页<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i+j);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;&nbsp;//求校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((uint8&nbsp;*)FlashBadBlockTable)[k]=Data;&nbsp;&nbsp;//读回一字节到坏块表中<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//读回重影射区的状态表<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(k=0;k&ltsizeof(FlashRemapBlockStatus[0])*FLASH_BAD_BLOCKS_REMAP;k++)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(0==(j&(FLASH_PAGE_SIZE-1)))&nbsp;//如果超过了页,则需要重新读新页<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i+j);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashReadByte(Data);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum+=Data;&nbsp;//求校验和<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((uint8&nbsp;*)FlashRemapBlockStatus)[k]=Data;&nbsp;&nbsp;&nbsp;//读回一字节到重影射区状态表中<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Sum==0)&nbsp;//如果校验成功,则说明数据正确<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FlashSaveBadBlockTable();&nbsp;//将其保存到FLASH中&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ok=0xFF;&nbsp;//设置为成功<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;&nbsp;&nbsp;//并退出循环<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />&nbsp;}<br />&nbsp;<br />&nbsp;if(Ok==0)&nbsp;//如果还是没找到,那么只好重新初始化了<br />&nbsp;{<br />&nbsp;&nbsp;FlashBadBlocksCount=0;&nbsp;//坏块数设置为0<br />&nbsp;&nbsp;for(i=0;i&ltFLASH_BAD_BLOCKS_REMAP;i++)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;//所有影射块都设置为好块<br />&nbsp;&nbsp;&nbsp;FlashRemapBlockStatus=FLASH_BLOCK_OK;<br />&nbsp;&nbsp;&nbsp;//所有影射关系设置为-1<br />&nbsp;&nbsp;&nbsp;FlashBadBlockTable[0]=-1;<br />&nbsp;&nbsp;&nbsp;FlashBadBlockTable[1]=-1;<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;//设置好之后保存起来<br />&nbsp;&nbsp;FlashSaveBadBlockTable();<br />&nbsp;}<br />&nbsp;//设置当前访问过的地址为无效值<br />&nbsp;FlashLastAccessAddr=-1;<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:保存坏块表到FLASH的特定位置。<br />入口参数:无。<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:无。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:无。<br />********************************************************************/<br />void&nbsp;FlashSaveBadBlockTable(void)<br />{<br />&nbsp;uint32&nbsp;i,j,k,Sum;<br />&nbsp;<br />&nbsp;for(i=0;i&ltFLASH_BLOCKS_TABLE;i++)&nbsp;//标志为准备擦除<br />&nbsp;{<br />&nbsp;&nbsp;FlashWriteCommand(0x80);<br />&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*(i+1)&nbsp;-&nbsp;FLASH_PAGE_SIZE);<br />&nbsp;&nbsp;FlashSetPortAsOut();&nbsp;&nbsp;//总线设置为输出口<br />&nbsp;&nbsp;FlashWriteByte(0x00);&nbsp;&nbsp;//将第一字节设置为0,表示准备擦除<br />&nbsp;&nbsp;//剩余字节写0xFF<br />&nbsp;&nbsp;for(j=1;j&ltFLASH_PAGE_SIZE;j++)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;FlashWriteByte(0xFF);<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;FlashWritePage();&nbsp;//写页<br />&nbsp;}<br />&nbsp;<br />&nbsp;for(i=0;i&ltFLASH_BLOCKS_TABLE;i++)&nbsp;//将坏块表写入这三块<br />&nbsp;{<br />&nbsp;&nbsp;FlashEraseBlock(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i);&nbsp;//擦除一块<br />&nbsp;&nbsp;FlashWriteCommand(0x80);<br />&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i);&nbsp;//写入第一块的开始位置<br />&nbsp;&nbsp;FlashSetPortAsOut();&nbsp;&nbsp;//总线设置为输出口<br />&nbsp;&nbsp;FlashWriteByte(0x00);&nbsp;&nbsp;//将第1字节设置为0<br />&nbsp;&nbsp;FlashWriteByte(0x55);&nbsp;&nbsp;//将第2字节设置为0x55<br />&nbsp;&nbsp;FlashWriteByte(0xAA);&nbsp;&nbsp;//将第3字节设置为0xAA<br />&nbsp;&nbsp;FlashWriteByte(0xFF);&nbsp;&nbsp;//将第4字节设置为0xFF<br />&nbsp;&nbsp;Sum=0x1FE;<br />&nbsp;&nbsp;//接着写坏块数量,并统计校验和<br />&nbsp;&nbsp;FlashWriteByte((FlashBadBlocksCount&gt&gt24)&0xFF);<br />&nbsp;&nbsp;Sum+=(FlashBadBlocksCount&gt&gt24)&0xFF;<br />&nbsp;&nbsp;FlashWriteByte((FlashBadBlocksCount&gt&gt16)&0xFF);<br />&nbsp;&nbsp;Sum+=(FlashBadBlocksCount&gt&gt16)&0xFF;<br />&nbsp;&nbsp;FlashWriteByte((FlashBadBlocksCount&gt&gt8)&0xFF);<br />&nbsp;&nbsp;Sum+=(FlashBadBlocksCount&gt&gt8)&0xFF;<br />&nbsp;&nbsp;FlashWriteByte((FlashBadBlocksCount)&0xFF);<br />&nbsp;&nbsp;Sum+=(FlashBadBlocksCount)&0xFF;<br />&nbsp;&nbsp;j=8;&nbsp;//写了8字节<br />&nbsp;&nbsp;//保存坏块表<br />&nbsp;&nbsp;for(k=0;k&ltsizeof(FlashBadBlockTable[0][0])*FLASH_BAD_BLOCKS_REMAP*2;k++)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;if(0==(j&(FLASH_PAGE_SIZE-1)))&nbsp;//如果超过了页,则需要重新写新页<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWritePage();&nbsp;//写页<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x80);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i&nbsp;+&nbsp;j);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashSetPortAsOut();&nbsp;&nbsp;//总线设置为输出口<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;Sum+=((uint8&nbsp;*)FlashBadBlockTable)[k];&nbsp;//求校验和<br />&nbsp;&nbsp;&nbsp;FlashWriteByte(((uint8&nbsp;*)FlashBadBlockTable)[k]);&nbsp;&nbsp;//写一字节<br />&nbsp;&nbsp;&nbsp;j++;<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;//保存重影射区的状态表<br />&nbsp;&nbsp;for(k=0;k&ltsizeof(FlashRemapBlockStatus[0])*FLASH_BAD_BLOCKS_REMAP;k++)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;if(0==(j&(FLASH_PAGE_SIZE-1)))&nbsp;//如果超过了页,则需要重新写新页<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWritePage();&nbsp;//写页<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteCommand(0x80);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*i&nbsp;+&nbsp;j);<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashSetPortAsOut();&nbsp;&nbsp;//总线设置为输出口<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;Sum+=((uint8&nbsp;*)FlashRemapBlockStatus)[k];&nbsp;//求校验和<br />&nbsp;&nbsp;&nbsp;FlashWriteByte(((uint8&nbsp;*)FlashRemapBlockStatus)[k]);&nbsp;&nbsp;//写一字节<br />&nbsp;&nbsp;&nbsp;j++;<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;for(;0!=(j&(FLASH_PAGE_SIZE-1));j++)&nbsp;//将剩余部分写入0xFF<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;FlashWriteByte(0xFF);<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;FlashWritePage();&nbsp;&nbsp;&nbsp;//写页<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;//已完成写状态及校验和写入到该块的倒数第二页<br />&nbsp;&nbsp;FlashWriteCommand(0x80);<br />&nbsp;&nbsp;FlashWriteAddr4Byte(FLASH_BLOCK_TABLE_ADDR&nbsp;+&nbsp;FLASH_BLOCK_SIZE*(i+1)&nbsp;-&nbsp;2*FLASH_PAGE_SIZE);<br />&nbsp;&nbsp;FlashSetPortAsOut();&nbsp;&nbsp;//总线设置为输出口<br />&nbsp;&nbsp;FlashWriteByte(0x00);&nbsp;&nbsp;//将第一字节设置为0,表示已经写入<br />&nbsp;&nbsp;//将校验和取反加1,这样累加结果就为0<br />&nbsp;&nbsp;Sum=(~Sum)+1;<br />&nbsp;&nbsp;//写校验和<br />&nbsp;&nbsp;FlashWriteByte((Sum&gt&gt24)&0xFF);<br />&nbsp;&nbsp;FlashWriteByte((Sum&gt&gt16)&0xFF);<br />&nbsp;&nbsp;FlashWriteByte((Sum&gt&gt8)&0xFF);<br />&nbsp;&nbsp;FlashWriteByte((Sum)&0xFF);<br />&nbsp;&nbsp;//剩余字节写0xFF<br />&nbsp;&nbsp;for(j=5;j&ltFLASH_PAGE_SIZE;j++)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;FlashWriteByte(0xFF);<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;FlashWritePage();&nbsp;//写页<br />&nbsp;}<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:更新坏块表。<br />入口参数:OldAddr:旧地址;NewAddr:影射之后的地址。<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:无。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:无。<br />********************************************************************/<br />void&nbsp;FlashUpdateBadBlockTable(uint32&nbsp;OldAddr,uint32&nbsp;NewAddr)<br />{<br />&nbsp;uint32&nbsp;i,j;<br />&nbsp;OldAddr&=~(FLASH_BLOCK_SIZE-1);&nbsp;//求得一块内起始地址<br />&nbsp;NewAddr&=~(FLASH_BLOCK_SIZE-1);<br />&nbsp;if(OldAddr&gtFLASH_MAX_SECTOR_ADDR)&nbsp;//如果比能够达到的最大地址还大,说明坏块地址本来就是被重新影射过的<br />&nbsp;{<br />&nbsp;&nbsp;//先要找到它原来影射的位置<br />&nbsp;&nbsp;for(i=0;i&ltFlashBadBlocksCount;i++)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;if(OldAddr==FlashBadBlockTable[1])&nbsp;//如果与某个地址吻合,则说明就是该地址了<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashBadBlockTable[1]=NewAddr;&nbsp;//重新影射到新的地址<br />&nbsp;&nbsp;&nbsp;&nbsp;//并将原来的交换块设置为已损坏<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashMarkRemapBlockBad(OldAddr);<br />&nbsp;&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />&nbsp;}<br />&nbsp;else&nbsp;//说明坏块地址是没有被影射过的<br />&nbsp;{<br />&nbsp;&nbsp;//查找比它大的块地址,将它插入到前面,排好序,方便二分查表<br />&nbsp;&nbsp;for(i=0;i&ltFlashBadBlocksCount;i++)&nbsp;<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;if(OldAddr&ltFlashBadBlockTable[0])&nbsp;//找到比它大的地址<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;for(j=FlashBadBlocksCount;j&gti;j--)&nbsp;//将上面的部分往上移动,腾出一个空位<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;FlashBadBlockTable[0][j]=FlashBadBlockTable[0][j-1];<br />&nbsp;&nbsp;&nbsp;FlashBadBlockTable[1][j]=FlashBadBlockTable[1][j-1];<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;//将当前块的影射写入<br />&nbsp;&nbsp;FlashBadBlockTable[0][j]=OldAddr;<br />&nbsp;&nbsp;FlashBadBlockTable[1][j]=NewAddr;<br />&nbsp;&nbsp;FlashBadBlocksCount++;&nbsp;//增加一个坏块计数<br />&nbsp;}<br />&nbsp;FlashSaveBadBlockTable();&nbsp;//存储坏块表<br />&nbsp;//修改当前访问过的地址为无效地址,这样下次操作时就会重新影射<br />&nbsp;FlashLastAccessAddr=-1;<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:FLASH坏块处理。<br />入口参数:Addr:&nbsp;字节地址。<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:无。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:处理后的地址。<br />********************************************************************/<br />uint32&nbsp;FlashDealBadBlock(uint32&nbsp;Addr,&nbsp;uint32&nbsp;Type)<br />{<br />&nbsp;uint32&nbsp;i;<br />&nbsp;uint32&nbsp;RemapBlockAddr;<br />&nbsp;uint32&nbsp;SwapBlockAddr;<br />&nbsp;while(1)<br />&nbsp;{<br />&nbsp;&nbsp;RemapBlockAddr=FlashGetNewRemapBlock();<br />&nbsp;&nbsp;if(RemapBlockAddr==-1)&nbsp;&nbsp;//如果已经找不到新的可用的替换品,那只好直接返回了。<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;return&nbsp;Addr;<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;switch(Type)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;//擦除时遇到的坏块,不需要将当前页缓冲区数据写回<br />&nbsp;&nbsp;&nbsp;//只需要返回新的地址即可。地址统一在最后返回,这里不用处理<br />&nbsp;&nbsp;&nbsp;case&nbsp;1:<br />&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;Exit;<br />&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;//复制页时遇到的坏块,需要将该块中前面的页及当前页从交换区中重新复制<br />&nbsp;&nbsp;&nbsp;case&nbsp;2:<br />&nbsp;&nbsp;&nbsp;//从交换区去复制前面页以及当前页的数据<br />&nbsp;&nbsp;&nbsp;SwapBlockAddr=FlashGetCurrentSwapBlock();&nbsp;&nbsp;//获取当前所使用的交换块<br />&nbsp;&nbsp;&nbsp;//复制前面以及当前页<br />&nbsp;&nbsp;&nbsp;for(i=0;i&lt(Addr&(FLASH_BLOCK_SIZE-1))/FLASH_PAGE_SIZE+1;i++)<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;if(0x01==(FlashCopyPage(SwapBlockAddr+i*FLASH_PAGE_SIZE,RemapBlockAddr+i*FLASH_PAGE_SIZE)&0x01))<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果复制失败,则说明该块有问题,需要找新的块<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;BadRemapBlock;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;//复制完毕,则退出循环<br />&nbsp;&nbsp;&nbsp;goto&nbsp;Exit;<br />&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;//写数据时遇到的坏块,需要将该块中前面的页从交换区中重新复制,<br />&nbsp;&nbsp;&nbsp;//还需要将当前页从交换区中复制并将缓冲区的输入写入到当前页中<br />&nbsp;&nbsp;&nbsp;//这里无法再获取到缓冲区的数据了,只好直接从原来的页复制数据<br />&nbsp;&nbsp;&nbsp;case&nbsp;3:&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;//从交换区去复制前面页数据<br />&nbsp;&nbsp;&nbsp;SwapBlockAddr=FlashGetCurrentSwapBlock();&nbsp;&nbsp;//获取当前所使用的交换块<br />&nbsp;&nbsp;&nbsp;//复制前面的页<br />&nbsp;&nbsp;&nbsp;for(i=0;i&lt(Addr&(FLASH_BLOCK_SIZE-1))/FLASH_PAGE_SIZE;i++)<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;if(0x01==(FlashCopyPage(SwapBlockAddr+i*FLASH_PAGE_SIZE,RemapBlockAddr+i*FLASH_PAGE_SIZE)&0x01))<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果复制失败,则说明该块有问题,需要找新的块<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;BadRemapBlock;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;//对于当前页,只好从刚刚写入的错误地址去复制<br />&nbsp;&nbsp;&nbsp;if(0x01==(FlashCopyPage(Addr,RemapBlockAddr+i*FLASH_PAGE_SIZE)&0x01))<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;//如果复制失败,则说明该块有问题,需要找新的块<br />&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;BadRemapBlock;<br />&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;//复制完毕,则退出循环<br />&nbsp;&nbsp;&nbsp;goto&nbsp;Exit;<br />&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;default:<br />&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;BadRemapBlock:<br />&nbsp;&nbsp;//如果操作过程中失败,则要标志该块已经损坏<br />&nbsp;&nbsp;FlashMarkRemapBlockBad(RemapBlockAddr);<br />&nbsp;}<br />&nbsp;Exit:<br />&nbsp;//更新坏块表<br />&nbsp;FlashUpdateBadBlockTable(Addr,RemapBlockAddr);<br />&nbsp;return&nbsp;RemapBlockAddr+(Addr&(FLASH_BLOCK_SIZE-1));<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:管理可用的交换块地址。<br />入口参数:Op:对应的操作。<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:下一个可用的交换块的地址。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:无。<br />********************************************************************/<br />uint32&nbsp;FlashManageSwapBlock(uint32&nbsp;Op)<br />{<br />&nbsp;static&nbsp;uint32&nbsp;Current;<br />&nbsp;static&nbsp;uint8&nbsp;FlashSwapBlockStatus[FLASH_SWAP_BLOCKS];<br />&nbsp;uint32&nbsp;i;<br />&nbsp;<br />&nbsp;switch(Op)<br />&nbsp;{<br />&nbsp;&nbsp;case&nbsp;0:&nbsp;&nbsp;//如果操作为1,表示初始化<br />&nbsp;&nbsp;&nbsp;Current=0;<br />&nbsp;&nbsp;&nbsp;for(i=0;i&ltFLASH_SWAP_BLOCKS;i++)<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;FlashSwapBlockStatus=0;&nbsp;//初始化所有交换块为好的<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;break;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;case&nbsp;1:&nbsp;//如果操作为1,表示获取下一个可用的交换区<br />&nbsp;&nbsp;&nbsp;while(1)//一直尝试,如果交换区都用完(坏)了,那么就死循环了,<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;Current++;<br />&nbsp;&nbsp;&nbsp;&nbsp;if(Current&gt=FLASH_SWAP_BLOCKS)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Current=0;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;if(FlashSwapBlockStatus[Current]==0)break;&nbsp;//如果该块标志为0,则说明未损坏<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;break;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;case&nbsp;2:&nbsp;//如果操作为2,说明获取当前交换区地址<br />&nbsp;&nbsp;break;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;case&nbsp;3:&nbsp;//如果操作为3,设置当前交换块为坏块<br />&nbsp;&nbsp;&nbsp;FlashSwapBlockStatus[Current]=FLASH_BLOCK_BAD;<br />&nbsp;&nbsp;break;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;default:<br />&nbsp;&nbsp;break;<br />&nbsp;}<br />&nbsp;return&nbsp;FLASH_SWAP_BLOCK_ADDR+Current*FLASH_BLOCK_SIZE;&nbsp;//返回可用的交换块地址<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:将一块数据复制到交换区。同时将原来的块删除,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;并将该块内Addr所在页前面的页面复制回原来的块。<br />入口参数:Addr:要复制出来的块地址。<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:原来块的地址。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:如果在复制回去的过程中,出现错误,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;那么说明原来的块已经损坏,需要重新影射到一个好的块。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这时返回的地址就是重新影射过后的地址。<br />********************************************************************/<br />uint32&nbsp;FlashCopyBlockToSwap(uint32&nbsp;Addr)<br />{<br />&nbsp;uint32&nbsp;SwapAddr;<br />&nbsp;uint32&nbsp;i;<br />&nbsp;uint32&nbsp;BlockStartAddr;<br />&nbsp;<br />&nbsp;BlockStartAddr=(Addr)&(~(FLASH_BLOCK_SIZE-1));&nbsp;&nbsp;//计算块起始地址<br />&nbsp;<br />&nbsp;while(1)<br />&nbsp;{<br />&nbsp;&nbsp;SwapAddr=FlashGetNextSwapBlock();&nbsp;//获取下一个交换区<br />&nbsp;&nbsp;if(0x00==(FlashEraseBlock(SwapAddr)&0x01))&nbsp;//如果擦除成功<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;for(i=0;i&ltFLASH_BLOCK_SIZE/FLASH_PAGE_SIZE;i++)&nbsp;&nbsp;//将对应块中所有页复制到交换区中<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;//复制一页<br />&nbsp;&nbsp;&nbsp;&nbsp;if(0x01&FlashCopyPage(BlockStartAddr+i*FLASH_PAGE_SIZE,SwapAddr+i*FLASH_PAGE_SIZE))<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果复制失败,则说明该交换块已经损坏,查找下一个可用的交换块<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;BadSwapBlock;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;//全部复制完毕,则擦除掉原来的块<br />&nbsp;&nbsp;&nbsp;if(0x01==(FlashEraseBlock(BlockStartAddr)&0x01))&nbsp;//如果擦除失败<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;Addr=FlashDealBadBlock(Addr,1);&nbsp;//处理擦除时遇到的坏块<br />&nbsp;&nbsp;&nbsp;&nbsp;BlockStartAddr=(Addr)&(~(FLASH_BLOCK_SIZE-1));&nbsp;&nbsp;//计算块起始地址<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;//将前面部分不会写到的页复制回去<br />&nbsp;&nbsp;&nbsp;for(i=0;i&lt(Addr-BlockStartAddr)/FLASH_PAGE_SIZE;i++)<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;//复制一页<br />&nbsp;&nbsp;&nbsp;&nbsp;if(0x01&FlashCopyPage(SwapAddr+i*FLASH_PAGE_SIZE,BlockStartAddr+i*FLASH_PAGE_SIZE))<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果复制失败,则处理该坏块<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//注意FlashDealBadBlock返回的是当前正在操作的扇区地址,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//需要取出其块地址加上Addr原来的扇区地址合成新的扇区地址<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Addr=(FlashDealBadBlock(BlockStartAddr+i*FLASH_PAGE_SIZE,2)&(~(FLASH_BLOCK_SIZE-1)))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+(Addr&(FLASH_BLOCK_SIZE-1));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BlockStartAddr=(Addr)&(~(FLASH_BLOCK_SIZE-1));&nbsp;&nbsp;//计算块起始地址<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;return&nbsp;Addr;&nbsp;//复制完毕,返回<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;else&nbsp;//否则,擦除失败<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;BadSwapBlock:<br />&nbsp;&nbsp;&nbsp;//标志该块擦除时被损坏<br />&nbsp;&nbsp;&nbsp;FlashMarkBadCurrentSwapBlock();<br />&nbsp;&nbsp;}<br />&nbsp;}<br />&nbsp;return&nbsp;Addr;<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:往FLASH中写一个扇区(FLASH_SECTOR_SIZE字节)。<br />入口参数:Addr:&nbsp;字节地址;pBuf:保存数据的缓冲区;Remain:预计接下来还需要写多少扇区<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:写入的状态。0:成功。非0:失败。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:当Remain不为0时,当前页以及该块内剩余部分将不会回写!<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果数据传输结束,应该将Remain置0,将数据写回。<br />********************************************************************/<br />uint32&nbsp;FlashWriteOneSector(uint32&nbsp;Addr,&nbsp;uint8&nbsp;*&nbsp;pBuf,&nbsp;uint32&nbsp;Remain)<br />{<br />&nbsp;uint32&nbsp;i;<br />&nbsp;uint32&nbsp;SwapPageAddr;<br />&nbsp;<br />&nbsp;FlashClrCe();&nbsp;//选中芯片<br />&nbsp;if(Addr&gtFLASH_MAX_SECTOR_ADDR)return&nbsp;1;&nbsp;//如果地址超出范围,则返回失败代码1,越界<br />&nbsp;Addr=FlashAddrRemap(Addr);&nbsp;//重新影射地址<br />&nbsp;if((Addr&(~(FLASH_PAGE_SIZE-1)))!=(FlashCurrentWriteSectorAddr&(~(FLASH_PAGE_SIZE-1))))&nbsp;//如果跨page<br />&nbsp;{<br />&nbsp;&nbsp;if(FlashNeedWriteBack)&nbsp;//如果前面写了数据,则需要将当前读出的page写回<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;if(FlashWritePage()&0x01)&nbsp;//写入失败<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;Addr=FlashDealBadBlock(Addr-FLASH_PAGE_SIZE,3)+FLASH_PAGE_SIZE;&nbsp;&nbsp;//坏块处理<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;if((Addr&(~(FLASH_BLOCK_SIZE-1)))!=(FlashCurrentWriteSectorAddr&(~(FLASH_BLOCK_SIZE-1))))&nbsp;&nbsp;//如果跨block,则需要擦除新的块,<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;//在擦除之前,要先将原来的块复制到交换区,并且将该块前面部分数据写回<br />&nbsp;&nbsp;&nbsp;//该函数除了将整块数据复制到交换区以外,并且还将擦除掉原来的块,然后将前面部分复制回原来的块<br />&nbsp;&nbsp;&nbsp;Addr=FlashCopyBlockToSwap(Addr);<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;//从交换区中读出对应的一页<br />&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;FlashWriteAddr4Byte(FlashGetCurrentSwapBlock()+(Addr&(FLASH_BLOCK_SIZE-1)));<br />&nbsp;&nbsp;FlashWriteCommand(0x35);<br />&nbsp;&nbsp;FlashWait();<br />&nbsp;&nbsp;//随机写<br />&nbsp;&nbsp;FlashWriteCommand(0x85);<br />&nbsp;&nbsp;FlashWriteAddr4Byte(Addr);&nbsp;//写4字节地址<br />&nbsp;&nbsp;FlashSetPortAsOut();&nbsp;&nbsp;//总线设置为输出口<br />&nbsp;&nbsp;for(i=0;i&ltFLASH_SECTOR_SIZE;i++)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;FlashWriteByte(pBuf);<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;FlashSetPortAsIn();&nbsp;//总线设置为输入口<br />&nbsp;&nbsp;FlashNeedWriteBack=1;&nbsp;//需要写回<br />&nbsp;}<br />&nbsp;else&nbsp;&nbsp;//没有超过一页地址,则直接写数据<br />&nbsp;{<br />&nbsp;&nbsp;//随机写<br />&nbsp;&nbsp;FlashWriteCommand(0x85);<br />&nbsp;&nbsp;FlashWriteAddr2Byte(Addr);<br />&nbsp;&nbsp;FlashSetPortAsOut();&nbsp;&nbsp;//总线设置为输出口<br />&nbsp;&nbsp;for(i=0;i&ltFLASH_SECTOR_SIZE;i++)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;FlashWriteByte(pBuf);<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;FlashSetPortAsIn();&nbsp;//总线设置为输入口<br />&nbsp;&nbsp;FlashNeedWriteBack=1;&nbsp;//需要写回<br />&nbsp;}<br />&nbsp;FlashCurrentWriteSectorAddr=Addr;&nbsp;//保存本次地址&nbsp;<br />&nbsp;if(Remain==0)&nbsp;//剩余扇区数为0,不会再写了,需要写回<br />&nbsp;{<br />&nbsp;&nbsp;if(FlashNeedWriteBack)&nbsp;//如果前面写了数据,则需要将当前读出的page写回<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;if(FlashWritePage()&0x01)&nbsp;//写入失败<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;Addr=FlashDealBadBlock(Addr,3);&nbsp;&nbsp;//坏块处理<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;//计算剩余页数<br />&nbsp;&nbsp;Remain=(((Addr+FLASH_BLOCK_SIZE)&(~(FLASH_BLOCK_SIZE-1)))-(Addr&(~(FLASH_PAGE_SIZE-1))))/FLASH_PAGE_SIZE-1;<br />&nbsp;&nbsp;//计算在交换块中的起始页地址<br />&nbsp;&nbsp;SwapPageAddr=FlashGetCurrentSwapBlock()+(Addr&(FLASH_BLOCK_SIZE-1));<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;for(i=0;i&ltRemain;i++)&nbsp;&nbsp;//将该块内保存在交换块中剩余部分页的数据复制回该块<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;Addr+=FLASH_PAGE_SIZE;&nbsp;&nbsp;&nbsp;//从下一页开始写<br />&nbsp;&nbsp;&nbsp;SwapPageAddr+=FLASH_PAGE_SIZE;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;if(0x01==(FlashCopyPage(SwapPageAddr,Addr)&0x01))&nbsp;//如果复制失败<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;Addr=FlashDealBadBlock(Addr,2);&nbsp;&nbsp;//处理坏块<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}<br />&nbsp;&nbsp;FlashNeedWriteBack=0;&nbsp;//清除需要写回标志<br />&nbsp;&nbsp;FlashCurrentWriteSectorAddr=-1;<br />&nbsp;}<br />&nbsp;FlashSetCe();&nbsp;//释放FLASH芯片<br />&nbsp;return&nbsp;0;<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////<br /><br />/********************************************************************<br />函数功能:从FLASH中读出一扇区数据保存到缓冲区中。<br />入口参数:Addr:&nbsp;字节地址;pBuf:保存数据的缓冲区;Remain:预计接下来还需要读多少扇区<br />返&nbsp;&nbsp;&nbsp;&nbsp;回:读取的状态。0:成功。非0:失败。<br />备&nbsp;&nbsp;&nbsp;&nbsp;注:当Remain不为0时,将保存当前地址以备后面的继续读当前页,当不为0时,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;设置当前读地址为无效,从而下次读时必须重新使用读命令将数据从flash中读入到页缓存。<br />********************************************************************/<br />uint32&nbsp;FlashReadOneSector(uint32&nbsp;Addr,&nbsp;uint8&nbsp;*&nbsp;pBuf,&nbsp;uint32&nbsp;Remain)<br />{<br />&nbsp;uint32&nbsp;i;<br />&nbsp;FlashClrCe();&nbsp;//选中芯片<br />&nbsp;if(Addr&gtFLASH_MAX_SECTOR_ADDR)return&nbsp;1;&nbsp;//如果地址超出范围,则返回失败代码1,越界<br />&nbsp;Addr=FlashAddrRemap(Addr);&nbsp;//重新影射地址<br />&nbsp;if((Addr&(~(FLASH_PAGE_SIZE-1)))<br />&nbsp;&nbsp;&nbsp;&nbsp;!=(FlashCurrentReadSectorAddr&(~(FLASH_PAGE_SIZE-1))))&nbsp;//如果跨page<br />&nbsp;{<br />&nbsp;&nbsp;//如果跨页的,则写读数据命令<br />&nbsp;&nbsp;FlashWriteCommand(0x00);<br />&nbsp;&nbsp;FlashWriteAddr4Byte(Addr);<br />&nbsp;&nbsp;FlashWriteCommand(0x30);<br />&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;}<br />&nbsp;else<br />&nbsp;{<br />&nbsp;&nbsp;//如果没有跨页,则可以直接读<br />&nbsp;&nbsp;FlashWriteCommand(0x05);<br />&nbsp;&nbsp;FlashWriteAddr2Byte(Addr);<br />&nbsp;&nbsp;FlashWriteCommand(0xE0);<br />&nbsp;&nbsp;FlashWait();&nbsp;//等待数据读回<br />&nbsp;}<br />&nbsp;for(i=0;i&ltFLASH_SECTOR_SIZE;i++)<br />&nbsp;{<br />&nbsp;&nbsp;FlashReadByte(pBuf);&nbsp;&nbsp;//读一字节数据<br />&nbsp;}<br />&nbsp;FlashCurrentReadSectorAddr=Addr;&nbsp;//保存当前操作的地址<br />&nbsp;if(Remain==0)&nbsp;//如果不会接着读,那么就设置当前读过的地址为无效值<br />&nbsp;{<br />&nbsp;&nbsp;FlashCurrentReadSectorAddr=-1;<br />&nbsp;}<br />&nbsp;FlashSetCe();&nbsp;//释放总线<br />&nbsp;return&nbsp;0;<br />}<br />/////////////////////////End&nbsp;of&nbsp;function/////////////////////////////
lhj200304 发表于 2009-3-27 14:45 | 显示全部楼层

留个记号

慢慢看,沙发
古道热肠 发表于 2009-3-27 16:16 | 显示全部楼层

呵呵,下载试试效果.

  
古道热肠 发表于 2009-3-27 17:05 | 显示全部楼层

哈哈,试过了,蛮好的,稳定性不错,截图与大家共赏

图中用红线框圈中的移动盘系开发板生成的优盘.软件由Computer00研制成功.
 楼主| computer00 发表于 2009-3-27 23:25 | 显示全部楼层

哈哈~~~格式化了没?烧几个大文件进去测试下吧...

顺便帮俺检查下bug……<br /><br />现在还有一个隐患,就是将数据随机写入后,如果这时发生写错误,那么将无法恢复<br />到原来的数据,只能使用错误的数据了。不单独在内存中开一个页缓冲,就没办法解决这个问题,<br />因为数据已经写入到FLASH的缓冲区去了。可以考虑再对代码进行改进,开一个2K的页缓冲,<br />这样出错时,就可以把页缓冲区中的数据写出去。但是牵涉到页数据的读出,速度又会降低一些。<br />
wswh2o 发表于 2009-3-28 08:47 | 显示全部楼层

oo真是高产

古道热肠 发表于 2009-3-28 10:19 | 显示全部楼层

俺测试是格式化了,而且拷贝了一大推文件进去

目前没有出现错误.
 楼主| computer00 发表于 2009-3-28 10:31 | 显示全部楼层

还没出现坏块时应该不会有什么问题。就是坏块处理时m可能

我只是简单地模拟了一些坏块调试了下,可能没有考虑到全部的情况。<br /><br />先不管了,用段时间发现问题再找原因吧....<br /><br />接下来就可以考虑放汉字字库进去拉,这样就可以显示汉字了~~~~~<br /><br />以前没研究过windows下的字库文件,啥时来研究下这个,最好能够直接用windows的字库文件就好了……<br />实在不行只好自己写个程序或者去网上找个汉字字库提取的软件了。
ch2003_23 发表于 2009-3-28 23:50 | 显示全部楼层

oo牛

  
古道热肠 发表于 2009-3-29 10:13 | 显示全部楼层

用点阵字库,12点阵和16点阵的最实用.

字库文件UcDos下面有现成的.
 楼主| computer00 发表于 2009-3-29 11:07 | 显示全部楼层

俺准备趁这个机会研究下windows的字库文件,嘿嘿。

  
alex74 发表于 2009-3-30 17:55 | 显示全部楼层

不错

这个原理很合理
alex74 发表于 2009-3-30 18:00 | 显示全部楼层

12点阵和16点阵的代码我给你

如题<br />把pdf后缀改成C就可以 <br /> 相关链接:<a href='https://bbs.21ic.com/upfiles/img/20093/2009330175816170.pdf'>https://bbs.21ic.com/upfiles/img/20093/2009330175816170.pdf</a>
alex74 发表于 2009-3-30 18:03 | 显示全部楼层

接上面

上面那个是16点阵<br />这个是12点阵.<br /><br /> <br /> 相关链接:<a href='https://bbs.21ic.com/upfiles/img/20093/200933018135876.pdf'>https://bbs.21ic.com/upfiles/img/20093/200933018135876.pdf</a>
 楼主| computer00 发表于 2009-3-30 18:58 | 显示全部楼层

谢谢alex74~~~俺在想能不能直接用windows自带的字库文件

这样以后想换个字体时,直接从windows下的字库文件下复制一个对应的字库文件到U盘中就可以拉~~~<br />而不想放到源文件中去编译……<br /><br /><br />
 楼主| computer00 发表于 2009-3-30 19:06 | 显示全部楼层

不小心发现程序中的一个bug,哈哈~~~~

&nbsp;//如果最后一次访问的地址和本次访问的地址属于同一个块地址,那么不需要重新影射<br />&nbsp;if(0==((Addr-FlashLastAccessAddr)&(FLASH_BLOCK_SIZE-1)))<br />&nbsp;{<br />&nbsp;&nbsp;return&nbsp;CurrentRemapBlockAddr+(Addr&(FLASH_BLOCK_SIZE-1));&nbsp;//由当前块地址加上块内偏移得到完整地址<br />&nbsp;}<br /><br />这里搞错了,判断是否跨块,应该保留高半部分……将代码修改成如下:<br /><br />&nbsp;//如果最后一次访问的地址和本次访问的地址属于同一个块地址,那么不需要重新影射<br />&nbsp;if((Addr&(~(FLASH_BLOCK_SIZE-1)))==(FlashLastAccessAddr&(~(FLASH_BLOCK_SIZE-1))))<br />&nbsp;{<br />&nbsp;&nbsp;return&nbsp;CurrentRemapBlockAddr+(Addr&(FLASH_BLOCK_SIZE-1));&nbsp;//由当前块地址加上块内偏移得到完整地址<br />&nbsp;}<br /><br /><br />另外,说明中的“当坏块数量不为0时,先判断最后一次访问和<br />本次访问的地址是否属于同一页,如果属于,那么就直接影射到上<br />一次影射过的块地址。”,应该是“是否属于同一块”,这里不小心<br />写成“同一页”了。<br /><br />
alex74 发表于 2009-3-30 21:44 | 显示全部楼层

...

我用的是ucdos&nbsp;7.0的字库.<br /><br />
alex74 发表于 2009-3-30 21:47 | 显示全部楼层

....

windows字库完全不同的.windows是用unicode的,unicode这个东西没有大内存(至少上百K字节)是玩不了的.<br />你别想了
alex74 发表于 2009-3-30 21:51 | 显示全部楼层

oo其实你这个代码和yaffs比有重大缺陷

就是写均衡没有做
您需要登录后才可以回帖 登录 | 注册

本版积分规则

247

主题

14716

帖子

213

粉丝
快速回复 在线客服 返回列表 返回顶部