前言
最近在收拾抽屜時找到一個某寶的spi flash模塊,如下圖所示,我就想用能不能串口來讀寫flash,大致過程就是,串口向fpga發(fā)送一條指令,fpga解析出指令控制flah,這個指令協(xié)議目前就是:
55 + AA + CMD + LEN_h + LEN_m + LEN_l + DATA
CMD:01 寫;02 讀;03 擦除(片擦除);
LEN_h/m/l:三個字節(jié)表示讀寫長度,高字節(jié)在前低字節(jié)災后;
DATA:如果是寫flah,DATA則為需要寫入的數(shù)據(jù),其它兩種狀態(tài)可以不填;
1. 串口指令解析
軟件使用序列式狀態(tài)機完成串口指令解析,最后解析出三個使能信號,以及相應的數(shù)據(jù)、長度、地址。
always@(posedge clk,negedge rst_n)
if(!rst_n)
state<=S0;
else begin
case(state)
S0:
if(uart_vld)begin
if(uart_dat == 8'h55)
state<=S1;
else
state<=S0;
end else
state<=S0;
S1:
if(uart_vld)begin
if(uart_dat == 8'hAA)
state<=S2;
else
state<=S0;
end else
state<=S1;
S2:
if(uart_vld)
state<=S3;
else
state<=S2;
S3://命令字
if(uart_vld)
state<=S4;
else
state<=S3;
S4://長度h
if(uart_vld)
state<=S5;
else
state<=S4;
S5://長度m
if(uart_vld)
state<=S6;
else
state<=S5;
S6://長度l
if(uart_vld)
state<=S7;
else
state<=S6;
S7:
state<=S7;
default:state<=S0;
endcase
end
2. flash 控制
對于flash三個功能(讀、寫、擦書)分別設計了三個模塊,每個模塊完成對應功能以及輸出flash的cs、sclk、sdi等信號,但是flash接口只有一組控制信號,因此需要對三個模塊輸出的flash控制信號進行選擇輸出,如下所示。
always@(posedge clk,negedge rst_n)
if(!rst_n)begin
o_spi_cen <=1'b1;
o_spi_sclk <=1'b0;
o_spi_sdi <=1'b0;
end else begin
case(work_state)
3'b001:begin//xie
o_spi_cen <= wr_flash_csn ;
o_spi_sclk <= wr_flash_sclk ;
o_spi_sdi <= wr_flash_sdi ;
end
3'b010:begin//du
o_spi_cen <= rd_flash_csn ;
o_spi_sclk <= rd_flash_sclk ;
o_spi_sdi <= rd_flash_sdi ;
end
3'b100:begin//cachu
o_spi_cen <= er_flash_csn ;
o_spi_sclk <= er_flash_sclk ;
o_spi_sdi <= er_flash_sdi ;
end
default:begin
o_spi_cen <=1'b1;
o_spi_sclk <=1'b0;
o_spi_sdi <=1'b0;
end
endcase
end
assign work_state ={spi_flash_erctl,spi_flash_rdctl,spi_flash_wrctl};
2.1 flash寫控制
軟件對flash寫控制的基本方法是收到一個串口數(shù)據(jù)就寫進flash,并不是先緩存256個字節(jié)然后直接進行頁編程,這樣搞控制邏輯比較復雜。方法確定后就是軟件實現(xiàn),上級輸出了vld和data(vld和data上上沿對齊,vld只有一個時鐘寬度),使用vld作為觸發(fā)條件,完成數(shù)據(jù)寫入。
同樣軟件使用序列式狀態(tài)機器進行流程控制。然后先寫使能,然后正常寫指令(02)、地址數(shù)據(jù)。
always@(posedge clk,negedge rst_n)
if(!rst_n)
state<=S0;
else if(clken)begin
case(state)
S0:
if(spi_flash_ctlr[2] && vld_zk)
state<=S1;
else
state<=S0;
S1://xieshineng function code 06
if(&cnt && cnt_bit=='d7)
state<=S2;
else
state<=S1;
S2://delay
if(&cnt && cnt_bit==WIDTH-1)
state<=S3;
else
state<=S2;
S3://xie gongneng ma 02
if(&cnt && cnt_bit=='d7)
state<=S4;
else
state<=S3;
S4://xie dizhi
if(&cnt && cnt_bit=='d23)
state<=S5;
else
state<=S4;
S5://xie shuju
if(&cnt && cnt_bit=='d7)
state<=S6;
else
state<=S5;
S6:
if(&cnt)
state<=S7;
else
state<=S6;
S7:
if(cnt_byte == wr_len)
state<=S8;
else
state<=S0;
S8:
state<=S8;
default:state<=S0;
endcase
end
2.2 flash擦除
直接在寫控制上面改,前面有個寫使能,下圖是擦除指令(C7/60)
always@(posedge clk,negedge rst_n)
if(!rst_n)
state<=S0;
else if(clken)begin
case(state)
S0:
if(spi_flash_ctlr[2:1]==2'b01)
state<=S1;
else
state<=S0;
S1://xieshineng function code 06
if(&cnt && cnt_bit=='d7)
state<=S2;
else
state<=S1;
S2://delay
if(&cnt && cnt_bit==WIDTH-1)
state<=S3;
else
state<=S2;
S3://
if(&cnt && cnt_bit=='d7)
state<=S6;
else
state<=S3;
S6:
if(&cnt)
state<=S7;
else
state<=S6;
S7:
state<=S8;
S8:
state<=S8;
default:state<=S0;
endcase
end
2.3 flash讀控制
從falsh讀數(shù)據(jù)比較簡單,接口時序如下圖,軟件實現(xiàn)同樣還是序列式狀態(tài)機,根據(jù)傳入的長度決定讀取的字節(jié)數(shù)。
因為數(shù)據(jù)從flash讀出后需要通過串口發(fā)送,因此為了減少工作量,從flash讀出一個數(shù)據(jù),串口就發(fā)送一個數(shù)據(jù),因此為了避免flash兩個數(shù)據(jù)都讀出來了串口一個都沒發(fā)完,需要控制flash讀數(shù)間隔,使得這個間隔大于串口發(fā)完一個字節(jié)的時間,舉個栗子,假設現(xiàn)在串口波特率為115200,那么發(fā)完一個字節(jié)的時間約為86.8us(10位),那么flash讀數(shù)間隔要大于86.9us。
always@(posedge clk,negedge rst_n)
if(!rst_n)
state<=S0;
else if(clken)begin
case(state)
S0:
if(spi_flash_ctlr[2:1]==2'b01)
state<=S1;
else
state<=S0;
S1:
state<=S2;
S2://cs xian ladi
if(&cnt)
state<=S3;
else
state<=S2;
S3://xie gongneng ma 02
if(&cnt && cnt_bit=='d7)
state<=S4;
else
state<=S3;
S4://xie dizhi
if(&cnt && cnt_bit=='d23)
state<=S5;
else
state<=S4;
S5://xie shuju
if(&cnt && cnt_bit=='d7)
state<=S6;
else
state<=S5;
S6:
if(&cnt)
state<=S7;
else
state<=S6;
S7:
if(cnt_byte == rd_len)
state<=S8;
else
state<=S9;
S9:
if(dly_end)
state<=S1;
else
state<=S9;
S8:
state<=S8;
default:state<=S0;
endcase
end
文章來源:http://www.zghlxwxcb.cn/news/detail-774422.html
3. 實物測試
開始我設置的波特率為921600,擦除和寫沒問題,至少在時序上是很完美的,但是回讀出來的數(shù)據(jù)如下圖前十個字節(jié)一樣,本來寫入是01~0a,現(xiàn)在讀出的數(shù)據(jù)中第2、3、5、7、9都是FF,后來我把波特率降到9600,然后就好了,下圖最后10個字節(jié)。中間10個ff是擦除完后讀出來數(shù)據(jù)。
軟件工程鏈接:
軟件工程、源碼、仿真、數(shù)據(jù)手冊、fllash仿真模型
最后來張全家福文章來源地址http://www.zghlxwxcb.cn/news/detail-774422.html
到了這里,關(guān)于FPGA解析串口指令控制spi flash完成連續(xù)寫、讀、擦除數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!