圈圈的加了坏块管理的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;
}
-
今天调试时:
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)
去读和写,结果读和写的数据都是完全一致的。
-