串口传图写进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教程