打印
[STM32]

关于圈圈的“往flash写一个扇区”函数:FlashWriteOneSector()的...

[复制链接]
2912|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
使用圈圈的“往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[1024]={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。
看nand  flash的datasheet手册,发现“页面复制-随机写入”的流程如图所示:
但上述程序只执行了前半部分,即最后一次0x85+具体的页内偏移地址+0x10(0x10命令用来启动写);
于是,对上述程序进行了修改:添加了的程序见蓝色字体。
调试的结果是:数据写入成功且正确,但只有512个数据,即只有一半,如图所示。
而至于原因:(1)确实只写入了一半;(2)确实全部写入了,只读了一半;
对这段程序,我不理解的是参数Remain。
上面已经提到,在我的main函数中,
我是这样调用写函数的:FlashWriteOneSector(0, TxBuffer, 2);
如果按照上述程序执行,写完一个扇区后,即写入512个数据后,就没有继续写入下一个扇区。
也进入了if(Remain==0)。确实没怎么搞懂,它到底是怎样连续写扇区的?
各位前辈,能给点提示吗?谢谢了













页面复制-随机写入流程.PNG (48.85 KB )

页面复制-随机写入流程

页面复制-随机写入流程

读取的RxBuffer数据.PNG (31.26 KB )

只有一半的数据

只有一半的数据

相关帖子

沙发
Mobile1991|  楼主 | 2015-4-2 21:23 | 只看该作者
今天调试时:
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)
去读和写,结果读和写的数据都是完全一致的。


使用特权

评论回复
板凳
Mobile1991|  楼主 | 2015-4-2 21:24 | 只看该作者
图1

1.PNG (21.88 KB )

图1

图1

使用特权

评论回复
地板
chenyelong| | 2015-4-9 13:00 | 只看该作者
没得人回复

使用特权

评论回复
5
cornrn| | 2017-5-15 14:03 | 只看该作者
这程序有一定BUG的不能用在USB模拟NAND FLASH U盘上面

使用特权

评论回复
6
影杀| | 2017-6-29 22:44 | 只看该作者
本帖最后由 影杀 于 2017-6-29 22:47 编辑
cornrn 发表于 2017-5-15 14:03
这程序有一定BUG的不能用在USB模拟NAND FLASH U盘上面

抄人家板子卖的爽吗?知道你nb 还在咸鱼装b   @正点原子

Screenshot_2017-06-29-22-33-03.png (236.13 KB )

Screenshot_2017-06-29-22-33-03.png

Screenshot_2017-06-29-22-33-40.png (295.25 KB )

Screenshot_2017-06-29-22-33-40.png

Screenshot_2017-06-29-22-33-16.png (302 KB )

Screenshot_2017-06-29-22-33-16.png

Screenshot_2017-06-29-22-33-25.png (276.22 KB )

Screenshot_2017-06-29-22-33-25.png

Screenshot_2017-06-29-22-33-31.png (297.39 KB )

Screenshot_2017-06-29-22-33-31.png

使用特权

评论回复
7
kingkits| | 2017-6-30 09:07 | 只看该作者
有些硬件是在一个页内循环呢,即写完这页的最后一个字节,会折返到第0字节重新写

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

11

主题

45

帖子

1

粉丝