基于FPGA的SPI控制FLASH讀寫
文章目錄
- 基于FPGA的SPI控制FLASH讀寫
- 一、SPI簡介
- 二、FLASH_M25P16簡介
- 信號描述
- 功能操作
- 注意時序
- 三、設計思路
- 框圖設計
- 狀態機設計
- 四、上板驗證
- 1、讀ID
- 2、讀數據
- 3、扇區擦除+寫數據
- 五、總結
- 六、代碼
一、SPI簡介
SPI是Serial Peripheral interface的縮寫,顧名思義就是串行外圍設備接口。是由Motorola(摩托羅拉)公司推出的一種全雙工、同步串行總線接口,只需要四根信號線即可實現多個芯片之間的主從連接結構,節約引腳,同時有利于PCB的布局。它主要應用在如:Flash存儲器、EEPROM存儲器、ADC、DAC、RTC等,實現主控器與芯片之間的串行數據傳輸。
SPI通信需要四根信號線,分別為sck、mosi、miso和cs n。其中cs n、sclk、mosi 是由主機輸出給從機,而miso由從機輸出給主機。
SCLK(Serial Clock):串行時鐘線(Master>Slave),控制數據交換的時機和速率;
MOSI(Master Out Slave In):主機輸出,從機輸入(Master>Slave),用于SPI設備發送數據;
MISO(Master In Slave Out):主機輸入,從機輸出(Slave>Master ),用于SPI設備接收數據:
CS_N(Chip Select):片選信號(Master->Slave),以控制與哪個從機通信。
SPI通訊設備之間的常見連接方式:一主機一從機、一主機多從機。其中一主機多從機連接方式又分常規多片選模式和菊花鏈(星鏈)模式。
SPI數據傳輸需要注意以下幾點:
1.SPI總線在一次數據傳輸過程中,只能有一個主機和一個從機通信,并且主機和從機可以同時向對方進行數據傳輸;
2.當SPI總線上有多個SPI接口的設備時,應注意區分各設備的主從地位,在某時刻只能有一個設備作為主機;
3.從機只能在主機發起通信時,才能接收或向主機傳輸數據;
4.SPI每次數據傳輸可以為8位或16位為單位,每次傳輸的單位數不受限制,且大多以MSB的方式進行傳輸。
SPI傳輸模式有四種,通過CPOL(時鐘極性)與CPHA(時鐘相位)控制;CPOL為0時代表時鐘空閑狀態為低,1時為高;CPHA為0時代表數據在時鐘周期的第一個改變沿(前沿)采樣,在第二個改變沿(后沿)輸出(改變),為1時代表數據在時鐘周期的第一個改變沿(前沿)輸出,在第二個改變沿(后沿)采樣(改變)。
CPOL\CPHA | 0 | 1 |
---|---|---|
0 | 模式0 | 模式1 |
1 | 模式2 | 模式3 |
二、FLASH_M25P16簡介
M25P16是一款16兆位(2M×8)串行閃存,配備先進的寫保護機制,通過高速SPI兼容總線進行訪問。該存儲器支持使用頁編程指令以1至256字節為單位進行編程。其存儲結構由32個扇區組成,每個扇區包含256頁,每頁寬度為256字節。因此整個存儲器可視為由8192頁(即2,097,152字節)構成。存儲器可通過批量擦除指令進行整體擦除,或使用扇區擦除指令逐扇區擦除。
扇區 | 最小地址 | 最大地址 |
---|---|---|
31 | 1F0000h | 1FFFFFh |
30 | 1E0000h | 1EFFFFh |
29 | 1D0000h | 1DFFFFh |
28 | 1C0000h | 1CFFFFh |
27 | 1B0000h | 1BFFFFh |
26 | 1A0000h | 1AFFFFh |
25 | 190000h | 19FFFFh |
24 | 180000h | 18FFFFh |
23 | 170000h | 17FFFFh |
22 | 160000h | 16FFFFh |
21 | 150000h | 15FFFFh |
20 | 140000h | 14FFFFh |
19 | 130000h | 13FFFFh |
18 | 120000h | 12FFFFh |
17 | 110000h | 11FFFFh |
16 | 100000h | 10FFFFh |
15 | 0F0000h | 0FFFFFh |
14 | 0E0000h | 0EFFFFh |
13 | 0D0000h | 0DFFFFh |
12 | 0C0000h | 0CFFFFh |
11 | 0B0000h | 0BFFFFh |
10 | 0A0000h | 0AFFFFh |
9 | 090000h | 09FFFFh |
8 | 080000h | 08FFFFh |
7 | 070000h | 07FFFFh |
6 | 060000h | 06FFFFh |
5 | 050000h | 05FFFFh |
4 | 040000h | 04FFFFh |
3 | 030000h | 03FFFFh |
2 | 020000h | 02FFFFh |
1 | 010000h | 01FFFFh |
0 | 000000h | 00FFFFh |
信號描述
串行數據輸出(Q):該輸出信號用于將數據以串行方式從設備中傳輸。數據在串行時鐘?的下降沿被移出。
串行數據輸入(D):該輸入信號用于將數據以串行方式輸入設備。它接收指令、地址及待編程數據。值在串行時鐘?的上升沿被鎖存。
串行時鐘(C):該輸入信號提供串行接口的時序控制。串行數據輸入(D)中的指令、地址或數據會在串行時鐘?的上升沿被鎖存。串行數據輸出(Q)的數據在串行時鐘?的下降沿后發生變化。
芯片選擇(S):當此輸入信號為高電平時,設備被取消選中且串行數據輸出(Q)處于高阻抗狀態。除非正在進行內部編程、擦除或寫入狀態寄存器周期,否則設備將處于待機模式(非深度休眠模式)。將芯片選擇(S)拉低可激活設備,使其進入活動電源模式。上電后,在開始任何指令前需等待芯片選擇(S)的下降沿。
保持(HOLD):保持(HOLD)信號用于暫停與設備的串行通信,但不取消選中狀態。在保持狀態下,串行數據輸出(Q)處于高阻抗狀態,而串行數據輸入(D)和串行時鐘?則不受影響。要啟動保持狀態,必須選中設備并將芯片選擇(S)拉低。
寫保護(W):該輸入信號的主要目的是凍結受程序或擦除指令保護的存儲器區域的大小(由狀態寄存器的BP2、BP1和BP0位的值指定)
其SPI外設運行在以下兩種模式之一:
CPOL=0,CPHA=0
CPOL=1,CPHA=1
對于這兩種模式,輸入數據會在串行時鐘?的上升沿被鎖存,輸出數據則從串行時鐘?的下降沿開始傳輸。當總線主控處于待機模式且不傳輸數據時,兩種模式的區別在于時鐘極性:當CPOL=0且CPHA=0時,C保持為0當CPOL=1且CPHA=1時,C保持為1。
功能操作
所有指令、地址和數據均以最高有效位為先進行設備輸入輸出。當芯片選擇信號(S)被置為低電平時,串行數據輸入端口(D)會在串行時鐘信號?的第一個上升沿進行采樣。隨后,每個字節指令代碼必須通過串行數據輸入端口(D)以最高有效位為先進行輸入,每個比特位會在串行時鐘信號?的上升沿被鎖存。每條指令序列均以一個字節指令代碼開頭,根據指令類型不同,可能后接地址字節、數據字節、兩者兼有或完全省略。對于讀取數據字節(READ)、高速讀取數據字節(Fast_Read)、讀取狀態寄存器(RDSR)、讀取標識符(RDID)、深度休眠釋放(DP)以及讀取電子簽名(RES)等指令,其輸入指令序列后會接續數據輸出序列。當數據輸出序列中的任意一位完成傳輸后,芯片選擇信號(S)可被置為高電平。對于頁程序(PP)、扇區擦除(SE)、批量擦除(BE)、寫入狀態寄存器(WRSR)、寫入使能(WREN)、寫入禁用(WRDI)或深度休眠(DP)等指令,芯片選擇信號(S)必須在字節邊界處精確置高,否則該指令將被拒絕且無法執行。即當芯片選擇(S)被驅動為低電平之后的時鐘脈沖數是8的整數倍時,芯片選擇(S)必須保持高電平。所有在寫入狀態寄存器周期、編程周期或擦除周期內對存儲陣列的訪問嘗試都將被忽略,且內部的寫入狀態寄存器周期、編程周期或擦除周期將繼續正常運行。
功能 | 命令(二進制) | 命令(16進制) |
---|---|---|
寫使能(WREN) | 0000_0110 | 06h |
讀ID(RDID) | 1001_1111 | 9Fh |
讀狀態(RDSR) | 0000_0101 | 05h |
字節讀(READ) | 0000_0011 | 03h |
快速讀(FAST_READ) | 0000_1011 | 0Bh |
頁讀(PP) | 0000_0010 | 02h |
扇區擦除(SE) | 1101_1000 | D8h |
全擦除(BE) | 1011_1001 | B9h |
寫使能
寫入使能(WREN)指令用于設置寫入使能鎖存器(WEL)位。在執行每頁程序(PP)、扇區擦除(SE)、批量擦除(BE)和寫入狀態寄存器(WRSR)指令前,必須先設置該位。輸入寫入使能(WREN)指令時,需先將芯片選擇(S)置低電平,發送指令代碼,隨后再將芯片選擇(S)置高電平。
讀ID
讀取標識符(RDID)指令用于讀取8位制造商標識符,隨后是兩個字節的設備標識符。制造商標識符由JEDEC分配,本次設備為BAh。設備標識符由設備制造商指定,其中第一個字節(60h)表示存儲器類型,第二個字節(15h)表示設備的存儲容量。
在擦除或編程周期進行期間,任何讀取標識符(RDID)指令都不會被解碼,且對正在進行的周期沒有任何影響。
首先通過將芯片選擇(S)置低電平來選定設備。隨后,輸入指令的8位代碼被移入。接著,存儲在內存中的24位設備標識符通過串行數據輸出端口(Q)逐位移出,每個比特位均在串行時鐘信號?的下降沿期間完成移出操作。
操作順序如圖所示。
Read Identification(RDID)指令通過在數據輸出期間的任何時刻將芯片選擇(S)置高來終止。
當Chip Select (S)被驅動為高電平時,設備進入待機電源模式。一旦進入待機電源模式,設備就等待被選中,以便接收、解碼和執行指令。
讀狀態寄存器
讀取狀態寄存器(RDSR)指令用于讀取狀態寄存器。即使在程序、擦除或寫入狀態寄存器周期進行期間,也可以隨時讀取狀態寄存器。當處于這些周期中的任一周期時,建議在向設備發送新指令前檢查寫入進行中(WIP)位。如表所示,也可以持續讀取狀態寄存器。
狀態寄存器格式 | SRWD | 0 | 0 | BP2 | BP1 | BP0 | WEL | WIP |
---|
WIP位:寫入進行中(WIP)位用于指示存儲器是否處于寫入狀態寄存器、編程或擦除周期的忙狀態。
WEL位:寫入使能鎖存器(WEL)位用于指示內部寫入使能鎖存器的狀態。
BP2、BP1、BP0位:塊保護(BP2、BP1、BP0)位是非易失性存儲單元,用于定義軟件保護編程和擦除指令的區域范圍。
SRWD位:狀態寄存器寫入禁用(SRWD)位與寫保護(W)信號協同工作。通過SRWD位和寫保護(W)信號,設備可切換至硬件保護模式。在此模式下,狀態寄存器的非易失性位(SRWD、BP2、BP1、BP0)將變為只讀位。
字節讀
該設備的選通首先通過驅動芯片選擇(S)低電平實現。讀取數據字節(READ)指令的控制碼后接3字節地址(A23-A0),每個地址位在串行時鐘?上升沿被鎖存。隨后,存儲器內存內容在該地址處通過串行數據輸出端口(Q)進行移位輸出,每個地址位在串行時鐘?下降沿以最大頻率fR完成移位操作。
操作順序如圖所示。
所尋址的第一個字節可以位于任何位置。
在每個數據字節被移出后,地址將自動遞增到下一個更高地址。因此,整個內存都可以通過一條讀取數據字節(READ)指令來讀取。
當達到最高地址時,addresscounter將翻轉為000000h,從而允許無限期地繼續讀取序列。
讀取數據字節(READ)指令通過將芯片選擇(S)置高電平來終止。芯片選擇(S)可在數據輸出過程中的任何時刻被置高電平。任何讀取數據字節(READ)指令在擦除、編程或寫入周期進行期間,將被拒絕且不會對正在進行的周期產生任何影響。
快速讀
該設備的選通首先通過驅動芯片選擇(S)低電平實現。執行“高速讀取數據字節(FAST_READ)”指令時,其代碼序列包含3字節地址(A23-A0)和一個虛擬字節,這些數據位會在串行時鐘?上升沿被鎖存。隨后,存儲器中對應地址的數據會以最大頻率fC,在串行時鐘?下降沿期間逐位輸出到串行數據輸出端口(Q)。
操作順序如圖所示。
所尋址的第一個字節可以位于任何位置。
地址在每次數據字節被移位輸出后,會自動遞增到下一個更高地址。因此,整個內存只需一條“高速讀取數據字節指令(FAST_READ)”即可完成全部讀取。當達到最高地址時,地址計數器將回滾至000000h,從而實現無限次的連續讀取操作。
高速讀取數據字節指令(FAST_READ)通過將芯片選擇信號(S)置高電平來終止。芯片選擇信號(S)可在數據輸出過程中的任意時刻被置高電平。任何正在進行擦除、編程或寫入周期的高速讀取數據字節指令(FAST_READ),都將被拒絕,且不會對當前進行的周期產生任何影響。
頁寫
頁面編程(PP)指令允許在內存中對字節進行編程(將位從1變為0)。在接收該指令之前,必須先執行寫使能(WREN)指令。解碼完寫使能(WREN)指令后,設備會設置寫使能鎖存器(WEL)。
頁面程序(PP)指令的輸入方式是:首先將芯片選擇信號(S)置低電平,隨后在串行數據輸入端口(D)發送指令代碼、三個地址字節及至少一個數據字節。若地址的最低8位(A7-A0)不全為零,則所有超出當前頁面范圍的數據傳輸,都將從該頁面的起始地址開始編程(即地址的最低8位A7-A0均為零時的起始地址)。
在整個序列持續時間內,必須將芯片選擇(S)驅動為低電平。
操作順序如圖所示。
當向設備發送的數據超過256字節時,系統會丟棄先前鎖存的數據,并確保最后256個數據字節在同一頁面內被正確編程。若發送的數據少于256字節,則會在指定地址正確編程,且不會影響同一頁面的其他數據字節。芯片選擇(S)信號必須在最后一個數據字節的第七位完成鎖存后保持高電平,否則頁面編程(PP)指令將無法執行。
當Chip Select (S)被驅動為高電平時,就會啟動自定時的頁面程序周期(持續時間tPP)。在頁面程序周期進行期間,可以讀取狀態寄存器以檢查Write In Progress(WIP)位的值。
在自定時的頁面程序周期中,Write In Progress(WIP)位為1,當該周期結束時為0。在周期結束前的某個未指定時間,Write Enable Latch(WEL)位被復位。
扇區擦除
扇區擦除(SE)指令將選定扇區內的所有位設置為1(FFh)。在該操作被接受之前,必須先執行寫使能(WREN)指令。當寫使能(WREN)指令被解碼后,設備會設置寫使能鎖存器(WEL)。
扇區擦除(SE)指令的輸入方式為:先將芯片選擇信號(S)置低電平,隨后輸入指令代碼,并通過串行數據輸入端口(D)發送三個地址字節。扇區內的任意地址(參見表3)均可作為扇區擦除(SE)指令的有效地址。整個操作過程中,芯片選擇信號(S)必須始終保持低電平狀態。該指令序列的具體實現如圖所示。
當最后一個地址字節的第八位被鎖存后,芯片選擇信號(S)必須驅動高電平,否則扇區擦除指令(SE)將無法執行。芯片選擇信號(S)一旦被驅動高電平,自定時扇區擦除周期(持續時間tSE)即刻啟動。在扇區擦除周期進行期間,可讀取狀態寄存器以檢查寫入進行中(WIP)位的數值。該位在自定時扇區擦除周期內保持1,在周期結束后轉為0。在周期完成前的某個未指定時刻,寫入使能鎖存器(WEL)位會被復位。
全擦除
全擦除(BE)指令會將所有位設置為1(FFh)。在該指令被接受之前,必須先執行寫使能(WREN)指令。在解碼完寫使能(WREN)指令后,設備會設置寫使能鎖存器(WEL)。
通過驅動芯片選擇(S)低電平,隨后在串行數據輸入(D)上輸入指令代碼,即可輸入批量擦除(BE)指令。在整個序列期間,必須將芯片選擇(S)保持為低電平。該指令序列如圖所示。
當指令代碼的第八位被鎖存后,芯片選擇信號(S)必須驅動為高電平,否則批量擦除指令將無法執行。一旦芯片選擇信號(S)被驅動為高電平,自定時批量擦除周期(持續時間是istBE)就會啟動。在批量擦除周期進行期間,可以通過讀取狀態寄存器來檢查寫入進行中(WIP)位的值。
在自定時的批量擦除周期期間,寫入進行中(WIP)位為1,當該周期完成時為0。在周期完成之前的某個未指定時間,寫入使能鎖存器(WEL)位被復位。
只有當所有塊保護(BP2、BP1、BP0)位為0時,才會執行批量擦除(BE)指令。如果一個或多個扇區受到保護,則會忽略批量擦除(BE)指令。
注意時序
操作 | 最小時間 | 最大時間 | 單位 |
---|---|---|---|
命令間的間隔 | 100 | 、 | ns |
頁寫 | 1.4 | 5 | ms |
扇區擦除 | 1 | 3 | s |
全擦除 | 17 | 40 | s |
三、設計思路
框圖設計
功能實現:
1.讀ID操作,按下按鍵key1,將讀出的ID顯示在數碼管,格式xx.xx.xx;同時,通過UARRT發送至上位機顯示,顯示格式為 設備ID:xx xx xx;
2.讀數據操作,按下按鍵key2,讀出3個字節數據,將讀出的輸出顯示在數碼管xx.xx.xx;同時,通過UARRT發送至上位機顯示,顯示格式為 讀數據:xx xx xx;
3.擦除操作,按下按鍵key3,進行扇區擦除;
4.寫數據操作,PC端通過串口連續發送多字節數據,每三個數據進行一次頁編程操作。
狀態機設計
扇出狀態機:
由于在spi_ctrl中有許多子模塊在傳輸數據,這里要多扇出的數據進行操作,這里用一個簡單的狀態機實現
寫數據狀態機:
由于寫數據涉及到多種命令、地址的發送,還有扇區擦除,寫數據,讀狀態數據等操作,所以設計一個狀態機實現一系列的功能。
四、上板驗證
1、讀ID
按下key2
數碼管顯示出本設備的flash的id為BA_60_15.
同時通過串口發送id至PC顯示出來
2、讀數據
按下key3
數碼管顯示出第一組數據,此數據為先前寫入的數據12_34_56
同時PC也顯示出數據;
連續按下,多次讀出數據
讀出78_90_11,后續為寫入數據顯示為ff。
3、扇區擦除+寫數據
按下復位key1+扇區擦除key4,擦除完成再讀數據
讀出數據全為ff,擦除成功;復位并通過串口發送A1 B2 C3 D4 E5 F6 99
連續按下讀數據key3
A1 B2 C3 D4 E5 F6被發送至flash寫入,而99暫存在fifo中未寫入,在此的fifo設置的為每三個數據發送給flash進行存儲。
驗證成功。
五、總結
本次的SPI控制flash讀寫項目完成了基本功能,在理解SPI協議后會比較容易,相較于IIC和UART,SPI沒有過多的協議層上數據的約束,理解起來也比較簡單。
六、代碼
模塊較多,代碼見此:代碼