1. 程式人生 > >STM32F407之SPI讀寫W25Q128

STM32F407之SPI讀寫W25Q128

1、SPI是一種告速全雙工、同步的通訊匯流排,並且在晶片引腳上佔用4根線: MISO:主裝置資料輸入線,從裝置資料輸出線 MOSI:主裝置資料輸出線,從裝置資料輸入線 SCLK:時鐘訊號,由主裝置產生 CS:從裝置片選訊號,由主裝置控制 2、主從裝置各都有兩個序列移位暫存器,主機通過向它的SPI序列暫存器寫入一個位元組發起一次傳輸。外設的讀寫操作是同步完成的。如果只進行寫操作主機只須忽略接收的位元組,反之,若主機要讀取從機的一個位元組,就必須傳送一個空位元組來引發從機的傳輸。 3、與AT24C02不同(AT24C02有固定的器件地址10100001/0,最後以為表示讀寫意思),W25Q128需要一些讀寫命令完成操作。和SSD1963相似,需要寫入固定命令。還有一個不同點,AT24C02寫之前不用擦除,而W25Q128需要。

//指令表
#define W25X_WriteEnable		0x06 
#define W25X_WriteDisable		0x04 
#define W25X_ReadStatusReg		0x05 
#define W25X_WriteStatusReg		0x01 
#define W25X_ReadData			0x03 
#define W25X_FastReadData		0x0B 
#define W25X_FastReadDual		0x3B 
#define W25X_PageProgram		0x02 
#define W25X_BlockErase			0xD8 
#define W25X_SectorErase		0x20 
#define W25X_ChipErase			0xC7 
#define W25X_PowerDown			0xB9 
#define W25X_ReleasePowerDown	0xAB 
#define W25X_DeviceID			0xAB 
#define W25X_ManufactDeviceID	0x90 
#define W25X_JedecDeviceID		0x9F

4、W25Q128是1個byte對應一個地址,一次需要擦除4K空間。有16M空間,分成256個塊,每個塊(64K)分成16個扇區,每個扇區(4K)分成16頁,每頁256個位元組。關於讀寫函式的理解:

//SPI1 讀寫一個位元組
//TxData:要寫入的位元組
//返回值:讀取到的位元組
u8 SPI1_ReadWriteByte(u8 TxData)
{		 			 
 
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}//等待發送區空  
	
	SPI_I2S_SendData(SPI1, TxData); //通過外設SPIx傳送一個byte  資料
		
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一個byte  
 
	return SPI_I2S_ReceiveData(SPI1); //返回通過SPIx最近接收的資料	
 		    
}

當需要讀取某個暫存器的值時,如A暫存器,先發送命令,再發送地址,然後再發送資料。在這個過程中出現三次傳送函式: SPI1_ReadWriteByte(W25X_ReadStatusReg); //傳送讀取狀態暫存器命令 SPI1_ReadWriteByte((u8)((ReadAddr)>>16)); //傳送24bit地址 byte=SPI1_ReadWriteByte(0Xff); 注意三個函式的引數,最後一個函式由於是讀命令,所以傳送的0Xff將不被從機接收。W25QXX系列的讀寫是需要一系列命令的,命令不對的話你傳送什麼資料都不會有反應的。

從機不產生時序,所以想要讀取某地址的值時,寫入地址後,從機將資料放入移位暫存器裡面,然後主機通過傳送oxff或者其他位元組來產生時序,使從機的資料得意傳送。 SPI的基本的操作是一進一出,主機發送資料後,從機才會回資料,相當於兩者交換了資料。跟管子一樣,一邊進,另外一頭才會出。只是有些設定命令,換或者推出來得資料,沒用而已。 關於同步的自己理解:當主機發送讀命令以後,從機將資料放入移位暫存器,然後當主機發送一個數據產生時序,從機就將資料移入主機的接收暫存器,需深刻理解同步的意義。

5、W25Q128容量為16M,所以需要24位地址。 6、關鍵語句的理解:

 u8 W25QXX_ReadSR(void)僅僅是讀暫存器,有幾個單獨的暫存器需要讀取。 
void W25QXX_Write_SR(u8 sr)僅僅是寫暫存器,有幾個單獨的暫存器需要寫。
~~u16 W25QXX_ReadID(void)中的四次讀取命令~~
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)  可以在任意地址讀。
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) 
寫操作需要判斷地址的位置和寫資料的個數。


//無檢驗寫SPI FLASH 
**//必須確保所寫的地址範圍內的資料全部為0XFF,否則在非0XFF處寫入的資料將失敗!**
//具有自動換頁功能 
//在指定地址開始寫入指定長度的資料,但是要確保地址不越界!
//pBuffer:資料儲存區
//WriteAddr:開始寫入的地址(24bit)
//NumByteToWrite:要寫入的位元組數(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{ 			 		 
	u16 pageremain;	   
	pageremain=256-WriteAddr%256; //該句可以確定地址的位置,WriteAddr%256取整的大小為地址的位置,取餘的部分可以知道單頁剩餘的位元組個數。		 	    
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大於256個位元組
	while(1)
	{	   
		W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
		if(NumByteToWrite==pageremain)break;//寫入結束了
	 	else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;//給指標加一個值賦值給指標表示陣列的首地址變了,資料移動了pageremain個。
			WriteAddr+=pageremain;	//地址同樣移動pageremain位。

			NumByteToWrite-=pageremain;			  //減去已經寫入了的位元組數
			if(NumByteToWrite>256)pageremain=256; //剩下的數一頁仍然不夠寫。一次可以寫入256個位元組
			else pageremain=NumByteToWrite; 	  //不夠256個位元組了
		}
	};	    
}

7、

//擦除一個扇區
//Dst_Addr:扇區地址 根據實際容量設定
//擦除一個山區的最少時間:150ms
void W25QXX_Erase_Sector(u32 Dst_Addr)   
{  
	//監視falsh擦除情況,測試用   
 	printf("fe:%x\r\n",Dst_Addr);	  
	Dst_Addr*=4096;     //是扇區的地址,一共有65536個扇區,地址也是從0-65536
    W25QXX_Write_Enable();                  //SET WEL 	 
    W25QXX_Wait_Busy();   
  	W25QXX_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_SectorErase);      //傳送扇區擦除指令 
    SPI1_ReadWriteByte((u8)((Dst_Addr)>>16));  //傳送24bit地址    
    SPI1_ReadWriteByte((u8)((Dst_Addr)>>8));   
    SPI1_ReadWriteByte((u8)Dst_Addr);  
	W25QXX_CS=1;                            //取消片選     	      
    W25QXX_Wait_Busy();   				   //等待擦除完成
}