OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 8765|回复: 5

带FATFS的外部Flash写数据特别慢

[复制链接]

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
发表于 2014-4-13 21:49:18 | 显示全部楼层 |阅读模式

Flash是W25Q系列的,读比较正常,写非常慢只有几K,采用了DMA来提高速度,之前也问过这个问题,一直没有得到解决,原子兄说可能是DMA的问题,我直接用Write函数写500K的数据到Flash中还是很慢,读写函数都是使用的战舰例程中的函数,DMA是我自己写的,请教一下大家可能会是哪些原因造成的速度奇慢,还有就是有没有朋友测试过Flash的读写可以达到多少?我的要求不高200K/s左右就可以了,下面是我的代码
DMA_DeInit(DMA1_Channel1);                          //将DMA的通道2寄存器重设为缺省值
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;             //DMA对应的外设基地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (DWORD)&ADCConvertedValue;     //内存存储基地址,对应的一个数组
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;           //DMA转换模式为SRC模式,由外设搬移到内存
  DMA_InitStructure.DMA_BufferSize = adc_buff_size;          //DMA缓存大小(设置DMA在传输时缓冲区的长度)
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;    //接收一次数据后设备地址禁止后移也就是说地址保持不变(设置DMA的外设递增模式)
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;      //关闭接收一次数据后目标内存地址后移(设置DMA内存递增模式)
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;      //外设数据宽度半字
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         //存储器数据宽度半字
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;               //DMA的传输模式为循环
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;           //DMA的通道拥有高优先级
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                  //非内存到内存传输
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);                  //初始化DMA通道
 
  // Enable DMA1 channel1
  DMA_Cmd(DMA1_Channel1, ENABLE);
  DMA_ITConfig(DMA1_Channel1, DMA_IT_TC | DMA_IT_HT, ENABLE);

u8 SPI_FLASH_BUF[4096];
void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)  
{
 u32 secpos;
 u16 secoff;
 u16 secremain;   
  u16 i;   

 secpos=WriteAddr/4096;//扇区地址 0~511 for w25x16
 secoff=WriteAddr%4096;//在扇区内的偏移
 secremain=4096-secoff;//扇区剩余空间大小  
 LED2 = !LED2;

 if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
 while(1)
 { 
  SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容
  for(i=0;i<secremain;i++)//校验数据
  {
   if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除    
  }
  if(i<secremain)//需要擦除
  {
   SPI_Flash_Erase_Sector(secpos);//擦除这个扇区
   for(i=0;i<secremain;i++)    //复制
   {
    SPI_FLASH_BUF[i+secoff]=pBuffer;  
   }
   SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区 

  }else SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.       
  if(NumByteToWrite==secremain)break;//写入结束了
  else//写入未结束
  {
   secpos++;//扇区地址增1
   secoff=0;//偏移位置为0  

      pBuffer+=secremain;  //指针偏移
   WriteAddr+=secremain;//写地址偏移   
      NumByteToWrite-=secremain;    //字节数递减
   if(NumByteToWrite>4096)secremain=4096; //下一个扇区还是写不完
   else secremain=NumByteToWrite;   //下一个扇区可以写完了
  } 
 };   
}

void SPI_Flash_Erase_Sector(u32 Dst_Addr)  
{  
 Dst_Addr*=4096;
    SPI_FLASH_Write_Enable();                  //SET WEL  
    SPI_Flash_Wait_Busy();  
   SPI_FLASH_CS=0;                            //使能器件  
    SPI2_ReadWriteByte(W25Q_SectorErase);      //发送扇区擦除指令
    SPI2_ReadWriteByte((u8)((Dst_Addr)>>16));  //发送24bit地址   
    SPI2_ReadWriteByte((u8)((Dst_Addr)>>8));  
    SPI2_ReadWriteByte((u8)Dst_Addr); 
 SPI_FLASH_CS=1;                            //取消片选           
    SPI_Flash_Wait_Busy();          //等待擦除完成


void SPI_Flash_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)  
{       
 u16 pageremain;   
 pageremain=256-WriteAddr%256; //单页剩余的字节数       
 if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
 while(1)
 {   
  SPI_Flash_Write_Page(pBuffer,WriteAddr,pageremain);
  if(NumByteToWrite==pageremain)break;//写入结束了
   else //NumByteToWrite>pageremain
  {
   pBuffer+=pageremain;
   WriteAddr+=pageremain; 

   NumByteToWrite-=pageremain;     //减去已经写入了的字节数
   if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
   else pageremain=NumByteToWrite;    //不够256个字节了
  }
 };    
}

void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)  
{
  u16 i;                   
 SPI_FLASH_CS=0;                            //使能器件  
    SPI2_ReadWriteByte(W25Q_ReadData);         //发送读取命令  
    SPI2_ReadWriteByte((u8)((ReadAddr)>>16));  //发送24bit地址   
    SPI2_ReadWriteByte((u8)((ReadAddr)>>8));  
    SPI2_ReadWriteByte((u8)ReadAddr);  
    for(i=0;i<NumByteToRead;i++)
 {
        pBuffer=SPI2_ReadWriteByte(0XFF);   //循环读数 
    }
 SPI_FLASH_CS=1;                            //取消片选           

还有就是我的Flash不是焊好在开发板上的而是单独的一个Flash芯片用几根铜丝把电源,地,片选,输入输出,还有时钟,焊接起来然后通过杜邦线插在相应的引脚之上的,这样会不会影响数据的传输速度呢?求教了!

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165475
金钱
165475
注册时间
2010-12-1
在线时间
2115 小时
发表于 2014-4-13 22:00:30 | 显示全部楼层
回复【楼主位】csf4824521:
---------------------------------
当SPI 不是全新的的时候(有内容需要擦除),就会大大降低写入速度。。。。
你要想快,先将整个SPI芯片擦除了,再写,测试下。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
 楼主| 发表于 2014-4-13 23:02:36 | 显示全部楼层
根据原子兄的指教擦了整个片子,文件系统没有了,重新格式化了一次,速度没有明显变化,我觉得写慢主要慢在擦除上面了,如果我在写中屏蔽掉擦除速度有明显提高,但是擦除又不可能不用,Flash这么慢的速度根本没有办法达到我的要求,想请教一下Flash的速度能达到多少?可以到200K/s左右吗?文件系统对Flash的读写速度影响大吗?如果不要文件系统可不可行?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165475
金钱
165475
注册时间
2010-12-1
在线时间
2115 小时
发表于 2014-4-13 23:12:14 | 显示全部楼层
如果是全新的,200K应该没问题。
但是是复写,那就大大的不行了。。。除非你做一些牺牲,比如要写1个扇区的时候,直接先擦掉整个扇区。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
 楼主| 发表于 2014-4-13 23:35:32 | 显示全部楼层
在写函数中不是有擦除整个扇区的函数吗?您的意思是不判断是否需要擦除,在写之前一律擦除?
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2014-4-14 08:36:21 | 显示全部楼层
回复【5楼】csf4824521:
---------------------------------
一次性写入一个扇区的内容(比如4K),这样试下,存够一个扇区的内容之后才写入
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-12 14:20

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表