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