关于圈圈的“往flash写一个扇区”函数:FlashWriteOneSector()的...
使用圈圈的“往flash写一个扇区”函数:uint32 FlashWriteOneSector(uint32 Addr, uint8 * pBuf, uint32 Remain),
调试时遇到较多让我不解的地方,希望各位前辈能指点解惑。
原函数如下:
uint32 FlashWriteOneSector(uint32 Addr, uint8 * pBuf, uint32 Remain)
{
uint32 i;
uint32 SwapPageAddr;
if(Addr>FLASH_MAX_SECTOR_ADDR)return 1; //如果地址超出范围,则返回失败代码1,越界
Addr=FlashAddrRemap(Addr); //重新影射地址
if((Addr&(~(FLASH_PAGE_SIZE-1)))!=(FlashCurrentWriteSectorAddr&(~(FLASH_PAGE_SIZE-1)))) //如果跨page
{
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,则需要擦除新的块,
{
//在擦除之前,要先将原来的块复制到交换区,并且将该块前面部分数据写回
//该函数除了将整块数据复制到交换区以外,并且还将擦除掉原来的块,然后将前面部分复制回原来的块
Addr=FlashCopyBlockToSwap(Addr);
}
//从交换区中读出对应的一页
FlashWriteCommand(0x00);
FlashWriteAddr4Byte(FlashGetCurrentSwapBlock()+(Addr&(FLASH_BLOCK_SIZE-1)));
FlashWriteCommand(0x35);
FlashWait();
//随机写
FlashWriteCommand(0x85);
FlashWriteAddr4Byte(Addr); //写4字节地址
for(i=0;i<FLASH_SECTOR_SIZE;i++)
{
FlashWriteDataByte(pBuf);
}
FlashWriteCommand(0x85);
FlashWriteAddr2Byte(Addr&(FLASH_BLOCK_SIZE-1));
for(i=0;i<FLASH_SECTOR_SIZE;i++)
{
FlashWriteDataByte(pBuf);
}
FlashWriteCommand(0x10);
FlashNeedWriteBack=1; //需要写回
}
else//没有超过一页地址,则直接写数据
{
//随机写
FlashWriteCommand(0x85);
FlashWriteAddr2Byte(Addr);
for(i=0;i<FLASH_SECTOR_SIZE;i++)
{
FlashWriteDataByte(pBuf);
}
FlashNeedWriteBack=1; //需要写回
}
FlashCurrentWriteSectorAddr=Addr; //保存本次地址
if(Remain==0) //剩余扇区数为0,不会再写了,需要写回
{
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<Remain;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;
}
在main函数中,int main(void)
{
SystemInit(); //系统时钟初始化
Fill_Buffer(TxBuffer, 1024 , 0x00);//给TxBuffer填充值
FlashInit();
FlashReadId(ID_Code);
FlashWriteOneSector(0, TxBuffer, 2);
FlashWriteOneSector(0,RxBuffer,2);
}
(1)首先,使用FlashInit()初始化了flash的一些参数:比如:FlashCurrentReadSectorAddr=~0,即为0xFFFFFFFF;
(2)然后,调用了“扇区写函数”:FlashWriteOneSector(0, TxBuffer, 2);
其中,数组TxBuffer={0,1,2,3...FF,0,1,2,3...FF,0,1,2,3...FF,1,2,3...FF...};
程序的目的是:使用FlashWriteOneSector将数组TxBuffer中的1024个数据存储在flash的两个
连续的扇区中(定义flash扇区大小为512字节)。
(3)最后,用FlashWriteOneSector(0,RxBuffer,2);验证写入扇区的数据的正确型。
不管程序对不对,直接使用上述程序,发现:读出的数据全部是0x00,可见TxBuffer中的数据
并没有写入flash。
看nandflash的datasheet手册,发现“页面复制-随机写入”的流程如图所示:
但上述程序只执行了前半部分,即最后一次0x85+具体的页内偏移地址+0x10(0x10命令用来启动写);
于是,对上述程序进行了修改:添加了的程序见蓝色字体。
调试的结果是:数据写入成功且正确,但只有512个数据,即只有一半,如图所示。
而至于原因:(1)确实只写入了一半;(2)确实全部写入了,只读了一半;
对这段程序,我不理解的是参数Remain。
上面已经提到,在我的main函数中,
我是这样调用写函数的:FlashWriteOneSector(0, TxBuffer, 2);
如果按照上述程序执行,写完一个扇区后,即写入512个数据后,就没有继续写入下一个扇区。
也进入了if(Remain==0)。确实没怎么搞懂,它到底是怎样连续写扇区的?
各位前辈,能给点提示吗?谢谢了
今天调试时:
unsigned char TxBuffer0;
unsigned char TxBuffer1;
unsigned char TxBuffer2;
unsigned char RxBuffer0;
unsigned char RxBuffer1;
unsigned char RxBuffer2;
Fill_Buffer(TxBuffer0, 512, 0);
Fill_Buffer(TxBuffer1, 512, 1);
Fill_Buffer(TxBuffer2, 512, 2);
数组TxBuffer0、TxBuffer1、TxBuffer2,分别通过
Fill_Buffer()函数填充,有
Fill_Buffer0={0,1,2,3...0xFF,0,1,2,3...0xFF,0,1,2,3...0XFF,0,1,2,3...0xFF};
Fill_Buffer1={1,2,3...0xFF,0,1,2,3...0xFF,0,1,2,3...0XFF,0,1,2,3...0xFF,0};
Fill_Buffer2={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
没得人回复 这程序有一定BUG的不能用在USB模拟NAND FLASH U盘上面 本帖最后由 影杀 于 2017-6-29 22:47 编辑
cornrn 发表于 2017-5-15 14:03
这程序有一定BUG的不能用在USB模拟NAND FLASH U盘上面
抄人家板子卖的爽吗?知道你nb 还在咸鱼装b @正点原子 有些硬件是在一个页内循环呢,即写完这页的最后一个字节,会折返到第0字节重新写
页:
[1]