
W25Q是一款flash存储芯片。可以进行写数据、读数据、擦除。通过通信接口与MCU进行通信。其片选引脚,低电平有效 其使用配合着SPI使用--可以单独配置spi底层函数,读取数据函数,也可以使用W25Q提供的stm32_eval_spi_flash.c里void sFLASH_Init(void)初始化配置。 其特点是:先擦除后写入。 存储芯片大小:16M-bit --2M Byte 1页 --256字节 1个扇区---16页 ---4K 1块 ----16个扇区 --64K 一个芯片 --32块 --2M 如何从一个字节空间存一个数据:第1块中第一个扇区的第一页第100个字节写一个数:0xAA 0000 0000 0KKK KKKK SSSS PPPP BBBB BBBB 0x0 0 0 1 1 64 0x00001364 MCU通过SPI给W25Q发送指令 2.WQ25的编写---可以直接引用该芯片本身写好的程序---比如stm32_eval_spi_flash.c uint8_t Tx_Buffer[] = "I Love China"; //发送的内容' a8 a5 s. K7 B. C; c- T1 S9 J S) r uint8_t Rx_Buffer[64]; //接收的内容* e6 S0 C. F" b7 W @ __IO uint32_t FlashID = 0; //ID地址 ·(1)读ID ---FlashID = sFLASH_ReadID(); (2)判断ID是否正确if (FlashID == sFLASH_W25Q16_ID) (3)正确的话;printf("ID 正确\r\n"); (4)擦除的内存空间0x00001364 /* Erase SPI FLASH Sector to write on */+ W M2 c0 j0 X9 h" i% f* C sFLASH_EraseSector(0x00001364); (5)写数据 /* Write Tx_Buffer data to SPI FLASH memory */ sFLASH_WriteBuffer(Tx_Buffer, 0x032100, sizeof(Tx_Buffer)); printf("tx_buff =%s\r\n",Tx_Buffer); (6)读数据 /* Read data from SPI FLASH memory */4 f& f# B* N. j sFLASH_ReadBuffer(Rx_Buffer, 0x032100, sizeof(Tx_Buffer));; {) n# b. l' k& @3 R printf("rx_buff =%s\r\n",Rx_Buffer); (7)ID不正确的话:printf("验证ID失败\r\n"); .........无论是读还是写操作,都是先进行busy判断在进行片选拉高,busy的判断在判断写完成函数里sFLASH_WaitForWriteEnd();,但是在有的函数里会出现 ![]() ![]() 这样可以理解为两个函数可以合并成一个,其过程也可以这样理解:就是先拉低选择芯片,写入数据,拉高芯片,在查询芯片的状态,拉低,查看busy,在拉高5 h8 X# r$ u, q" a
![]() ![]() + g+ O$ l+ i* B 二。指令 1.读ID (1)片选拉低: sFLASH_CS_LOW(); (2)发送读ID指令:sFLASH_SendByte(0x9F); (3)发送数据: Temp0 = sFLASH_SendByte(sFLASH_DUMMY_BYTE); (4)片选拉高:sFLASH_CS_HIGH(); (5)返回读的值:Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2; 2.扇区擦除 (1)发送写使能指令:sFLASH_WriteEnable();//写使能 (2)片选拉低 (3)发送扇区擦除指令:sFLASH_SendByte(0x20); (4)发送扇区擦除地址: /*!< Send SectorAddr high nibble address byte */* `# l% r# t; d d0 v9 @# Z sFLASH_SendByte((SectorAddr & 0xFF0000) >> 16);, i4 \% v8 ~# _* U4 I, m/ p ] /*!< Send SectorAddr medium nibble address byte */6 ~5 P' O; H" W& M6 |5 f sFLASH_SendByte((SectorAddr & 0xFF00) >> 8); /*!< Send SectorAddr low nibble address byte */ sFLASH_SendByte(SectorAddr & 0xFF); (判断busy位) (5)片选拉高 (6)等待写完成:sFLASH_WaitForWriteEnd();//里面含有判断busy,写入数据是需要时间的,W25Q通过busy的进行判断是否写完的 3.写操作-------1~256字节空间--页编程 (1)写使能:sFLASH_WriteEnable(); (2)片选拉低 (3)发送页写指令:sFLASH_SendByte(0x02); (4)发送页写地址--24位 /*!< Send WriteAddr high nibble address byte to write to */ sFLASH_SendByte((WriteAddr & 0xFF0000) >> 16);1 z) o6 H) r' _- U' z+ [ /*!< Send WriteAddr medium nibble address byte to write to */# a% ^2 f4 r5 Y' W sFLASH_SendByte((WriteAddr & 0xFF00) >> 8);# J A \; ] X" _4 Z /*!< Send WriteAddr low nibble address byte to write to */ sFLASH_SendByte(WriteAddr & 0xFF); (5)判断写的数据大小-----状态位: while (NumByteToWrite--) //NumByteToWrite--这个是写的字节数,有多少个数据写入. K( C' \( n E+ @ {0 v' q& d9 ~7 C" F* Q6 M/ M* e /*!< Send the current byte */ sFLASH_SendByte(*pBuffer); /*!< Point on the next byte to be written */ pBuffer++;9 ^9 g, U# h! { } (6)片选拉高 (5)等待写完成:sFLASH_WaitForWriteEnd(); 4.写操作---写buff (1)判断 Writedaddr 是 sflash pagesize 对齐 if(Addr == 0)//页内地址 (2)是的话,判断页数大小:if (NumOfPage == 0) (2.1)是的话:页编程 (2.2)不是的话 ,while (NumOfPage--)->页编程sFLASH_WritePage(pBuffer, WriteAddr, sFLASH_SPI_PAGESIZE);--->WriteAddr += sFLASH_SPI_PAGESIZE;pBuffer += sFLASH_SPI_PAGESIZE; (3)不是的话,,类似 5.读操作--读buff (1)片选拉低 (2)发送读指令: sFLASH_SendByte(0x03); (3)发送读地址--24位:21位地址,3个字节 /*!< Send ReadAddr high nibble address byte to read from *// b8 X# ~7 }( y0 S/ G* O sFLASH_SendByte((ReadAddr & 0xFF0000) >> 16); /*!< Send ReadAddr medium nibble address byte to read from */5 w4 ` r4 m# z7 ~) m- N" b sFLASH_SendByte((ReadAddr& 0xFF00) >> 8); /*!< Send ReadAddr low nibble address byte to read from */% k; u- K! |0 M- w sFLASH_SendByte(ReadAddr & 0xFF); (//判断busy位) (4)判断要读的数据大小: while (NumByteToRead--)//判断busy位 (5)while里读数据位 /*!< Read a byte from the FLASH */4 T" Y- l* b$ W0 t4 l4 n *pBuffer = sFLASH_SendByte(sFLASH_DUMMY_BYTE); /*!< Point to the next location where the byte read will be saved */ pBuffer++; (6)片选拉高 9 ~! Z# D4 L$ o" Z7 g: k |