摘要:本篇博客具體包括SPI協議的基本原理、模式選擇以及時序邏輯要求,采用FPGA(EPCE4),通過SPI通信協議,對flash(W25Q16BV)存儲的固化程序進行芯片擦除操作。
關鍵詞:SPI;Verilog HDL;Flash
【SPI協議通信模式】
SPI是Motorola公司推出的一種同步串行接口,是一種高速、全雙工、同步的通信總線,廣泛應用于存儲器,數模轉換器,實時時鐘等。
優點:支持全雙工通信,通訊方式簡單,相對數據傳輸速率較快。
缺點:沒有指定的流控制,沒有應答機制,數據可靠性上存在缺陷。
SPI協議通過四根線進行數據傳輸,即SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、/SS(Slave Select,低電平有效)(或/CS)。
接口處理方式:一主一從(左)、一主多從【星型鏈式】(右)SPI通信要求主機和從機具有同步的時鐘信號,傳輸速率直接受到時鐘頻率(SCLK)的影響。

信號線說明:
MOSI、MISO數據在SCK同步信號下傳輸,每個時鐘周期傳輸一位數據,輸入輸出同步進行,要保證MSB或LSB先行需一致。/SS從設備信號選擇線,由高變低,是SPI通訊的起始信號。當從設備/SS線檢測到起始信號后,即為選中使能與主機通訊。/SS信號由低變高,為停止信號,從設備的選中狀態被取消。
注:SPI每次數據傳輸可以8位或16位為單位,每次傳輸的單位數不受限制。
SPI通信時鐘模式:
SPI通信加入了時鐘相位(CPHA)和時鐘極性(CPOL)的設置,通過組合CPOL和CPHA的不同設置,SPI共支持四種常見的時鐘配置模式。
| CPOL | CPHA |
|---|---|
| 時鐘極性,定義時鐘信號在空閑狀態下的電平 | 時鐘相位,定義數據采樣和轉換的時鐘邊沿 |
| CPOL=0:SCK空閑為低電平 | CPHA=0:SCK的第一個邊沿采樣數據并轉換輸出信號 |
| CPOL=1:SCK空閑為高電平 | CPHA=1:SCK的第二個邊沿采樣數據并轉換輸出信號 |
在CPHA指示為l時, 數據就會在SCLK的第二個有效邊沿被采樣(/SS拉低后,空閑為高,為上升沿;空閑為低,下降沿),同時被鎖存到寄存器中;如果CPHA 清零,數據就會在SCLK的第一個有效邊沿被采樣(/SS拉低后,空閑為高,為下降沿;空閑為低,為上升沿),同時被鎖存起來。SPI的主從設備須配置相同的時序模式,見下圖。

【W25Q16BV操作說明】
板載Flash芯片型號:W25Q16BV;總容量為16M bit,即2M字節;存儲陣列被分成8192個可編程頁,每頁容量256字節;支持Standard SPI、Dual SPI和Quad SPI三種SPI通信協議,最大讀/寫傳輸速率達50MB/s。它支持多種擦除操作,包括扇區擦除(4KB)、塊擦除(32KB或64KB)以及全芯片擦除。
1、接口處理與結構邏輯

上圖可以看到,除SPI經典的四個引腳外,還有/WP和/HOLD,分別用于寫保護和輸入保持。對于不同倍率SPI協議,引腳使用搭配是有區別的。
W25Q16BV內部存儲結構的邏輯和功能組織見下圖,SPI接口負責接收命令和地址,并通過控制邏輯進行解析和執行。狀態寄存器(Status Register)用于存儲設備的狀態信息,如是否忙碌(BUSY位);寫控制通過IO2引腳控制,用于啟動寫操作;高電平生成器(High Voltage Generators)用于執行如擦除等操作;控制邏輯(Control Logic)負責解析SPI接口接收到的命令,并根據需要控制存儲器的讀/寫操作。列解碼(Column Decode)和頁面緩沖(256-Byte Page Buffer)用于支持頁面的讀/寫操作。

存儲器部分被分割成32個塊(Block),單個塊區包含16個扇區(Sector),每個扇區又由16個頁組成,單頁存儲256字節數據,共計32 x 16 x 16 x 256 ≈ 2M 字節。存儲器通過頁地址和字節地址來定位特定的數據位置。
24位地址線通過上述的層次結構來映射整個存儲器的地址空間,具體見下面表格。
| 分區 | 地址位 |
|---|---|
| 塊(Block)地址 | 23~16位(0x1F0000到0x1FFFFF) |
| 扇區(Sector)地址 | 15~12位(0x00F000到0x00FFFF) |
| 頁(Page)地址 | 11~8位 |
| 字節(Byte)地址 | 7~0位 |
2、指令與時序說明
軟件命令:W25Q16BV的指令集由30條基本指令組成,指令完全通過SPI總線控制。指令的啟動是通過/CS的下降邊緣來觸發的,/CS拉高前須完成指令輸入,否則無效。DI輸入的第一個字節提供指令代碼,DI輸入上的數據是在時鐘的上升沿采樣的,首先采樣的是最高有效位(MSB)。
指令的長度從單個字節到幾個字節不等,后面可能跟著地址字節、數據字節、虛擬字節(可選),在某些情況下,還可能是它們組合。所有的讀指令都可以在任何一個時鐘位之后完成。
| 指令 | 編碼 | 指令 | 編碼 |
|---|---|---|---|
| Write Enable | 06h | Write Disable | 04h |
| Sector Erase (4KB) | 20h | Block Erase (32KB) | 52h |
| Block Erase (64KB) | D8h | Chip Erase | C7h/60h |
| Continuous Read Mode Reset | FFh | Read Data | 03h |
| Fast Read | 0Bh | Write Status Register | 01h |
所有寫、編程或擦除指令必須在字節邊界上完成(即,在完整的8位數據被時鐘同步后,/CS被驅動為高)。如果不在字節邊界上完成,該指令將被終止。這一特性旨在保護設備免受意外寫入的影響。
當內存正在被編程或擦除,或者當狀態寄存器正在被寫入時,除了讀狀態寄存器指令之外的所有指令都將被忽略,直到編程或擦除周期完成。
電平切換時序要求:
下圖為Serial Input Timing,其中片選線/CS待輸入完成后拉高電平保持時間(tSHSL) (for Array Read Array Read / Erase or Program Read Status Registers) :至少7/40 ns;片選信號有效建立時間(tSLCH):至少為5ns;片選信號有效保持時間(tCHSH):至少為5ns。注意:讀指令/寫指令時鐘頻率最大為50Mhz。

寫使能(Write Enable ):該指令用于設置(狀態寄存器中)寫使能鎖存器(WEL)位為1,確保存儲器處于可寫狀態。

首先,將/CS(Chip Select)引腳拉低,SPI通信啟動。在CLK上升沿,將數據輸入(DI)引腳上的數據位設置為指令代碼“06h”,即0000 0110。完成后,將/CS引腳拉高,SPI通信的結束和寫使能完成。
讀操作(Read Data):這個指令允許從存儲器中順序地讀取一個或多個數據字節。首先,通過將/CS引腳拉低來啟動指令,將指令代碼“03h”(0000 0011)和一個24位地址(A23-A0)通過DI引腳移位輸入,代碼和地址位在CLK上升沿時被鎖定。最后,通過將/CS引腳拉高完成指令。

如果在擦除、編程或寫入周期正在進行時(BUSY=1)發出讀取數據指令,該指令將被忽略。
芯片全擦除操作(Chip Erase):Chip Erase 指令會將設備內的所有存儲器設置為擦除狀態,即所有位都設為1。

①擦除啟動:在執行芯片擦除指令之前,必須先執行一個“寫使能”指令,使設備能夠接受芯片擦除指令(狀態寄存器的WEL位必須等于1)。將/CS引腳拉低來啟動指令,移位輸入指令代碼“C7h”或“60h”,在第八位被鎖定后,/CS引腳須被拉高。
②擦除過程:/CS被拉高后,自計時的芯片擦除指令將開始執行。芯片擦除周期(典型3s,最大10s)進行期間,仍然可以通過“讀取狀態寄存器”指令來檢查BUSY位的狀態(BUSY位在芯片擦除周期期間為1)。
③擦除后的狀態:WEL位會被置0,注意:存儲數據的任何部分受到塊保護(BP2、BP1和BP0)位的保護,則不會執行芯片擦除指令。
【Flash全擦除操作】
1、Quartus II進行程序固化下載及擦除
燒錄程序方式:①將程序下載到FPGA內部的SRAM之中,燒錄過程耗時較短,但掉電后程序丟失;②將程序固化到FPGA外部掛載的非易失性存儲器Flash芯片,掉電后程序不丟失。
在Quartus II的主界面中,選擇“File”菜單下的“Convert Programming Files”選項,用于將編譯生成的特定文件(如sof文件)轉換為其他格式的文件,如jic文件,以便下載到FPGA板載的flash或其他目標設備中,流程見下圖。

下載程序時,目標.jic文件后,右下指示框很明顯看到下載至Flash(這里是EPCS16類似W25Q16),僅勾選Program/Configure 進行程序固化下載,僅勾選Erase表示擦除Flash操作。

2、Verilog程序實現Flash芯片擦除操作(SPI)
根據Flash讀/寫時序要求,片選信號拉低后,需進行5ns(tSLCH≥5ns)等待時間,及后寫入寫使能指令。寫入完成后,再次進行5ns(tCHSH≥5ns)等待,拉高片選線維持≥100ns,接續完成寫入操作指令流程。

Flash芯片數據讀操作的時鐘頻率(SCK)上限為50MHz,這里通過四分頻設定SCK頻率為12.5Mhz。單個時鐘周期寫入1 bit數據,完整的單字節指令需要8個完整的SCK時鐘周期,即32個完整的系統時鐘,系統時鐘頻率為50MHz,完整指令的寫入需要640ns。

mosi信號輸出采用了狀態機轉移的邏輯方法:
| 狀態 | 說明 | 狀態 | 說明 |
|---|---|---|---|
| IDLE | 空閑初始狀態,等待觸發信號 | WR_EN | 發送寫使能指令 |
| DELAY | 等待狀態,保持時序 | CH_ER | 芯片擦除指令發送 |
當key_flag信號有效時,從IDLE轉移到WR_EN狀態,在WR_EN和CH_ER狀態中,分別寫入相應的寫使能和指令后,等待tCHSH時間,然后拉高片選信號。在WR_EN狀態寫入指令后,轉移到DELAY狀態等待tSHSL時間。在DELAY狀態等待完成后,轉移到CH_ER狀態,返回IDLE狀態。相關代碼如下:
parameter IDLE =4'b0001,WREN =4'b0010,DELAY=4'b0100,CH_ER=4'b1000;parameter WREN_CODE =8'b0000_0110,CH_ER_CODE =8'b1100_0111; always@(posedgesys_clkornegedgesys_rst)beginif(!sys_rst)state <= IDLE; ? ?elsecase(state) ? ? ? ? ? ? IDLE :if(key_flag)state <= WREN; ? ? ? ? ? ? WREN :if((cnt_byte ==?3'd2)&&(cnt_clk ==?5'd31))state <= DELAY; ? ? ? ? ? ? DELAY:if((cnt_byte ==?3'd3)&&(cnt_clk ==?5'd31))state <= CH_ER; ? ? ? ? ? ? CH_ER:if((cnt_byte ==?3'd6)&&(cnt_clk ==?5'd31))state <= IDLE; ? ? ? ? ? ?default:state <= IDLE; ? ? ? ?endcaseendalways?@(posedge?sys_clk?ornegedge?sys_rst)beginif(!sys_rst)mosi <=?1'b0; ? ?elseif((state == WREN)&&(cnt_byte ==?3'd2)) mosi <=?1'b0; ? ?elseif((state == CH_ER)&&(cnt_byte ==?3'd6)) mosi <=?1'b0; ? ?elseif((state == WREN)&&(cnt_byte ==?3'd1)&&(cnt_sck ==?2'd0)) ? ? ? ? mosi <= WREN_CODE[7?- cnt_bit]; ? ?elseif((state == CH_ER) && (cnt_byte ==?3'd5) && (cnt_sck ==?2'd0)) ? ? ? ? mosi <= CH_ER_CODE[7?- cnt_bit];end
而對于其他的信號邏輯處理:cnt_clk作為預期設定單位間距(640ns)的計數器,cnt_byte根據其完成7個階段的轉換。sck為寫操作的時鐘信號,cnt_sck作為其在有效時間段內計數器,使得sck按sys_clk四分配輸出。
always@(posedgesys_clkornegedgesys_rst)beginif(!sys_rst) cnt_clk <=?5'd0; ? ?elseif(state != IDLE)cnt_clk <= cnt_clk +?1'b1; ?//位寬清零endalways?@(posedge?sys_clk?ornegedge?sys_rst)beginif(!sys_rst)cnt_byte <=?3'd0; ? ?elseif((cnt_byte ==?3'd6)&&(cnt_clk ==?5'd31))cnt_byte <=?3'd0; ? ?elseif(cnt_clk ==?5'd31) cnt_byte <= cnt_byte +?1'b1;endalways?@(posedge?sys_clk?ornegedge?sys_rst)beginif(!sys_rst)cnt_sck <=?2'd0; ? ?elseif((state == WREN)&&(cnt_byte ==?3'd1))cnt_sck <= cnt_sck +?1'b1; ?//位寬清零elseif((state == CH_ER)&&(cnt_byte ==?3'd5))cnt_sck <= cnt_sck +?1'b1; ?//位寬清零endalways?@(posedge?sys_clk?ornegedge?sys_rst)beginif(!sys_rst)cnt_bit <=?3'd0; ? ?elseif(cnt_sck ==?2'd2)cnt_bit <= cnt_bit +?1'b1;endalways?@(posedge?sys_clk?ornegedge?sys_rst)beginif(!sys_rst)ss_n <=?1'b1; ? ?elseif(key_flag)ss_n <=?1'b0; ? ?elseif((cnt_byte ==?3'd2)&&(cnt_clk ==?5'd31)&&(state == WREN))ss_n <=?1'b1; ? ?elseif((cnt_byte ==?3'd3)&&(cnt_clk ==?5'd31)&&(state == DELAY))ss_n <=?1'b0; ? ?elseif((cnt_byte ==?3'd6)&&(cnt_clk ==?5'd31)&&(state == CH_ER))ss_n <=?1'b1;endalways?@(posedge?sys_clk?ornegedge?sys_rst)beginif(!sys_rst)sck <=?1'b0; ? ?elseif(cnt_sck ==?2'd0)sck <=?1'b0; ? ?elseif(cnt_sck ==?2'd2)sck <=?1'b1;end
導入仿真文件,對芯片擦除操作進行仿真,由于該操作耗時長,仿真前在Flash參數文件縮放擦除周期至4000ns。從上圖仿真結果可以看到,在4710ns處,Flash啟動芯片擦除,在8710ns結束擦除操作。


根據仿真結果顯示,sys_clk拉高后,程序正常工作,當檢測到key_flag為高電平后,片選線SS_n拉低,指令操作開啟。等待一個有效建立時間后(這里是640ns,便于編寫代碼),sck正式輸出八段時鐘切換(12.5Mhz)。首先,按寫使能指令,輸出一個時序(0000_0110,06h)。等待一個片選線建立時間后拉高,進入等待狀態(≥100ns,640ns)接續完成芯片擦除指令的錄入。cnt_byte和state的狀態,隨cnt_clk時鐘計數變換。

-
FPGA
+關注
關注
1662文章
22450瀏覽量
637707 -
FlaSh
+關注
關注
10文章
1753瀏覽量
155700 -
SPI協議
+關注
關注
0文章
24瀏覽量
8848 -
通信總線
+關注
關注
0文章
47瀏覽量
10245
原文標題:Flash驅動控制--芯片擦除(SPI協議)
文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設計論壇】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
基于FPGA的SPI Flash控制器的設計方案
基于FPGA的SPI Flash控制器的設計方案
FPGA零基礎學習:SPI 協議驅動設計
基于FPGA 的SPI Flash 控制器設計及驗證
基于FPGA的SPI協議及設計實現
FPGA實現的SPI協議(二)----基于SPI接口的FLASH芯片M25P16的使用
FPGA實現的SPI協議(一)----SPI驅動
FPGA實現基于SPI協議的Flash驅動控制芯片擦除
評論