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(); //等待擦除完成
}