浅析spi flash驱动及其程序

电子说

1.3w人已加入

描述

  SPI Flash
 
  首先它是个Flash,Flash是什么东西就不多说了(非易失性存储介质),分为NOR和NAND两种(NOR和NAND的区别本篇不做介绍)。SPI一种通信接口。那么严格的来说SPI Flash是一种使用SPI通信的Flash,即,可能指NOR也可能是NAND。但现在大部分情况默认下人们说的SPI Flash指的是SPI NorFlash。早期Norflash的接口是parallel的形式,即把数据线和地址线并排与IC的管脚连接。但是后来发现不同容量的Norflash不能硬件上兼容(数据线和地址线的数量不一样),并且封装比较大,占用了较大的PCB板位置,所以后来逐渐被SPI(串行接口)Norflash所取代。同时不同容量的SPI Norflash管脚也兼容封装也更小。,至于现在很多人说起NOR flash直接都以SPI flash来代称。
 
  NorFlash根据数据传输的位数可以分为并行(Parallel,即地址线和数据线直接和处理器相连)NorFlash和串行(SPI,即通过SPI接口和处理器相连)NorFlash;区别主要就是:1、SPI NorFlash每次传输一bit位的数据,parallel连接的NorFlash每次传输多个bit位的数据(有x8和x16bit两种); 2、SPI NorFlash比parallel便宜,接口简单点,但速度慢。
 
  NandFlash是地址数据线复用的方式,接口标准统一(x8bit和x16bit),所以不同容量再兼容性上基本没什么问题。但是目前对产品的需求越来越小型化以及成本要求也越来越高,所以SPI NandFlash渐渐成为主流,并且采用SPI NANDFlash方案,主控也可以不需要传统NAND控制器,只需要有SPI接口接口操作访问,从而降低成本。另外SPI NandFlash封装比传统的封装也小很多,故节省了PCB板的空间。
 
  怎么用说白了对于Flash就是读写擦,也就是实现flash的驱动。先简单了解下spi flash的物理连接。
 
  之前介绍SPI的时候说过,SPI接口目前的使用是多种方式(具体指的是物理连线有几种方式),Dual SPI、Qual SPI和标准的SPI接口(这种方式肯定不会出现在连接外设是SPI Flash上,这玩意没必要全双工),对于SPI Flash来说,主要就是Dual和Qual这两种方式。具体项目具体看了,理论上在CLK一定的情况下, 线数越多访问速度也越快。我们项目采用的Dual SPI方式,即两线。
SPI Flash

  移植需要更改sendrcv函数里面内容,宏定义内容

  [cpp] view plain copy《code class=“language-cpp”》#define DRV_SPI_FLASH_WRITE_ENABLE (0x06) //Write Enable

  #define DRV_SPI_FLASH_WRITE_DISABLE (0x04) //Write Disable

  #define DRV_SPI_FLASH_READ_STATUS_REG (0x05) //Read Status Register

  #define DRV_SPI_FLASH_WRITE_STATUS_REG (0x01) //Write Status Register

  #define DRV_SPI_FLASH_READ_DATA (0x03) //Read Data

  #define DRV_SPI_FLASH_FAST_READ (0x0B) //Fast Read

  #define DRV_SPI_FLASH_FAST_READ_DUAL_OUTPUT (0x3B) //Fast Read Dual Output

  #define DRV_SPI_FLASH_PAGEPROGRAM (0x02) //Page Program

  #define DRV_SPI_FLASH_BLOCK_ERASE (0xD8) //Block Erase(64KB)

  #define DRV_SPI_FLASH_HALF_BLOCK_ERASE (0x52) //Half Block Erase(32KB)

  #define DRV_SPI_FLASH_SECTOR_ERASE (0x20) //Sector Erase(4KB)

  #define DRV_SPI_FLASH_CHIP_ERASE (0xC7) //Chip Erase

  #define DRV_SPI_FLASH_JEDEC_ID (0x9F) //JEDEC ID

  #define APP_SPI3_CS_LOW SCU_SetSpiCsn(SPI3_CSN,LOW)

  #define APP_SPI3_CS_HIGH SCU_SetSpiCsn(SPI3_CSN,HIGH)

  uint8_t DrvFlashSendRcvByte(uint8_t ucData)

  {

  uint8_t ucTemp;

  while(SPI_GetFlagStatus(SGCC_SPI3_P,SPI_FLAG_RFNE))

  ucTemp = SPI_ReceiveData(SGCC_SPI3_P);

  SPI_SendData(SGCC_SPI3_P, ucData);

  while(0 == SPI_GetFlagStatus(SGCC_SPI3_P,SPI_FLAG_RFNE));

  ucTemp = SPI_ReceiveData(SGCC_SPI3_P);

  return ucTemp;

  }

  uint32_t DrvFlashReadID(void)

  {

  uint32_t ulDevID = 0;

  APP_SPI3_CS_LOW;

  DrvFlashSendRcvByte(DRV_SPI_FLASH_JEDEC_ID);

  ulDevID |= DrvFlashSendRcvByte(0xFF) 《《 16;

  ulDevID |= DrvFlashSendRcvByte(0xFF) 《《 8;

  ulDevID |= DrvFlashSendRcvByte(0xFF);

  APP_SPI3_CS_HIGH;

  return ulDevID;

  }

  uint8_t DrvFlashReadStausReg(void)

  {

  uint8_t ucReg;

  APP_SPI3_CS_LOW;

  DrvFlashSendRcvByte(DRV_SPI_FLASH_READ_STATUS_REG);

  ucReg = DrvFlashSendRcvByte(0xFF);

  APP_SPI3_CS_HIGH;

  return ucReg;

  }

  void DrvFlashWaitBusy(void)

  {

  while((DrvFlashReadStausReg() & 0x01) == 0x01);

  }

  void DrvFlashWriteEnable(void)

  {

  APP_SPI3_CS_LOW;

  DrvFlashSendRcvByte(DRV_SPI_FLASH_WRITE_ENABLE);

  APP_SPI3_CS_HIGH;

  }

  void DrvFlashWriteDisable(void)

  {

  APP_SPI3_CS_LOW;

  DrvFlashSendRcvByte(DRV_SPI_FLASH_WRITE_DISABLE);

  APP_SPI3_CS_HIGH;

  }

  void DrvFlashReadData(uint8_t* pRcvBuf, uint32_t ulReAddr, uint16_t usReNum)

  {

  uint16_t i;

  APP_SPI3_CS_LOW;

  DrvFlashSendRcvByte(DRV_SPI_FLASH_READ_DATA);

  DrvFlashSendRcvByte((uint8_t)((ulReAddr)》》16));

  DrvFlashSendRcvByte((uint8_t)((ulReAddr)》》8));

  DrvFlashSendRcvByte((uint8_t)ulReAddr);

  for(i=0; i 《 usReNum; i++)

  {

  pRcvBuf[i] = DrvFlashSendRcvByte(0XFF);

  }

  APP_SPI3_CS_HIGH;

  }

  void DrvFlashPageWrite(uint8_t* pWrBuf, uint32_t ulWrAddr, uint16_t usWrNum)

  {

  uint16_t i;

  DrvFlashWriteEnable();

  APP_SPI3_CS_LOW;

  DrvFlashSendRcvByte(DRV_SPI_FLASH_PAGEPROGRAM);

  DrvFlashSendRcvByte((uint8_t)((ulWrAddr)》》16));

  DrvFlashSendRcvByte((uint8_t)((ulWrAddr)》》8));

  DrvFlashSendRcvByte((uint8_t)ulWrAddr);

  for(i = 0; i 《 usWrNum; i++)

  DrvFlashSendRcvByte(pWrBuf[i]);

  APP_SPI3_CS_HIGH;

  DrvFlashWaitBusy();

  }

  void DrvFlashWriteNoCheck(uint8_t* pBuffer, uint32_t addr, uint16_t num)

  {

  uint16_t pageremain;

  pageremain = 256 - addr % 256;//鍗曢〉鍓╀綑瀛楄妭鏁�

  if(num 《= pageremain)//涓嶅ぇ浜�256

  pageremain = num;

  while(1)

  {

  DrvFlashPageWrite(pBuffer, addr, pageremain);

  if(num == pageremain)

  break;//鍐欑粨鏉熶簡

  else

  {

  pBuffer += pageremain;

  addr += pageremain;

  num -= pageremain;//鍑忓幓宸茬粡鍐欏叆鐨勫瓧鑺傛暟

  if(num 》 256)

  pageremain = 256;//鏈鍙互鍐欏叆涓�椤垫暟鎹�

  else

  pageremain = num;//鏈�鍚庝竴娆″啓

  }

  };

  }

  void DrvFlashWriteData(uint8_t* pBuffer,uint32_t addr,uint16_t num)

  {

  uint32_t secpos;

  uint16_t secoff;

  uint16_t secremain;

  uint16_t i;

  uint8_t * W25QXX_BUF;

  uint8_t W25QXX_BUFFER[4096];

  W25QXX_BUF = W25QXX_BUFFER;

  secpos = addr / 4096;//鎵囧尯鍦板潃

  secoff = addr % 4096;//鍦ㄦ墖鍖哄唴鐨勫亸绉�

  secremain = 4096 - secoff;//鎵囧尯鍓╀綑绌洪棿澶у皬

  // printf

  if(num 《= secremain)//涓嶅ぇ浜庡綋鍓嶆墖鍖哄墿浣欏瓧鑺�

  {

  secremain = num;

  }

  while(1)

  {

  DrvFlashReadData(W25QXX_BUF, secpos * 4096, 4096);//璇诲彇鏁翠釜鎵囧尯

  for(i = 0; i 《 secremain; i++)//鏍¢獙鏁版嵁

  {

  if(W25QXX_BUF[secoff + i] != 0XFF)//闇�瑕佹摝鍑�

  break;

  }

  if(i 《 secremain)//闇�瑕佹摝鍑�

  {

  DrvFlashSectorErase(secpos * 4096);//鎿﹂櫎鏁翠釜鎵囧尯

  for(i = 0; i 《 secremain; i++)

  {

  W25QXX_BUF[i + secoff] = pBuffer[i];//澶嶅埗

  }

  DrvFlashWriteNoCheck(W25QXX_BUF, secpos * 4096, 4096);//鍐欏叆鏁翠釜鎵囧尯

  }

  else

  DrvFlashWriteNoCheck(pBuffer, addr, secremain);//鍐欏凡缁忔摝闄や簡鐨勶紝鐩存帴鍐欏叆鎵囧尯鍓╀綑绌洪棿

  if(num == secremain)

  break;//鍐欑粨鏉熶簡

  else//

  {

  secpos++;//鎵囧尯鍦板潃澧炲姞1

  secoff = 0;//鍋忕Щ浣嶇疆涓�0

  pBuffer += secremain;//鎸囬拡鍋忕Щ

  addr += secremain;//鍐欏湴鍧�鍋忕Щ

  num -= secremain;//瀛楄妭鏁伴�掑噺

  if(num 》 4096)

  secremain = 4096;//涓嬩竴涓墖鍖鸿繕鏄啓涓嶅畬

  else

  secremain = num;//涓嬩竴涓墖鍖哄彲浠ュ啓瀹屼簡

  }

  };

  }

  void DrvFlashChipErase(void)

  {

  DrvFlashWriteEnable();

  DrvFlashWaitBusy();

  APP_SPI3_CS_LOW;

  DrvFlashSendRcvByte(DRV_SPI_FLASH_CHIP_ERASE);

  APP_SPI3_CS_HIGH;

  DrvFlashWaitBusy();

  }

  void DrvFlashSectorErase(uint32_t ulErAddr)

  {

  DrvFlashWriteEnable();

  DrvFlashWaitBusy();

  APP_SPI3_CS_LOW;

  DrvFlashSendRcvByte(DRV_SPI_FLASH_SECTOR_ERASE);

  DrvFlashSendRcvByte((uint8_t)((ulErAddr)》》16));

  DrvFlashSendRcvByte((uint8_t)((ulErAddr)》》8));

  DrvFlashSendRcvByte((uint8_t)ulErAddr);

  APP_SPI3_CS_HIGH;

  DrvFlashWaitBusy();

  }

  《/code》


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分