SDRAM学习与实现串口传图

串口传图写进SDRAM再读出

        为啥这样干:节省BRAM资源:X

                             学习SRAM控制器写法:√

        实际上确实也不太够用就是了,A7100T的bram也只有1M多,存个一行数据得了。

实现思路:

        1.串口发送图像数据进入rx模块,rx模块发给SDRAM写模块;

        细节:考虑到图像格式不一,本次使用的SDRAM的一个地址放16Bit数据,你需要额外准备一个FIFO来按SDRAM行的大小来存储,每发完一行数据把这部分写入SDRAM,比如SDRAM一行512个元素你就得设置一个读取位数和宽度分别为为16x1024的fifo,写入数据则是串口的8x2048。

        2.发完以后通知读模块,同样需要fifo,这次是写入位数和宽度分别为为16x1024的fifo,读取多少得看图像是几位的,读取完一行数据以后通知VGA模块可以输出图像,VGA读取图像的速率不算快,所以直接读就行了。

         这个显示分辨率只需要25MHZ左右,只需要约定FIFO内的数据小于一个数值,例如小于SDRAM的一行数据的时候就从SDRAM读取数据填补,便可以满足需求,因为SDRAM自身每次切换行都需要重新激活,所以每次读也就读一行数据,并不会导致FIFO的溢出。     

        3.这个项目最需要注意的就是约束好FIFO,不要出现读空了还在读,写满了还在写,唯一一次空信号应该出现在发送完一张图片到下一张图片的间隔。

SDRAM控制器的编写方法

总之只要阅读操作手册,按照时序来,完全不难!

        器件记录: 

小梅哥AC620上SDRAM:M12L2561616A-6TG2T

        其的存储空间为16M*16=256MB,第二行的数字则与其速度等级有关;其分为:

        4bank*16bit*4M 即:8192*512 = 2^13 * 2^9 = 2^22 = 4M

        bank数目*数据位宽*存储深度

HY57V281620F,所以其具备的是

        4bank*16bits*2M 即 2^12 * 2^9 = 2^21 = 2M

SDRAM原理:

        SDRAM 存储数据是利用了电容能够保持电荷以及其充放电特性。一位数据的存取电路 如图 所示,该存储单元主要由行列选通三极管,存储电容,刷新放大器组成。对于这 一位的数据,首先需要打开行地址,然后打开列地址,则电容的电平状态就能呈现在数据线 (data_bit)上,即实现了读取。 或者,数据线上的电平值被送到电容上,从而实现写入数据。

        但是,打开行地址(激活行)是需要一定时间的,即从打开行地址到可以打开列地址进 行数据读/写,这之间有一定的时间间隔,这个间隔叫做 tRCD(ACTIVE-to-READ or WRITE delay),对于不同型号或不同速度等级的器件,这个值是不一样的。

        需要自行查阅产品手册获得这个速度等级,而M12L2561616A-6则对应的是速度等级6,其tRCD等于18ns。

        当列地址被打开后,数据并不是立即出现在最终的数据总线引脚上,而是有若干个时钟 的延迟,这个延迟叫做列选通潜伏期(CL,CL = CAS (READ) latency)。如图 32.3 为不同速 度等级的器件的列选通潜伏期值,速度等级不一样,其值也是不一样的。

用户手册原文:

        Bank activate 命令用于在空闲 Bank 中选择随机行。通过将 RAS 和 CS 以及所需的行和存储体地址置为低电平,即可启动行访问。从存储体激活时间起,经过 tRCD(min) 的时间延迟后,可以进行读或写操作。 tRCD是SDRAM的内部时序参数,因此它取决于工作时钟频率。

SDRAM命令

        不同的SDRAM命令是一样的,如果不一样说明可能使用的命令不是低有效吧。(或者有额外的命令控制)

执行时间

        除了在指定的命令外,我们还需要关心执行命令所需的时间。

        例如:

M12L2561616A-6TG2T:

        初始化时序(小梅哥文档):

tRP :

预充电需要时间;

tRFC:(tRRC)

一次自刷新需要的时间

tREF

Refresh Period,表示“刷新周期”。它指内存模块的刷新周期。

tRAS

激活行到预充电需要的时间

tRCD:

激活到读或写命令的延迟(激活行到列操作的时间),也是激活命令到读写操作的等待时间

CL

列选通潜伏期(读取指令到数据端口复现的时间)

WL

写入指令到输入数据端口的时间

HY57V281620F:

Brust length

        对于SDRAM来说,区分于RAM和FIFO的读写方法,并不是连续地给出读写使能和地址,而是一次读写操作"Brust length"长度的数据。

        SDRAM的读指令都是默认突发的,但是写指令可以不突发,直接写一整行。

自动刷新:

        自动刷新(AUTO REFRESH)一般用于对 SDRAM 进行常规操作的 过程中。该命令是非持续性的,即每次需要时,都需要发送此命令。在执 行自动刷新命令之前,所有的 BANK 必须被预充电(关闭)。在自动刷新 和预充电命令之间,必须间隔最少 tRP 时间。自动刷新时,行地址由 SDRAM 芯片内部的刷新控制器自动更新,因此,在执行自动刷新命令时, 用户不需要关心地址总线上的值。不管器件的数据位宽是多少,对于 256Mbit 的 SDRAM,在商业和工业级的器件中,每 64ms 内需要执行 8192 次自动刷新操作,即每 7.813us 执行一次;在汽车级的器件中,每 16ms 内 执行 8192 次自动刷新操作,即每 1.953us 执行一次。另外,自动刷新操作 也可以采用突发的方式执行,即每 64ms(商业和工业级)/16ms(汽车级) 都连续不间断的执行 8192 次自动刷新命令,然后其他时间再执行读写或 者其他命令。如图 32.10 为刷新过程示意图。

        一些差别:

        M12L2561616A-6TG2T的自动刷新需要先发送预充电命令(ALL BANK),而且需要发送两次刷新指令,即需要一个tRP和两个tRFC的时间,而HY57V281620F却不需要,仅需要发送刷新指令然后等待刷新完成即可。

        后面的读写时序其实根据不同的器件来看还是有很多不一样的步骤的,请按照自己的芯片的操作手册来,应该不会有问题。

        比较重要的是仲裁器的写法,根据划定好的优先级来约束就好了。

        可参考:

参数配置:

//COMMAND  = {CS_N,RAS_N,CAS_N,WE_N};
parameter  COMMAND_MRS          = 4'b0000 ;
parameter  COMMAND_ARF          = 4'b0001 ;
parameter  COMMAND_PRE          = 4'b0010 ;
parameter  COMMAND_ACT          = 4'b0011 ;
parameter  COMMAND_WRITE        = 4'b0100 ;
parameter  COMMAND_READ         = 4'b0101 ;
parameter  COMMAND_interrupt    = 4'b0110 ;
parameter  COMMAND_NOP          = 4'b0111 ;

//time_wait
parameter  TIME_WAIT_ABOVE_100US = 10000 ;//wait_time > 100us set:200us Power up wait time
parameter  TIME_PRE_CHARGE       = 2     ;//tRP       > 18ns  set:40ns; Precharge cost time
parameter  TIME_Auto_refresh     = 5     ;//tRFC=TRRC > 60ns  set:100ns ARF cost time
parameter  TIME_MRS_done_wait    = 2     ;//During 2CLK following this command, the SDRAM cannot accept any other commands. 

//MRS_OPCODE
parameter  INIT_OPMODE_Brust_Mode   = 1'b0   ;//A9
parameter  INIT_OPMODE_STANDRD      = 2'b00  ;//A8 A7
parameter  INIT_CAS_Latency         = 3      ;//A6 A5 A4 ;CAS Latency ( 2 & 3 ) 
parameter  INIT_Burst_type          = 1'b0   ;//A3 0:Sequential 1:Interleave
parameter  INIT_Burst_length        = 4      ;//A2 A1 A0 ;Burst Length ( 1, 2, 4, 8 & full page )
parameter  INIT_OPMODE_Brust_Length = (INIT_Burst_length == 1)?(3'b000):
                                      (INIT_Burst_length == 2)?(3'b001):
                                      (INIT_Burst_length == 4)?(3'b010):
                                      (INIT_Burst_length == 8)?(3'b011):(3'b111);//( 1, 2, 4, 8 & full page )
parameter  INIT_OPMODE_CL           = (INIT_CAS_Latency  == 2)?(3'b010):(3'b011);//A6 A5 A4 ;

//auto refresh
parameter ARF_PERIOD = 750;// ARF_period = Row_nums/64ms 64ms = 64_000us = 64_000_000ns = 3_200_000 cycles (1 ARF/782 cycles)
//ACT
parameter TIME_RCD = 3;//tRCD > 20ns act RAS to CAS delay


主控制器和仲裁: 

        1.状态机的状态位宽要对齐。

        2.不同信号的优先级要提前约定好。

module SDRAM_CTRL_TOP #(
    parameter SDRAM_DATA_WIDTH   = 16,
    parameter SDRAM_BANK_WIDTH   = 2 ,
    parameter SDRAM_ADDR_WIDTH   = 12
)(
    input   wire         Sys_clk,
    input   wire         Rst_n  ,
//PLL
    input   wire            VGA_CLOCK       ,//25MHZ = 800X525X60 
//SDRAM 
    //COMMAND
    output  wire            SDRAM_CS_N                      ,
    output  wire            SDRAM_RAS_N                     ,
    output  wire            SDRAM_CAS_N                     ,
    output  wire            SDRAM_WE_N                      ,
    output  wire            SDRAM_CKE                       ,
    output  wire    [1:0]   SDRAM_DQM                       ,
    output  wire            SDRAM_CLK                       ,
    output  reg     [SDRAM_ADDR_WIDTH-1:0]  SDRAM_A_ADDR    ,
    output  reg     [SDRAM_BANK_WIDTH-1:0]  SDRAM_BANK_ADDR ,
    //WR_FIFO
    input   wire            FIFO_WR_EN                      ,
    input   wire    [7:0]   FIFO_WR_data                    ,
    //DATA
    inout           [SDRAM_DATA_WIDTH-1:0]  SDRAM_DQ        ,
    //VGA
    output  wire    [2:0]   red_sign                        ,
    output  wire    [2:0]   grenn_sign                      ,
    output  wire    [1:0]   blue_sign                       ,
    output  wire            H_Sync_sign                     ,
    output  wire            V_Sync_sign                     
);
`include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h"
    localparam  STATE_IDLE = 6'b00_0001;
    localparam  STATE_INIT = 6'b00_0010;
    localparam  STATE_ARB  = 6'b00_0100;
    localparam  STATE_ARF  = 6'b00_1000;
    localparam  STATE_RD   = 6'b01_0000;
    localparam  STATE_WE   = 6'b10_0000;
    //Main
            reg  [3:0]                    SDRAM_COMMAND_SEND;
            reg  [5:0]                    STATE             ;
           wire                           WR_avai           ;
           wire  [SDRAM_DATA_WIDTH-1:0]   WR_SDRAM_DQ       ;
           reg   [SDRAM_DATA_WIDTH-1:0]   READ_SDRAM_DQ     ;
    //init
           wire                           INIT_DONE         ;
           wire  [3:0]                    COMMAND_INIT      ;       
           wire  [SDRAM_ADDR_WIDTH-1:0]   INIT_A_ADDR       ;
           wire  [SDRAM_BANK_WIDTH-1:0]   INIT_BANK_ADDR    ;
    //ARF
           wire                           ARF_access        ;
           wire  [3:0]                    COMMAND_REF       ;
           wire  [SDRAM_ADDR_WIDTH-1:0]   ARF_A_ADDR        ;
           wire  [SDRAM_BANK_WIDTH-1:0]   ARF_BANK_ADDR     ;
           wire                           REF_DONE          ;
           wire                           ARF_req           ;
    //WR
           wire                           WR_req            ;
           wire                           WR_access         ;
           wire  [3:0]                    COMMAND_RD        ;
           wire  [SDRAM_ADDR_WIDTH-1:0]   RD_A_ADDR         ;
           wire  [SDRAM_BANK_WIDTH-1:0]   RD_BANK_ADDR      ;
           wire                           WR_data_done      ;
    //RD
           wire                           RD_req            ;
           wire                           RD_access         ;
           wire                           RD_DATA_DONE      ;
           wire  [3:0]                    COMMAND_WR        ;
           wire  [SDRAM_ADDR_WIDTH-1:0]   WR_A_ADDR         ;
           wire  [SDRAM_BANK_WIDTH-1:0]   WR_BANK_ADDR      ;
    //VGA
           wire                           VGA_START         ;
           wire                           VGA_FIFO_RD_EN    ;
           wire  [7:0]                    VGA_FIFO_RD_DATA  ;
           wire  [9:0]                    H_addr            ;
           wire  [9:0]                    V_addr            ;
    //break
           wire                           Break_WR_to_ARF   ;
           wire                           Break_RD_other    ;
//DQ
    assign  WR_avai   = (STATE == STATE_WE)?1'b1:1'b0;
    always@(posedge Sys_clk) begin
        READ_SDRAM_DQ <= SDRAM_DQ;
    end
    assign  SDRAM_DQ  = (WR_avai == 1'b1)?WR_SDRAM_DQ :16'dz;
    assign  SDRAM_DQM = 2'b00  ;
    assign  SDRAM_CKE = 1'b1   ;
    assign  SDRAM_CLK = Sys_clk;
//COMMAND
    assign  {SDRAM_CS_N,
             SDRAM_RAS_N,
             SDRAM_CAS_N,
             SDRAM_WE_N } = SDRAM_COMMAND_SEND;
    always@(*) begin
        if(STATE == STATE_INIT) begin
            SDRAM_COMMAND_SEND <= COMMAND_INIT  ;
            SDRAM_A_ADDR       <= INIT_A_ADDR   ;
            SDRAM_BANK_ADDR    <= INIT_BANK_ADDR;
        end else if(STATE == STATE_ARF) begin
            SDRAM_COMMAND_SEND <= COMMAND_REF   ;
            SDRAM_A_ADDR       <= ARF_A_ADDR    ;
            SDRAM_BANK_ADDR    <= ARF_BANK_ADDR ;
        end else if(STATE == STATE_WE) begin
            SDRAM_COMMAND_SEND <= COMMAND_WR    ;
            SDRAM_A_ADDR       <= WR_A_ADDR     ;
            SDRAM_BANK_ADDR    <= WR_BANK_ADDR  ;
        end else if(STATE == STATE_RD) begin
            SDRAM_COMMAND_SEND <= COMMAND_RD    ;
            SDRAM_A_ADDR       <= RD_A_ADDR     ;
            SDRAM_BANK_ADDR    <= RD_BANK_ADDR  ;
        end else begin
            SDRAM_COMMAND_SEND <= COMMAND_NOP   ;
            SDRAM_A_ADDR       <= 'd0           ;
            SDRAM_BANK_ADDR    <= 'd0           ;
        end
    end
    //access
    assign ARF_access = (STATE == STATE_ARB) && (ARF_req == 1'b1);
    assign WR_access  = (STATE == STATE_ARB) && (WR_req  == 1'b1) 
                     && (ARF_req == 1'b0);
    assign RD_access  = (STATE == STATE_ARB) && (RD_req  == 1'b1) 
                     && (WR_req  == 1'b0   ) && (ARF_req == 1'b0);
//-------------------STATE MAIN-----------------------//
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            STATE <= STATE_IDLE;
        end else begin
            case (STATE) //ARG > WR > RD
                STATE_IDLE: begin
                    STATE <= STATE_INIT;
                end
                STATE_INIT: begin
                    if(INIT_DONE == 'd1) begin
                        STATE <= STATE_ARB;
                    end else begin
                        STATE <= STATE_INIT;
                    end
                end
                STATE_ARB: begin
                    if(ARF_req == 1'b1) begin
                        STATE <= STATE_ARF;
                    end else if(WR_req == 1'b1 && ARF_req == 1'b0) begin
                        STATE <= STATE_WE;
                    end else if(RD_req == 1'b1 && WR_req == 1'b0 && ARF_req == 1'b0) begin
                        STATE <= STATE_RD;
                    end else begin
                        STATE <= STATE_ARB;
                    end
                end
                STATE_ARF: begin
                    if(REF_DONE == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else begin
                        STATE <= STATE_ARF;
                    end
                end
                STATE_WE: begin
                    if(Break_WR_to_ARF == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else if(WR_data_done == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else begin
                        STATE <= STATE_WE;
                    end
                end
                STATE_RD: begin
                    if(RD_DATA_DONE == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else if(Break_RD_other == 1'b1) begin
                        STATE <= STATE_ARB;
                    end else begin
                        STATE <= STATE_RD;
                    end
                end
                default: begin
                    STATE <= STATE_IDLE;
                end
            endcase
        end
    end
//-------------------STATE END------------------------//

/*-------------------instance begin---------------------------*/

/*-------------------instance end-----------------------------*/
endmodule

初始化:

        1.初始化只需要进行一次。

        2.不同SDRAM的初始化步骤大同小异。

module SDRAM_INIT(
    input   wire            Sys_clk       ,
    input   wire            Rst_n         ,
    output  reg     [ 3:0]  COMMAND_INIT  ,//COMMAND  = {CS_N,RAS_N,CAS_N,WE_N}
    output  reg     [11:0]  INIT_A_ADDR   ,
    output  reg     [ 1:0]  INIT_BANK_ADDR,
    output  reg             INIT_DONE
);
    `include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h"
    localparam TIME_TO_PRE   = TIME_WAIT_ABOVE_100US;
    localparam TIME_TO_ARF   = TIME_WAIT_ABOVE_100US + TIME_PRE_CHARGE;
    localparam TIME_TO_ARF_2 = TIME_WAIT_ABOVE_100US + TIME_PRE_CHARGE 
                             + TIME_Auto_refresh;
    localparam TIME_TO_MRS   = TIME_WAIT_ABOVE_100US + TIME_PRE_CHARGE 
                             + TIME_Auto_refresh + TIME_Auto_refresh;
    localparam INIT_END      = TIME_TO_MRS + TIME_MRS_done_wait     ;

            reg     [13:0]  INIT_CNT     ;
            reg             INIT_DONE_NOW;
            
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            INIT_DONE <= 'd0;
        end else if(INIT_CNT == INIT_END) begin
            INIT_DONE <= 'd1;
        end else begin
            INIT_DONE <= 'd0;
        end
    end
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            INIT_DONE_NOW <= 1'b0;
        end else if(INIT_CNT == INIT_END) begin
            INIT_DONE_NOW <= 1'b1;
        end else begin
            INIT_DONE_NOW <= INIT_DONE_NOW;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            INIT_CNT <= 'd0;
        end else if(INIT_DONE_NOW == 1'b0) begin
            if(INIT_CNT == INIT_END) begin
                INIT_CNT <= 'd0;
            end else begin
                INIT_CNT <= INIT_CNT + 1'b1;
            end
        end else begin
            INIT_CNT <= 'd0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_INIT   <= COMMAND_NOP;
            INIT_A_ADDR    <= 12'd0      ;
            INIT_BANK_ADDR <= 2'b00      ;
        end else begin
            case (INIT_CNT)
                TIME_TO_PRE: begin
                    COMMAND_INIT      <= COMMAND_PRE;
                    INIT_A_ADDR[10]   <= 1'b1;
                end
                TIME_TO_ARF: begin
                    COMMAND_INIT <= COMMAND_ARF;
                end
                TIME_TO_ARF_2: begin
                    COMMAND_INIT <= COMMAND_ARF;
                end
                TIME_TO_MRS: begin
                    COMMAND_INIT <= COMMAND_MRS;
                    INIT_A_ADDR       <= {
                        2'b00                   ,//A11 A10
                        INIT_OPMODE_Brust_Mode  ,//A9
                        INIT_OPMODE_STANDRD     ,//A8 A7
                        INIT_OPMODE_CL          ,//A6 A5 A4 ;CAS Latency ( 2 & 3 ) 
                        INIT_Burst_type         ,//A3 0:Sequential 1:Interleave          
                        INIT_OPMODE_Brust_Length //A2 A1 A0 ;Burst Length ( 1, 2, 4, 8 & full page )
                    };
                end
                default:begin
                    COMMAND_INIT   <= COMMAND_NOP;
                    INIT_A_ADDR    <= 12'd0      ;
                    INIT_BANK_ADDR <= 2'b00		;
                end
            endcase
        end
	end
endmodule

刷新: 

        64ms刷新/row_num 此处4096行,按理说应该是780个cycle一次。

        我改成了750cycle一次,留点余量。

module SDRAM_ARF #(

)(
    input   wire        Sys_clk,
    input   wire        Rst_n  ,
    //SDRAM
    input   wire            INIT_DONE     ,
    output  reg     [3:0]   COMMAND_REF   ,
    output  reg     [11:0]  ARF_A_ADDR    ,
    output  reg     [ 1:0]  ARF_BANK_ADDR ,
    output  reg             REF_DONE      ,
    output  reg             ARF_req       ,
    input   wire            ARF_access    
);
`include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h"
    localparam  TIME_ARF_BEGIN   = 1'b1                  ;
    // localparam  TIME_PRE_to_ARF  = 1'b1 + TIME_PRE_CHARGE;
    // localparam  TIME_ARF_to_done = 1'b1 + TIME_PRE_CHARGE + TIME_Auto_refresh;
    localparam  TIME_ARF_to_done = 'd9;
            reg  [9:0]  ARF_CNT    ;
            reg  [3:0]  COMMAND_CNT;
//ARF_CNT
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            ARF_req <= 'd0;
        end else if(ARF_access == 1'b1) begin
            ARF_req <= 1'b0;
        end else if(ARF_CNT == ARF_PERIOD) begin
            ARF_req <= 1'b1;
        end
    end
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            ARF_CNT <= 'd0;
        end else if(INIT_DONE == 1'b1) begin
            ARF_CNT <= 'd1;
        end else if(ARF_CNT == ARF_PERIOD) begin
            ARF_CNT <= 'd1;
        end else if(ARF_CNT > 'd0) begin
            ARF_CNT <= ARF_CNT + 1'd1;
        end else begin
            ARF_CNT <= ARF_CNT;
        end
    end
always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            REF_DONE <= 1'b0;
        end else if(COMMAND_CNT == TIME_ARF_to_done) begin
            REF_DONE <= 1'b1;
        end else begin
            REF_DONE <= 1'b0;
        end
    end
//COMMAND_CNT
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_CNT <= 'd0;
        end else if(ARF_access == 1'b1) begin
            COMMAND_CNT <= 'd1;
        end else if(COMMAND_CNT == TIME_ARF_to_done) begin
            COMMAND_CNT <= 'd0;
        end else if(COMMAND_CNT > 'd0) begin
            COMMAND_CNT <= COMMAND_CNT + 1'b1;
        end else begin
            COMMAND_CNT <= COMMAND_CNT;
        end
    end
//COMMAND
    always@(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_REF   <= COMMAND_NOP;
            ARF_A_ADDR    <= 12'd0      ;
            ARF_BANK_ADDR <= 2'b00      ;
        end else if(COMMAND_CNT == TIME_ARF_BEGIN) begin
            COMMAND_REF   <= COMMAND_ARF;
        end else begin
            COMMAND_REF   <= COMMAND_NOP;
            ARF_A_ADDR    <= 12'd0      ;
            ARF_BANK_ADDR <= 2'b00      ;
        end
    end
endmodule

写入:

        1.注意每一行结束以后要重新激活。

        2.写完了就不要继续req了。

        此处写请求产生条件:

//WR_req
    always @(posedge Sys_clk or negedge Rst_n) begin
    if(Rst_n == 'd0) begin
        WR_req <= 'd0;
    end else if(FIFO_RD_cnt >= 512 && STATE == STATE_WR_wait) begin
        WR_req <= 1'b1;
    end else if(Break_WR_to_ARF 
        && CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 
        && ((FIFO_RD_cnt >>2'd2) >= (SDRAM_COLS_MAX - CNT_SDRAM_COLS))) begin 
        WR_req <= 1'd1;
    end else if(Done_image == 1'b1 || WR_access == 1'b1 || STATE != STATE_WR_wait) begin
        WR_req <= 'd0;
    end else begin
        WR_req <= WR_req;
    end
end

        是由于我发现在最后一行的时候如果遭遇刷新时刻, 则会导致读不完的情况,但是直接使用打断标注来拉高读请求,又会出现读到FIFO为空的情况,设置某个具体的值的话,原定这个模块是通过串口来发送的,即使是115200速率,在SDRAM的写入速度下依然会出现跟不上的情况(根本不是一个量级),所以我使用了:

        “当前FIFO内可读取数据个数等于当前距离行满的列个数”来判别,其实是很合理的!

        Done_image    的拉低让多次传入图像成为了可能。

//SDRAM SIZE = 8192X512X16
  //8192ROWS 512COLS 16BITS
module SDRAM_WR #(
    parameter SDRAM_COLS_MAX  = 128,
    parameter IMAGE_NEED_ROW  = 300, //300 = 640*480*8/16*512 
    parameter TIME_PRE_CHARGE_long = 8
)(
    input   wire        Sys_clk,
    input   wire        Rst_n  ,
    //FIFO
    input   wire            FIFO_WR_EN   ,//8bits
    input   wire    [ 7:0]  FIFO_WR_data ,
    //SDRAM
    input   wire            INIT_DONE    ,
    output  reg     [ 3:0]  COMMAND_WR   ,
    output  reg     [11:0]  WR_A_ADDR    ,
    output  reg     [ 1:0]  WR_BANK_ADDR ,
    output  wire            WR_data_done ,
    output  reg             WR_req       ,
    input   wire            ARF_req      ,
    output  reg             Break_WR_to_ARF,
    input   wire            WR_access    ,
    output  wire    [15:0]  WRITE_SDRAM_DQ    
);
`include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h"
            localparam  STATE_IDLE      = 5'b0_0001;
            localparam  STATE_WR_wait   = 5'b0_0010;
            localparam  STATE_ACT       = 5'b0_0100;
            localparam  STATE_WR_NOW    = 5'b0_1000;
            localparam  STATE_Precharge = 5'b1_0000;
            reg     [ 4:0]       STATE         ;
            reg     [ 1:0]       CNT_ACT       ;
            reg     [ 9:0]       CNT_SDRAM_COLS;
            reg     [12:0]       CNT_SDRAM_ROWS;
            wire                 ROWS_END_Flag ;
            reg     [ 1:0]       CNT_Brust     ;
            reg     [ 3:0]       CNT_Precharge ;
            reg                  Done_image    ;
    //FIFO
            wire                 FIFO_FULL     ;
            wire                 FIFO_EMPTY    ;
            wire    [10:0]       FIFO_RD_cnt   ;
            reg                  FIFO_RD_EN    ;
            wire    [15:0]       FIFO_RD_DATA  ;
    assign WRITE_SDRAM_DQ = FIFO_RD_DATA;
//FIFO_RD_EN
always @(posedge Sys_clk or negedge Rst_n) begin
    if(Rst_n == 'd0) begin
        FIFO_RD_EN <= 'd0;
    end else if(STATE == STATE_WR_NOW) begin
        FIFO_RD_EN <= 1'b1;
    end else begin
        FIFO_RD_EN <= 'd0;
    end
end
//WR_req
    always @(posedge Sys_clk or negedge Rst_n) begin
    if(Rst_n == 'd0) begin
        WR_req <= 'd0;
    end else if(FIFO_RD_cnt >= 512 && STATE == STATE_WR_wait) begin
        WR_req <= 1'b1;
    end else if(Break_WR_to_ARF 
        && CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 
        && ((FIFO_RD_cnt >>2'd2) >= (SDRAM_COLS_MAX - CNT_SDRAM_COLS))) begin 
        WR_req <= 1'd1;
    end else if(Done_image == 1'b1 || WR_access == 1'b1 || STATE != STATE_WR_wait) begin
        WR_req <= 'd0;
    end else begin
        WR_req <= WR_req;
    end
end
//Done_image
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Done_image <= 'd0;
        end else if(STATE == STATE_WR_NOW
        && (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 )
        && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)    
        && (CNT_Brust == INIT_Burst_length -2'd2)) begin
            Done_image <= 1'b1;
        end else if(STATE == STATE_Precharge 
            && CNT_Precharge == TIME_PRE_CHARGE_long) begin
            Done_image <= 'd0;
        end else begin
            Done_image <= Done_image;
        end
    end
//WR_data_done
    assign WR_data_done = (STATE == STATE_Precharge 
        && CNT_Precharge == TIME_PRE_CHARGE_long 
        && Done_image == 1'b1);
//Break_WR_to_ARF
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Break_WR_to_ARF <= 'd0;
        end else if(STATE == STATE_Precharge 
        && CNT_Precharge == TIME_PRE_CHARGE_long 
        && Done_image == 1'b0) begin
            Break_WR_to_ARF <= 'd1;
        end else if(WR_req == 1'b1)begin
            Break_WR_to_ARF <= 'd0;
        end else begin
            Break_WR_to_ARF <= Break_WR_to_ARF;
        end
    end
//CNT_ACT
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_ACT <= 'd0;
        end else if(STATE == STATE_ACT) begin
            if(CNT_ACT == TIME_RCD) begin
                CNT_ACT <= 'd0; 
            end else begin
                CNT_ACT <= CNT_ACT + 1'b1;
            end
        end else begin
            CNT_ACT <= 'd0;
        end
    end
//CNT_Brust
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_Brust <= 'd0;
        end else if(STATE == STATE_WR_NOW) begin
            if(CNT_Brust == INIT_Burst_length -1'b1) begin
                CNT_Brust <= 'd0;
            end else begin
                CNT_Brust <= CNT_Brust + 1'b1;
            end
        end else begin
            CNT_Brust <= 'd0;
        end
    end
//CNT_SDRAM_ROWS
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_SDRAM_ROWS <= 'd0;
        end else if(STATE == STATE_WR_NOW) begin
            if (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 
            && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)
            && (CNT_Brust == INIT_Burst_length -1'b1)) begin
                CNT_SDRAM_ROWS <= 'd0;
            end else if((CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)
            && (CNT_Brust == INIT_Burst_length -1'b1)) begin
                CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS + 1'b1;
            end else begin
                CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS;
            end
        end else begin
            CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS;
        end
    end
//CNT_SDRAM_COLS
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_SDRAM_COLS <= 'd0;
        end else if(STATE == STATE_WR_NOW) begin
            if((CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) 
            && (CNT_Brust == INIT_Burst_length -1'b1)) begin
                CNT_SDRAM_COLS <= 'd0;
            end else if(CNT_Brust == INIT_Burst_length -1'b1) begin
                CNT_SDRAM_COLS <= CNT_SDRAM_COLS + 1'b1;
            end else begin
                CNT_SDRAM_COLS <= CNT_SDRAM_COLS;
            end
        end else begin
            CNT_SDRAM_COLS <= CNT_SDRAM_COLS;
        end
    end
assign ROWS_END_Flag  = (STATE == STATE_WR_NOW) && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) && (CNT_Brust == INIT_Burst_length -1'b1);
//CNT_Precharge
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_Precharge <= 'd0;
        end else if(STATE == STATE_Precharge && CNT_Precharge == TIME_PRE_CHARGE_long) begin
            CNT_Precharge <= 'd0;
        end else if(STATE == STATE_Precharge) begin
            CNT_Precharge <= CNT_Precharge + 1'b1;
        end else begin
            CNT_Precharge <= CNT_Precharge;
        end
    end
//COMMAND
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_WR   <= COMMAND_NOP;
            WR_A_ADDR    <= 12'd0      ;
            WR_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_WR_wait && WR_access == 1'b1) begin
            COMMAND_WR   <= COMMAND_ACT;
            WR_A_ADDR    <= CNT_SDRAM_ROWS;//row_addr
            WR_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_WR_NOW  && CNT_Brust  == 'd0) begin
            COMMAND_WR   <= COMMAND_WRITE;
            WR_A_ADDR    <= CNT_SDRAM_COLS<<2'd2;
            WR_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_Precharge && CNT_Precharge == 'd0) begin
            COMMAND_WR <= COMMAND_PRE;
            WR_A_ADDR[10]<= 1'b1       ;
            WR_BANK_ADDR <= 2'b00      ;
        end else begin
            COMMAND_WR   <= COMMAND_NOP;
            WR_A_ADDR    <= 12'd0      ;
            WR_BANK_ADDR <= 2'b00      ;
        end
    end
//STATE
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            STATE <= STATE_IDLE;
        end else begin
            case (STATE)
                STATE_IDLE: begin
                    if(INIT_DONE == 1'b1) begin
                        STATE <= STATE_WR_wait;
                    end else begin
                        STATE <= STATE_IDLE;
                    end
                end
                STATE_WR_wait: begin
                    if(WR_access == 1'b1) begin
                        STATE <= STATE_ACT;
                    end else begin
                        STATE <= STATE_WR_wait;
                    end
                end
                STATE_ACT: begin
                    if(ARF_req == 1'b1 && CNT_ACT == TIME_RCD) begin
                        STATE <= STATE_Precharge;
                    end else if(CNT_ACT == TIME_RCD) begin
                        STATE <= STATE_WR_NOW;
                    end else begin
                        STATE <= STATE_ACT;
                    end
                end
                STATE_WR_NOW:begin
                    if(ARF_req == 1'b1 && CNT_Brust == INIT_Burst_length - 1'b1) begin
                        STATE <= STATE_Precharge;
                    end else if(ROWS_END_Flag == 1'b1) begin
                        STATE <= STATE_Precharge;
                    end else if(Done_image == 1'b1) begin
                        STATE <= STATE_Precharge;
                    end else begin
                        STATE <= STATE_WR_NOW;
                    end
                end
                STATE_Precharge: begin
                    if(CNT_Precharge == TIME_PRE_CHARGE_long) begin
                        STATE <= STATE_WR_wait;
                    end else begin
                        STATE <=  STATE_Precharge;
                    end
                end
                default: begin
                    STATE <= STATE_IDLE;
                end
            endcase
        end
    end
/*------------------------------------------------------------------------*/
AS_FIFO_w2048x8_r1024x16 INST0_AS_FIFO_w2048x8_r1024x16 (
  .wr_clk       ( Sys_clk       ), // input wr_clk
  .rd_clk       ( Sys_clk       ), // input rd_clk
  .din          ( FIFO_WR_data  ), // input [7 : 0] din
  .wr_en        ( FIFO_WR_EN    ), // input wr_en
  .rd_en        ( FIFO_RD_EN    ), // input rd_en
  .dout         ( FIFO_RD_DATA  ), // output [15 : 0] dout
  .full         ( FIFO_FULL     ), // output full
  .empty        ( FIFO_EMPTY    ), // output empty
  .rd_data_count( FIFO_RD_cnt   )  // output [9 : 0] rd_data_count
  /*------------------------------------------------------------------------*/
);
endmodule

读取:

SDRAM读写时序介绍(配时序图) - 知乎 (zhihu.com)

        读命令从输入信号BA0、BA1中选取要进行读数据操作的BANK,并在已激活的行中进行突发读操作。输入的A0-A7用来进行列寻址。在选定列地址后,就已经确定了具体的存储单元,剩下的事情就是数据通过数据I/O通道(DQ)输出到内存总线上了。但是在CAS (列地址选通脉冲)发出之后,仍要经过一定的时间才能有数据输出,从CAS与读取命令发出到第一个数据输出的这段时间,被定义为CL(CAS Latency,CAS潜伏期)。由于CL只在读取时出现,所以CL又被称为读取潜伏期(RL,ReadLatency)。CL的单位与tRCD一样,为时钟周期数,具体耗时由时钟频率决定。CAS并不是在经过CL 周期之后才送达存储单元。实际上CAS与RAS一样是瞬间到达的,但CAS的响应时间要更快一些。下图展示了CAS=3时的读时序:

图4 CAS Latency=3的示意图

        由于存储体中晶体管存在反应时间,从而造成数据不可能与CAS在同一上升沿触发,因此要延后至少一个时钟周期。考虑到芯片体积较小的因素,存储单元中的电容容量很小,所以信号要经过放大来保证其有效的识别性,这个放大/驱动工作由S-AMP负责,一个存储体对应一个S-AMP通道。但它要有一个准备时间才能保证信号的发送强度(事前还要进行电压比较以进行逻辑电平的判断),因此从数据I/O总线上有数据输出之前的一个时钟上升沿开始,数据即已传向S-AMP,也就是说此时数据已经被触发,经过一定的驱动时间最终传向数据I/O 总线进行输出,这段时间我们称之为tAC(Access-Time-from-CLK,时钟触发后的访问时间),单位是ns。在突发读操作完成后,如果选择了自动预充电模式,那么该行就会直接进入充电。如果没有选择此模式,那么该行将保持打开状态,供后续访问。自动预充电模式的选择与A10的值有关,A10为高时为自动预充电命令模式。

读取:

         小总结:列选通时间

         CAS Latency=3的时候,可以视为RD_COMMAND发出后的第四个时钟周期才有数据浮现在端口上。(中间隔了三个时钟周期)

        为此:FIFO_WR_EN 可以用RD_COMMAND产生的那个时刻延四拍得到(包括其本身的一个周期+中间隔了三个时钟周期)。

        其实三拍也行,用ASSIGN存输入数据就行,但是会看到更多高阻态,很不好。

//FIFO_WR_EN INIT_CAS_Latency = 3
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            FIFO_WR_EN <= 'd0;
        end else if(STATE == STATE_RD_NOW) begin
            FIFO_WR_EN <= 1'b1;
        end else begin
            FIFO_WR_EN <= 'd0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
    if(Rst_n == 'd0) begin
        FIFO_WR_delay <= 'd0;
    end else begin
        FIFO_WR_delay <= {FIFO_WR_delay[2:0],FIFO_WR_EN};
    end
end

        因为是预备传图640x480的SDRAM,每次打算使用SDRAM读出一行数据进FIFO,再由FIFO发给VGA控制器显示数据,所以定义一个能放得下相应数据的FIFO。

        SDRAM_RD的时序和WR时序差不多,唯一要注意的只有上面提过的列选通时间。

此外:这里PRE命令的发出时间点纯粹是因为我喜欢,

        如果感兴趣为什么在这个时间点才发送可以仿真试试看。

                (其实是不影响整体的,但是会好看一些哦)

//COMMAND
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_RD   <= COMMAND_NOP;
            RD_A_ADDR    <= 12'd0      ;
            RD_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_RD_WAIT && RD_access == 1'b1) begin
            COMMAND_RD   <= COMMAND_ACT;
            RD_A_ADDR    <= CNT_SDRAM_ROWS;//row_addr
            RD_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_RD_NOW  && CNT_Brust  == 'd0 && ROWS_END_Flag == 'd0) begin
            COMMAND_RD   <= COMMAND_READ;
            RD_A_ADDR    <= CNT_SDRAM_COLS<<2'd2;
            RD_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_Precharge && CNT_Precharge == 'd2) begin
            COMMAND_RD <= COMMAND_PRE;
            RD_A_ADDR[10]<= 1'b1       ;
            RD_BANK_ADDR <= 2'b00      ;
        end else begin
            COMMAND_RD   <= COMMAND_NOP;
            RD_A_ADDR    <= 12'd0      ;
            RD_BANK_ADDR <= 2'b00      ;
        end
    end

        

//SDRAM SIZE = 8192X512X16
  //8192ROWS 512COLS 16BITS
module SDRAM_RD #(
    parameter SDRAM_COLS_MAX  = 128,
    parameter IMAGE_NEED_ROW  = 300, //300 = 640*480*8/16*512 
    parameter TIME_PRE_CHARGE_long = 10
)(
    input   wire        Sys_clk,
    input   wire        Rst_n  ,
    //VGA 640x480x60hz
    input   wire            VGA_CLOCK       ,
    output  reg             VGA_START       ,
    //FIFO
    input   wire            VGA_FIFO_RD_EN  ,
    output  wire    [ 7:0]  VGA_FIFO_RD_DATA,
    //CTRL 
    input   wire            WR_data_done    ,
    //SDRAM
    input   wire            INIT_DONE       ,
    output  reg     [ 3:0]  COMMAND_RD      ,
    output  reg     [11:0]  RD_A_ADDR       ,
    output  reg     [ 1:0]  RD_BANK_ADDR    ,
    output  wire            RD_DATA_DONE    ,
    output  reg             RD_req          ,
    input   wire            WR_req          ,
    input   wire            ARF_req         ,
    output  reg             Break_RD_other  ,
    input   wire            RD_access       ,
    input   wire    [15:0]  READ_SDRAM_DQ    
);
`include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h"
            localparam  STATE_IDLE      = 5'b0_0001;
            localparam  STATE_RD_WAIT   = 5'b0_0010;
            localparam  STATE_ACT       = 5'b0_0100;
            localparam  STATE_RD_NOW    = 5'b0_1000;
            localparam  STATE_Precharge = 5'b1_0000;
            reg     [ 4:0]       STATE         ;
            reg     [ 1:0]       CNT_ACT       ;
            reg     [ 9:0]       CNT_SDRAM_COLS;
            reg     [12:0]       CNT_SDRAM_ROWS;
            wire                 ROWS_END_Flag ;
            reg     [ 1:0]       CNT_Brust     ;
            reg     [ 3:0]       CNT_Precharge ;
            reg                  Done_image    ;
    //FIFO
            wire                 FIFO_FULL     ;
            wire                 FIFO_EMPTY    ;
            wire    [11:0]       FIFO_RD_cnt   ;
            wire    [10:0]       FIFO_WR_cnt   ;
            wire    [15:0]       FIFO_WR_data  ;
            reg                  FIFO_WR_EN    ;
            reg     [ 3:0]       FIFO_WR_delay ;
    //SIM
            reg                  Time_to_Read  ;
    assign FIFO_WR_data = READ_SDRAM_DQ;
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Time_to_Read <= 'd0;
        end else if(WR_data_done == 'd1) begin
            Time_to_Read <= 'd1;
        end else begin
            Time_to_Read <= Time_to_Read;
        end
    end
//FIFO_WR_EN INIT_CAS_Latency = 3
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            FIFO_WR_EN <= 'd0;
        end else if(STATE == STATE_RD_NOW) begin
            FIFO_WR_EN <= 1'b1;
        end else begin
            FIFO_WR_EN <= 'd0;
        end
    end
    always @(posedge Sys_clk or negedge Rst_n) begin
    if(Rst_n == 'd0) begin
        FIFO_WR_delay <= 'd0;
    end else begin
        FIFO_WR_delay <= {FIFO_WR_delay[2:0],FIFO_WR_EN};
    end
end
//VGA_START
    always @(posedge VGA_CLOCK) begin
        if(Rst_n == 'd0) begin
            VGA_START <= 'd0;
        end else if(FIFO_RD_cnt >= 'd640) begin
            VGA_START <= 'd1;
        end else begin
            VGA_START <= VGA_START;
        end
     end
//RD_req:FIFO_WR_cnt <= 'd320时,从SDRAM读取数据给FIFO
    //640x480 一行为640x8bits数据 
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            RD_req <= 'd0;
        end else if(FIFO_WR_cnt <= 'd512 
                && STATE == STATE_RD_WAIT
                && Time_to_Read ==1
                && Done_image == 'd0) begin
            RD_req <= 1'b1;
        end else if(Break_RD_other == 1'b1 
                && STATE == STATE_RD_WAIT
                && FIFO_WR_cnt <= 'd512) begin 
            RD_req <= 1'd1;
        end else if(Done_image == 1'b1 || RD_access == 1'b1 || STATE != STATE_RD_WAIT) begin
            RD_req <= 'd0;
        end else begin
            RD_req <= RD_req;
        end
    end
//Done_image
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Done_image <= 'd0;
        end else if(STATE == STATE_RD_NOW
        && (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 )
        && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)    
        && (CNT_Brust == INIT_Burst_length -2'd2)) begin
            Done_image <= 1'b1;
        end else if(STATE == STATE_Precharge 
            && CNT_Precharge == TIME_PRE_CHARGE_long) begin
            Done_image <= 'd0;
        end else begin
            Done_image <= Done_image;
        end
    end
//RD_DATA_DONE
    assign RD_DATA_DONE = (STATE == STATE_Precharge 
        && CNT_Precharge == TIME_PRE_CHARGE_long 
        && Done_image == 1'b1);
//Break_RD_other
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            Break_RD_other <= 'd0;
        end else if(STATE == STATE_Precharge 
        && CNT_Precharge == TIME_PRE_CHARGE_long 
        && Done_image == 1'b0) begin
            Break_RD_other <= 'd1;
        end else if(RD_req == 1'b1)begin
            Break_RD_other <= 'd0;
        end else begin
            Break_RD_other <= Break_RD_other;
        end
    end
//CNT_ACT
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_ACT <= 'd0;
        end else if(STATE == STATE_ACT) begin
            if(CNT_ACT == TIME_RCD) begin
                CNT_ACT <= 'd0; 
            end else begin
                CNT_ACT <= CNT_ACT + 1'b1;
            end
        end else begin
            CNT_ACT <= 'd0;
        end
    end
//CNT_Brust
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_Brust <= 'd0;
        end else if(STATE == STATE_RD_NOW) begin
            if(CNT_Brust == INIT_Burst_length -1'b1) begin
                CNT_Brust <= 'd0;
            end else begin
                CNT_Brust <= CNT_Brust + 1'b1;
            end
        end else begin
            CNT_Brust <= 'd0;
        end
    end
//CNT_SDRAM_ROWS
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_SDRAM_ROWS <= 'd0;
        end else if(STATE == STATE_RD_NOW) begin
            if (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 
            && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)
            && (CNT_Brust == INIT_Burst_length -1'b1)) begin
                CNT_SDRAM_ROWS <= 'd0;
            end else if((CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1)
                     && (CNT_Brust == INIT_Burst_length -1'b1)) begin
                CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS + 1'b1;
            end else begin
                CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS;
            end
        end else begin
            CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS;
        end
    end
//CNT_SDRAM_COLS
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_SDRAM_COLS <= 'd0;
        end else if(STATE == STATE_RD_NOW) begin
            if((CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) 
            && (CNT_Brust == INIT_Burst_length -1'b1)) begin
                CNT_SDRAM_COLS <= 'd0;
            end else if(CNT_Brust == INIT_Burst_length -1'b1) begin
                CNT_SDRAM_COLS <= CNT_SDRAM_COLS + 1'b1;
            end else begin
                CNT_SDRAM_COLS <= CNT_SDRAM_COLS;
            end
        end else begin
            CNT_SDRAM_COLS <= CNT_SDRAM_COLS;
        end
    end
assign ROWS_END_Flag  = (STATE == STATE_RD_NOW) 
    && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) 
    && (CNT_Brust == INIT_Burst_length -1'b1);
//CNT_Precharge
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            CNT_Precharge <= 'd0;
        end else if(STATE == STATE_Precharge && CNT_Precharge == TIME_PRE_CHARGE_long) begin
            CNT_Precharge <= 'd0;
        end else if(STATE == STATE_Precharge) begin
            CNT_Precharge <= CNT_Precharge + 1'b1;
        end else begin
            CNT_Precharge <= CNT_Precharge;
        end
    end
//COMMAND
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            COMMAND_RD   <= COMMAND_NOP;
            RD_A_ADDR    <= 12'd0      ;
            RD_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_RD_WAIT && RD_access == 1'b1) begin
            COMMAND_RD   <= COMMAND_ACT;
            RD_A_ADDR    <= CNT_SDRAM_ROWS;//row_addr
            RD_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_RD_NOW  && CNT_Brust  == 'd0 && ROWS_END_Flag == 'd0) begin
            COMMAND_RD   <= COMMAND_READ;
            RD_A_ADDR    <= CNT_SDRAM_COLS<<2'd2;
            RD_BANK_ADDR <= 2'b00      ;
        end else if(STATE == STATE_Precharge && CNT_Precharge == 'd2) begin
            COMMAND_RD <= COMMAND_PRE;
            RD_A_ADDR[10]<= 1'b1       ;
            RD_BANK_ADDR <= 2'b00      ;
        end else begin
            COMMAND_RD   <= COMMAND_NOP;
            RD_A_ADDR    <= 12'd0      ;
            RD_BANK_ADDR <= 2'b00      ;
        end
    end
//STATE
    always @(posedge Sys_clk or negedge Rst_n) begin
        if(Rst_n == 'd0) begin
            STATE <= STATE_IDLE;
        end else begin
            case (STATE)
                STATE_IDLE: begin
                    if(INIT_DONE == 1'b1) begin
                        STATE <= STATE_RD_WAIT;
                    end else begin
                        STATE <= STATE_IDLE;
                    end
                end
                STATE_RD_WAIT: begin
                    if(RD_access == 1'b1) begin
                        STATE <= STATE_ACT;
                    end else begin
                        STATE <= STATE_RD_WAIT;
                    end
                end
                STATE_ACT: begin
                    if((ARF_req == 1'b1 || WR_req == 1'b1) && CNT_ACT == TIME_RCD) begin
                        STATE <= STATE_Precharge;
                    end else if(CNT_ACT == TIME_RCD) begin
                        STATE <= STATE_RD_NOW;
                    end else begin
                        STATE <= STATE_ACT;
                    end
                end
                STATE_RD_NOW:begin
                    if((ARF_req == 1'b1 || WR_req == 1'b1) 
                    && CNT_Brust == INIT_Burst_length - 1'b1) begin
                        STATE <= STATE_Precharge;
                    end else if(ROWS_END_Flag == 1'b1) begin
                        STATE <= STATE_Precharge;
                    end else if(Done_image == 1'b1) begin
                        STATE <= STATE_Precharge;
                    end else begin
                        STATE <= STATE_RD_NOW;
                    end
                end
                STATE_Precharge: begin
                    if(CNT_Precharge == TIME_PRE_CHARGE_long) begin
                        STATE <= STATE_RD_WAIT;
                    end else begin
                        STATE <=  STATE_Precharge;
                    end
                end
                default: begin
                    STATE <= STATE_IDLE;
                end
            endcase
        end
    end
/*------------------------------------------------------------------------*/
AS_FIFO_w2048x16_r4096x8 Inst_AS_FIFO_w2048x16_r4096x8 (
  .wr_clk       ( Sys_clk         ), // input wr_clk
  .rd_clk       ( VGA_CLOCK       ), // input rd_clk
  .din          ( FIFO_WR_data    ), // input [15 : 0] din
  .wr_en        ( FIFO_WR_delay[3]), // input wr_en
  .rd_en        ( VGA_FIFO_RD_EN  ), // input rd_en
  .dout         ( VGA_FIFO_RD_DATA), // output [7 : 0] dout
  .full         ( FIFO_FULL       ), // output full
  .empty        ( FIFO_EMPTY      ), // output empty
  .rd_data_count( FIFO_RD_cnt     ), // output [11 : 0] rd_data_count
  .wr_data_count( FIFO_WR_cnt     )  // output [10 : 0] wr_data_count
);
/*------------------------------------------------------------------------*/
endmodule

串口传图的VGA部分可由 串口传图并图像处理(sobel)的简单实现_串口图像传输_NoNoUnknow的博客-CSDN博客

取得,展示视频:

想起来再拍。

参考资料:

[1]威三学院FPGA教程

[2]小梅哥AC620V2教程

[3]SDRAM读写时序介绍(配时序图) - 知乎 (zhihu.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值