您的位置 首页 系统

SST25VF080B SPI接口FLASH STM32驱动

所有的FLASHA 都一样只能从1变0,要想从0变1 只有擦除一个页扇, SST25VF080B 最小可以擦除4KB的页 速度也不错 50MHz 容量1MB 挺够用的 10万次的擦写寿命。最低2.

  一切的FLASHA 都相同只能从1变0,要想从0变1 只要擦除一个页扇, SST25VF080B 最小能够擦除4KB的页 速度也不错 50MHz 容量1MB 挺够用的 10万次的擦写寿数。最低2.7V 就可正常作业。

  Flexible Erase Capability

  – Uniform 4 KByte sectors

  – Uniform 32 KByte overlay blocks

  – Uniform 64 KByte overlay blocks

  先记下 这些个7788的指令

  

 

  SST25VF080B 的各种指令比较繁琐

 

  Status Register这个设置写维护多点 我这儿只用它的判忙BUSY

  

 

  相同先装备SPI与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 */

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

  **函数名:FLASH_SPI_Config

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

  **留意事项:串行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); //预置为高

  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 时钟悬空低

  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //CPHA=0 数据捕获第1个

  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //软件NSS

  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //2分频=36M SST25VF说是50M没事

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

  SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC7 我不解的是假设犯错要怎么处理

  SPI_Init(SPI1, &SPI_InitStructure);

  //SPI_SSOutputCmd(SPI1, ENABLE); //使能NSS脚可用 我这就一个SPI 器材

  SPI_Cmd(SPI1, ENABLE);

  }

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

  **函数名:SPIByte

  **功用:读写SPI总线

  **留意事项:关于SPI来说,主机的读也需求先写,

  **运用此函数,读的时分主张参数设置为0xff,写的时分则写参数.这儿运用直接操作寄存器的方法完成SPI硬件层读写,是为了加速速写速度 在说LCD 的时分我用的便是库函数 比方

  SPI_I2S_SendData SPI_I2S_ReceiveData SPI_I2S_GetFlagStatus

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

  static u8 SPIByte(u8 byte)

  {

  /*等候发送寄存器空*/

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

  /*发送一个字节*/

  SPI1->DR = byte;

  /* 等候接纳寄存器有用*/

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

  return(SPI1->DR);

  }

  

 

  //咱用形式0

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

  **函数名:SSTCmd1/2/4

  **功用:写一个SST指令/写一个指令后接一个数据/写一个指令后再写3个数据

  **留意事项:这是一个完好的单指令操作,不回来

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

  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();

  }

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

  **函数名:SSTCmdb1b/SSTCmd4bs

  **功用:写一个SST指令,回来1字节数据/写1个指令字,3个地址字,回来多个字节

  **更多运用在读出上的

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

  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();

  }

  //指令时序杂乱啊~~当然了我这为了求全都写出来了

  常用的芯片功用

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

  SST25WREN 答应写功用

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

  void SST25WREN(void)

  {

  SSTCmd1(0x06);

  }

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

  SST25WRDI 屏蔽写功用

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

  void SST25WRDI(void)

  {

  SSTCmd1(0x04);

  }

  

 

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

  SST25BY 检测忙

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

  u8 SST25BY(void)

  {

  u8 sta;

  sta=SSTCmdb1b(0x05);

  return(sta&0x01);

  }

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

  SST25WPEN 答应软件写维护

  留意事项:25的写入比较繁琐,主张在每次操作前都撤销掉写维护,操作完成后则从头答应写维护

  

 

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

  void SST25WPEN(void)

  {

  u8 sta;

  sta=SSTCmdb1b(0x05)|0x1c; //读出寄存器并参加维护位

  SSTCmd1(0x50); //答应写Status Register

  SSTCmd2(0x01,sta);

  }

  //先消除维护位,再答应写位

  void SST25WriteEn(void)

  {

  u8 sta;

  sta=SSTCmdb1b(0x05)&(~0x1c); //读出寄存器并消除维护位

  SSTCmd1(0x50); //答应写寄存器Status Register

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

  SSTCmd1(0x06); //答应写

  }

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

  

 

  便是这样完成写维护。

  

 

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

  SST25ReadID 读取SST的ID 这个功用 呵呵不必多说~当然单纯的读写操作必定用不上

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

  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 刷扇区 用的是4kb巨细 假设地址在0~4095 之间那么这之间的地址都会刷除

  当然我给 4096 的话4096到4096+4095 之间都会刷掉

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

  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 写一个字节*留意在此前要调用撤销写维护,实践写应运用AAI,此函数在AAI中调用,用于写奇数个字节

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

  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 写多个字节

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

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

  {

  u8 ad[3];

  u32 cnt;

  if(no==0)

  return;

  SST25WriteEn();

  if(no==1) //no<2则应运用一般单字节方法

  {

  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()); //判忙

  //中心的双字节写

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

  {

  SST_SELECT();

  SPIByte(0xad);

  SPIByte(*p_data++);

  SPIByte(*p_data++);

  SST_DESELECT();

  while(SST25BY()); //判忙

  }

  SST25WRDI(); //WRDI用于退出AAI写形式 所谓AAI 便是地址主动加

  //假设有最终一个字节(no为奇数)

  if(cnt==1)

  {

  SST25WriteEn();

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

  }

  }

  SST25WPEN();//WP维护

  }

  

 

  //咱们用的是下边这种

  

 

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

  SST25Read 高速读 关于后续带5的芯片,可调用此函数读

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

  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 地址之间的数据

  SST25Write(addr,db_sst1,64); //往addr 写入db_sst164个字节

  SST25Read(addr,db_sst1,64); //从addr读64个字节到db_sst1

  就这些接口常用了~~~

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/xitong/298635.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部