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"; //發送的內容
uint8_t Rx_Buffer[64]; //接收的內容
__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 */
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 */
sFLASH_ReadBuffer(Rx_Buffer, 0x032100, sizeof(Tx_Buffer));
printf("rx_buff =%s\r\n",Rx_Buffer);
(7)ID不正確的話:printf("驗證ID失敗\r\n");
.........無論是讀還是寫操作,都是先進行busy判斷在進行片選拉高,busy的判斷在判斷寫完成函數里sFLASH_WaitForWriteEnd();,但是在有的函數里會出現
這樣可以理解為兩個函數可以合並成一個,其過程也可以這樣理解:就是先拉低選擇芯片,寫入數據,拉高芯片,在查詢芯片的狀態,拉低,查看busy,在拉高
二。指令
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 */
sFLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
/*!< Send SectorAddr medium nibble address byte */
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);
/*!< Send WriteAddr medium nibble address byte to write to */
sFLASH_SendByte((WriteAddr & 0xFF00) >> 8);
/*!< Send WriteAddr low nibble address byte to write to */
sFLASH_SendByte(WriteAddr & 0xFF);
(5)判斷寫的數據大小-----狀態位:
while (NumByteToWrite--) //NumByteToWrite--這個是寫的字節數,有多少個數據寫入
{
/*!< Send the current byte */
sFLASH_SendByte(*pBuffer);
/*!< Point on the next byte to be written */
pBuffer++;
}
(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 */
sFLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/*!< Send ReadAddr medium nibble address byte to read from */
sFLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/*!< Send ReadAddr low nibble address byte to read from */
sFLASH_SendByte(ReadAddr & 0xFF);
(//判斷busy位)
(4)判斷要讀的數據大小: while (NumByteToRead--)//判斷busy位
(5)while里讀數據位
/*!< Read a byte from the FLASH */
*pBuffer = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
/*!< Point to the next location where the byte read will be saved */
pBuffer++;
(6)片選拉高