新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > SST25VF080B SPI接口FLASH STM32驅(qū)動(dòng)

SST25VF080B SPI接口FLASH STM32驅(qū)動(dòng)

作者: 時(shí)間:2016-10-07 來(lái)源:網(wǎng)絡(luò) 收藏

  所有的FLASHA 都一樣只能從1變0,要想從0變1 只有擦除一個(gè)頁(yè)扇, SST25VF080B 最小可以擦除4KB的頁(yè) 速度也不錯(cuò) 50MHz 容量1MB 挺夠用的 10萬(wàn)次的擦寫壽命。最低2.7V 就可正常工作。

本文引用地址:http://m.butianyuan.cn/article/201610/310909.htm

  Flexible Erase Capability

  – Uniform 4 KByte sectors

  – Uniform 32 KByte overlay blocks

  – Uniform 64 KByte overlay blocks

  先記下 這些個(gè)7788的命令

  

 

  SST25VF080B 的各種命令比較繁瑣

 

  Status Register這個(gè)設(shè)置寫保護(hù)多點(diǎn) 我這里只用它的判忙BUSY

  

 

  一樣先配置與GPIO口 上圖~~

 

  

 

  

 

  在這也就是CE有用片選嘛~~

  #define SST_SELECT() GPIO_ResetBits(GPIOC, GPIO_Pin_13) /* SST CS = L */

  #define SST_DESELECT() GPIO_SetBits(GPIOC, GPIO_Pin_13) /* SST CS = H */

  /***********************************************

  **函數(shù)名:FLASH__Config

  **功能:初始化串行FLASH的接口

  **注意事項(xiàng):串行FLASH使用了SPI1接口

  ***********************************************/

  void FLASH_SPI_Config(void)

  {

  SPI_InitTypeDef SPI_InitStructure;

  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |

  RCC_APB2Periph_AFIO |

  RCC_APB2Periph_SPI1,

  ENABLE);

  /* SCK, MISO and MOSI A5=CLK,A6=MISO,A7=MOSI*/

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* PC.13 作片選*/

  GPIO_SetBits(GPIOC, GPIO_Pin_13); //預(yù)置為高

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

  GPIO_Init(GPIOC, &GPIO_InitStructure);

  /* SPI1 configuration */

  SPI_Cmd(SPI1, DISABLE); //必須先禁能,才能改變MODE

  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //兩線全雙工

  SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主

  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8位

  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //CPOL=0 時(shí)鐘懸空低

  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //CPHA=0 數(shù)據(jù)捕獲第1個(gè)

  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //軟件NSS

  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //2分頻=36M SST25VF說(shuō)是50M沒(méi)事

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //高位在前

  SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC7 我不解的是如果出錯(cuò)要如何處理

  SPI_Init(SPI1, &SPI_InitStructure);

  //SPI_SSOutputCmd(SPI1, ENABLE); //使能NSS腳可用 我這就一個(gè)SPI 器件

  SPI_Cmd(SPI1, ENABLE);

  }

  /***************************************

  **函數(shù)名:SPIByte

  **功能:讀寫SPI總線

  **注意事項(xiàng):對(duì)于SPI來(lái)說(shuō),主機(jī)的讀也需要先寫,

  **使用此函數(shù),讀的時(shí)候建議參數(shù)設(shè)置為0xff,寫的時(shí)候則寫參數(shù).這里使用直接操作寄存器的辦法實(shí)現(xiàn)SPI硬件層讀寫,是為了加快速寫速度 在說(shuō)LCD 的時(shí)候我用的就是庫(kù)函數(shù) 比如

  SPI_I2S_SendData SPI_I2S_ReceiveData SPI_I2S_GetFlagStatus

  ***************************************/

  static u8 SPIByte(u8 byte)

  {

  /*等待發(fā)送寄存器空*/

  while((SPI1->SR & SPI_I2S_FLAG_TXE)==RESET);

  /*發(fā)送一個(gè)字節(jié)*/

  SPI1->DR = byte;

  /* 等待接收寄存器有效*/

  while((SPI1->SR & SPI_I2S_FLAG_RXNE)==RESET);

  return(SPI1->DR);

  }

  

 

  //咱用模式0

  /*****************************************

  **函數(shù)名:SSTCmd1/2/4

  **功能:寫一個(gè)SST命令/寫一個(gè)命令后接一個(gè)數(shù)據(jù)/寫一個(gè)命令后再寫3個(gè)數(shù)據(jù)

  **注意事項(xiàng):這是一個(gè)完整的單命令操作,不返回

  *****************************************/

  void SSTCmd1(u8 cmd)

  {

  SST_SELECT();

  SPIByte(cmd);

  SST_DESELECT();

  }

  void SSTCmd2(u8 cmd,u8 data)

  {

  SST_SELECT();

  SPIByte(cmd);

  SPIByte(data);

  SST_DESELECT();

  }

  void SSTCmd4(u8 cmd,u8 *addr)

  {

  SST_SELECT();

  SPIByte(cmd); //首命令

  SPIByte(*addr++);

  SPIByte(*addr++);

  SPIByte(*addr);

  SST_DESELECT();

  }

  /****************************************

  **函數(shù)名:SSTCmdb1b/SSTCmd4bs

  **功能:寫一個(gè)SST命令,返回1字節(jié)數(shù)據(jù)/寫1個(gè)命令字,3個(gè)地址字,返回多個(gè)字節(jié)

  **更多使用在讀出上的

  ****************************************/

  u8 SSTCmdb1b(u8 cmd)

  {

  u8 tmp;

  SST_SELECT();

  SPIByte(cmd);

  tmp=SPIByte(0xff);

  SST_DESELECT();

  return(tmp);

  }

  void SSTCmd4bs(u8 cmd,u8* addr,u8* data,u32 no)

  {

  SST_SELECT();

  SPIByte(cmd); //首命令

  SPIByte(*addr++);

  SPIByte(*addr++);

  SPIByte(*addr);

  for(;no>0;no--)

  {

  *data++=SPIByte(0xff);

  }

  SST_DESELECT();

  }

  //命令時(shí)序復(fù)雜啊~~當(dāng)然了我這為了求全都寫出來(lái)了

  常用的芯片功能

  /***************************************

  SST25WREN 允許寫功能

  ***************************************/

  void SST25WREN(void)

  {

  SSTCmd1(0x06);

  }

  /***********************************

  SST25WRDI 屏蔽寫功能

  ***********************************/

  void SST25WRDI(void)

  {

  SSTCmd1(0x04);

  }

  

 

  /**********************************

  SST25BY 檢測(cè)忙

  **********************************/

  u8 SST25BY(void)

  {

  u8 sta;

  sta=SSTCmdb1b(0x05);

  return(sta&0x01);

  }

  /***********************************

  SST25WPEN 允許軟件寫保護(hù)

  注意事項(xiàng):25的寫入比較繁瑣,建議在每次操作前都取消掉寫保護(hù),操作完成后則重新允許寫保護(hù)

  

 

  ***********************************/

  void SST25WPEN(void)

  {

  u8 sta;

  sta=SSTCmdb1b(0x05)|0x1c; //讀出寄存器并加入保護(hù)位

  SSTCmd1(0x50); //允許寫Status Register

  SSTCmd2(0x01,sta);

  }

  //先消除保護(hù)位,再允許寫位

  void SST25WriteEn(void)

  {

  u8 sta;

  sta=SSTCmdb1b(0x05)&(~0x1c); //讀出寄存器并消除保護(hù)位

  SSTCmd1(0x50); //允許寫寄存器Status Register

  SSTCmd2(0x01,sta); //寫寄存器

  SSTCmd1(0x06); //允許寫

  }

  /********************************寄存器Status Register**********************************/

  

 

  就是這樣實(shí)現(xiàn)寫保護(hù)。

  

 

  /**********************************

  SST25ReadID 讀取SST的ID 這個(gè)功能 呵呵不用多說(shuō)~當(dāng)然單純的讀寫操作肯定用不上

  **********************************/

  u16 SST25ReadID(void)

  {

  u8 id[3];

  u8 addr[3]={0,0,0};

  SSTCmd4bs(0x90,addr,id,3);

  return((id[0]<<8)+id[1]);

  }

  

 

  /**********************************

  SST25ChipErase 刷除CHIP

  **********************************/

  void SST25ChipErase(void)

  {

  SST25WriteEn();

  SSTCmd1(0x60);

  while(SST25BY());

  SST25WPEN();

  }

  

 

  /***********************************

  SST25SectorErase 刷扇區(qū) 用的是4kb大小 假如地址在0~4095 之間那么這之間的地址都會(huì)刷除

  當(dāng)然我給 4096 的話4096到4096+4095 之間都會(huì)刷掉

  ***********************************/

  void SST25SectorErase(u32 addr)

  {

  u8 ad[3];

  ad[0]=(addr>>16)&0xff;

  ad[1]=(addr>>8)&0xff;

  ad[2]=addr&0xff;

  SST25WriteEn();

  SST_SELECT();

  SPIByte(0x20);

  SPIByte(ad[0]);

  SPIByte(ad[1]);

  SPIByte(ad[2]);

  SST_DESELECT();

  while(SST25BY());

  // SST25WPEN();

  }

  /**********************************

  SST25ByteProgram 寫一個(gè)字節(jié)*注意在此前要調(diào)用取消寫保護(hù),實(shí)際寫應(yīng)使用AAI,此函數(shù)在AAI中調(diào)用,用于寫奇數(shù)個(gè)字節(jié)

  **********************************/

  void SST25ByteProgram(u32 addr,u8 byte)

  {

  u8 ad[3];

  ad[0]=(addr>>16)&0xff;

  ad[1]=(addr>>8)&0xff;

  ad[2]=addr&0xff;

  SST_SELECT();

  SPIByte(0x02);

  SPIByte(ad[0]);

  SPIByte(ad[1]);

  SPIByte(ad[2]);

  SPIByte(byte);

  SST_DESELECT();

  while(SST25BY());

  }

  /***********************************

  SST25Write 寫多個(gè)字節(jié)

  ***********************************/

  void SST25Write(u32 addr,u8* p_data,u32 no)

  {

  u8 ad[3];

  u32 cnt;

  if(no==0)

  return;

  SST25WriteEn();

  if(no==1) //no<2則應(yīng)使用普通單字節(jié)方式

  {

  SST25ByteProgram(addr,*p_data);

  // SST25WPEN();

  }

  else

  {

  cnt=no;

  ad[2]=(addr>>16)&0xff;

  ad[1]=(addr>>8)&0xff;

  ad[0]=addr&0xff;

  SST_SELECT();

  SPIByte(0xad);

  SPIByte(ad[2]);

  SPIByte(ad[1]);

  SPIByte(ad[0]);

  SPIByte(*p_data++);

  SPIByte(*p_data++);

  SST_DESELECT();

  cnt-=2;

  while(SST25BY()); //判忙

  //中間的雙字節(jié)寫

  for(;cnt>1;cnt-=2)

  {

  SST_SELECT();

  SPIByte(0xad);

  SPIByte(*p_data++);

  SPIByte(*p_data++);

  SST_DESELECT();

  while(SST25BY()); //判忙

  }

  SST25WRDI(); //WRDI用于退出AAI寫模式 所謂AAI 就是地址自動(dòng)加

  //如果有最后一個(gè)字節(jié)(no為奇數(shù))

  if(cnt==1)

  {

  SST25WriteEn();

  SST25ByteProgram(addr+no-1,*p_data);

  }

  }

  SST25WPEN();//WP保護(hù)

  }

  

 

  //我們用的是下邊這種

  

 

  /*************************************

  SST25Read 高速讀 對(duì)于后續(xù)帶5的芯片,可調(diào)用此函數(shù)讀

  *************************************/

  void SST25Read(u32 addr,u8* p_data,u32 no)

  {

  SST_SELECT();

  SPIByte(0x0b);

  SPIByte(addr>>16);

  SPIByte(addr>>8);

  SPIByte(addr);

  SPIByte(0xff);

  for(;no>0;no--)

  *p_data++=SPIByte(0xff);

  SST_DESELECT();

  }

  /****************************************

  SST25ReadL 低速讀

  ****************************************/

  void SST25ReadL(u32 addr,u8* p_data,u32 no)

  {

  u8 ad[3];

  ad[2]=(addr>>16)&0xff;

  ad[1]=(addr>>8)&0xff;

  ad[0]=addr&0xff;

  SSTCmd4bs(0x03,ad,p_data,no);

  }

  

 

  好了 所有的底層讀寫都做好了~!

  后面~~

  SST25SectorErase(0); //擦除 0~4095 地址之間的數(shù)據(jù)

  SST25Write(addr,db_sst1,64); //往addr 寫入db_sst164個(gè)字節(jié)

  SST25Read(addr,db_sst1,64); //從addr讀64個(gè)字節(jié)到db_sst1

  就這些接口常用了~~~



關(guān)鍵詞: STM32 SPI

評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉