- 通信方式:高速全雙工
- 作用: 主機與從機之間同步交換數據
- 時鍾: 最大18Mhz,支持DMA,可以配置SPI協議
- 通信線
-
MISO 主輸入從輸出
MOSI 主輸出從輸入
SCLK 時鍾信號,主設備產生
CS 片選信號,主設備控制
-
- 協議層
- 起始信號
- NSS 信號由高變低
- 終止信號
- NSS 信號由低變高
- 數據有效性
- 采樣:
- MOSI 及 MISO 的數據在 SCK 的上升沿期間變化輸出,在 SCK 的下降沿時被采樣。
- 即在 SCK 的下降沿時刻,MOSI 及 MISO 的數據有效,高電平時表示數據“1”,為低電平時表示數據“0”。在其它時刻,數據無效,
- 觸發:
- MOSI 及 MISO 的數據在 SCK 的上升沿期間變化輸出,在 SCK 的下降沿時被采樣.
- 通訊模式
- 共4種,區別於 SCK 的時鍾狀態以及數據采樣時刻
- SPI外設
- 時鍾:
- SPI1 是 APB2 上的設備,最高通信速率達 36Mbtis/s,SPI2、SPI3 是 APB1 上的設備,最高通信速率為 18Mbits/s
- 引腳

- 通訊過程
- (1) 控制 NSS 信號線,產生起始信號(NSS拉低,圖中沒有畫出);
- (2) 把要發送的數據寫入到“數據寄存器 DR”中,該數據會被存儲到發送緩沖區;
- (3) 通訊開始,SCK 時鍾開始運行。MOSI 把發送緩沖區中的數據一位一位地傳輸出去;MISO 則把數據一位一位地存儲進接收緩沖區中;
- (4) 當發送完一幀數據的時候,“狀態寄存器 SR”中的“TXE 標志位”會被置 1,表示傳輸完一幀,發送緩沖區已空;類似地,當接收完一幀數據的時候,“RXNE標志位”會被置 1,表示傳輸完一幀,接收緩沖區非空;
- (5) 等待到“TXE 標志位”為 1 時,若還要繼續發送數據,則再次往“數據寄存器DR”寫入數據即可;等待到“RXNE 標志位”為 1 時,通過讀取“數據寄存器DR”可以獲取接收緩沖區中的內容。
- 處理收發數據
- 中斷方式
- 使能TXE 或 RXNE 中斷,TXE 或 RXNE 置 1 時會產生 SPI 中斷信號,進入同一個中斷服務函數,到 SPI 中斷服務程序后,可通過檢查寄存器位來了解是哪一個事件,再分別進行處理
- DMA方式
- 使用 DMA 方式來收發“數據寄存器 DR”中的數據。
-
配置流程
- 配置相關引腳的復用功能,使能 SPI2 時鍾 ,設置 SPI2 的相關引腳為復用輸出,這樣才會連接到 SPI2
- 初始化 SPI2,設置 SPI2 工作模式
- 使能 SPI2
- SPI 傳輸數據
- 查看 SPI 傳輸狀態
裸機--SPI--FLASH讀寫
- 硬件連接
- WP 引腳可控制寫保護功能,當該引腳為低電平時,禁止寫入數據。我們直接接電源,不使用寫保護功能。

- 指令表
- 帶括號的字節參數,方向為 FLASH 向主機傳輸,即命令響應,不帶括號的則為主機向 FLASH 傳輸
- 表中“A0~A23”指 FLASH 芯片內部存儲器組織的地址;
- “M0~M7”為廠商號(MANUFACTURER ID);
- “ID0-ID15”為 FLASH 芯片的ID;
- “dummy”指該處可為任意數據;
- “D0~D7”為 FLASH 內部存儲矩陣的內容。

- FLASH操作
- 一般流程
- CS拉低
- 發送指令
- 操作數據
- CS拉高
- 等待
- 扇區擦除
- 只能把原來為“1”的數據位改寫成“0”,而原來為“0”的數據位不能直接改寫為“1”。在寫入前,必須要對目標存儲矩陣進行擦除操作,把矩陣中的數據位擦除為“1”,在數據寫入的時候,如果要存儲數據“1”,那就不修改存儲矩陣 ,在要存儲數據“0”時,才更改該位。
- FLASH 芯片的最小擦除單位為扇區(Sector),而一個塊(Block)包含 16 個扇區,
- 流程:
- 發送寫使能
- CS拉低
- 發送擦除指令
- 發送擦除地址
- CS拉高
- 等待擦除完畢
1 /** 2 * @brief 擦除 FLASH 扇區 3 * @param SectorAddr:要擦除的扇區地址 4 * @retval 無 5 */ 6 void SPI_FLASH_SectorErase(u32 SectorAddr) 7 { 8 /* 發送 FLASH 寫使能命令 */ 9 SPI_FLASH_WriteEnable(); 10 SPI_FLASH_WaitForWriteEnd(); 11 /* 擦除扇區 */ 12 /* 選擇 FLASH: CS 低電平 */ 13 SPI_FLASH_CS_LOW(); 14 /* 發送扇區擦除指令*/ 15 SPI_FLASH_SendByte(W25X_SectorErase); 16 /*發送擦除扇區地址的高位*/ 17 SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16); 18 /* 發送擦除扇區地址的中位 */ 19 SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8); 20 /* 發送擦除扇區地址的低位 */ 21 SPI_FLASH_SendByte(SectorAddr & 0xFF); 22 /* 停止信號 FLASH: CS 高電平 */ 23 SPI_FLASH_CS_HIGH(); 24 /* 等待擦除完畢*/ 25 SPI_FLASH_WaitForWriteEnd(); 26 }
- 頁寫入
- 最多寫入256字節
- 一般以扇區單位進行讀寫
- 流程
- 發送寫使能
- CS拉低
- 發送寫指令
- 發送寫地址
- 寫入數據
- CS拉高
- 等待
1 /** 2 * @brief 對 FLASH 按頁寫入數據,調用本函數寫入數據前需要先擦除扇區 3 * @param pBuffer,要寫入數據的指針 4 * @param WriteAddr,寫入地址 5 * @param NumByteToWrite,寫入數據長度,必須小於等於頁大小 6 * @retval 無 7 */ 8 void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite) 9 { 10 /* 發送 FLASH 寫使能命令 */ 11 SPI_FLASH_WriteEnable(); 12 13 /* 選擇 FLASH: CS 低電平 */ 14 SPI_FLASH_CS_LOW(); 15 /* 寫送寫指令*/ 16 SPI_FLASH_SendByte(W25X_PageProgram); 17 /*發送寫地址的高位*/ 18 SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16); 19 /*發送寫地址的中位*/ 20 SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8); 21 /*發送寫地址的低位*/ 22 SPI_FLASH_SendByte(WriteAddr & 0xFF); 23 24 if (NumByteToWrite > SPI_FLASH_PerWritePageSize) 25 { 26 NumByteToWrite = SPI_FLASH_PerWritePageSize; 27 FLASH_ERROR("SPI_FLASH_PageWrite too large!"); 28 } 29 30 /* 寫入數據*/ 31 while (NumByteToWrite--) 32 { 33 /* 發送當前要寫入的字節數據 */ 34 SPI_FLASH_SendByte(*pBuffer); 35 /* 指向下一字節數據 */ 36 pBuffer++; 37 } 38 39 /* 停止信號 FLASH: CS 高電平 */ 40 SPI_FLASH_CS_HIGH(); 41 42 /* 等待寫入完畢*/ 43 SPI_FLASH_WaitForWriteEnd(); 44 }
- 讀取數據
- 流程
- CS拉低
- 發送讀指令
- 發送讀地址
- 讀取數據
- CS拉高