整体架构设计
代码模块分析
总体分析
cmos 摄像头配置模块
iic 进行发数据或者读数据,此处为读数据/分频
capture 采集数据模块
rgb2gray 灰度转化(0~255)___彩色信息多,灰度化有助于提高运算速度
gauss_filter 高斯滤波器___线性平滑滤波,降低高斯噪音,即服从正太分布的噪声,图像去噪
gray2bin 二值化(0或1)__防止在灰度处理后信息还是过多
sobel 基于一阶导数的边缘检测算子/离散性差分算子__运算图像亮度函数的灰度近似值
sdram_ctrl 数据缓存__含乒乓操作、读写异步fifo (fifo的ram的内存太小故使用sdram
vga_interface 显示__含buf缓存
顶层代码
设计总流程
-
在上电等待20ms后,利用IIC协议进行摄像头的配置,
配置完252个寄存器后,会输出一个配置完成有效信号给摄像头采集模块 capture; -
capture接收摄像头配置完成的信号,当场同步信号拉低后,且行参考信号有效时进行数据的采集。但是摄像头的数据是把16位RGB拆分为高八位和低八位发送的,我们需要通过移位+位拼接的方式把两个8bit数据合并成16bit数据输出,同时为了SDRAM模块更好的识别帧头和帧尾,
在图像的第一个像素点以及最后一个像素点的时候分别拉高sop和eop信号,其余像素点拉低。 -
数据处理:包括图像的灰度转化、高斯滤波、二值化,和Sobel边沿检测等。
-
sdram读写操作:主要⽤于控制数据流,使显⽰屏帧与帧之间切换瞬间完成。
-
显示(vga):利用VGA接口将数据显示到显示屏上。
module top(
input clk ,
input rst_n ,
//摄像头接口
input cmos_vsync ,
input cmos_pclk ,
input cmos_href ,
input [7:0] cmos_din ,
output cmos_xclk ,
output cmos_pwdn ,
output cmos_reset ,
output cmos_scl ,
inout cmos_sda ,
//sdram
output sdram_clk ,
output sdram_cke ,
output sdram_csn ,
output sdram_rasn ,
output sdram_casn ,
output sdram_wen ,
output [1:0] sdram_bank ,
output [12:0] sdram_addr ,
inout [15:0] sdram_dq ,
output [1:0] sdram_dqm ,
output [15:0] vga_rgb ,
output vga_hsync ,
output vga_vsync
);
//信号定义
wire cfg_done ;
wire clk_cmos ;
wire [15:0] pixel ;
wire pixel_vld ;
wire pixel_sop ;
wire pixel_eop ;
wire mem_din_sop ;
wire mem_din_eop ;
wire mem_din_vld ;
wire [15:0] mem_din ;
wire clk_100m ;
wire clk_100m_s ;
wire clk_vga ;
wire pclk ;
wire rd_req ;
wire [15:0] dout ;
wire dout_vld ;
wire sys_rst_n ;
assign sys_rst_n = rst_n & cfg_done;
assign cmos_xclk = clk_cmos;
assign sdram_clk = clk_100m_s;
//模块例化
pll0 u_pll0(
.areset (~rst_n ),
.inclk0 (clk ),
.c0 (clk_cmos ),
.c1 (clk_vga )
);
pll1 u_pll1(
.areset (~rst_n ),
.inclk0 (clk ),
.c0 (clk_100m ),
.c1 (clk_100m_s ),
.locked ()
);
iobuf u_iobuf(//io端口为直接连接FPGA与外部芯片
.datain (cmos_pclk ),
.dataout (pclk )
);
cmos_top u_cmos(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*output */.scl (cmos_scl ),
/*inout */.sda (cmos_sda ),
/*output */.pwdn (cmos_pwdn ),
/*output */.reset (cmos_reset),
/*output */.cfg_done(cfg_done )
);
capture u_capture(
/*input */.clk (pclk ),
/*input */.rst_n (rst_n ),
/*input */.vsync (cmos_vsync),
/*input */.href (cmos_href ),
/*input [7:0] */.din (cmos_din ),
/*input */.enable (cfg_done ),
/*output [15:0] */.dout (pixel ),
/*output */.dout_vld(pixel_vld ),
/*output */.dout_sop(pixel_sop ),
/*output */.dout_eop(pixel_eop )
);
`ifdef ENABLE_IMAG_PROCESS
wire ip_dout_sop ;
wire ip_dout_eop ;
wire ip_dout_vld ;
wire [15:0] ip_dout ;
imag_process u_ip(
/*input */.clk (pclk ),
/*input */.rst_n (rst_n ),
/*input */.din_sop (pixel_sop ),
/*input */.din_eop (pixel_eop ),
/*input */.din_vld (pixel_vld ),
/*input [15:0] */.din (pixel ),//RGB565
/*output */.dout_sop (ip_dout_sop ),
/*output */.dout_eop (ip_dout_eop ),
/*output */.dout_vld (ip_dout_vld ),
/*output [15:0] */.dout (ip_dout )
);
assign mem_din = ip_dout ;
assign mem_din_vld = ip_dout_vld;
assign mem_din_sop = ip_dout_sop;
assign mem_din_eop = ip_dout_eop;
`else
assign mem_din = pixel ;
assign mem_din_vld = pixel_vld;
assign mem_din_sop = pixel_sop;
assign mem_din_eop = pixel_eop;
`endif
sdram_controller u_mem_controller(
/*input */.clk (clk_100m ),//100M 控制器主时钟
/*input */.clk_in (pclk ),//数据输入时钟
/*input */.clk_out (clk_vga ),//数据输出时钟 75m
/*input */.rst_n (rst_n ),
/*input [15:0] */.din (mem_din ),
/*input */.din_vld (mem_din_vld ),
/*input */.din_sop (mem_din_sop ),
/*input */.din_eop (mem_din_eop ),
/*input */.rd_req (rd_req ),//读请求
/*output [15:0] */.dout (dout ),//
/*output */.dout_vld(dout_vld ),
//sdram接口
/*output */.cke (sdram_cke ),
/*output */.csn (sdram_csn ),
/*output */.rasn (sdram_rasn ),
/*output */.casn (sdram_casn ),
/*output */.wen (sdram_wen ),
/*output [1:0] */.bank (sdram_bank ),
/*output [12:0] */.addr (sdram_addr ),
/*inout [15:0] */.dq (sdram_dq ),
/*output [1:0] */.dqm (sdram_dqm )
);
vga_interface u_vga(
/*input */.clk (clk_vga ),
/*input */.rst_n (sys_rst_n ),
/*input [15:0] */.din (dout ),
/*input */.din_vld (dout_vld ),
/*output */.rdy (rd_req ),
/*output [15:0] */.vga_rgb (vga_rgb ),
/*output */.vga_hsync(vga_hsync ),
/*output */.vga_vsync(vga_vsync )
);
endmodule
摄像头配置代码
- 利用IIC协议来写摄像头的控制模块,采用状态机加计数器的方式来设计配置模块;
- 当上电之后计数20ms,之后就可以进行摄像头的配置,有一个配置完成信号config_flag,
- 当配置完252个寄存器后,配置信号有效。
- 配置模块主要就是通过IIC_master模块向摄像头里面写入数据,完成配置。
- 发送数据是以任务的方式发请求、命令和数据。
module cmos_top(
input clk ,
input rst_n ,
output scl ,
inout sda ,
output pwdn ,
output reset ,
output cfg_done
);
//信号定义
wire req ;
wire [3:0] cmd ;
wire done ;
wire [7:0] dout ;
wire i2c_scl ;
wire i2c_sda_i ;
wire i2c_sda_o ;
wire i2c_sda_oe ;
//模块例化
cmos_config u_cfg(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
//i2c_master
/*output */.req (req ),
/*output [3:0] */.cmd (cmd ),
/*output [7:0] */.dout (dout ),
/*input */.done (done ),
/*output */.config_done (cfg_done )
);
i2c_master u_i2c(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input */.req (req ),
/*input [3:0] */.cmd (cmd ),
/*input [7:0] */.din (dout ),
/*output [7:0] */.dout ( ),
/*output */.done (done ),
/*output */.slave_ack ( ),
/*output */.i2c_scl (scl ),
/*input */.i2c_sda_i (i2c_sda_i ),
/*output */.i2c_sda_o (i2c_sda_o ),
/*output */.i2c_sda_oe (i2c_sda_oe)
);
assign i2c_sda_i = sda;
assign sda = i2c_sda_oe?i2c_sda_o:1'bz;
assign pwdn = 1'b0;
assign reset = 1'b1;
endmodule
图片处理代码
`include"param.v"
module imag_process(
input clk ,
input rst_n ,
input din_sop ,
input din_eop ,
input din_vld ,
input [15:0] din ,//RGB565
output dout_sop ,
output dout_eop ,
output dout_vld ,
output [15:0] dout
);
//信号定义
wire gray_sop ;
wire gray_eop ;
wire gray_vld ;
wire [7:0] gray ;
wire gray_din_sop;
wire gray_din_eop;
wire gray_din_vld;
wire [7:0] gray_din ;
wire binary_sop ;
wire binary_eop ;
wire binary_vld ;
wire binary ;
wire sobel ;
wire sobel_sop ;
wire sobel_eop ;
wire sobel_vld ;
//模块例化
//灰度化
rgb2gray u_gray(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input */.din_sop (din_sop ),
/*input */.din_eop (din_eop ),
/*input */.din_vld (din_vld ),
/*input [15:0] */.din (din ),//RGB565
/*output */.dout_sop (gray_sop ),
/*output */.dout_eop (gray_eop ),
/*output */.dout_vld (gray_vld ),
/*output [7:0] */.dout (gray ) //灰度输出
);
`ifdef ENABLE_GAUSS //高斯
wire gs_dout_sop ;
wire gs_dout_eop ;
wire gs_dout_vld ;
wire [7:0] gs_dout ;
//高斯平滑处理
gauss_filter u_guass(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input */.din_sop (gray_sop ),
/*input */.din_eop (gray_eop ),
/*input */.din_vld (gray_vld ),
/*input [7:0] */.din (gray ),//灰度输入
/*output */.dout_sop (gs_dout_sop ),
/*output */.dout_eop (gs_dout_eop ),
/*output */.dout_vld (gs_dout_vld ),
/*output [7:0] */.dout (gs_dout ) //灰度输出
);
assign gray_din_sop = gs_dout_sop ;
assign gray_din_eop = gs_dout_eop ;
assign gray_din_vld = gs_dout_vld ;
assign gray_din = gs_dout ;
`else
assign gray_din_sop = gray_sop ;
assign gray_din_eop = gray_eop ;
assign gray_din_vld = gray_vld ;
assign gray_din = gray ;
`endif
//二值化使图像明暗不明显部分丢失,最后在做边缘检测时显现的图像失真严重
gray2bin u_bin(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input */.din_sop (gray_din_sop ),
/*input */.din_eop (gray_din_eop ),
/*input */.din_vld (gray_din_vld ),
/*input [7:0] */.din (gray_din ),//灰度输入
/*output */.dout_sop (binary_sop ),
/*output */.dout_eop (binary_eop ),
/*output */.dout_vld (binary_vld ),
/*output */.dout (binary ) //二值输出
);
sobel u_sobel(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input */.din (binary ),//binary 输入二值图像
/*input */.din_sop (binary_sop ),//binary_sop
/*input */.din_eop (binary_eop ),//binary_eop
/*input */.din_vld (binary_vld ),//binary_vld
/*output */.dout (sobel ),
/*output */.dout_sop(sobel_sop ),
/*output */.dout_eop(sobel_eop ),
/*output */.dout_vld(sobel_vld )
);
assign dout_sop = sobel_sop;
assign dout_eop = sobel_eop;
assign dout_vld = sobel_vld;
assign dout = {16{sobel}};
endmodule
vga代码
`include "param.v"
/****************************************************
vga显示
设计思路
1. 计数器来设计行有效与场有效区域
2. 在行场有效显示区域进行输出数据
3. 用一个fifo来缓存数据
****************************************************/
module vga_interface ( //1280*720
input clk ,//75MHz
input rst_n ,
input [15:0] din ,
input din_vld ,
output rdy ,
output [15:0] vga_rgb ,
output vga_hsync,
output vga_vsync
);
//信号定义
reg [10:0] cnt_h ;
wire add_cnt_h ;
wire end_cnt_h ;
reg [9:0] cnt_v ;
wire add_cnt_v ;
wire end_cnt_v ;
reg h_vld ;
reg v_vld ;
reg hsync ;
reg vsync ;
reg rd_req ;
wire rdreq ;
wire wrreq ;
wire empty ;
wire full ;
wire [15:0] q_out ;
wire [3:0] usedw ;
//计数器
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
cnt_h <= 0;
end
else if(add_cnt_h) begin
if(end_cnt_h)
cnt_h <= 0;
else
cnt_h <= cnt_h+1 ;
end
end
assign add_cnt_h = 1;
assign end_cnt_h = add_cnt_h && cnt_h == `H_TP-1 ;
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
cnt_v <= 0;
end
else if(add_cnt_v) begin
if(end_cnt_v)
cnt_v <= 0;
else
cnt_v <= cnt_v+1 ;
end
end
assign add_cnt_v = end_cnt_h;
assign end_cnt_v = add_cnt_v && cnt_v == `V_TP-1 ;
//h_vld
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
h_vld <= 1'b0;
end
else if(cnt_h == `H_START-1)begin
h_vld <= 1'b1;
end
else if(cnt_h == `H_END-1)begin
h_vld <= 1'b0;
end
end
//v_vld
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
v_vld <= 1'b0;
end
else if(end_cnt_h && cnt_v == `V_START)begin
v_vld <= 1'b1;
end
else if(end_cnt_h && cnt_v == `V_END)begin
v_vld <= 1'b0;
end
end
//rd_req
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
rd_req <= 1'b0;
end
else if(usedw <= 4)begin
rd_req <= 1'b1;
end
else if(usedw >= 12)begin
rd_req <= 1'b0;
end
end
//hsync
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
hsync <= 0;
end
else if(add_cnt_h && cnt_h == `H_SW-1)begin
hsync <= 1'b1;
end
else if(add_cnt_h && cnt_h == `H_TP-1)begin
hsync <= 1'b0;
end
end
//vsync
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
vsync <= 1'b0;
end
else if(add_cnt_v && cnt_v == `V_SW-1)begin
vsync <= 1'b1;
end
else if(add_cnt_v && cnt_v == `V_TP-1)begin
vsync <= 1'b0;
end
end
//FIFO例化
vga_buf u_buf(
.aclr (~rst_n ),
.clock (clk ),
.data (din ),
.rdreq (rdreq ),
.wrreq (wrreq ),
.empty (empty ),
.full (full ),
.q (q_out ),
.usedw (usedw )
);
assign wrreq = ~full && din_vld;
assign rdreq = ~empty && h_vld && v_vld;
//输出
assign rdy = rd_req;
assign vga_rgb = (h_vld & v_vld)?q_out:0;
assign vga_hsync = hsync;
assign vga_vsync = vsync;
endmodule
sdram代码
`include"param.v"
/****************************************************
SDRAM接口模块直接调用IP核,写一个控制模块
用来向SDRAM里卖弄突发写或者突发读,
由于涉及到跨时钟域的数据传输,
从摄像头采集到的数据写到SDRAM里面是慢时钟域到快时钟域,
从SDRAM里面读取数据显示到屏幕上是快时钟域到慢时钟域。
因此设计了两个异步FIFO用来缓存数据。
****************************************************/
module sdram_ctrl (
input clk ,
input clk_in ,
input clk_out ,
input rst_n ,
//数据输入
input [15:0] din ,//摄像头输入像素数据
input din_sop ,
input din_eop ,
input din_vld ,
//数据输出
input rdreq ,//vga的读数据请求
output [15:0] dout ,//输出给vga的数据
output dout_vld ,//输出给vga的数据有效标志
//sdram_interface
output avm_write ,//输出给sdram 接口 IP 的写请求
output avm_read ,//输出给sdram 接口 IP 的读请求
output [23:0] avm_addr ,//输出给sdram 接口 IP 的读写地址
output [15:0] avm_wrdata ,//输出给sdram 接口 IP 的写数据
input [15:0] avs_rddata ,//sdram 接口 IP 输入的读数据
input avs_rddata_vld ,
input avs_waitrequest
);
//参数定义
localparam IDLE = 4'b0001,
WRITE = 4'b0010,
READ = 4'b0100,
DONE = 4'b1000;
//信号定义
reg [3:0] state_c ;
reg [3:0] state_n ;
reg [8:0] cnt ;//突发读写计数器
wire add_cnt ;
wire end_cnt ;
reg [1:0] wr_bank ;//写bank
reg [1:0] rd_bank ;//读bank
reg [21:0] wr_addr ;//写地址 行地址 + 列地址
wire add_wr_addr ;
wire end_wr_addr ;
reg [21:0] rd_addr ;//读地址 行地址 + 列地址
wire add_rd_addr ;
wire end_rd_addr ;
reg change_bank ;//切换bank
reg wr_finish ;//一帧数据写完
reg [1:0] wr_finish_r ;//同步到写侧
reg wr_data_flag;//wrfifo写数据的标志
reg wr_flag ;
reg rd_flag ;
reg flag_sel ;
reg prior_flag ;
wire idle2write ;
wire idle2read ;
wire write2done ;
wire read2done ;
reg [15:0] rd_data ;//rfifo读数据输出
reg rd_data_vld ;
wire [17:0] wfifo_data ;
wire wfifo_rdreq ;
wire wfifo_wrreq ;
wire [17:0] wfifo_q ;
wire wfifo_empty ;
wire [10:0] wfifo_usedw ;
wire wfifo_full ;
wire [15:0] rfifo_data ;
wire rfifo_rdreq ;
wire rfifo_wrreq ;
wire [15:0] rfifo_q ;
wire rfifo_empty ;
wire rfifo_full ;
wire [10:0] rfifo_usedw ;
//状态机
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
always @(*)begin
case(state_c)
IDLE :begin
if(idle2write)
state_n = WRITE;
else if(idle2read)
state_n = READ;
else
state_n = state_c;
end
WRITE :begin
if(write2done)
state_n = DONE;
else
state_n = state_c;
end
READ :begin
if(read2done)
state_n = DONE;
else
state_n = state_c;
end
DONE :state_n = IDLE;
default:state_n = IDLE;
endcase
end
assign idle2write = state_c == IDLE && (~prior_flag && wfifo_usedw >= `USER_BL);
assign idle2read = state_c == IDLE && prior_flag && rfifo_usedw <= `RD_UT;
assign write2done = state_c == WRITE && end_cnt;
assign read2done = state_c == READ && end_cnt;
//计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = (state_c == WRITE | state_c == READ) & ~avs_waitrequest;
assign end_cnt = add_cnt && cnt== `USER_BL-1;
/************************读写优先级仲裁
如果读写信号同时拉高,根据上一次是读还是写进行判断下一次的读写
如果只有读信号或写信号,就进行相应的读或写操作
*****************************/
//rd_flag ;//读请求标志
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
rd_flag <= 0;
end
else if(rfifo_usedw <= `RD_LT)begin
rd_flag <= 1'b1;
end
else if(rfifo_usedw > `RD_UT)begin
rd_flag <= 1'b0;
end
end
//wr_flag ;//写请求标志
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
wr_flag <= 0;
end
else if(wfifo_usedw >= `USER_BL)begin
wr_flag <= 1'b1;
end
else begin
wr_flag <= 1'b0;
end
end
//flag_sel ;//标记上一次操作
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
flag_sel <= 0;
end
else if(read2done)begin
flag_sel <= 1;
end
else if(write2done)begin
flag_sel <= 0;
end
end
//prior_flag ;//优先级标志 0:写优先级高 1:读优先级高 仲裁读、写的优先级
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
prior_flag <= 0;
end
else if(wr_flag && (flag_sel || (~flag_sel && ~rd_flag)))begin //突发写优先级高
prior_flag <= 1'b0;
end
else if(rd_flag && (~flag_sel || (flag_sel && ~wr_flag)))begin //突发读优先级高
prior_flag <= 1'b1;
end
end
/******************************************************************/
/****************************************************
乒乓操作(bank)
1、将第 1 帧数据存入 bank1 中, 当 bank1 中完整的存储了第 1 帧图像数据后,然后进入乒乓操作。
2、将第 2 帧数据存入 bank0 , 同时从 bank1 中读取存储的第 1 帧数据。
对于存储:只要一帧图像数据存储完成,则立刻切换到另一个乒乓块继续存储,而与是否读取完成无关。(因此如果存储的速度和读取的速度不相同,就会出现存储和读取位于同一个乒乓块,或者位于不同乒乓块)
对于读取:读取一帧数据完成后,只要存储数据和读取数据同时处于一个乒乓块,则切换到另一个乒乓块继续进行读取,否则不切换,继续在原乒乓块进行读取。
乒乓操作主要⽤于控制数据流,
在此项⽬中主要体现为先写SDRAM bank1的数据,同时读SDRAM bank3的数据,
当两块bank的数据读写完毕后,切换操作为读bank1的数据,写bank3的数据,
这样可以保持数据为完整的⼀帧,使显⽰屏帧与帧之间切换瞬间完成。
保证读取到的数据是一帧的效果,如果一帧数据没有读完,就开始写入会丢帧。
****************************************************/
//wr_bank rd_bank
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
wr_bank <= 2'b00;
rd_bank <= 2'b11;
end
else if(change_bank)begin
wr_bank <= ~wr_bank;
rd_bank <= ~rd_bank;
end
end
// wr_addr rd_addr
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
wr_addr <= 0;
end
else if(add_wr_addr) begin
if(end_wr_addr)
wr_addr <= 0;
else
wr_addr <= wr_addr+1 ;
end
end
assign add_wr_addr = (state_c == WRITE) && ~avs_waitrequest;
assign end_wr_addr = add_wr_addr && wr_addr == `BURST_MAX-1 ;
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
rd_addr <= 0;
end
else if(add_rd_addr) begin
if(end_rd_addr)
rd_addr <= 0;
else
rd_addr <= rd_addr+1 ;
end
end
assign add_rd_addr = (state_c == READ) && ~avs_waitrequest;
assign end_rd_addr = add_rd_addr && rd_addr == `BURST_MAX-1;
//wr_finish 一帧数据全部写到SDRAM
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
wr_finish <= 1'b0;
end
else if(~wr_finish & wfifo_q[17])begin //写完 从wrfifo读出eop
wr_finish <= 1'b1;
end
else if(wr_finish && end_rd_addr)begin //读完
wr_finish <= 1'b0;
end
end
//change_bank ;//切换bank
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
change_bank <= 1'b0;
end
else begin
change_bank <= wr_finish && end_rd_addr;
end
end
/****************************************************************/
/****************************************************
wrfifo写数据
控制像素数据帧 写入 或 丢帧 eop和sop都表示一个像素点
1、同步:将写入sdram的一帧数据信号 wr_finish 从wirfifo的读侧同步到写侧
2、wrfifo写入数据信号定义:
①写数据:未写入数据 + (开始信号sop + 写入的一帧数据未同步完成,即正在写入数据)
②不写入数据:已经写入数据 + 结束信号eop
****************************************************/
//控制像素数据帧 写入 或 丢帧
always @(posedge clk_in or negedge rst_n)begin
if(~rst_n)begin
wr_data_flag <= 1'b0;
end
else if(~wr_data_flag & ~wr_finish_r[1] & din_sop)begin//可以向wrfifo写数据
wr_data_flag <= 1'b1;
end
else if(/*wr_finish_r[1] && din_sop*/wr_data_flag & din_eop)begin//不可以向wrfifo写入数据
wr_data_flag <= 1'b0;
end
end
always @(posedge clk_in or negedge rst_n)begin //把wr_finish从wrfifo的读侧同步到写侧
if(~rst_n)begin
wr_finish_r <= 0;
end
else begin
wr_finish_r <= {wr_finish_r[0],wr_finish};
end
end
/****************************************************************/
always @(posedge clk_out or negedge rst_n)begin
if(~rst_n)begin
rd_data <= 0;
rd_data_vld <= 1'b0;
end
else begin
rd_data <= rfifo_q;
rd_data_vld <= rfifo_rdreq;
end
end
//wfifo设计,慢时钟域写到快时钟域读
//数据进行拼接,将eop,sop和 数据拼接到一起,用于判断能不能写入
wrfifo wrfifo_inst (
.aclr (~rst_n ),
.data (wfifo_data ),
.rdclk (clk ),
.rdreq (wfifo_rdreq),
.wrclk (clk_in ),
.wrreq (wfifo_wrreq),
.q (wfifo_q ),
.rdempty(wfifo_empty),
.rdusedw(wfifo_usedw),
.wrfull (wfifo_full )
);
assign wfifo_data = {din_eop,din_sop,din};
assign wfifo_wrreq = ~wfifo_full & din_vld & ((~wr_finish_r[1] & din_sop) ||wr_data_flag);
assign wfifo_rdreq = state_c == WRITE && ~avs_waitrequest;
/*wrfifo的写请求拉高条件
wrfifo非空
sdr从机输入数据有效信号
(开始标志sop + 正在写入一帧数据且未完成写入 或者 wrfifo的写入数据标志
*/
//读写不能同时进行,只有dq一组数据线
//rdfifo设计 ,快时钟写到慢时钟读
rdfifo u_rdfifo(
.aclr (~rst_n ),
.data (rfifo_data ),
.rdclk (clk_out ),
.rdreq (rfifo_rdreq),
.wrclk (clk ),
.wrreq (rfifo_wrreq),
.q (rfifo_q ),
.rdempty (rfifo_empty),
.wrfull (rfifo_full ),
.wrusedw (rfifo_usedw)
);
assign rfifo_data = avs_rddata;
assign rfifo_wrreq = ~rfifo_full & avs_rddata_vld;
assign rfifo_rdreq = ~rfifo_empty & rdreq;
//输出
assign dout = rd_data;
assign dout_vld = rd_data_vld;
assign avm_wrdata = wfifo_q[15:0];
assign avm_write = ~(state_c == WRITE && ~avs_waitrequest);
assign avm_read = ~(state_c == READ && ~avs_waitrequest);
assign avm_addr = (state_c == WRITE)?{wr_bank[1],wr_addr[21:9],wr_bank[0],wr_addr[8:0]}
:((state_c == READ)?{rd_bank[1],rd_addr[21:9],rd_bank[0],rd_addr[8:0]}
:0);
endmodule
tcl
# Copyright (C) 2018 Intel Corporation. All rights reserved.
# Your use of Intel Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Intel Program License
# Subscription Agreement, the Intel Quartus Prime License Agreement,
# the Intel FPGA IP License Agreement, or other applicable license
# agreement, including, without limitation, that your use is for
# the sole purpose of programming logic devices manufactured by
# Intel and sold by Intel or its authorized distributors. Please
# refer to the applicable agreement for further details.
# Quartus Prime Version 18.1.0 Build 625 09/12/2018 SJ Standard Edition
# File: C:\Users\EDY\Desktop\fpga_coms_sdram_vga-main\cmos_sdram_vga\prj\top.tcl
# Generated on: Thu May 25 20:16:22 2023
package require ::quartus::project
set_location_assignment PIN_D15 -to vga_vsync
set_location_assignment PIN_C15 -to vga_rgb[0]
set_location_assignment PIN_B16 -to vga_rgb[1]
set_location_assignment PIN_D2 -to vga_rgb[2]
set_location_assignment PIN_B14 -to vga_rgb[3]
set_location_assignment PIN_A14 -to vga_rgb[4]
set_location_assignment PIN_B13 -to vga_rgb[5]
set_location_assignment PIN_A13 -to vga_rgb[6]
set_location_assignment PIN_B12 -to vga_rgb[7]
set_location_assignment PIN_A12 -to vga_rgb[8]
set_location_assignment PIN_B11 -to vga_rgb[9]
set_location_assignment PIN_A11 -to vga_rgb[10]
set_location_assignment PIN_B10 -to vga_rgb[11]
set_location_assignment PIN_A10 -to vga_rgb[12]
set_location_assignment PIN_B9 -to vga_rgb[13]
set_location_assignment PIN_A9 -to vga_rgb[14]
set_location_assignment PIN_C8 -to vga_rgb[15]
set_location_assignment PIN_C16 -to vga_hsync
set_location_assignment PIN_N1 -to sdram_wen
set_location_assignment PIN_R6 -to sdram_rasn
set_location_assignment PIN_R4 -to sdram_clk
set_location_assignment PIN_T6 -to sdram_csn
set_location_assignment PIN_R14 -to sdram_cke
set_location_assignment PIN_T5 -to sdram_casn
set_location_assignment PIN_E15 -to rst_n
set_location_assignment PIN_E1 -to clk
set_location_assignment PIN_R7 -to sdram_bank[0]
set_location_assignment PIN_T7 -to sdram_bank[1]
set_location_assignment PIN_N2 -to sdram_dqm[0]
set_location_assignment PIN_T14 -to sdram_dqm[1]
set_location_assignment PIN_R5 -to sdram_dq[0]
set_location_assignment PIN_T4 -to sdram_dq[1]
set_location_assignment PIN_T3 -to sdram_dq[2]
set_location_assignment PIN_R3 -to sdram_dq[3]
set_location_assignment PIN_T2 -to sdram_dq[4]
set_location_assignment PIN_R1 -to sdram_dq[5]
set_location_assignment PIN_P2 -to sdram_dq[6]
set_location_assignment PIN_P1 -to sdram_dq[7]
set_location_assignment PIN_R13 -to sdram_dq[8]
set_location_assignment PIN_T13 -to sdram_dq[9]
set_location_assignment PIN_R12 -to sdram_dq[10]
set_location_assignment PIN_T12 -to sdram_dq[11]
set_location_assignment PIN_T10 -to sdram_dq[12]
set_location_assignment PIN_R10 -to sdram_dq[13]
set_location_assignment PIN_T11 -to sdram_dq[14]
set_location_assignment PIN_R11 -to sdram_dq[15]
set_location_assignment PIN_T8 -to sdram_addr[0]
set_location_assignment PIN_P9 -to sdram_addr[1]
set_location_assignment PIN_T9 -to sdram_addr[2]
set_location_assignment PIN_R9 -to sdram_addr[3]
set_location_assignment PIN_R16 -to sdram_addr[11]
set_location_assignment PIN_T15 -to sdram_addr[12]
set_location_assignment PIN_R8 -to sdram_addr[10]
set_location_assignment PIN_N16 -to sdram_addr[6]
set_location_assignment PIN_N15 -to sdram_addr[7]
set_location_assignment PIN_P16 -to sdram_addr[8]
set_location_assignment PIN_P15 -to sdram_addr[9]
set_location_assignment PIN_L16 -to sdram_addr[4]
set_location_assignment PIN_L15 -to sdram_addr[5]
set_location_assignment PIN_D3 -to cmos_xclk
set_location_assignment PIN_F6 -to cmos_vsync
set_location_assignment PIN_C6 -to cmos_scl
set_location_assignment PIN_D6 -to cmos_sda
set_location_assignment PIN_D5 -to cmos_pclk
set_location_assignment PIN_C3 -to cmos_din[7]
set_location_assignment PIN_F5 -to cmos_din[0]
set_location_assignment PIN_G5 -to cmos_din[1]
set_location_assignment PIN_D4 -to cmos_din[2]
set_location_assignment PIN_F3 -to cmos_din[4]
set_location_assignment PIN_F2 -to cmos_din[5]
set_location_assignment PIN_E5 -to cmos_din[6]
set_location_assignment PIN_D1 -to cmos_href
set_location_assignment PIN_G2 -to cmos_pwdn
set_location_assignment PIN_F1 -to cmos_reset
set_location_assignment PIN_M1 -to cmos_din[3]