FPGA中利用fifo时钟域转换---慢时钟域转快时钟域
一、时间计算方法
FIFO的输入数据的时钟是40MHz,FIFO输出数据取60MHz,刚好是40MHz的1.5倍,将慢时钟域转快时钟域。另外,fifo输出的数据,要输出给上位机,一帧数据要传输640*512=327680个像素数据,要求帧频为100Hz,对应的时间是1/100Hz=10ms,即要求10ms内将327680个数据传输完毕。验证fifo的输出时钟60MHz是否满足要求的方法:输出一帧数据的时间 = 一帧的总数据量/频率,T=(640 ×1.5 ×512 )/ 60M=8.192 ms
什么是频率:单位时间内周期变化的次数。1 Hz 表示每秒发生一次
二、注意的问题
1、FPGA中的计数器其实就是在计时。FIFO输入端的时钟频率小,输出时钟频率快,为了保证输入FIFO的数据与输出数据速度相等,即FIFO不至于读空,行计数器计数的最大值也必须放大1.5倍,即640*1.5=960,从FIFO中读数据时前640个计数时数据有效,这640个计数期间可以至一个标志rd_en位为1,作为FIFO读使能信号,960中的后320个计时为FIFO读数据消隐期,此时rd_en=0,即不读数据。这样输入FIFO的数据读出FIFO的数据时间上就可以匹配上,不至于将FIFO读空。
2、先预存一行640个数据到FIFO中,存第二行数据的同时,读取第一行的数据,这样FIFO就不会被读空;
3、FIFO输出后面的模块必须要60M的时钟来接收数据,不然数据会不正确。后面模块的时钟慢了数据会丢失,时钟快了会多出无效的数据。
三、代码设计:
verilog
module Slow2Fast(
input i_reset,
input i_clk_60m ,
input i_clk_40m,
input i_valid ,
input [15:0] data ,
output o_hsync,
output o_vsync,
output [11:0]o_vcnt,
output [15:0] o_data
);
reg fifo_clr;
reg vsync ;
reg hsync ;
reg vsync_d ;
reg hsync_d;
wire fifo_rd_req ;
wire fifo_wr_req ;
wire [15:0] fifo_wr_data ;
wire [15:0] fifo_rd_data ;
reg [11:0] hcnt;
reg [11:0] vcnt ;
reg i_valid_d1;
reg i_valid_d2,i_valid_d3;
reg valid_shift_out,valid_buf;
//行场计数器,就是计时
always@(posedge i_clk_60m)begin
i_valid_d1 <= i_valid;
i_valid_d2 <= i_valid_d1;
i_valid_d3 <= i_valid_d2;
if ((i_valid_d2 == 1'b1) && (i_valid_d3 == 1'b0)) begin //valid 信号的上升沿。上升沿到来,行场计数器清零
hcnt <= 0;
vcnt <= 0;
end
else begin
if (hcnt == (960 - 1))begin //输入时钟为40M,输出时钟为60M,60M=1.5*40M。 640*513 乘1.5时得: 960*563
if (vcnt = (566 - 1)) //563
vcnt <= vcnt;
else begin
vcnt <= vcnt + 1;
end
hcnt <=0;
end
else
hcnt <= hcnt + 1;
end
//vcnt:0到513 hcnt:0到639
always@(posedge i_clk_60m) begin
if (vcnt >= 1 and vcnt <= 512)// vcnt从1开始,因为要预存一行
vsync <= 1'b1;
else
vsync <= 1'b0;
if((hcnt >= 0 && hcnt <= 639) && (vcnt >= 1 && vcnt <= 512))//FIFO读使能信号,在60M下在前640个计数,读信号为1,后320个计数为读FIFO消隐期
hsync <= 1'b1;
else
hsync <= 1'b0;
if(vcnt = 513)
fifo_clr <= 1'b1;
else
fifo_clr <= 1'b0;
end
// 打拍
always@(posedge i_clk_60m) begin //60M
hsync_d <= hsync;
vsync_d <= vsync;
end
assign fifo_wr_req = i_valid;
assign fifo_wr_data = i_data;
assign fifo_rd_req = hsync;
assign o_hsync = hsync_d;
assign o_vsync = vsync_d;
assign o_data = fifo_rd_data;
assign o_vcnt = vcnt;
fifo_out inst_fifo_out
(
.rst ( fifo_clr ),
.wr_clk ( i_clk_40m ),//写FIFO时钟为40M
.rd_clk (i_clk_60m) ,//读FIFO时钟为60M
.din (fifo_wr_data) ,
.wr_en (fifo_wr_req) ,
.rd_en (fifo_rd_req) ,
.dout (fifo_rd_data) ,
.full (),
.empty (),
.wr_rst_busy (),
.rd_rst_busy ()
);
endmodule
c
---晓凡 2025年2月20日于武汉书