国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

FPGA怎么讀寫(xiě)外部FLASH中的用戶(hù)數(shù)據(jù)?(超詳細(xì))

這篇具有很好參考價(jià)值的文章主要介紹了FPGA怎么讀寫(xiě)外部FLASH中的用戶(hù)數(shù)據(jù)?(超詳細(xì))。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

【接口時(shí)序】QSPI Flash的原理與QSPI時(shí)序的Verilog實(shí)現(xiàn)

一、 軟件平臺(tái)與硬件平臺(tái)

  軟件平臺(tái):

    1、操作系統(tǒng):Windows-8.1

    2、開(kāi)發(fā)套件:ISE14.7

    3、仿真工具:ModelSim-10.4-SE

    4、Matlab版本:Matlab2014b/Matlab2016a

  硬件平臺(tái):

    1、 FPGA型號(hào):Xilinx公司的XC6SLX45-2CSG324

    2、 Flash型號(hào):WinBond公司的W25Q128BV?? Quad SPI Flash存儲(chǔ)器

  提示:如果圖片不清晰,請(qǐng)把圖片在瀏覽器的新建標(biāo)簽頁(yè)打開(kāi)或保存到本地打開(kāi)。

二、 原理介紹

  上一篇博客《SPI總線的原理與FPGA實(shí)現(xiàn)》中已經(jīng)有關(guān)于標(biāo)準(zhǔn)SPI協(xié)議的原理與時(shí)序的介紹,這里不再贅述。本節(jié)主要是討論QSPI(Quad SPI,四線SPI總線)的相關(guān)內(nèi)容。我的開(kāi)發(fā)板上有一片型號(hào)是W25Q128BV的Quad SPI Flash存儲(chǔ)器,本文將以它為例子來(lái)說(shuō)明QSPI操作的一些內(nèi)容。

  W25Q128BV的Quad SPI Flash存儲(chǔ)器的Top View如下圖所示

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  這塊芯片一共有8個(gè)有用的管腳,其每個(gè)管腳的功能定義如下圖所示

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  由上圖可知2號(hào)管腳DO(IO1),3號(hào)管腳 /WP(IO2),5號(hào)管腳DI(IO0)以及7號(hào)管腳/HOLD(IO3)均為雙向IO口,所以在編寫(xiě)Verilog代碼的時(shí)候要把它們定義為inout類(lèi)型,inout類(lèi)型的信號(hào)既可以做輸出也可以作為輸入,具體在代碼里面如何處理后文會(huì)有介紹。

  QSPI Flash每個(gè)引腳的詳細(xì)描述如下:

  1、Chip Select(/CS)

?????   片選信號(hào)Chip Select(/CS)的作用是使能或者不使能設(shè)備的操作,當(dāng)CS為高時(shí),表示設(shè)備未被選中,串行數(shù)據(jù)輸出線(DO或IO0,IO1,IO2,IO3)均處于高阻態(tài),當(dāng)CS為低時(shí),表示設(shè)備被選中,F(xiàn)PGA可以給QSPI Flash發(fā)送數(shù)據(jù)或從QSPI Flash接收數(shù)據(jù)。

  2、串行數(shù)據(jù)輸入信號(hào)DI以及串行輸出信號(hào)DO

?????   W25Q128BV支持標(biāo)準(zhǔn)SPI協(xié)議,雙線SPI(Dual SPI)協(xié)議與四線SPI(Quad SPI)協(xié)議。標(biāo)準(zhǔn)的SPI協(xié)議在串行時(shí)鐘信號(hào)(SCLK)的上升沿把串行輸入信號(hào)DI上的數(shù)據(jù)存入QSPI Flash中,在串行時(shí)鐘信號(hào)(SCLK)的下降沿把QSPI Flash中的數(shù)據(jù)串行化通過(guò)單向的DO引腳輸出。而在Dual SPI與Quad SPI中,DI與DO均為雙向信號(hào)(既可以作為輸入,也可以作為輸出)。

  3、Write Project(/WP)

?????   寫(xiě)保護(hù)信號(hào)的作用是防止QSPI Flash的狀態(tài)寄存器被寫(xiě)入錯(cuò)誤的數(shù)據(jù),WP信號(hào)低電平有效,但是當(dāng)狀態(tài)寄存器2的QE位被置1時(shí),WP信號(hào)失去寫(xiě)保護(hù)功能,它變成Quad SPI的一個(gè)雙向數(shù)據(jù)傳輸信號(hào)。

  4、HOLD(/HOLD)

?????   HOLD信號(hào)的作用是暫停QSPI Flash的操作。當(dāng)HOLD信號(hào)為低,并且CS也為低時(shí),串行輸出信號(hào)DO將處于高阻態(tài),串行輸入信號(hào)DI與串行時(shí)鐘信號(hào)SCLK將被QSPI Flash忽略。當(dāng)HOLD拉高以后,QSPI Flash的讀寫(xiě)操作能繼續(xù)進(jìn)行。當(dāng)多個(gè)SPI設(shè)備共享同一組SPI總線相同的信號(hào)的時(shí)候,可以通過(guò)HOLD來(lái)切換信號(hào)的流向。和WP信號(hào)一樣,當(dāng)當(dāng)狀態(tài)寄存器2的QE位被置1時(shí),HOLD信號(hào)失去保持功能,它也變成Quad SPI的一個(gè)雙向數(shù)據(jù)傳輸信號(hào)。

  5、串行時(shí)鐘線

?????   串行時(shí)鐘線用來(lái)提供串行輸入輸出操作的時(shí)鐘。

  W25Q128BV的內(nèi)部結(jié)構(gòu)框圖如下圖所示:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  更多詳細(xì)的內(nèi)容請(qǐng)閱讀W25Q128BV的芯片手冊(cè)。由于本文要進(jìn)行4線SPI的操作,但QSPI Flash默認(rèn)的操作模式是標(biāo)準(zhǔn)單線SPI模式,所以在每次進(jìn)行4線SPI操作的時(shí)候一定要先把狀態(tài)寄存器2的QE位(倒數(shù)第2位)置1,然后才能進(jìn)行QSPI操作。

  最后介紹一下我的開(kāi)發(fā)板上QSPI Flash硬件原理圖如下圖所示:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

三、 目標(biāo)任務(wù)

  1、編寫(xiě)標(biāo)準(zhǔn)SPI 協(xié)議 Verilog代碼來(lái)操作QSPI Flash,并用ChipScope抓出各個(gè)指令的時(shí)序與芯片手冊(cè)提供的時(shí)序進(jìn)行對(duì)比

  2、在標(biāo)準(zhǔn)SPI協(xié)議的基礎(chǔ)上增加Quad SPI的功能,并用ChipScope抓出Quad SPI的讀寫(xiě)數(shù)據(jù)的時(shí)序

  3、對(duì)比標(biāo)準(zhǔn)SPI與Quad SPI讀寫(xiě)W25Q128BV的ChipScope時(shí)序,感受二者的效率差距

四、 設(shè)計(jì)思路與Verilog代碼編寫(xiě)

4.1、 命令類(lèi)型的定義

  W25Q128BV一共有35條命令,這里不可能把所有命令的邏輯都寫(xiě)出來(lái),所以截取了一部分常用的命令作為示例來(lái)說(shuō)明QSPI Flash的操作方法。由于命令數(shù)目很多,所以在這個(gè)部分先對(duì)各個(gè)命令類(lèi)型做一個(gè)初步定義,下文的代碼就是按照這個(gè)定義來(lái)編寫(xiě)的。

命令編號(hào)

命令類(lèi)型(自定義)

命令碼(芯片手冊(cè)定義)

命令功能

1

5’b0XXXX

8’h00

無(wú)

2

5’b10000

8’h90

讀設(shè)備ID

3

5’b10001

8’h06

寫(xiě)使能

4

5’b10010

8’h20

扇區(qū)擦除

5

5’b10011

8’h05/8’h35

讀狀態(tài)寄存器1/2

6

5’b10100

8’h04

關(guān)閉寫(xiě)使能

7

5’b10101

8’h02

寫(xiě)數(shù)據(jù)操作(單線模式)

8

5’b10110

8’h01

寫(xiě)狀態(tài)寄存器

9

5’b10111

8’h03

讀數(shù)據(jù)操作(單線模式)

10

5’b11000

8’h32

寫(xiě)數(shù)據(jù)操作(四線模式)

11

5’b11001

8’h6b

讀數(shù)據(jù)操作(四線模式)

  說(shuō)明:

  1、命令類(lèi)型是我自己隨便定義的,可以隨便修改。命令碼是芯片手冊(cè)上定義好,不能修改,更詳細(xì)的內(nèi)容請(qǐng)參考W25Q128芯片手冊(cè)。

  2、命令類(lèi)型的最高位是使能位,只有當(dāng)最高位為1時(shí),命令才有效(在代碼里面寫(xiě)的就是只有當(dāng)最高位為1時(shí)才能進(jìn)入SPI操作的狀態(tài)機(jī))。

  3、進(jìn)行四線讀寫(xiě)操作之前,一定要把四線讀寫(xiě)功能的使能位打開(kāi),方法是通過(guò)寫(xiě)狀態(tài)寄存器命令把狀態(tài)寄存器2的QE位(倒數(shù)第二位)置1。

4.2、 如何用Matlab產(chǎn)生存放在ROM中的.coe文件格式的數(shù)據(jù)

  上一節(jié)設(shè)計(jì)了一個(gè)把存放在ROM中的數(shù)據(jù)用SPI總線發(fā)出來(lái)的例子,ROM里面只存放了10個(gè)數(shù)據(jù),所以可以直接把這10個(gè)數(shù)據(jù)填寫(xiě)到.coe文件就可以了,由于QSPI Flash的頁(yè)編程(寫(xiě)數(shù)據(jù))指令最大支持256字節(jié)的寫(xiě)操作,所以下面的例子的功能是把ROM中存放的256個(gè)字節(jié)(8-bit)數(shù)據(jù)先寫(xiě)入QSPI Flash中,然后在讀出來(lái)。由于數(shù)據(jù)太多(256個(gè)),所以一個(gè)一個(gè)填寫(xiě)肯定不現(xiàn)實(shí),所以可以利用Matlab來(lái)直接產(chǎn)生.coe文件,Matlab的完整代碼如下:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

width=8;   %rom中數(shù)據(jù)的寬度
depth=256; %rom的深度
y=0:255;   
y=fliplr(y); %產(chǎn)生要發(fā)送的數(shù)據(jù),255,254,253,...... ,2,1,0
fid = fopen('test_data.coe', 'w'); % 打開(kāi)一個(gè).coe文件

% 存放在ROM中的.coe文件第一行必須是這個(gè)字符串,16表示16進(jìn)制,可以改成其他進(jìn)制
fprintf(fid,'memory_initialization_radix=16;\n'); 

% 存放在ROM中的.coe文件第二行必須是這個(gè)字符串
fprintf(fid,'memory_initialization_vector=\n'); 

% 把前255個(gè)數(shù)據(jù)寫(xiě)入.coe文件中,并用逗號(hào)隔開(kāi),為了方便知道數(shù)據(jù)的個(gè)數(shù),每行只寫(xiě)一個(gè)數(shù)據(jù)
fprintf(fid,'%x,\n',y(1:end-1));
 
% 把最后一個(gè)數(shù)據(jù)寫(xiě)入.coe文件中,并用分號(hào)結(jié)尾
fprintf(fid,'%x;\n',y(end)); 
fclose(fid);  % 關(guān)閉文件指針

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  用Matlab2014b運(yùn)行上面的代碼以后會(huì)在與這個(gè).m文件相同的目錄下產(chǎn)生一個(gè).coe文件,這個(gè).coe文件可以導(dǎo)入到ROM中。

4.3、 標(biāo)準(zhǔn)SPI總線操作QSPI Flash思路與代碼編寫(xiě)

  上一篇博客《SPI總線的原理與FPGA實(shí)現(xiàn)》已經(jīng)介紹過(guò)用spi_module這個(gè)模塊去讀取QSPI Flash的Manufacturer/Device? ID,事實(shí)上除了上篇博客提供的那種方法以外,還可以直接在時(shí)鐘信號(hào)的下降沿發(fā)送數(shù)據(jù),時(shí)鐘信號(hào)的上升沿來(lái)接受數(shù)據(jù)來(lái)完成讀ID的操作,當(dāng)FPGA在時(shí)鐘的下降沿發(fā)送數(shù)據(jù)的時(shí)候,那么時(shí)鐘的上升沿剛好在數(shù)據(jù)的正中間,QSPI Flash剛好可以在這個(gè)上升沿把數(shù)據(jù)讀進(jìn)來(lái),讀操作則正好相反。但是有很多有經(jīng)驗(yàn)的人告訴我在設(shè)計(jì)中如非必要最好不要使用時(shí)鐘下降沿觸發(fā)的設(shè)計(jì)方法,可能是因?yàn)榇蠖鄶?shù)FPGA里面的Flip Flops資源都是上升沿觸發(fā)的,如果在Verilog代碼采用下降沿觸發(fā)的話 ,綜合的時(shí)候會(huì)在CLK輸入信號(hào)前面綜合出一個(gè)反相器,這個(gè)反相器可能會(huì)對(duì)時(shí)鐘信號(hào)的質(zhì)量有影響,具體的原因等我再Google上繼續(xù)搜索一段時(shí)間在說(shuō)。這個(gè)例子由于狀態(tài)機(jī)相較前幾篇博客來(lái)說(shuō)相對(duì)復(fù)雜,所以接下來(lái)寫(xiě)代碼我還是采用下降沿發(fā)送數(shù)據(jù),上升沿接收數(shù)據(jù)的方式來(lái)描述這個(gè)狀態(tài)機(jī)。

  接下來(lái)的任務(wù)就是抽象出一個(gè)狀態(tài)機(jī)。上一篇博客僅僅讀一個(gè)ID就用了6個(gè)狀態(tài),所以采用上一篇博客的設(shè)計(jì)思路顯然不太現(xiàn)實(shí),但對(duì)于初學(xué)者而言,上一篇博客仍然有一個(gè)基本的指引作用。通過(guò)閱讀QSPI Flash的芯片手冊(cè),可以發(fā)現(xiàn),所有的命令其實(shí)至多由以下三個(gè)部分組成:

    1、發(fā)送8-bit的命令碼

    2、發(fā)送24-bit的地址碼

    3、發(fā)送數(shù)據(jù)或接收數(shù)據(jù)

  所有命令的狀態(tài)跳變圖可由下圖描述

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  所以按照這個(gè)思路來(lái)思考的話抽象出來(lái)的狀態(tài)機(jī)的狀態(tài)并不多。單線模式的狀態(tài)為以下幾個(gè):

    1、空閑狀態(tài):用來(lái)初始化各個(gè)寄存器的值

    2、發(fā)送命令狀態(tài):用來(lái)發(fā)送8-bit的命令碼

    3、發(fā)送地址狀態(tài):用來(lái)發(fā)送24-bit的地址碼

    4、讀等待狀態(tài):當(dāng)讀數(shù)據(jù)操作正在進(jìn)行的時(shí)候進(jìn)入此狀態(tài)等待讀數(shù)據(jù)完畢

    5、寫(xiě)數(shù)據(jù)狀態(tài)(單線模式):在這個(gè)狀態(tài)FPGA往QSPI Flash里面寫(xiě)數(shù)據(jù)

    6、結(jié)束狀態(tài):一條指令操作結(jié)束,并給出一個(gè)結(jié)束標(biāo)志

  完整的代碼如下:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

`timescale 1ns / 1ps

module qspi_driver
(
output                  O_qspi_clk          , // SPI總線串行時(shí)鐘線
output reg              O_qspi_cs           , // SPI總線片選信號(hào)
output reg              O_qspi_mosi         , // SPI總線輸出信號(hào)線,也是QSPI Flash的輸入信號(hào)線
input                   I_qspi_miso         , // SPI總線輸入信號(hào)線,也是QSPI Flash的輸出信號(hào)線
                                            
input                   I_rst_n             , // 復(fù)位信號(hào)

input                   I_clk_25M           , // 25MHz時(shí)鐘信號(hào)
input       [4:0]       I_cmd_type          , // 命令類(lèi)型
input       [7:0]       I_cmd_code          , // 命令碼
input       [23:0]      I_qspi_addr         , // QSPI Flash地址

output reg              O_done_sig          , // 指令執(zhí)行結(jié)束標(biāo)志
output reg  [7:0]       O_read_data         , // 從QSPI Flash讀出的數(shù)據(jù)
output reg              O_read_byte_valid   , // 讀一個(gè)字節(jié)完成的標(biāo)志
output reg  [3:0]       O_qspi_state          // 狀態(tài)機(jī),用于在頂層調(diào)試用
);


parameter   C_IDLE            =   4'b0000  ; // 空閑狀態(tài)
parameter   C_SEND_CMD        =   4'b0001  ; // 發(fā)送命令碼
parameter   C_SEND_ADDR       =   4'b0010  ; // 發(fā)送地址碼
parameter   C_READ_WAIT       =   4'b0011  ; // 讀等待
parameter   C_WRITE_DATA      =   4'b0101  ; // 寫(xiě)數(shù)據(jù)
parameter   C_FINISH_DONE     =   4'b0110  ; // 一條指令執(zhí)行結(jié)束

reg         [7:0]   R_read_data_reg     ; // 從Flash中讀出的數(shù)據(jù)用這個(gè)變量進(jìn)行緩存,等讀完了在把這個(gè)變量的值給輸出
reg                 R_qspi_clk_en       ; // 串行時(shí)鐘使能信號(hào)
reg                 R_data_come_single  ; // 單線操作讀數(shù)據(jù)使能信號(hào),當(dāng)這個(gè)信號(hào)為高時(shí)
            
reg         [7:0]   R_cmd_reg           ; // 命令碼寄存器
reg         [23:0]  R_address_reg       ; // 地址碼寄存器 
reg         [7:0]   R_write_bits_cnt    ; // 寫(xiě)bit計(jì)數(shù)器,寫(xiě)數(shù)據(jù)之前把它初始化為7,發(fā)送一個(gè)bit就減1
reg         [8:0]   R_write_bytes_cnt   ; // 寫(xiě)字節(jié)計(jì)數(shù)器,發(fā)送一個(gè)字節(jié)數(shù)據(jù)就把它加1
reg         [7:0]   R_read_bits_cnt     ; // 寫(xiě)bit計(jì)數(shù)器,接收一個(gè)bit就加1
reg         [8:0]   R_read_bytes_cnt    ; // 讀字節(jié)計(jì)數(shù)器,接收一個(gè)字節(jié)數(shù)據(jù)就把它加1
reg         [8:0]   R_read_bytes_num    ; // 要接收的數(shù)據(jù)總數(shù)
reg                 R_read_finish       ; // 讀數(shù)據(jù)結(jié)束標(biāo)志位

wire        [7:0]   W_rom_addr          ;  
wire        [7:0]   W_rom_out           ;  

assign O_qspi_clk = R_qspi_clk_en ? I_clk_25M : 0   ; // 產(chǎn)生串行時(shí)鐘信號(hào)
assign W_rom_addr = R_write_bytes_cnt               ;


// 功能:用時(shí)鐘的下降沿發(fā)送數(shù)據(jù)

always @(negedge I_clk_25M)
begin
    if(!I_rst_n)
        begin
            O_qspi_cs           <=  1'b1   ;        
            O_qspi_state        <=  C_IDLE ;
            R_cmd_reg           <=  0      ;
            R_address_reg       <=  0      ;
            R_qspi_clk_en       <=  1'b0   ;  //SPI clock輸出不使能
            R_write_bits_cnt    <=  0      ;
            R_write_bytes_cnt   <=  0      ;
            R_read_bytes_num    <=  0      ;    
            R_address_reg       <=  0      ;
            O_done_sig          <=  1'b0   ;
            R_data_come_single  <=  1'b0   ;           
        end
    else
        begin
            case(O_qspi_state)
                C_IDLE:  // 初始化各個(gè)寄存器,當(dāng)檢測(cè)到命令類(lèi)型有效(命令類(lèi)型的最高位位1)以后,進(jìn)入發(fā)送命令碼狀態(tài)
                    begin                              
                        R_qspi_clk_en  <=   1'b0         ;
                        O_qspi_cs      <=   1'b1         ;
                        O_qspi_mosi    <=   1'b0         ;    
                        R_cmd_reg      <=   I_cmd_code   ;
                        R_address_reg  <=   I_qspi_addr  ;
                        O_done_sig     <=   1'b0         ;            
                        if(I_cmd_type[4] == 1'b1) 
                            begin                //如果flash操作命令請(qǐng)求
                                O_qspi_state        <=  C_SEND_CMD  ;
                                R_write_bits_cnt    <=  7           ;        
                                R_write_bytes_cnt   <=  0           ;
                                R_read_bytes_num    <=  0           ;                    
                            end
                    end
                C_SEND_CMD: // 發(fā)送8-bit命令碼狀態(tài) 
                    begin
                        R_qspi_clk_en       <=  1'b1    ; // 打開(kāi)SPI串行時(shí)鐘SCLK的使能開(kāi)關(guān)
                        O_qspi_cs           <=  1'b0    ; // 拉低片選信號(hào)CS
                        if(R_write_bits_cnt > 0) 
                            begin                           //如果R_cmd_reg還沒(méi)有發(fā)送完
                                O_qspi_mosi        <=  R_cmd_reg[R_write_bits_cnt] ;         //發(fā)送bit7~bit1位
                                R_write_bits_cnt   <=  R_write_bits_cnt-1'b1       ;
                            end                            
                        else 
                            begin                                 //發(fā)送bit0
                                O_qspi_mosi <=  R_cmd_reg[0]    ;
                                if ((I_cmd_type[3:0] == 4'b0001) | (I_cmd_type[3:0] == 4'b0100)) 
                                    begin    //如果是寫(xiě)使能指令(Write Enable)或者寫(xiě)不使能指令(Write Disable)
                                        O_qspi_state    <=  C_FINISH_DONE   ;
                                    end                          
                                else if (I_cmd_type[3:0] == 4'b0011) 
                                    begin    //如果是讀狀態(tài)寄存器指令(Read Register)
                                        O_qspi_state        <=  C_READ_WAIT ;
                                        R_write_bits_cnt    <=  7           ;
                                        R_read_bytes_num    <=  1           ;//讀狀態(tài)寄存器指令需要接收一個(gè)數(shù)據(jù) 
                                    end                             
                                else if( (I_cmd_type[3:0] == 4'b0010) || (I_cmd_type[3:0] == 4'b0101) || (I_cmd_type[3:0] == 4'b0111) || (I_cmd_type[3:0] == 4'b0000) ) 
                                    begin // 如果是扇區(qū)擦除(Sector Erase),頁(yè)編程指令(Page Program),讀數(shù)據(jù)指令(Read Data),讀設(shè)備ID指令(Read Device ID)                          
                                        O_qspi_state        <=  C_SEND_ADDR ;
                                        R_write_bits_cnt    <=  23          ; // 這幾條指令后面都需要跟一個(gè)24-bit的地址碼
                                    end
                            end
                    end
                C_SEND_ADDR: // 發(fā)送地址狀態(tài)
                    begin
                        if(R_write_bits_cnt > 0)  //如果R_cmd_reg還沒(méi)有發(fā)送完
                            begin                                 
                                O_qspi_mosi        <=  R_address_reg[R_write_bits_cnt] ; //發(fā)送bit23~bit1位
                                R_write_bits_cnt   <=  R_write_bits_cnt    -   1       ;    
                            end                                 
                        else 
                            begin 
                                O_qspi_mosi <=  R_address_reg[0]    ;   //發(fā)送bit0
                                if(I_cmd_type[3:0] == 4'b0010) // 扇區(qū)擦除(Sector Erase)指令
                                    begin  //扇區(qū)擦除(Sector Erase)指令發(fā)完24-bit地址碼就執(zhí)行結(jié)束了,所以直接跳到結(jié)束狀態(tài)
                                        O_qspi_state <= C_FINISH_DONE   ;    
                                    end
                                else if (I_cmd_type[3:0] == 4'b0101) // 頁(yè)編程(Page Program)指令
                                    begin                              
                                        O_qspi_state        <=  C_WRITE_DATA    ;
                                        R_write_bits_cnt    <=  7               ;                       
                                    end
                                else if (I_cmd_type[3:0] == 4'b0000) // 讀Device ID指令
                                    begin             
                                        O_qspi_state        <=  C_READ_WAIT     ;
                                        R_read_bytes_num    <=  2               ; //接收2個(gè)數(shù)據(jù)的Device ID
                                    end                                                         
                                else if (I_cmd_type[3:0] == 4'b0111) // 讀數(shù)據(jù)(Read Data)指令
                                    begin
                                        O_qspi_state        <=  C_READ_WAIT     ;
                                        R_read_bytes_num    <=  256             ;   //接收256個(gè)數(shù)據(jù)        
                                    end                                        
                            end
                    end                  
                C_READ_WAIT: // 讀等待狀態(tài)
                    begin
                        if(R_read_finish)  
                            begin
                                O_qspi_state        <=  C_FINISH_DONE   ;
                                R_data_come_single  <=  1'b0            ;
                            end
                        else
                            begin
                                R_data_come_single  <=  1'b1            ; // 單線模式下讀數(shù)據(jù)標(biāo)志信號(hào),此信號(hào)為高標(biāo)志正在接收數(shù)據(jù)
                            end
                    end
                C_WRITE_DATA: // 寫(xiě)數(shù)據(jù)狀態(tài)
                    begin
                        if(R_write_bytes_cnt < 256) // 往QSPI Flash中寫(xiě)入 256個(gè)數(shù)據(jù)
                            begin                       
                                if(R_write_bits_cnt > 0) //如果數(shù)據(jù)還沒(méi)有發(fā)送完
                                    begin                           
                                        O_qspi_mosi         <=  W_rom_out[R_write_bits_cnt] ; //發(fā)送bit7~bit1位
                                        R_write_bits_cnt    <=  R_write_bits_cnt  - 1'b1    ;                        
                                    end                 
                                else 
                                    begin                                 
                                        O_qspi_mosi         <=  W_rom_out[0]                ; //發(fā)送bit0
                                        R_write_bits_cnt    <=  7                           ;
                                        R_write_bytes_cnt   <=  R_write_bytes_cnt + 1'b1    ;
                                    end
                            end
                        else 
                            begin
                                O_qspi_state    <=  C_FINISH_DONE   ;
                                R_qspi_clk_en   <=  1'b0            ;
                            end
                    end
                C_FINISH_DONE:
                    begin
                        O_qspi_cs           <=  1'b1    ;
                        O_qspi_mosi         <=  1'b0    ;
                        R_qspi_clk_en       <=  1'b0    ;
                        O_done_sig          <=  1'b1    ;
                        R_data_come_single  <=  1'b0    ;
                        O_qspi_state        <=  C_IDLE  ;
                    end
                default:O_qspi_state    <=  C_IDLE      ;
            endcase         
        end
end

//
// 功能:接收QSPI Flash發(fā)送過(guò)來(lái)的數(shù)據(jù)    
//
always @(posedge I_clk_25M)
begin
    if(!I_rst_n)
        begin
            R_read_bytes_cnt    <=  0       ;
            R_read_bits_cnt     <=  0       ;
            R_read_finish       <=  1'b0    ;
            O_read_byte_valid   <=  1'b0    ;
            R_read_data_reg     <=  0       ;
            O_read_data         <=  0       ;
        end
    else if(R_data_come_single)   // 此信號(hào)為高表示接收數(shù)據(jù)從QSPI Flash發(fā)過(guò)來(lái)的數(shù)據(jù)
        begin
            if(R_read_bytes_cnt < R_read_bytes_num) 
                begin            
                    if(R_read_bits_cnt < 7)  //接收一個(gè)Byte的bit0~bit6    
                        begin                         
                            O_read_byte_valid   <=  1'b0                               ;
                            R_read_data_reg     <=  {R_read_data_reg[6:0],I_qspi_miso} ;
                            R_read_bits_cnt     <=  R_read_bits_cnt +   1'b1           ;
                        end
                    else  
                        begin
                            O_read_byte_valid   <=  1'b1                               ;  //一個(gè)byte數(shù)據(jù)有效
                            O_read_data         <=  {R_read_data_reg[6:0],I_qspi_miso} ;  //接收bit7
                            R_read_bits_cnt     <=  0                                  ;
                            R_read_bytes_cnt    <=  R_read_bytes_cnt    +   1'b1       ;
                        end
                end                               
            else 
                begin 
                    R_read_bytes_cnt    <=  0       ;
                    R_read_finish       <=  1'b1    ;
                    O_read_byte_valid   <=  1'b0    ;
                end
        end                               
    else 
        begin
            R_read_bytes_cnt    <=  0       ;
            R_read_bits_cnt     <=  0       ;
            R_read_finish       <=  1'b0    ;
            O_read_byte_valid   <=  1'b0    ;
            R_read_data_reg     <=  0       ;
        end
end         

rom_data rom_data_inst (
  .clka(I_clk_25M), // input clka
  .addra(W_rom_addr), // input [7 : 0] addra
  .douta(W_rom_out) // output [7 : 0] douta
);

endmodule

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  接下來(lái)就是寫(xiě)一個(gè)測(cè)試代碼對(duì)這個(gè)單線模式SPI驅(qū)動(dòng),為了保證把上面的所有指令都測(cè)試一遍,測(cè)試代碼如下:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

module qspi_top
(
    input         I_clk         ,
    input         I_rst_n       ,

    output        O_qspi_clk    , // SPI總線串行時(shí)鐘線
    output        O_qspi_cs     , // SPI總線片選信號(hào)
    output        O_qspi_mosi   , // SPI總線輸出信號(hào)線,也是QSPI Flash的輸入信號(hào)線
    input         I_qspi_miso     // SPI總線輸入信號(hào)線,也是QSPI Flash的輸出信號(hào)線
     
);
     
reg [3:0]   R_state             ;
reg [7:0]   R_flash_cmd         ;
reg [23:0]  R_flash_addr        ;
reg         R_clk_25M           ;
reg [4:0]   R_cmd_type          ;
                                
wire        W_done_sig          ;
wire [7:0]  W_read_data         ;
wire        W_read_byte_valid   ;
wire [2:0]  R_qspi_state        ;


          
//功能:二分頻邏輯          
          
always @(posedge I_clk or negedge I_rst_n)
begin
    if(!I_rst_n) 
        R_clk_25M   <=  1'b0        ;
    else 
        R_clk_25M   <=  ~R_clk_25M  ;
end



//功能:測(cè)試狀態(tài)機(jī)

always @(posedge R_clk_25M or negedge I_rst_n)
begin
    if(!I_rst_n) 
        begin
            R_state         <=  4'd0        ;
            R_flash_addr    <=  24'd0       ;
            R_flash_cmd     <=  8'h00       ;
            R_cmd_type      <=  5'b0_0000   ;
        end
     else 
        begin
            case(R_state)           
                4'd0://讀Device ID指令
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd  <= 8'h90           ; 
                                R_flash_addr <= 24'd0           ; 
                                R_cmd_type   <= 5'b1_0000       ; 
                            end     
                    end 
                4'd1://寫(xiě)Write disable instruction
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ;
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h04            ; 
                                R_cmd_type  <= 5'b1_0100        ; 
                            end     
                    end                
                4'd2://寫(xiě)使能(Write Enable)指令
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin
                                R_flash_cmd <= 8'h06            ; 
                                R_cmd_type  <= 5'b1_0001        ; 
                            end
                    end         
                4'd3:// 扇區(qū)擦除(Sector Erase)指令
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h20            ; 
                                R_flash_addr<= 24'd0            ; 
                                R_cmd_type  <= 5'b1_0010        ; 
                            end
                    end
            
                4'd4://讀狀態(tài)寄存器1, 當(dāng)Busy位(狀態(tài)寄存器1的最低位)為0時(shí)表示擦除操作完成
                    begin
                        if(W_done_sig) 
                            begin 
                                if(W_read_data[0]==1'b0) 
                                    begin 
                                        R_flash_cmd <= 8'h00            ; 
                                        R_state     <= R_state + 1'b1   ;
                                        R_cmd_type  <= 5'b0_0000        ; 
                                    end
                                else 
                                    begin 
                                        R_flash_cmd <= 8'h05        ; 
                                        R_cmd_type  <= 5'b1_0011    ; 
                                    end
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h05        ; 
                                R_cmd_type  <= 5'b1_0011    ; 
                            end
                    end
                4'd5://寫(xiě)使能(Write Enable)指令
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin
                                R_flash_cmd <= 8'h06            ; 
                                R_cmd_type  <= 5'b1_0001        ; 
                            end
                    end             
                4'd6: //頁(yè)編程操作(Page Program): 把存放在ROM中的數(shù)據(jù)寫(xiě)入QSPI Flash中
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h02            ; 
                                R_flash_addr<= 24'd0            ; 
                                R_cmd_type  <= 5'b1_0101        ; 
                            end
                    end
                4'd7://讀狀態(tài)寄存器1, 當(dāng)Busy位(狀態(tài)寄存器1的最低位)為0時(shí)表示寫(xiě)操作完成
                    begin
                        if(W_done_sig) 
                            begin 
                                if(W_read_data[0]==1'b0) 
                                    begin 
                                        R_flash_cmd <= 8'h00            ; 
                                        R_state     <= R_state + 1'b1   ;
                                        R_cmd_type  <= 5'b0_0000        ; 
                                    end
                                else 
                                    begin 
                                        R_flash_cmd <= 8'h05        ; 
                                        R_cmd_type  <= 5'b1_0011    ; 
                                    end
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h05        ; 
                                R_cmd_type  <= 5'b1_0011    ; 
                            end
                    end           
                4'd8://讀256 Bytes
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ;
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h03            ; 
                                R_flash_addr<= 24'd0            ; 
                                R_cmd_type  <= 5'b1_0111        ; 
                            end
                    end
            
                4'd9:// 空閑狀態(tài)
                    begin
                        R_flash_cmd <= 8'h00            ; 
                        R_state     <= 4'd9             ;
                        R_cmd_type  <= 5'b0_0000        ; 
                    end
                default :   R_state     <= 4'd0         ;
            endcase
        end           
end 
qspi_driver U_qspi_driver
(
.O_qspi_clk          (O_qspi_clk        ), // SPI總線串行時(shí)鐘線
.O_qspi_cs           (O_qspi_cs         ), // SPI總線片選信號(hào)
.O_qspi_mosi         (O_qspi_mosi       ), // SPI總線輸出信號(hào)線,也是QSPI Flash的輸入信號(hào)線
.I_qspi_miso         (I_qspi_miso       ), // SPI總線輸入信號(hào)線,也是QSPI Flash的輸出信號(hào)線
                   
.I_rst_n             (I_rst_n           ), // 復(fù)位信號(hào)

.I_clk_25M           (R_clk_25M         ), // 25MHz時(shí)鐘信號(hào)
.I_cmd_type          (R_cmd_type        ), // 命令類(lèi)型
.I_cmd_code          (R_flash_cmd       ), // 命令碼
.I_qspi_addr         (R_flash_addr      ), // QSPI Flash地址

.O_done_sig          (W_done_sig        ), // 指令執(zhí)行結(jié)束標(biāo)志
.O_read_data         (W_read_data       ), // 從QSPI Flash讀出的數(shù)據(jù)
.O_read_byte_valid   (W_read_byte_valid ), // 讀一個(gè)字節(jié)完成的標(biāo)志
.O_qspi_state        (R_qspi_state      )  // 狀態(tài)機(jī),用于在頂層調(diào)試用
);
     
wire [35:0]     CONTROL0    ;
wire [69:0]     TRIG0       ;
icon icon_inst (
    .CONTROL0(CONTROL0) // INOUT BUS [35:0]
);

ila ila_inst (
    .CONTROL(CONTROL0)  , // INOUT BUS [35:0]
    .CLK(I_clk)           ,      // IN
    .TRIG0(TRIG0)      // IN BUS [255:0]
);                                                     

assign  TRIG0[7:0]      =   W_read_data         ;                                               
assign  TRIG0[8]        =   W_read_byte_valid   ;   
assign  TRIG0[12:9]     =   R_state             ;        
assign  TRIG0[16:13]    =   R_qspi_state        ;   
assign  TRIG0[17]       =   W_done_sig          ;    
assign  TRIG0[18]       =   I_qspi_miso         ;  
assign  TRIG0[19]       =   O_qspi_mosi         ;  
assign  TRIG0[20]       =   O_qspi_cs           ;  
assign  TRIG0[21]       =   O_qspi_clk          ; 
assign  TRIG0[26:22]    =   R_cmd_type          ; 
assign  TRIG0[34:27]    =   R_flash_cmd         ; 
assign  TRIG0[58:35]    =   R_flash_addr        ; 
assign  TRIG0[59]       =   I_rst_n             ; 


endmodule

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  接下來(lái)主要看看用ChipScope抓出來(lái)的時(shí)序圖和芯片手冊(cè)規(guī)定的時(shí)序圖是否完全一致。

  1、讀ID指令

??????? 芯片手冊(cè)指令的讀ID指令時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  ChipScope抓出來(lái)的時(shí)序圖

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  2、寫(xiě)不使能(Write Disable)指令

??????? 芯片手冊(cè)指令的寫(xiě)不使能時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

??????? ChipScope抓出來(lái)的寫(xiě)不使能時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  3、寫(xiě)使能(Write Enable)指令

??????? 芯片手冊(cè)指令的寫(xiě)使能時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

???????? ChipScope抓出來(lái)的寫(xiě)使能時(shí)序圖

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  3、扇區(qū)擦除(Sector Erase)指令

??????? 芯片手冊(cè)的扇區(qū)擦除指令時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

??????? 芯片手冊(cè)的扇區(qū)擦除指令時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  4、讀狀態(tài)寄存器(Read Status Register)指令

??????? 芯片手冊(cè)的讀狀態(tài)寄存器指令時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

??????? ChipScope抓回來(lái)的讀狀態(tài)寄存器指令時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  由于在擦除操作和寫(xiě)操作(Page Program)操作指令發(fā)送完畢以后,芯片內(nèi)部會(huì)自己執(zhí)行相關(guān)的操作并把狀態(tài)寄存器1中的最低位Busy位拉高,狀態(tài)寄存器1的各位如下:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  所以讀狀態(tài)寄存器指令的目的是為了檢測(cè)Busy是否為高,Busy為高的話說(shuō)明擦除操作或?qū)懖僮?Page Program)操作指令并未完成,這種情況應(yīng)該等待不發(fā)送其他指令,等到Busy位拉低以后說(shuō)明擦除操作或?qū)懖僮?Page Program)操作指令已經(jīng)完成,這時(shí)才可以執(zhí)行后續(xù)的操作。值得注意的是,在上圖中讀到8個(gè)bit數(shù)據(jù)(上圖讀到的數(shù)據(jù)是0000_0011(8’h03))以后,O_qpsi_cs和O_qspi_clk信號(hào)仍然持續(xù)了2個(gè)周期的時(shí)間才變?yōu)榭臻e狀態(tài),實(shí)際上,回過(guò)頭去看代碼的話很容易解釋這種情況,由于代碼里面是用時(shí)鐘的下降沿發(fā)送數(shù)據(jù),而用時(shí)鐘的上升沿來(lái)接收數(shù)據(jù),發(fā)送數(shù)據(jù)與接收數(shù)據(jù)的狀態(tài)切換是通過(guò)R_data_coming_signal和R_read_finish信號(hào)來(lái)轉(zhuǎn)換的,所以導(dǎo)致了這種情況的發(fā)生。但是讀數(shù)據(jù)相關(guān)的指令并不要求完全8-bit對(duì)齊,如果在讀數(shù)據(jù)的過(guò)程中只要O_qpsi_cs一直為低,那么會(huì)一直重復(fù)讀下去,直至O_qpsi_cs拉高為止才停止讀數(shù)據(jù),所以上面多出來(lái)的兩個(gè)時(shí)鐘并不會(huì)影響結(jié)果的正確性。

  5、寫(xiě)數(shù)據(jù)(Page Program)指令(單線模式)

??????? 芯片手冊(cè)的寫(xiě)數(shù)據(jù)指令時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  ChipScope抓回來(lái)的時(shí)序圖

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  6、讀數(shù)據(jù)(Read Data)指令(單線模式)

??????? 芯片手冊(cè)的讀數(shù)據(jù)指令時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  ChipScope抓回來(lái)的時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  通過(guò)上面用ChipScope抓回來(lái)的時(shí)序圖與芯片手冊(cè)的時(shí)序圖進(jìn)行對(duì)比可以很清晰的理解整個(gè)QSPI Flash的操作流程與時(shí)序細(xì)節(jié)。

4.4、 如何處理雙向信號(hào)(Verilog中用關(guān)鍵詞inout定義的信號(hào)都是雙向信號(hào))

  四線操作中IO0,IO1,IO2和IO3全部都可以用來(lái)發(fā)送數(shù)據(jù)以及接收數(shù)據(jù),所以在編寫(xiě)代碼的時(shí)候要把它們?nèi)慷x成雙向類(lèi)型的信號(hào),即inout類(lèi)型。所以在編寫(xiě)四線操作的代碼之前有必要提前熟悉一下inout信號(hào)的處理方法。

  總的來(lái)說(shuō),inout信號(hào)大致有以下4個(gè)特征:

    1、inout端口不能被賦值為reg型,因此,不能用于always語(yǔ)句中。

    2、對(duì)于inout端口的邏輯判斷,要用到?:條件表達(dá)式,來(lái)控制高阻的賦值

    3、inout信號(hào)需要有一個(gè)中轉(zhuǎn)的寄存器,在always語(yǔ)句中才可以將輸入的信號(hào)賦給輸出(用inout代替純output)

    4、高阻態(tài)不要用于芯片內(nèi)部,應(yīng)該用邏輯引到引腳處,然后用高阻來(lái)實(shí)現(xiàn)。

  實(shí)際上,F(xiàn)PGA內(nèi)部的雙向信號(hào)是通過(guò)一個(gè)三態(tài)門(mén)來(lái)實(shí)現(xiàn)的,一個(gè)典型的三態(tài)門(mén)結(jié)構(gòu)如下

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  描述這個(gè)三態(tài)門(mén)的Verilog代碼如下:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

module Test_inout
(
input   I_clk,
input   I_rst_n,
    .
    .
    .
inout   IO_data,
    .
    .
    . 
)

reg     R_data_out  ;
wire    I_data_in   ;
assign  IO_data = Control ? R_data_out : 1'bz ;
assign  I_data_in   =   IO_data ;

always @(posedge I_clk or negedge I_rst_n)
begin
    .
    .
    .
    ;
end

endmodule

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

?  上面的代碼表達(dá)的意思是:當(dāng)Control為1是,IO_data信號(hào)作為輸出,輸出R_data_out的值,當(dāng)Control為0時(shí),IO_data信號(hào)作為輸入,輸入的值賦給I_data_in變量。

  值得注意的是,inout作為輸出的時(shí)候不能直接給他賦值,而需要通過(guò)一個(gè)中間變量R_data_out來(lái)間接賦值,同時(shí)inout變量的輸入輸出屬性必須通過(guò)一個(gè)控制信號(hào)Control來(lái)控制,控制性號(hào)為高時(shí)為inout信號(hào)作為輸出,輸出R_data_out的值,為低時(shí)inout處于高阻狀態(tài),這時(shí)才作為輸入接收外部的數(shù)據(jù)。

4.5、 四線SPI總線操作QSPI Flash思路與代碼編寫(xiě)

  上一小節(jié)已經(jīng)完成了單線模式QSPI Flash的讀寫(xiě)以及其他相關(guān)操作,這一節(jié)將在上一節(jié)的基礎(chǔ)上加上四線讀寫(xiě)功能。通過(guò)進(jìn)一步閱讀W25Q128BV的芯片手冊(cè)可知,在進(jìn)行四線讀寫(xiě)操作之前一定要把QE(Quad Enable)位置為1,而QE位在狀態(tài)寄存器2的倒數(shù)第二位,見(jiàn)下圖

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  除此以外,四線讀操作還需要在讀數(shù)據(jù)之前等待8個(gè)dummy clock用來(lái)加快讀數(shù)據(jù)的速度(詳細(xì)內(nèi)容請(qǐng)閱讀芯片手冊(cè))。所以,四線操作相對(duì)于單線操作而言除了要增加四線模式讀寫(xiě)數(shù)據(jù)的狀態(tài)以外還要增加一個(gè)寫(xiě)狀態(tài)寄存器的功能用來(lái)開(kāi)啟QE(Quad Enable)位以及一個(gè)dummy用來(lái)等待8個(gè)clock。

  綜上所述,四線模式的狀態(tài)為以下幾個(gè):

    1、空閑狀態(tài):用來(lái)初始化各個(gè)寄存器的值

    2、發(fā)送命令狀態(tài):用來(lái)發(fā)送8-bit的命令碼

    3、發(fā)送地址狀態(tài):用來(lái)發(fā)送24-bit的地址碼

    4、讀等待狀態(tài)(單線模式):當(dāng)讀數(shù)據(jù)操作正在進(jìn)行的時(shí)候進(jìn)入此狀態(tài)等待讀數(shù)據(jù)完畢

    5、寫(xiě)數(shù)據(jù)狀態(tài)(單線模式):在這個(gè)狀態(tài)FPGA往QSPI Flash里面寫(xiě)數(shù)據(jù)

    6、寫(xiě)狀態(tài)寄存器狀態(tài):用來(lái)把狀態(tài)寄存器的QE(Quad Enable)置1

    7、Dummy Clock狀態(tài):四線讀數(shù)據(jù)之前需要等待8個(gè)dummy clock

    8、寫(xiě)數(shù)據(jù)狀態(tài)(四線模式):在這個(gè)狀態(tài)FPGA往QSPI Flash里面通過(guò)四線模式寫(xiě)數(shù)據(jù)

    9、讀等待狀態(tài)(四線模式):在這個(gè)狀態(tài)等待FPGA從QSPI Flash里面通過(guò)四線模式讀數(shù)據(jù)完成

    10、結(jié)束狀態(tài):一條指令操作結(jié)束,并給出一個(gè)結(jié)束標(biāo)志

  其中標(biāo)紅的狀態(tài)是四線模式的代碼在單線模式代碼的基礎(chǔ)上增加的四個(gè)狀態(tài)。

  四線模式的完整代碼如下所示:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

`timescale 1ns / 1ps

module qspi_driver
(
output                  O_qspi_clk          , // QSPI Flash Quad SPI(QPI)總線串行時(shí)鐘線
output reg              O_qspi_cs           , // QPI總線片選信號(hào)
inout                   IO_qspi_io0         , // QPI總線輸入/輸出信號(hào)線
inout                   IO_qspi_io1         , // QPI總線輸入/輸出信號(hào)線
inout                   IO_qspi_io2         , // QPI總線輸入/輸出信號(hào)線
inout                   IO_qspi_io3         , // QPI總線輸入/輸出信號(hào)線
                                            
input                   I_rst_n             , // 復(fù)位信號(hào)

input                   I_clk_25M           , // 25MHz時(shí)鐘信號(hào)
input       [4:0]       I_cmd_type          , // 命令類(lèi)型
input       [7:0]       I_cmd_code          , // 命令碼
input       [23:0]      I_qspi_addr         , // QSPI Flash地址
input       [15:0]      I_status_reg        , // QSPI Flash狀態(tài)寄存器的值

output reg              O_done_sig          , // 指令執(zhí)行結(jié)束標(biāo)志
output reg  [7:0]       O_read_data         , // 從QSPI Flash讀出的數(shù)據(jù)
output reg              O_read_byte_valid   , // 讀一個(gè)字節(jié)完成的標(biāo)志
output reg  [3:0]       O_qspi_state          // 狀態(tài)機(jī),用于在頂層調(diào)試用
);


parameter   C_IDLE            =   4'b0000  ; // 空閑狀態(tài)
parameter   C_SEND_CMD        =   4'b0001  ; // 發(fā)送命令碼
parameter   C_SEND_ADDR       =   4'b0010  ; // 發(fā)送地址碼
parameter   C_READ_WAIT       =   4'b0011  ; // 單線模式讀等待
parameter   C_WRITE_DATA      =   4'b0101  ; // 單線模式寫(xiě)數(shù)據(jù)到QSPI Flash
parameter   C_FINISH_DONE     =   4'b0110  ; // 一條指令執(zhí)行結(jié)束

parameter     C_WRITE_STATE_REG =   4'b0111  ; // 寫(xiě)狀態(tài)寄存器
parameter     C_WRITE_DATA_QUAD =   4'b1000  ; // 四線模式寫(xiě)數(shù)據(jù)到QSPI Flash
parameter     C_DUMMY           =   4'b1001  ; // 四線模式讀數(shù)據(jù)需要8個(gè)時(shí)鐘周期的dummy clock,這可以加快讀數(shù)據(jù)的速度
parameter     C_READ_WAIT_QUAD  =   4'b1010  ; // 四線模式讀等待狀態(tài)

// QSPI Flash IO輸入輸出狀態(tài)控制寄存器
reg         R_qspi_io0          ;
reg         R_qspi_io1          ;
reg         R_qspi_io2          ;
reg         R_qspi_io3          ;          
reg         R_qspi_io0_out_en   ;
reg         R_qspi_io1_out_en   ;
reg         R_qspi_io2_out_en   ;
reg         R_qspi_io3_out_en   ;

reg         [7:0]   R_read_data_reg     ; // 從Flash中讀出的數(shù)據(jù)用這個(gè)變量進(jìn)行緩存,等讀完了在把這個(gè)變量的值給輸出
reg                 R_qspi_clk_en       ; // 串行時(shí)鐘使能信號(hào)
reg                 R_data_come_single  ; // 單線操作讀數(shù)據(jù)使能信號(hào),當(dāng)這個(gè)信號(hào)為高時(shí)
reg                 R_data_come_quad      ; // 單線操作讀數(shù)據(jù)使能信號(hào),當(dāng)這個(gè)信號(hào)為高時(shí)
            
reg         [7:0]   R_cmd_reg           ; // 命令碼寄存器
reg         [23:0]  R_address_reg       ; // 地址碼寄存器 
reg         [15:0]  R_status_reg        ; // 狀態(tài)寄存器

reg         [7:0]   R_write_bits_cnt    ; // 寫(xiě)bit計(jì)數(shù)器,寫(xiě)數(shù)據(jù)之前把它初始化為7,發(fā)送一個(gè)bit就減1
reg         [8:0]   R_write_bytes_cnt   ; // 寫(xiě)字節(jié)計(jì)數(shù)器,發(fā)送一個(gè)字節(jié)數(shù)據(jù)就把它加1
reg         [7:0]   R_read_bits_cnt     ; // 寫(xiě)bit計(jì)數(shù)器,接收一個(gè)bit就加1
reg         [8:0]   R_read_bytes_cnt    ; // 讀字節(jié)計(jì)數(shù)器,接收一個(gè)字節(jié)數(shù)據(jù)就把它加1
reg         [8:0]   R_read_bytes_num    ; // 要接收的數(shù)據(jù)總數(shù)
reg                 R_read_finish       ; // 讀數(shù)據(jù)結(jié)束標(biāo)志位

wire        [7:0]   W_rom_addr          ;  
wire        [7:0]   W_rom_out           ;  

assign O_qspi_clk = R_qspi_clk_en ? I_clk_25M : 0   ; // 產(chǎn)生串行時(shí)鐘信號(hào)
assign W_rom_addr = R_write_bytes_cnt               ;

// QSPI IO方向控制
assign IO_qspi_io0     =   R_qspi_io0_out_en ? R_qspi_io0 : 1'bz ;                
assign IO_qspi_io1     =   R_qspi_io1_out_en ? R_qspi_io1 : 1'bz ;                
assign IO_qspi_io2     =   R_qspi_io2_out_en ? R_qspi_io2 : 1'bz ;                
assign IO_qspi_io3     =   R_qspi_io3_out_en ? R_qspi_io3 : 1'bz ; 

// 功能:用時(shí)鐘的下降沿發(fā)送數(shù)據(jù)

always @(negedge I_clk_25M)
begin
    if(!I_rst_n)
        begin
            O_qspi_cs           <=  1'b1   ;        
            O_qspi_state        <=  C_IDLE ;
            R_cmd_reg           <=  0      ;
            R_address_reg       <=  0      ;
            R_qspi_clk_en       <=  1'b0   ;  //QSPI clock輸出不使能
            R_write_bits_cnt    <=  0      ;
            R_write_bytes_cnt   <=  0      ;
            R_read_bytes_num    <=  0      ;    
            R_address_reg       <=  0      ;
            O_done_sig          <=  1'b0   ;
            R_data_come_single  <=  1'b0   ;           
            R_data_come_quad      <=  1'b0   ;           
        end
    else
        begin
            case(O_qspi_state)
                C_IDLE:  // 初始化各個(gè)寄存器,當(dāng)檢測(cè)到命令類(lèi)型有效(命令類(lèi)型的最高位位1)以后,進(jìn)入發(fā)送命令碼狀態(tài)
                    begin                              
                        R_qspi_clk_en          <=   1'b0         ;
                        O_qspi_cs              <=   1'b1         ;
                        R_qspi_io0             <=   1'b0         ;    
                        R_cmd_reg              <=   I_cmd_code   ;
                        R_address_reg          <=   I_qspi_addr  ;
                        R_status_reg           <=   I_status_reg ;
                        O_done_sig             <=   1'b0         ;
                        R_qspi_io3_out_en   <=   1'b0         ; // 設(shè)置IO_qspi_io3為高阻
                        R_qspi_io2_out_en   <=   1'b0         ; // 設(shè)置IO_qspi_io2為高阻
                        R_qspi_io1_out_en   <=   1'b0         ; // 設(shè)置IO_qspi_io1為高阻
                        R_qspi_io0_out_en   <=   1'b0         ; // 設(shè)置IO_qspi_io0為高阻
                        if(I_cmd_type[4] == 1'b1) 
                            begin                //如果flash操作命令請(qǐng)求
                                O_qspi_state        <=  C_SEND_CMD  ;
                                R_write_bits_cnt    <=  7           ;        
                                R_write_bytes_cnt   <=  0           ;
                                R_read_bytes_num    <=  0           ;                    
                            end
                    end
                C_SEND_CMD: // 發(fā)送8-bit命令碼狀態(tài) 
                    begin
                        R_qspi_io0_out_en   <=  1'b1    ; // 設(shè)置IO_qspi_io0為輸出
                        R_qspi_clk_en       <=  1'b1    ; // 打開(kāi)SPI串行時(shí)鐘SCLK的使能開(kāi)關(guān)
                        O_qspi_cs           <=  1'b0    ; // 拉低片選信號(hào)CS
                        if(R_write_bits_cnt > 0) 
                            begin                           //如果R_cmd_reg還沒(méi)有發(fā)送完
                                R_qspi_io0            <=  R_cmd_reg[R_write_bits_cnt] ;         //發(fā)送bit7~bit1位
                                R_write_bits_cnt       <=  R_write_bits_cnt-1'b1       ;
                            end                            
                        else 
                            begin                                 //發(fā)送bit0
                                R_qspi_io0 <=  R_cmd_reg[0]    ;
                                if ((I_cmd_type[3:0] == 4'b0001) | (I_cmd_type[3:0] == 4'b0100)) 
                                    begin    //如果是寫(xiě)使能指令(Write Enable)或者寫(xiě)不使能指令(Write Disable)
                                        O_qspi_state    <=  C_FINISH_DONE   ;
                                    end                          
                                else if (I_cmd_type[3:0] == 4'b0011) 
                                    begin    //如果是讀狀態(tài)寄存器指令(Read Register)
                                        O_qspi_state        <=  C_READ_WAIT ;
                                        R_write_bits_cnt    <=  7           ;
                                        R_read_bytes_num    <=  1           ;//讀狀態(tài)寄存器指令需要接收一個(gè)數(shù)據(jù) 
                                    end                             
                                else if( (I_cmd_type[3:0] == 4'b0010) ||  // 如果是扇區(qū)擦除(Sector Erase)
                                         (I_cmd_type[3:0] == 4'b0101) ||  // 如果是頁(yè)編程指令(Page Program)
                                         (I_cmd_type[3:0] == 4'b0111) ||  // 如果是讀數(shù)據(jù)指令(Read Data)
                                         (I_cmd_type[3:0] == 4'b0000) ||  // 如果是讀設(shè)備ID指令(Read Device ID)
                                         (I_cmd_type[3:0] == 4'b1000) ||  // 如果是四線模式頁(yè)編程指令(Quad Page Program)
                                         (I_cmd_type[3:0] == 4'b1001)     // 如果是四線模式讀數(shù)據(jù)指令(Quad Read Data)
                                        ) 
                                    begin                          
                                        O_qspi_state        <=  C_SEND_ADDR ;
                                        R_write_bits_cnt    <=  23          ; // 這幾條指令后面都需要跟一個(gè)24-bit的地址碼
                                    end
                                else if (I_cmd_type[3:0] == 4'b0110) 
                                    begin    //如果是Write Status Register
                                        O_qspi_state        <=  C_WRITE_STATE_REG   ;
                                        R_write_bits_cnt    <=  15                  ;
                                    end 
                            end
                    end
                C_WRITE_STATE_REG   :
                    begin
                        R_qspi_io0_out_en   <=  1'b1    ;   // 設(shè)置IO0為輸出
                        if(R_write_bits_cnt > 0)  
                            begin                           //如果R_cmd_reg還沒(méi)有發(fā)送完
                                R_qspi_io0         <=  R_status_reg[R_write_bits_cnt] ;   //發(fā)送bit15~bit1位
                                R_write_bits_cnt   <=  R_write_bits_cnt    -   1      ;    
                            end                                 
                        else 
                            begin                                        //發(fā)送bit0
                                R_qspi_io0      <=  R_status_reg[0]    ;   
                                O_qspi_state    <=  C_FINISH_DONE      ;                                          
                            end                            
                    end 
                C_SEND_ADDR: // 發(fā)送地址狀態(tài)
                    begin
                        R_qspi_io0_out_en   <=  1'b1    ;
                        if(R_write_bits_cnt > 0)  //如果R_cmd_reg還沒(méi)有發(fā)送完
                            begin                                 
                                R_qspi_io0            <=  R_address_reg[R_write_bits_cnt] ; //發(fā)送bit23~bit1位
                                R_write_bits_cnt       <=  R_write_bits_cnt    -   1       ;    
                            end                                 
                        else 
                            begin 
                                R_qspi_io0 <=  R_address_reg[0]    ;   //發(fā)送bit0
                                if(I_cmd_type[3:0] == 4'b0010) // 扇區(qū)擦除(Sector Erase)指令
                                    begin  //扇區(qū)擦除(Sector Erase)指令發(fā)完24-bit地址碼就執(zhí)行結(jié)束了,所以直接跳到結(jié)束狀態(tài)
                                        O_qspi_state <= C_FINISH_DONE   ;    
                                    end
                                else if (I_cmd_type[3:0] == 4'b0101) // 頁(yè)編程(Page Program)指令,頁(yè)編程指令和寫(xiě)數(shù)據(jù)指令是一個(gè)意思
                                    begin                              
                                        O_qspi_state        <=  C_WRITE_DATA    ;
                                        R_write_bits_cnt    <=  7               ;                       
                                    end
                                else if (I_cmd_type[3:0] == 4'b0000) // 讀Device ID指令
                                    begin             
                                        O_qspi_state        <=  C_READ_WAIT     ;
                                        R_read_bytes_num    <=  2               ; //接收2個(gè)數(shù)據(jù)的Device ID
                                    end                                                         
                                else if (I_cmd_type[3:0] == 4'b0111) // 讀數(shù)據(jù)(Read Data)指令
                                    begin
                                        O_qspi_state        <=  C_READ_WAIT     ;
                                        R_read_bytes_num    <=  256             ;   //接收256個(gè)數(shù)據(jù)        
                                    end 
                                else if (I_cmd_type[3:0] == 4'b1000) 
                                    begin   //如果是四線模式頁(yè)編程指令(Quad Page Program)                               
                                        O_qspi_state        <=  C_WRITE_DATA_QUAD   ;
                                        R_write_bits_cnt    <=  7                   ;                       
                                    end 
                                else if (I_cmd_type[3:0] == 4'b1001) 
                                    begin   //如果是四線讀操作                               
                                        O_qspi_state        <=  C_DUMMY         ;
                                        R_read_bytes_num    <=  256             ; //接收256個(gè)數(shù)據(jù)    
                                        R_write_bits_cnt    <=  7               ;                      
                                    end 
                            end
                    end 
                C_DUMMY:  // 四線讀操作之前需要等待8個(gè)dummy clock
                    begin  
                        R_qspi_io3_out_en   <=  1'b0            ; // 設(shè)置IO_qspi_io3為高阻
                        R_qspi_io2_out_en   <=  1'b0            ; // 設(shè)置IO_qspi_io2為高阻
                        R_qspi_io1_out_en   <=  1'b0            ; // 設(shè)置IO_qspi_io1為高阻
                        R_qspi_io0_out_en   <=  1'b0            ; // 設(shè)置IO_qspi_io0為高阻       
                        if(R_write_bits_cnt > 0)    
                            R_write_bits_cnt    <=  R_write_bits_cnt - 1 ;                                    
                        else 
                            O_qspi_state        <=  C_READ_WAIT_QUAD     ;                                          
                    end   
                C_READ_WAIT: // 單線模式讀等待狀態(tài)
                    begin
                        if(R_read_finish)  
                            begin
                                O_qspi_state        <=  C_FINISH_DONE   ;
                                R_data_come_single  <=  1'b0            ;
                            end
                        else
                            begin
                                R_data_come_single  <=  1'b1            ; // 單線模式下讀數(shù)據(jù)標(biāo)志信號(hào),此信號(hào)為高標(biāo)志正在接收數(shù)據(jù)
                                R_qspi_io1_out_en   <=  1'b0            ;
                            end
                    end
                C_READ_WAIT_QUAD: // 四線模式讀等待狀態(tài)
                    begin
                        if(R_read_finish)  
                            begin
                                O_qspi_state        <=  C_FINISH_DONE   ;
                                R_data_come_quad    <=  1'b0            ;
                            end
                        else
                            R_data_come_quad        <=  1'b1            ;
                    end
                C_WRITE_DATA: // 寫(xiě)數(shù)據(jù)狀態(tài)
                    begin
                        if(R_write_bytes_cnt < 256) // 往QSPI Flash中寫(xiě)入 256個(gè)數(shù)據(jù)
                            begin                       
                                if(R_write_bits_cnt > 0) //如果數(shù)據(jù)還沒(méi)有發(fā)送完
                                    begin                           
                                        R_qspi_io0             <=  W_rom_out[R_write_bits_cnt] ; //發(fā)送bit7~bit1位
                                        R_write_bits_cnt    <=  R_write_bits_cnt  - 1'b1    ;                        
                                    end                 
                                else 
                                    begin                                 
                                        R_qspi_io0             <=  W_rom_out[0]                ; //發(fā)送bit0
                                        R_write_bits_cnt    <=  7                           ;
                                        R_write_bytes_cnt   <=  R_write_bytes_cnt + 1'b1    ;
                                    end
                            end
                        else 
                            begin
                                O_qspi_state    <=  C_FINISH_DONE   ;
                                R_qspi_clk_en   <=  1'b0            ;
                            end
                    end
                C_WRITE_DATA_QUAD    :
                    begin
                        R_qspi_io0_out_en   <=  1'b1    ;   // 設(shè)置IO0為輸出
                        R_qspi_io1_out_en   <=  1'b1    ;   // 設(shè)置IO1為輸出
                        R_qspi_io2_out_en   <=  1'b1    ;   // 設(shè)置IO2為輸出
                        R_qspi_io3_out_en   <=  1'b1    ;   // 設(shè)置IO3為輸出                          
                        if(R_write_bytes_cnt == 9'd256)
                            begin
                                O_qspi_state   <=  C_FINISH_DONE    ;    
                                R_qspi_clk_en  <=  1'b0             ; 
                            end 
                        else
                            begin      
                                if(R_write_bits_cnt == 8'd3)
                                    begin
                                        R_write_bytes_cnt   <=  R_write_bytes_cnt + 1'b1         ;
                                        R_write_bits_cnt    <=  8'd7                             ;
                                        R_qspi_io3          <=  W_rom_out[3]                     ; // 分別發(fā)送bit3
                                        R_qspi_io2          <=  W_rom_out[2]                     ; // 分別發(fā)送bit2
                                        R_qspi_io1          <=  W_rom_out[1]                     ; // 分別發(fā)送bit1
                                        R_qspi_io0          <=  W_rom_out[0]                     ; // 分別發(fā)送bit0
                                    end
                                else
                                    begin
                                        R_write_bits_cnt    <=  R_write_bits_cnt - 4            ;
                                        R_qspi_io3          <=  W_rom_out[R_write_bits_cnt - 0] ; // 分別發(fā)送bit7
                                        R_qspi_io2          <=  W_rom_out[R_write_bits_cnt - 1] ; // 分別發(fā)送bit6
                                        R_qspi_io1          <=  W_rom_out[R_write_bits_cnt - 2] ; // 分別發(fā)送bit5
                                        R_qspi_io0          <=  W_rom_out[R_write_bits_cnt - 3] ; // 分別發(fā)送bit4
                                    end 
                            end                                            
                    end 
                C_FINISH_DONE:
                    begin
                        O_qspi_cs           <=  1'b1    ;
                        R_qspi_io0             <=  1'b0    ;
                        R_qspi_clk_en       <=  1'b0    ;
                        O_done_sig          <=  1'b1    ;
                        R_qspi_io3_out_en   <=  1'b0    ; // 設(shè)置IO_qspi_io3為高阻
                        R_qspi_io2_out_en   <=  1'b0    ; // 設(shè)置IO_qspi_io2為高阻
                        R_qspi_io1_out_en   <=  1'b0    ; // 設(shè)置IO_qspi_io1為高阻
                        R_qspi_io0_out_en   <=  1'b0    ; // 設(shè)置IO_qspi_io0為高阻
                        R_data_come_single  <=  1'b0    ;
                        R_data_come_quad    <=  1'b0    ;
                        O_qspi_state        <=  C_IDLE  ;
                    end
                default:O_qspi_state    <=  C_IDLE      ;
            endcase         
        end
end

//
// 功能:接收QSPI Flash發(fā)送過(guò)來(lái)的數(shù)據(jù)    
//
always @(posedge I_clk_25M)
begin
    if(!I_rst_n)
        begin
            R_read_bytes_cnt    <=  0       ;
            R_read_bits_cnt     <=  0       ;
            R_read_finish       <=  1'b0    ;
            O_read_byte_valid   <=  1'b0    ;
            R_read_data_reg     <=  0       ;
            O_read_data         <=  0       ;
        end
    else if(R_data_come_single)   // 此信號(hào)為高表示接收數(shù)據(jù)從QSPI Flash發(fā)過(guò)來(lái)的數(shù)據(jù)
        begin
            if(R_read_bytes_cnt < R_read_bytes_num) 
                begin            
                    if(R_read_bits_cnt < 7)  //接收一個(gè)Byte的bit0~bit6    
                        begin                         
                            O_read_byte_valid   <=  1'b0                               ;
                            R_read_data_reg     <=  {R_read_data_reg[6:0],IO_qspi_io1} ;
                            R_read_bits_cnt     <=  R_read_bits_cnt +   1'b1           ;
                        end
                    else  
                        begin
                            O_read_byte_valid   <=  1'b1                               ;  //一個(gè)byte數(shù)據(jù)有效
                            O_read_data         <=  {R_read_data_reg[6:0],IO_qspi_io1} ;  //接收bit7
                            R_read_bits_cnt     <=  0                                  ;
                            R_read_bytes_cnt    <=  R_read_bytes_cnt    +   1'b1       ;
                        end
                end                               
            else 
                begin 
                    R_read_bytes_cnt    <=  0       ;
                    R_read_finish       <=  1'b1    ;
                    O_read_byte_valid   <=  1'b0    ;
                end
        end 
    else if(R_data_come_quad)   
        begin
            if(R_read_bytes_cnt < R_read_bytes_num) 
                begin  //接收數(shù)據(jù)              
                    if(R_read_bits_cnt < 8'd1)
                        begin
                            O_read_byte_valid       <=  1'b0                    ;
                            R_read_data_reg         <=  {R_read_data_reg[3:0],IO_qspi_io3,IO_qspi_io2,IO_qspi_io1,IO_qspi_io0};//接收前四位
                            R_read_bits_cnt         <=  R_read_bits_cnt + 1     ; 
                        end
                    else    
                        begin
                            O_read_byte_valid       <=  1'b1                    ;
                            O_read_data             <=  {R_read_data_reg[3:0],IO_qspi_io3,IO_qspi_io2,IO_qspi_io1,IO_qspi_io0};  //接收后四位
                            R_read_bits_cnt         <=  0                       ;
                            R_read_bytes_cnt        <=  R_read_bytes_cnt + 1'b1 ;     
                        end
                end                               
            else 
                begin 
                    R_read_bytes_cnt    <=  0       ;
                    R_read_finish       <=  1'b1    ;
                    O_read_byte_valid   <=  1'b0    ;
                end
        end
    else 
        begin
            R_read_bytes_cnt    <=  0       ;
            R_read_bits_cnt     <=  0       ;
            R_read_finish       <=  1'b0    ;
            O_read_byte_valid   <=  1'b0    ;
            R_read_data_reg     <=  0       ;
        end
end         

rom_data rom_data_inst (
  .clka(I_clk_25M), // input clka
  .addra(W_rom_addr), // input [7 : 0] addra
  .douta(W_rom_out) // output [7 : 0] douta
);

endmodule

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  頂層測(cè)試狀態(tài)機(jī)的完整代碼如下:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

module qspi_top
(
    input         I_clk         ,
    input         I_rst_n       ,

    output        O_qspi_clk    , // QPI總線串行時(shí)鐘線
    output        O_qspi_cs     , // QPI總線片選信號(hào)
    inout         IO_qspi_io0   , // QPI總線輸入/輸出信號(hào)線
    inout         IO_qspi_io1    , // QPI總線輸入/輸出信號(hào)線
    inout         IO_qspi_io2    , // QPI總線輸入/輸出信號(hào)線
    inout         IO_qspi_io3      // QPI總線輸入/輸出信號(hào)線  
);
     
reg [3:0]   R_state             ;
reg [7:0]   R_flash_cmd         ;
reg [23:0]  R_flash_addr        ;
reg         R_clk_25M           ;
reg [4:0]   R_cmd_type          ;
reg    [15:0]    R_status_reg        ;
                                
wire        W_done_sig          ;
wire [7:0]  W_read_data         ;
wire        W_read_byte_valid   ;
wire [2:0]  R_qspi_state        ;


          
//功能:二分頻邏輯          
          
always @(posedge I_clk or negedge I_rst_n)
begin
    if(!I_rst_n) 
        R_clk_25M   <=  1'b0        ;
    else 
        R_clk_25M   <=  ~R_clk_25M  ;
end



//功能:測(cè)試狀態(tài)機(jī)

always @(posedge R_clk_25M or negedge I_rst_n)
begin
    if(!I_rst_n) 
        begin
            R_state         <=  4'd0        ;
            R_flash_addr    <=  24'd0       ;
            R_flash_cmd     <=  8'h00       ;
            R_cmd_type      <=  5'b0_0000   ;
        end
     else 
        begin
            case(R_state)           
                4'd0://讀Device ID指令
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd  <= 8'h90           ; 
                                R_flash_addr <= 24'd0           ; 
                                R_cmd_type   <= 5'b1_0000       ; 
                            end     
                    end 
                4'd1://寫(xiě)不使能(Write disable)指令
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ;
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h04            ; 
                                R_cmd_type  <= 5'b1_0100        ; 
                            end     
                    end                
                4'd2://寫(xiě)使能(Write Enable)指令
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin
                                R_flash_cmd <= 8'h06            ; 
                                R_cmd_type  <= 5'b1_0001        ; 
                            end
                    end         
                4'd3:// 扇區(qū)擦除(Sector Erase)指令
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h20            ; 
                                R_flash_addr<= 24'd0            ; 
                                R_cmd_type  <= 5'b1_0010        ; 
                            end
                    end
            
                4'd4://讀狀態(tài)寄存器1, 當(dāng)Busy位(狀態(tài)寄存器1的最低位)為0時(shí)表示擦除操作完成
                    begin
                        if(W_done_sig) 
                            begin 
                                if(W_read_data[0]==1'b0) 
                                    begin 
                                        R_flash_cmd <= 8'h00            ; 
                                        R_state     <= R_state + 1'b1   ;
                                        R_cmd_type  <= 5'b0_0000        ; 
                                    end
                                else 
                                    begin 
                                        R_flash_cmd <= 8'h05        ; 
                                        R_cmd_type  <= 5'b1_0011    ; 
                                    end
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h05        ; 
                                R_cmd_type  <= 5'b1_0011    ; 
                            end
                    end
                4'd5://寫(xiě)狀態(tài)寄存器2(Write Status Register2)指令,用來(lái)把QE(Quad Enable)位置1
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin
                                R_flash_cmd <= 8'h01            ; 
                                R_cmd_type  <= 5'b1_0110        ; 
                                R_status_reg<= 16'h0002            ;
                            end
                    end 
                4'd6://寫(xiě)使能(Write Enable)指令
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin
                                R_flash_cmd <= 8'h06            ; 
                                R_cmd_type  <= 5'b1_0001        ; 
                            end
                    end             
                4'd7: //四線模式頁(yè)編程操作(Quad Page Program): 把存放在ROM中的數(shù)據(jù)寫(xiě)入QSPI Flash中
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ; 
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h32            ; 
                                R_flash_addr<= 24'd0            ; 
                                R_cmd_type  <= 5'b1_1000        ; 
                            end
                    end
                4'd8://讀狀態(tài)寄存器1, 當(dāng)Busy位(狀態(tài)寄存器1的最低位)為0時(shí)表示寫(xiě)操作完成
                    begin
                        if(W_done_sig) 
                            begin 
                                if(W_read_data[0]==1'b0) 
                                    begin 
                                        R_flash_cmd <= 8'h00            ; 
                                        R_state     <= R_state + 1'b1   ;
                                        R_cmd_type  <= 5'b0_0000        ; 
                                    end
                                else 
                                    begin 
                                        R_flash_cmd <= 8'h05        ; 
                                        R_cmd_type  <= 5'b1_0011    ; 
                                    end
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h05        ; 
                                R_cmd_type  <= 5'b1_0011    ; 
                            end
                    end           
                4'd9://四線模式讀256 Bytes數(shù)據(jù)
                    begin
                        if(W_done_sig) 
                            begin 
                                R_flash_cmd <= 8'h00            ; 
                                R_state     <= R_state + 1'b1   ;
                                R_cmd_type  <= 5'b0_0000        ; 
                            end
                        else 
                            begin 
                                R_flash_cmd <= 8'h6b            ; 
                                R_flash_addr<= 24'd0            ; 
                                R_cmd_type  <= 5'b1_1001        ; 
                            end
                    end
            
                4'd10:// 結(jié)束狀態(tài)
                    begin
                        R_flash_cmd <= 8'h00            ; 
                        R_state     <= 4'd10            ;
                        R_cmd_type  <= 5'b0_0000        ; 
                    end
                default :   R_state     <= 4'd0         ;
            endcase
        end           
end 
qspi_driver U_qspi_driver
(
.O_qspi_clk          (O_qspi_clk        ), // QPI總線串行時(shí)鐘線
.O_qspi_cs           (O_qspi_cs         ), // QPI總線片選信號(hào)
.IO_qspi_io0         (IO_qspi_io0       ), // QPI總線輸入/輸出信號(hào)線
.IO_qspi_io1         (IO_qspi_io1       ), // QPI總線輸入/輸出信號(hào)線
.IO_qspi_io2         (IO_qspi_io2       ), // QPI總線輸入/輸出信號(hào)線
.IO_qspi_io3         (IO_qspi_io3       ), // QPI總線輸入/輸出信號(hào)線
                   
.I_rst_n             (I_rst_n           ), // 復(fù)位信號(hào)

.I_clk_25M           (R_clk_25M         ), // 25MHz時(shí)鐘信號(hào)
.I_cmd_type          (R_cmd_type        ), // 命令類(lèi)型
.I_cmd_code          (R_flash_cmd       ), // 命令碼
.I_qspi_addr         (R_flash_addr      ), // QSPI Flash地址
.I_status_reg         (R_status_reg        ), // QSPI Flash狀態(tài)寄存器

.O_done_sig          (W_done_sig        ), // 指令執(zhí)行結(jié)束標(biāo)志
.O_read_data         (W_read_data       ), // 從QSPI Flash讀出的數(shù)據(jù)
.O_read_byte_valid   (W_read_byte_valid ), // 讀一個(gè)字節(jié)完成的標(biāo)志
.O_qspi_state        (R_qspi_state      )  // 狀態(tài)機(jī),用于在頂層調(diào)試用
);
     
wire [35:0]     CONTROL0    ;
wire [99:0]     TRIG0       ;
icon icon_inst (
    .CONTROL0(CONTROL0) // INOUT BUS [35:0]
);

ila ila_inst (
    .CONTROL(CONTROL0)  , // INOUT BUS [35:0]
    .CLK(I_clk)           ,      // IN
    .TRIG0(TRIG0)      // IN BUS [255:0]
);                                                     

assign  TRIG0[7:0]      =   W_read_data         ;                                               
assign  TRIG0[8]        =   W_read_byte_valid   ;   
assign  TRIG0[12:9]     =   R_state             ;        
assign  TRIG0[16:13]    =   R_qspi_state        ;   
assign  TRIG0[17]       =   W_done_sig          ;    
assign  TRIG0[18]       =   IO_qspi_io0         ;  
assign  TRIG0[19]       =   IO_qspi_io1         ;  
assign  TRIG0[20]       =   IO_qspi_io2         ;  
assign  TRIG0[21]       =   IO_qspi_io3         ;  
assign  TRIG0[22]       =   O_qspi_cs           ;  
assign  TRIG0[23]       =   O_qspi_clk          ; 
assign  TRIG0[28:24]    =   R_cmd_type          ; 
assign  TRIG0[36:29]    =   R_flash_cmd         ; 
assign  TRIG0[60:37]    =   R_flash_addr        ; 
assign  TRIG0[61]       =   I_rst_n             ; 
assign  TRIG0[77:62]    =   R_status_reg        ; 


endmodule

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

?

  接下來(lái)就對(duì)比一下各個(gè)指令的時(shí)序圖,由于有一部分時(shí)序圖在單線模式已經(jīng)對(duì)比過(guò)了,這里只對(duì)比寫(xiě)狀態(tài)寄存器,四線讀操作,四線寫(xiě)操作三個(gè)指令的時(shí)序圖

1、寫(xiě)寫(xiě)狀態(tài)寄存器(Write Status Register)指令

??????? 芯片手冊(cè)寫(xiě)狀態(tài)寄存器時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

??????? ChipScope抓出來(lái)的寫(xiě)狀態(tài)寄存器時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  2、四線寫(xiě)數(shù)據(jù)(Quad Input Page Program)指令

??????? 芯片手冊(cè)四線寫(xiě)數(shù)據(jù)時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

??????? ChipScope抓回來(lái)的四線寫(xiě)數(shù)據(jù)時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

3、四線讀數(shù)據(jù)(Quad Read Data)指令

??????? 芯片手冊(cè)四線讀數(shù)據(jù)(Fast Read Quad Output)時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

ChipScope抓回來(lái)的四線讀數(shù)據(jù)(Fast Read Quad Output)時(shí)序圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  通過(guò)對(duì)比各個(gè)指令與芯片手冊(cè)的指令,可以發(fā)現(xiàn)各個(gè)指令的時(shí)序與芯片手冊(cè)完全吻合,至此四線SPI操作QSPI Flash的代碼全部測(cè)試通過(guò)。你可以把ROM里面的數(shù)據(jù)換成你自己的數(shù)據(jù)發(fā)給QSPI Flash,ROM里面數(shù)據(jù)則可以通過(guò)4.2小節(jié)的Matlab自定義產(chǎn)生。

4.6、 四線模式與單線模式讀寫(xiě)數(shù)據(jù)時(shí)的性能對(duì)比

  由于QSPI Flash四線模式中共有四根信號(hào)線,它們?nèi)靠梢杂米鲚斎胼敵鰜?lái)傳輸數(shù)據(jù),所以傳輸同樣大小的數(shù)據(jù)塊時(shí)候,四線模式的速度是單線模式的四倍。下面列出我在最初調(diào)試QSPI Flash的時(shí)候抓出來(lái)的兩張圖,分別是四線模式與單線模式寫(xiě)數(shù)據(jù)對(duì)比圖與 四線模式與單線模式讀數(shù)據(jù)對(duì)比圖

  四線模式與單線模式寫(xiě)數(shù)據(jù)對(duì)比圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  四線模式與單線模式讀數(shù)據(jù)對(duì)比圖:

fpga怎么從flash讀程序,fpga開(kāi)發(fā)

  從上面可以很清晰的看出讀寫(xiě)同一塊數(shù)據(jù)的時(shí)候,四線模式相較于單線模式而言,速度有了4倍的提升。

五、 進(jìn)一步思考

5.1、 用Verilog編寫(xiě)QSPI Flash驅(qū)動(dòng)的意義何在?

  事實(shí)上,Xilinx的FPGA的已經(jīng)有專(zhuān)門(mén)的引腳用來(lái)與QSPI Flash相連,當(dāng)我們把.bin文件或者.mcs文件通過(guò)Jtag固化到QSPI Flash中的時(shí)候,ISE軟件中的iMPACT會(huì)自動(dòng)把.bin文件或者.mcs文件以SPI協(xié)議的格式寫(xiě)入到QSPI Flash中,由于QSPI Flash是一種非易失性存儲(chǔ)器,所以斷電后,數(shù)據(jù)并不會(huì)丟失,當(dāng)FPGA斷電重啟以后,它會(huì)自動(dòng)從QSPI Flash中加載事先固化到QSPI Flash里面的程序到內(nèi)部的RAM中執(zhí)行,而不像.bit掉電程序就會(huì)丟失。既然FPGA已經(jīng)支持QSPI Flash的協(xié)議,為什么還要寫(xiě)QSPI Flash的驅(qū)動(dòng)呢?原因是在實(shí)際的項(xiàng)目中,如果要遠(yuǎn)程對(duì)FPGA的代碼進(jìn)行在線升級(jí)的話就必須有一套QSPI Flash的驅(qū)動(dòng)來(lái)配合CPU進(jìn)行升級(jí)操作。

  比如,某廠家生產(chǎn)了幾千臺(tái)4G基站,而且已經(jīng)發(fā)貨到國(guó)外各個(gè)國(guó)家商用。而后期研發(fā)人員調(diào)試的時(shí)候發(fā)現(xiàn)FPGA部分有一個(gè)小Bug需要修復(fù)或者說(shuō)需要增加一個(gè)新功能,代碼寫(xiě)好了以后如果沒(méi)有在線升級(jí)的功能,你只能一個(gè)一個(gè)去用jtag重新固化程序,這樣會(huì)耗費(fèi)大量的人力成本而且極其不方便,而如果有在線升級(jí)的功能只需要通過(guò)遠(yuǎn)程登錄連接到CPU上發(fā)送幾條指令就可以完成升級(jí)功能,大大提高了工作效率。

5.2、 關(guān)于在代碼中同時(shí)使用時(shí)鐘的上升沿和下降沿操作時(shí)有什么風(fēng)險(xiǎn)

  關(guān)于這個(gè)問(wèn)題目前還沒(méi)有找到比較權(quán)威的說(shuō)法,以下兩個(gè)說(shuō)法是提的最多的:

  1、FPGA內(nèi)部的觸發(fā)器都是上升沿觸發(fā)的,所以,如果在代碼中用下降沿觸發(fā)的話會(huì)在時(shí)鐘引腳的前面綜合出一個(gè)反相器,這個(gè)反相器可能會(huì)對(duì)時(shí)鐘信號(hào)的質(zhì)量有影響

  2、集成電路設(shè)計(jì)的書(shū)中有對(duì)晶振的描述,外部晶振產(chǎn)生的時(shí)鐘信號(hào)上升沿的時(shí)間幾乎是一樣的,但是每個(gè)周期的下降沿的時(shí)間卻無(wú)法保證完全一致,這與工藝有很大關(guān)系,所以采用下降沿觸發(fā)有可能存在風(fēng)險(xiǎn)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-734105.html

到了這里,關(guān)于FPGA怎么讀寫(xiě)外部FLASH中的用戶(hù)數(shù)據(jù)?(超詳細(xì))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 基于FPGA 外置qspi Flash的讀寫(xiě)

    1.寫(xiě)在前面 FPGA內(nèi)部不具有掉電存儲(chǔ)程序的功能,所以都需要外置的flash存儲(chǔ)器來(lái)存儲(chǔ)程序,上電后從flash加載程序到FPGA中運(yùn)行。外置的flash可以存儲(chǔ)程序,也可以存儲(chǔ)任何用戶(hù)數(shù)據(jù),可以更有效的利用flash的存儲(chǔ)空間。 值得注意的是,用于存儲(chǔ)程序的flash和fpga連接用的是fpga的

    2024年02月12日
    瀏覽(22)
  • STM32使用QUADSPI讀寫(xiě)外部Nor Flash(以W25Q64為例)

    STM32使用QUADSPI讀寫(xiě)外部Nor Flash(以W25Q64為例)

    QUADSPI 是一種專(zhuān)用的通信接口,連接單、雙或四(條數(shù)據(jù)線) SPI Flash 存儲(chǔ)介質(zhì)。該接 口可以在以下三種模式下工作: ①間接模式:使用 QUADSPI 寄存器執(zhí)行全部操作。 ②狀態(tài)輪詢(xún)模式:周期性讀取外部 Flash 狀態(tài)寄存器,而且標(biāo)志位置 1 時(shí)會(huì)產(chǎn)生中斷(如擦除或燒寫(xiě)完成,會(huì)

    2024年02月11日
    瀏覽(19)
  • K7系列FPGA進(jìn)行FLASH讀寫(xiě)1——CCLK控制(STARTUPE2原語(yǔ))

    K7系列FPGA進(jìn)行FLASH讀寫(xiě)1——CCLK控制(STARTUPE2原語(yǔ))

    ??最近的工作涉及對(duì) FPGA 進(jìn)行遠(yuǎn)程更新,也就是通過(guò)遠(yuǎn)程通信接口將 .bin 文件送到 FPGA,然后寫(xiě)入 FLASH,這樣當(dāng) FPGA 重新上電后就可以執(zhí)行更新后的程序了。因此第一步工作就是進(jìn)行 FLASH 的讀寫(xiě)控制。 ??然而如果嘗試配置 FLASH 管腳時(shí),會(huì)發(fā)現(xiàn) CCLK 管腳是不可配置的,這

    2024年02月05日
    瀏覽(31)
  • (超詳細(xì))STM32芯片F(xiàn)lash讀寫(xiě)操作講解和代碼(寄存器版本)

    (超詳細(xì))STM32芯片F(xiàn)lash讀寫(xiě)操作講解和代碼(寄存器版本)

    關(guān)于Flash,官方的解釋為:Flash為32位寬的存儲(chǔ)單元,可用于存儲(chǔ)代碼和數(shù)據(jù)常量。Flash模塊位于微控制器內(nèi)存映射中的特定基址……。而對(duì)于我們來(lái)說(shuō),只要知道Flash閃存區(qū)是一個(gè)掉電后也不會(huì)清除的數(shù)據(jù)存儲(chǔ)地。(相信大家對(duì)于Flash閃存也有著一定 的了解了,我也不多說(shuō)廢話

    2023年04月19日
    瀏覽(23)
  • FPGA純verilog代碼讀寫(xiě)N25Q128A QSPI Flash 提供工程源碼和技術(shù)支持

    FPGA純verilog代碼讀寫(xiě)N25Q128A QSPI Flash 提供工程源碼和技術(shù)支持

    N25Q128A的參數(shù)有很多,作為FPGA開(kāi)發(fā)者,需要關(guān)注如下參數(shù): 1、4KBytes為1個(gè)Sector(扇區(qū)); 2、16個(gè)Sector(扇區(qū))是1個(gè)Block(塊)64KBytes; 3、容量為16M=128Mbite字節(jié),共有256個(gè)Block,4096個(gè)Sector; 這三個(gè)參數(shù)直接決定了你怎么組織數(shù)據(jù)的讀寫(xiě)操作,比如你的數(shù)據(jù)量很小,則考慮寫(xiě)入1個(gè)Sector(扇

    2024年02月02日
    瀏覽(78)
  • STM32 FLASH 讀寫(xiě)數(shù)據(jù)

    STM32 FLASH 讀寫(xiě)數(shù)據(jù)

    2.1 修改代碼后編譯,會(huì)有提示信息 KEIL,計(jì)算出來(lái)代碼總共 61076 Byte 2.2 如果什么都沒(méi)有改,直接編譯是沒(méi)有這個(gè)提示信息的 0x08000000 是存放代碼的起始地址,我們保存的數(shù)據(jù)要和代碼分開(kāi),放在代碼區(qū)域后面,所以后面加了個(gè)80000, 比keil 編譯里面算出來(lái)的和要大將近2 萬(wàn)個(gè)

    2024年02月12日
    瀏覽(24)
  • STM32單片機(jī)初學(xué)8-SPI flash(W25Q128)數(shù)據(jù)讀寫(xiě)

    STM32單片機(jī)初學(xué)8-SPI flash(W25Q128)數(shù)據(jù)讀寫(xiě)

    ????????當(dāng)使用單片機(jī)進(jìn)行項(xiàng)目開(kāi)發(fā),涉及大量數(shù)據(jù)需要儲(chǔ)存時(shí)(例如使用了屏幕作為顯示設(shè)備,常常需要存儲(chǔ)圖片、動(dòng)畫(huà)等數(shù)據(jù)),單靠單片機(jī)內(nèi)部的Flash往往是不夠用的。 ????????如STM32F103系列,內(nèi)部Flash最多只能達(dá)到512KByte,假設(shè)要儲(chǔ)存240*240分辨率、64K彩色圖片,

    2024年02月03日
    瀏覽(21)
  • FPGA解析串口指令控制spi flash完成連續(xù)寫(xiě)、讀、擦除數(shù)據(jù)

    FPGA解析串口指令控制spi flash完成連續(xù)寫(xiě)、讀、擦除數(shù)據(jù)

    最近在收拾抽屜時(shí)找到一個(gè)某寶的spi flash模塊,如下圖所示,我就想用能不能串口來(lái)讀寫(xiě)flash,大致過(guò)程就是,串口向fpga發(fā)送一條指令,fpga解析出指令控制flah,這個(gè)指令協(xié)議目前就是: 55 + AA + CMD + LEN_h + LEN_m + LEN_l + DATA CMD:01 寫(xiě);02 讀;03 擦除(片擦除); LEN_h/m/l:三個(gè)字

    2024年02月03日
    瀏覽(21)
  • Flash讀取數(shù)據(jù)庫(kù)中的數(shù)據(jù)

    Flash讀取數(shù)據(jù)庫(kù)中的數(shù)據(jù)

    ?Flash讀取數(shù)據(jù)庫(kù)中的數(shù)據(jù) 要讀取數(shù)據(jù)庫(kù)的記錄,首先需要建立一個(gè)數(shù)據(jù)庫(kù),并輸入一些數(shù)據(jù)。數(shù)據(jù)庫(kù)建立完畢后,由Flash向ASP提交請(qǐng)求,ASP根據(jù)請(qǐng)求對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作后將結(jié)果返回給Flash,F(xiàn)lash以某種方式把結(jié)果顯示出來(lái)。 1.啟動(dòng)Access2003,新建一名為“userInfo.mdb”的數(shù)據(jù)庫(kù),

    2024年01月25日
    瀏覽(21)
  • stm32讀寫(xiě)內(nèi)部Flash

    stm32讀寫(xiě)內(nèi)部Flash

    因?yàn)槲业膕tm32f407的內(nèi)部flash是1M的所以塊2不存在,但他的地址仍然存在,只是沒(méi)有作用,這是stm32的整體框架。? ? 一般我們說(shuō) STM32 內(nèi)部 FLASH 的時(shí)候,都是指這個(gè)主存儲(chǔ)器區(qū)域,它是存儲(chǔ)用戶(hù)應(yīng)用程序的空間,芯片型號(hào)說(shuō)明中的 1M FLASH、2M FLASH 都是指這個(gè)區(qū)域的大小。 主存儲(chǔ)

    2024年02月01日
    瀏覽(18)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包