[FPGA] 读写SPI FLASH IP核

[复制链接]
1161|1
 楼主| feihufuture 发表于 2021-1-21 21:03 | 显示全部楼层 |阅读模式
本帖最后由 feihufuture 于 2021-1-21 21:55 编辑

多年之前写的一个IP核,读写SPI FLASH的,读写长度可以自定义,有用可下载用用,还算方便!读出的数据是从0开始的累加的测试数据,与写入一致。



  1. spi_flash
  2.         (
  3.         input                                                        Clk10M,//Clk的180°反相
  4.         input                                                        Clk,//10MHz
  5.         input                                                        Rst,
  6.         output                                                         F2M25p16SpiClk,                                //FPGA 输出至外部SPI时钟
  7.         output                                                         F2M25p16SpiCsn,                                //FPGA输出至外部SPI片选
  8.         output                                                         F2M25p16SpiDout,                        //FPGA输出至外部器件SPI数据
  9.         input                                                         F2M25p16SpiDin,                                //外部器件输入到FPGASPI数据

  10.         input                                                        UserFlash,
  11.         input                 [23                :        0]                UserFlashAddr,                                
  12.         input                                                         UserRd,        
  13.         input                [23                :        0]                UserRdAddr,//UserRdAddr[23] is the msb
  14.         input                [15                :        0]                UserRdSize,//in bytes
  15.         output                [7                :        0]                UserDataRx,
  16.         output                                                        UserDataRxVld,
  17.         input                                                        UserWr,
  18.         input                [23                :        0]                UserWrAddr,
  19.         input                [15                :        0]                UserWrSize,//in bytes
  20.         input                [7                :        0]                UserDataTx,
  21.         output                                                        UserDataTxVld,
  22.         output                                                        UserFlashBusy,
  23.         output                                                        UserDataDone
  24.         );

[payamount]5.00[/payamount]
[pay]
        `timescale 1ns/1ps

        // 在进行写操作的时候,需要的步骤为

        // 1、写使能

        // 2、擦除数据(可以是扇区,可以是整个芯片)

        // 3、判断状态寄存器忙不忙(忙则阻塞等待不忙)
        
        // 4、写使能(对于写禁止(04H)写禁止指令使得状态寄存器中的WEL 位为0。写禁止指令是以/CS 低电平开始的,然后在DI传输指令代码04H到芯片,最后是以/CS 拉高结束。
        //当上电后,以及完成写状态寄存器,擦写安全寄存器,页写,QUAD 页写,扇区擦写,块擦写,芯片擦写指令后,WEL 位是自动清零的。)

        // 5、然后写入指令 0x02是写指令,后边跟三个字节的地址,(在写操作的时候函数接口不需要偏移量)


        


        // 读之前要

        // 1、判断这个FLASH忙不忙 如果忙的话则一直等待着不忙。

        // 2、然后进行才能进行读指令的操作。
               


        //注意:如果想要更好的时序关系,spi输出的时钟,最好用二倍频的时钟去产生
        //UserDataTxVld,相当于外部fifo的读使能,一个脉冲对应移走当前一个byte的数据,输出下一个byte的数据;
        //UserDataRxVld,相当于外部fifo的写使能,一个脉冲对应一个byte的有效数据;
        
        
        
        module spi_flash
        (
        input                                                        Clk10M,
        input                                                        Clk,//10MHz
        input                                                        Rst,
        output                                                         F2M25p16SpiClk,                                //FPGA 输出至外部SPI时钟
        output                                                         F2M25p16SpiCsn,                                //FPGA输出至外部SPI片选
        output                                                         F2M25p16SpiDout,                        //FPGA输出至外部器件SPI数据
        input                                                         F2M25p16SpiDin,                                //外部器件输入到FPGASPI数据

        input                                                        UserFlash,
        input                 [23                :        0]                UserFlashAddr,                                
        input                                                         UserRd,        
        input                [23                :        0]                UserRdAddr,//UserRdAddr[23] is the msb
        input                [15                :        0]                UserRdSize,//in bytes
        output                [7                :        0]                UserDataRx,
        output                                                        UserDataRxVld,
        input                                                        UserWr,
        input                [23                :        0]                UserWrAddr,
        input                [15                :        0]                UserWrSize,//in bytes
        input                [7                :        0]                UserDataTx,
        output                                                        UserDataTxVld,
        output                                                        UserFlashBusy,
        output                                                        UserDataDone,
        output                [31                :        0]                TRIG0
        );

        

        //--------------------------------------------------------------------------------------------------
        //------------------------------------work state----------------------------------------------------
        parameter         IDLE                         =         4'd0;
        parameter        RD_JUDGE_BUSY         =        4'd1;        
        parameter         RD                                 =        4'd2;
        parameter        RD_DONE                        =        4'd3;
        parameter         WR_EN1                         =        4'd4;
        parameter        DATA_FLASH                =        4'd5;
        parameter        FLASH_DONE                =        4'd6;
        parameter        WR_JUDGE_BUSY        =        4'd7;
        parameter         WR_EN2                         =        4'd8;
        parameter        WR                                =        4'd9;        
        parameter         WR_DONE                 =        4'd10;

        
        
        `define        STS_REG_RD_CMD                                8'h05
        `define        DATA_RD_CMD                                        8'h03
        `define        WR_EN_CMD                                        8'h06
        `define        PAGE_WR_CMD                                        8'h02
        `define        SECTOR_FLASH_CMD                        8'h20
        
        
        
        reg         [3                :        0]                WorkSts                                =        0;
        reg                [15                :        0]                 WorkCnt                                =        0;
        reg                                                        UserFlashBusyReg        =        0;
        reg          [23                :        0]                Address                                =        0;
        reg                [15                :        0]                UserSize                        =        0;
        reg                [7                :        0]                F2M25p16SpiDoutReg         =         0;
        reg                [2                :        0]                WrLoopCnt                        =        0;
        reg                [7                :        0]                UserDataRxReg                =        0;
        reg                [2                :        0]                RdLoopCnt                        =        0;
        reg                                                        UserDataRxVldReg        =        0;
        reg                                                        F2M25p16SpiCsnReg        =        1;        
        reg                                                        UserDataTxVldReg        =        0;
        reg                                                        UserDataDoneReg                =        0;
        
        
        

        
        
        
        always @ ( posedge Clk )
        begin  
        if( Rst ) WorkSts <= IDLE;
        else
                case( WorkSts )
                IDLE                                :        if( UserRd ) WorkSts <= RD_JUDGE_BUSY;
                                                                else if( UserWr ) WorkSts <= WR_JUDGE_BUSY;
                                                                else if( UserFlash ) WorkSts <= WR_EN1;
                                                                else WorkSts <= IDLE;
                                
                                
               
                RD_JUDGE_BUSY                :        if( WorkCnt == 16'd17 )
                                                                        begin
                                                                        if( UserFlashBusy ) WorkSts <= RD_JUDGE_BUSY;
                                                                        else WorkSts <= RD;
                                                                        end
                RD                                        :        if( WorkCnt == {UserSize[12:0],3'b0} + 6'd33 ) WorkSts <= RD_DONE;
                RD_DONE                                :        WorkSts <= IDLE;
               
               
               
                WR_EN1                                :        if( WorkCnt == 16'd9 ) WorkSts <= DATA_FLASH;
                DATA_FLASH                        :        if( WorkCnt == 16'd33 ) WorkSts <= FLASH_DONE;
                FLASH_DONE                        :        WorkSts <= IDLE;
               
               
               
                WR_JUDGE_BUSY                :        if( WorkCnt == 16'd17 )
                                                                        begin
                                                                        if( UserFlashBusy ) WorkSts <= WR_JUDGE_BUSY;
                                                                        else WorkSts <= WR_EN2;
                                                                        end
                WR_EN2                                :        if( WorkCnt == 16'd9  ) WorkSts <= WR;
                WR                                        :        if( WorkCnt == {UserSize[12:0],3'b0} + 6'd33 ) WorkSts <= WR_DONE;
                WR_DONE                                :        WorkSts <= IDLE;
               
                default                                :        ;
                endcase
        end



        always @ ( posedge Clk )
        begin  
        case( WorkSts )
        IDLE                                                        :        WorkCnt <= 16'b0;               
        RD_JUDGE_BUSY, WR_JUDGE_BUSY        :        if( WorkCnt == 16'd17 ) WorkCnt <= 16'b0;        
                                                                                else WorkCnt <= WorkCnt + 1'b1;
        RD,WR                                                        :        WorkCnt <= WorkCnt + 1'b1;
        WR_EN1,WR_EN2                                        :        if( WorkCnt == 16'd9 ) WorkCnt <= 16'b0;        
                                                                                else WorkCnt <= WorkCnt + 1'b1;
        DATA_FLASH                                                :        if( WorkCnt == 16'd33 ) WorkCnt <= 16'b0;        
                                                                                else WorkCnt <= WorkCnt + 1'b1;
        default                                                        :        ;
        endcase
        end
        
        
        always @ ( posedge Clk )
        begin  
        if( UserRd ) Address <= UserRdAddr;
        else if( UserWr ) Address <= UserWrAddr;
        else if( UserFlash ) Address <= UserFlashAddr;
        end
        
        
        
        always @ ( posedge Clk )
        begin  
        if( UserRd ) UserSize <= UserRdSize;
        else if( UserWr ) UserSize <= UserWrSize;
        end
        
        assign UserDataDone = UserDataDoneReg;
        always @ ( posedge Clk )
        begin  
        case( WorkSts )
        FLASH_DONE, RD_DONE, WR_DONE : UserDataDoneReg <= 1'b1;
        default        : UserDataDoneReg <= 1'b0;
        endcase
        end
        //--------------------------------------------------------------------------------------------------
        
        
        
        
        
        
        //--------------------------------------------------------------------------------------------------
        //-------------------------------------------data transmit------------------------------------------
        assign F2M25p16SpiDout = F2M25p16SpiDoutReg[7];
        always @ ( posedge Clk )
        begin  
        case( WorkSts )
        IDLE                                                        :        F2M25p16SpiDoutReg <= 8'b0;
        RD_JUDGE_BUSY, WR_JUDGE_BUSY        :        case( WorkCnt )
                                                                                16'd0                :        F2M25p16SpiDoutReg <= `STS_REG_RD_CMD;
                                                                                default                :        F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
                                                                                endcase
        DATA_FLASH                                                :        case( WorkCnt )        
                                                                                16'd0                :        F2M25p16SpiDoutReg <= `SECTOR_FLASH_CMD;
                                                                                16'd8                :        F2M25p16SpiDoutReg <= Address[23:16];
                                                                                16'd16                :        F2M25p16SpiDoutReg <= Address[15:8];
                                                                                16'd24                :        F2M25p16SpiDoutReg <= Address[7:0];
                                                                                default                :        F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
                                                                                endcase
        WR_EN1,WR_EN2                                        :         case( WorkCnt )
                                                                                16'd0                :        F2M25p16SpiDoutReg <= `WR_EN_CMD;
                                                                                default                :        F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
                                                                                endcase
        RD                                                                :        case( WorkCnt )
                                                                                16'd0                :        F2M25p16SpiDoutReg <= `DATA_RD_CMD;
                                                                                16'd8                :        F2M25p16SpiDoutReg <= Address[23:16];
                                                                                16'd16                :        F2M25p16SpiDoutReg <= Address[15:8];
                                                                                16'd24                :        F2M25p16SpiDoutReg <= Address[7:0];
                                                                                default                :        F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
                                                                                endcase
        WR                                                                :        case( WorkCnt )
                                                                                16'd0                :        F2M25p16SpiDoutReg <= `PAGE_WR_CMD;
                                                                                16'd8                :        F2M25p16SpiDoutReg <= Address[23:16];
                                                                                16'd16                :        F2M25p16SpiDoutReg <= Address[15:8];
                                                                                16'd24                :        F2M25p16SpiDoutReg <= Address[7:0];
                                                                                default                :        begin
                                                                                                                if( ( WorkCnt > 16'd31 ) & ( WrLoopCnt == 3'd0 ) ) F2M25p16SpiDoutReg <= UserDataTx;
                                                                                                                else F2M25p16SpiDoutReg <= {F2M25p16SpiDoutReg[6:0],1'b0};
                                                                                                                end
                                                                                endcase

        default                                                        :        F2M25p16SpiDoutReg <= 8'b0;
        endcase
        end
        

        always @ ( posedge Clk )
        begin  
        case( WorkSts )
        WR                :        WrLoopCnt <= WrLoopCnt + 1'b1;
        default        :        WrLoopCnt <= 3'b0;
        endcase
        end
        
        always @ ( posedge Clk )
        begin  
        case( WorkSts )
        RD                :        RdLoopCnt <= RdLoopCnt + 1'b1;
        default        :        RdLoopCnt <= 3'b0;
        endcase
        end
        
        
        assign UserDataTxVld = UserDataTxVldReg;
        always @ ( posedge Clk )
        begin  
        case( WorkSts )
        WR                        :        if( ( WorkCnt > 16'd31 ) & ( WrLoopCnt == 3'd3 ) ) UserDataTxVldReg <= 1'b1;
                                        else UserDataTxVldReg <= 1'b0;
        default                :        UserDataTxVldReg <= 1'b0;
        endcase
        end
        //--------------------------------------------------------------------------------------------------
        
        
        
        
        
        

        //--------------------------------------------------------------------------------------------------
        //-----------------------------------------data receive---------------------------------------------
        assign         UserDataRx = UserDataRxReg;
        assign        UserDataRxVld = UserDataRxVldReg;
        always @ ( negedge Clk )
        begin  
        case( WorkSts )
        RD                :        begin
                                if( WorkCnt > 16'd32 )
                                        begin
                                        UserDataRxReg <= {UserDataRxReg[6:0],F2M25p16SpiDin};
                                        if ( RdLoopCnt == 3'd0 )  UserDataRxVldReg <= 1'b1;
                                        else UserDataRxVldReg <= 1'b0;
                                        end
                                else
                                        begin
                                        UserDataRxReg <= 8'b0;
                                        UserDataRxVldReg <= 1'b0;
                                        end
                                end
        default        :        begin
                                UserDataRxReg <= 8'b0;
                                UserDataRxVldReg <= 1'b0;
                                end
        endcase
        end
        
        
        assign UserFlashBusy = UserFlashBusyReg;
        always @ ( negedge Clk )
        begin  
        case( WorkSts )
        RD_JUDGE_BUSY, WR_JUDGE_BUSY        :        if( WorkCnt > 16'd16 ) UserFlashBusyReg <= F2M25p16SpiDin;
        default        :        UserFlashBusyReg <= 1'b0;
        endcase
        end
        
        
        //--------------------------------------------------------------------------------------------------
        

        

        //--------------------------------------------------------------------------------------------------
        //-------------------------------------SPI CS-------------------------------------------------------
        assign F2M25p16SpiCsn = F2M25p16SpiCsnReg;
        always @ ( posedge Clk )
        begin  
        case( WorkSts )
        IDLE                                        :        F2M25p16SpiCsnReg <= 1'b1;
        RD_JUDGE_BUSY, WR_JUDGE_BUSY        
                                                        :        case( WorkCnt )
                                                                16'd0                :        F2M25p16SpiCsnReg <= 1'b0;
                                                                16'd17                :        F2M25p16SpiCsnReg <= 1'b1;
                                                                default                :        ;
                                                                endcase
        WR_EN1, WR_EN2                        :        case( WorkCnt )
                                                                16'd0                :        F2M25p16SpiCsnReg <= 1'b0;
                                                                16'd9                :        F2M25p16SpiCsnReg <= 1'b1;
                                                                default                :        ;
                                                                endcase
        DATA_FLASH                                :        case( WorkCnt )        
                                                                16'd0                :        F2M25p16SpiCsnReg <= 1'b0;
                                                                16'd33                :        F2M25p16SpiCsnReg <= 1'b1;
                                                                default                :        ;
                                                                endcase
        WR, RD                                        :        if( WorkCnt == 16'd0 ) F2M25p16SpiCsnReg <= 1'b0;
                                                                else if(  WorkCnt == {UserSize[12:0],3'b0} + 6'd33 ) F2M25p16SpiCsnReg <= 1'b1;
        default                                        :        F2M25p16SpiCsnReg <= 1'b1;
        endcase
        end
        //--------------------------------------------------------------------------------------------------




        assign F2M25p16SpiClk = ( ( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd9 ) & ( WorkSts == WR_EN1 ) ) |
                                                          ( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd9 ) & ( WorkSts == WR_EN2 ) ) |
                                                          ( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd33 ) & ( WorkSts == DATA_FLASH ) ) |
                                                          ( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd17 ) & ( WorkSts == RD_JUDGE_BUSY ) ) |
                                                          ( ( WorkCnt > 16'b0 ) & ( WorkCnt < 16'd17 ) & ( WorkSts == WR_JUDGE_BUSY ) ) |
                                                          ( ( WorkCnt > 16'b0 ) & ( WorkCnt < {UserSize[12:0],3'b0} + 6'd33 ) & ( WorkSts == WR ) ) |
                                                          ( ( WorkCnt > 16'b0 ) & ( WorkCnt < {UserSize[12:0],3'b0} + 6'd33 ) & ( WorkSts == RD ) )
                                                        ) ? Clk10M : 1'b0 ;




        endmodule
        
        
        
        
[/pay]


     

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
雷北城 发表于 2021-1-22 08:59 | 显示全部楼层
此帖仅作者可见
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:WX:feihu612 免费合作开发ECAT主从站

171

主题

1029

帖子

101

粉丝
快速回复 在线客服 返回列表 返回顶部