[求助] "写nand flash一个扇区":uint32 FlashWriteOneSector()

qiwan   2015-3-31 22:09 楼主
圈圈的加了坏块管理的flash写函数:
uint32 FlashWriteOneSector(uint32 Addr, uint8 * pBuf, uint32 Remain),
具体程序如下:
程序有点长,但咱先不看程序。
先看看这段程序的大体功能(用引号引的这段话,来自圈圈):
"连续写扇区的实现原理:当检测到扇区地址跨块时,就把原来
的整块数据复制到交换块中,然后将块内当前所写地址的前面
部分页复制到原来的块中,接着就从交换块中取出当前扇区地址
所在页(使用页复制-随机写入命令),再把一个扇区的数据写入,
并接着写入其他扇区,当扇区地址跨页时,就把该页写入原来的
块中,直到扇区被写完(当然,如果写的过程中跨块了,还需要
擦除重复前面的块擦除以及复制过程。)接着,把交换块中剩余
的页再复制回到原来的快中,这样一个连续的写过程就完成了
"
通过程序调试,结合程序,我看懂了程序的前半部分(红色字节部分),
即一个扇区的写入过程。
但怎样实现扇区的连续写,确实没太懂。
Remain表征的是"剩余写入的扇区“,我不太理解.
我尝试着在main()中这样调用写扇区函数:
        FlashWriteOneSector(0,TxBuffer , 2);
其中TxBuffer[1024]={0,1,2,3...FF,1,2,3...FF...};
目的是:从flash的第0块第0页第0个字节的地址开始,依次写入数组
TxBuffer的1024个数据,flash的一个扇区大小为512个字节,即需要
连续写两个扇区。
然后调用读扇区函数:FlashReadOneSector(0, RxBuffer, 2);来验证
写入数据的正确性。
调试的结果如图1所示:只有一半的数据,即512个数据。
至于原因,要么是:确实只写了512个数据;
                 要么是:1024个数据全部写入,但只读都了512个数据。
疑惑继续:在main函数中调用,写扇区函数FlashWriteOneSector(0,TxBuffer , 2);
即这里Remain=2,当程序写完一个扇区后,调试过程中好像没有继续写第二个扇区。
没有Remain--,程序也进不了if(Remain==0)中。

硬件条件是:STM32F103VET6和128M的nand  flash K9F1G08U,希望有过类似经验的

朋友能点拨一下,如果有朋友有这样的硬件条件,希望能够帮忙试试,然后讨论交流一下。

谢谢!


uint32 FlashWriteOneSector(uint32 Addr, uint8 * pBuf, uint32 Remain)

{

uint32 i;

uint32 SwapPageAddr;

// printf("Addr = 0x%x\r\n",Addr);

// printf("Remain = 0x%x\r\n",Remain);



if(Addr>FLASH_MAX_SECTOR_ADDR)return 1; //如果地址超出范围,则返回失败代码1,越界

Addr=FlashAddrRemap(Addr); //重新影射地址

if((Addr&(~(FLASH_PAGE_SIZE-1)))!=(FlashCurrentWriteSectorAddr&(~(FLASH_PAGE_SIZE-1)))) //如果跨page

{

//  printf("跨页\r\n");

  if(FlashNeedWriteBack) //如果前面写了数据,则需要将当前读出的page写回

  {

   if(FlashWritePage()&0x01) //写入失败

   {

    Addr=FlashDealBadBlock(Addr-FLASH_PAGE_SIZE,3)+FLASH_PAGE_SIZE;  //坏块处理

   }

  }

  if((Addr&(~(FLASH_BLOCK_SIZE-1)))!=(FlashCurrentWriteSectorAddr&(~(FLASH_BLOCK_SIZE-1))))  //如果跨block,则需要擦除新的块,

  {

   //在擦除之前,要先将原来的块复制到交换区,并且将该块前面部分数据写回

   //该函数除了将整块数据复制到交换区以外,并且还将擦除掉原来的块,然后将前面部分复制回原来的块

//   printf("跨块\r\n");

   Addr=FlashCopyBlockToSwap(Addr);

  }

  //从交换区中读出对应的一页

  FlashWriteCommand(0x00);

  FlashWriteAddr4Byte(FlashGetCurrentSwapBlock()+(Addr&(FLASH_BLOCK_SIZE-1)));

  FlashWriteCommand(0x35);

  FlashWait();

  //随机写

  FlashWriteCommand(0x85);

  FlashWriteAddr4Byte(Addr); //写4字节地址

  for(i=0;i
  {

   FlashWriteDataByte(pBuf);

  }



  FlashWriteCommand(0x85);

  FlashWriteAddr2Byte(Addr&(FLASH_BLOCK_SIZE-1));

  for(i=0;i
  {

   FlashWriteDataByte(pBuf);

  }         

  FlashWriteCommand(0x10);



  FlashNeedWriteBack=1; //需要写回

}



else  //没有超过一页地址,则直接写数据

{

  //随机写

//  printf("直接写\r\n");

  FlashWriteCommand(0x85);

  FlashWriteAddr2Byte(Addr);



  for(i=0;i
  {

   FlashWriteDataByte(pBuf);

  }

  FlashNeedWriteBack=1; //需要写回

}

FlashCurrentWriteSectorAddr=Addr; //保存本次地址

if(Remain==0) //剩余扇区数为0,不会再写了,需要写回

{

//  printf("写回\r\n");

  if(FlashNeedWriteBack) //如果前面写了数据,则需要将当前读出的page写回

  {

   if(FlashWritePage()&0x01) //写入失败

   {

    Addr=FlashDealBadBlock(Addr,3);  //坏块处理

   }

  }

  //计算剩余页数

  Remain=(((Addr+FLASH_BLOCK_SIZE)&(~(FLASH_BLOCK_SIZE-1)))-(Addr&(~(FLASH_PAGE_SIZE-1))))/FLASH_PAGE_SIZE-1;

  //计算在交换块中的起始页地址

  SwapPageAddr=FlashGetCurrentSwapBlock()+(Addr&(FLASH_BLOCK_SIZE-1));



  for(i=0;i
  {

   Addr+=FLASH_PAGE_SIZE;   //从下一页开始写

   SwapPageAddr+=FLASH_PAGE_SIZE;   

   if(0x01==(FlashCopyPage(SwapPageAddr,Addr)&0x01)) //如果复制失败

   {

    Addr=FlashDealBadBlock(Addr,2);  //处理坏块

   }

  }

  FlashNeedWriteBack=0; //清除需要写回标志

  FlashCurrentWriteSectorAddr=~0;

}

return 0;

}





  • 图1:读到的数据

    3s_debug.rar (2015-3-31 22:09 上传)

    4.58 MB, 下载次数: 11

回复评论 (3)

今天调试时:


unsigned char TxBuffer0[512];

unsigned char TxBuffer1[512];

unsigned char TxBuffer2[512];






unsigned char RxBuffer0[512];

unsigned char RxBuffer1[512];

unsigned char RxBuffer2[512];






Fill_Buffer(TxBuffer0, 512, 0);

Fill_Buffer(TxBuffer1, 512, 1);

Fill_Buffer(TxBuffer2, 512, 2);


数组TxBuffer0、TxBuffer1、TxBuffer2,分别通过

Fill_Buffer()函数填充,有

Fill_Buffer0[512]={0,1,2,3...0xFF,0,1,2,3...0xFF,0,1,2,3...0XFF,0,1,2,3...0xFF};

Fill_Buffer1[512]={1,2,3...0xFF,0,1,2,3...0xFF,0,1,2,3...0XFF,0,1,2,3...0xFF,0};

Fill_Buffer2[512]={2,3...0xFF,0,1,2,3...0xFF,0,1,2,3...0XFF,0,1,2,3...0xFF,0,1};

然后:


FlashWriteOneSector(788,TxBuffer0);

FlashWriteOneSector(1300,TxBuffer1);

FlashWriteOneSector(1812,TxBuffer2);


即:

数组Fill_Buffer0中的512个数据,写入flash起始地址为788(十进制)的一个扇区内:788~1299;

数组Fill_Buffer1中的512个数据,写入flash起始地址为1300(十进制)的一个扇区内:1300~1811;

数组Fill_Buffer2中的512个数据,写入flash起始地址为1812(十进制)的一个扇区内:1812~2323;

其中:1812~2323这个扇区时跨页的,1812~2047属于Page0,2048~2323 属于Page1。

最后通过读扇区来验证数据的正确性:


FlashReadOneSector(788,RxBuffer0);

FlashReadOneSector(1300,RxBuffer1);

FlashReadOneSector(1812,RxBuffer2);         


结果是:

地址范围为788~1299,1300~1800的两个扇区中的数据:读出的与之前写入的完全一致;

但地址范围为1812~2323,即跨页的这个扇区的数据:前面部分数据一致,后面的数据却是D3。

如图1所示。




后来我也试了一下跨块的扇区,


FlashWriteOneSector(130000,TxBuffer3);

FlashWriteOneSector(130512,TxBuffer4);

FlashWriteOneSector(131024,TxBuffer5);//跨块扇区






FlashReadOneSector(130000,RxBuffer3);

FlashReadOneSector(130512,RxBuffer4);

FlashReadOneSector(131024,RxBuffer5); //跨块扇区


结果依旧是:跨块扇区的数据:前面部分数据一致,后面的数据则是D3。




在此之前,我一直以为,当数据比较长时,会自动的跨到下一页。

但,这是错误的。

“NAND flash存储器会自动累加器内部的操作地址,读写数据时没有必要变换

数据的操作地址,即不必对连续的地址区操作”

写入过程在NAND flash内部是有边界对齐的,也就是说,写入起始地址不是

页对齐时,只能从当前字节写到本页末尾,而不能跨越到第二页继续写,即使

写入够长,也不能一次跨两页

读取过程在NAND flash内部也是有边界对齐的,也就是说,读取地址不是

页对齐时,之恩给你从当前字节地址开始读到本页末尾,而不能跨越到第二页

继续读取,即使读取够长,也不能跨越两页读取



后来,我避开跨块和跨页的问题,将地址都改成页对齐(Addr%FLASH_PAGE_SIZE==0)

去读和写,结果读和写的数据都是完全一致的。




  • 图1
点赞  2015-4-2 21:22
谢谢分享 a
11
点赞  2015-4-3 12:34
貌似NAND flash 是按页操作的
点赞  2016-5-25 17:06
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复