在FPGA处理图像过程中,经常遇到需要对于像素按照行对齐的输出,比如说 在求取图像sobel运算 需要一个像素点周围的8个像素,着九个像素怎么得到呢? 首先需要得到第一行 第二行 第三行的第一个像素,然后通过移位寄存器保存该三个像素, 再得到第一行 第二行 第三行的第二个像素,由此可见,每一行的像素都是对齐输出的。
怎么样确保每一行的像素都能够对齐输出呢?这就需要用到lineBuffer 行缓冲器。
一、行缓冲的设计
1.1 起始写地址、读地址
起始的写地址为0
起始的读地址位(0-w) w为图像一行像素的个数
这样定义可以使读和写的地址差距时钟保持在一行w个像素
1.2 读写使能信号
记住最关键的一点:写比读延迟两个时钟周期 因为RAM 2个时钟周期才出数
当数据以及数据有效信号到来时 直接将数据有效信号赋给ren
assign ren = dataInValid;
而对于wen来说 需要将dataInValid延迟两拍再输入给lineBuffer
always @(posedge clkin)
begin
dataInValid1 <= dataInValid;
dataInValid2 <= dataInValid1;
dataIn1 <= dataIn;
dataIn2 <= dataIn1;
end
assign wen = dataInValid2;
1.3 缓冲单元的设计
缓冲单元就是一个RAM
主要设定来初始地址 以及后续每一次地址++的过程
module LineBuffer
(
input rst_n,
input wclk,
input wen,
input [7:0] dataIn,
input rclk,
input ren,
output [7:0] dataOut
);
//写比读延迟两个时钟周期 因为RAM 2个时钟周期才出数
parameter ROW_WIDTH = 11'd720;
parameter RD_INITADDR = (11'd0-ROW_WIDTH); //读写起始地址相差一行
parameter WR_INITADDR = 11'd0;
reg [10:0] RDAddr = RD_INITADDR;
reg [10:0] WRAddr = WR_INITADDR;
always @(posedge rclk or negedge rst_n)
if(!rst_n)
RDAddr <= RD_INITADDR;
else if(ren)
RDAddr <= RDAddr + 1'b1;
else
RDAddr <= RDAddr;
always @(posedge wclk or negedge rst_n)
if(!rst_n)
WRAddr <= WR_INITADDR;
else if(wen)
WRAddr <= WRAddr + 1'b1;
else
WRAddr <= WRAddr;
RAM RAM0
(
.data ( dataIn ),
.wraddress ( WRAddr ),
.wrclock ( wclk ),
.wren ( wen ),
.rdaddress ( RDAddr ),
.rdclock ( rclk ),
.q ( dataOut )
);
endmodule
二、行缓冲的使用
上文已经定义来LineBuffer模块 这里介绍该如何使用这个LineBuffer
我们采用两个LineBuffer来缓存两行的数据 再加上当前输入行 共三行数据同时输出
就像上文介绍到的 写比读延迟两个时钟周期 因为RAM 2个时钟周期才出数 所以将最初的输入数据以及数据有效信号延迟两个时钟周期分别给了LineBuffer的写数据以及写有效 而将数据有效直接给了读使能
always @(posedge clkin)
begin
dataInValid1 <= dataInValid;
dataInValid2 <= dataInValid1;
dataIn1 <= dataIn;
dataIn2 <= dataIn1;
end
wire ren;
wire wen;
//读和写之间差两个时钟周期
assign wen = dataInValid2;
assign ren = dataInValid;
wire [7:0]D1;
LineBuffer LineBuf_1
(
.rst_n ( rst_n ),
.wclk ( wclk ),
.wen ( wen ),
.dataIn ( dataIn2 ),
.rclk ( rclk ),
.ren ( ren ),
.dataOut ( D1 )
);
wen比ren延迟两个clk 正好使得LineBuf_1的输出有效时 LineBuf_2wen有效 数据可以对齐
wire [7:0]D2;
LineBuffer LineBuf_2
(
.rst_n ( rst_n ),
.wclk ( wclk ),
.wen ( wen ),
.dataIn ( D1 ),
.rclk ( rclk ),
.ren ( ren ),
.dataOut ( D2 )
);
//D1出来的是第2行的数据(上一行)
//dataIn2是当前行n的数据(本行)
//D1出来的是第n-1行的数据(上一行)
//D2出来的是第n-2行的数据(上上行)
缓存的设置:
reg [10:0]pix_11,pix_12,pix_13;
reg [10:0]pix_21,pix_22,pix_23;
reg [10:0]pix_31,pix_32,pix_33;
reg [10:0]pix_1, pix_2, pix_3;
always @(posedge clkin)
begin
pix_3 <= dataIn2;
pix_2 <= D1;
pix_1 <= D2;
{pix_11,pix_12,pix_13} <= {pix_12,pix_13,pix_1};
{pix_21,pix_22,pix_23} <= {pix_22,pix_23,pix_2};
{pix_31,pix_32,pix_33} <= {pix_32,pix_33,pix_3};
end
pix_11,pix_12,pix_13;
pix_21,pix_22,pix_23;
pix_31,pix_32,pix_33;
即为所求
这样 LineBuffer设计完毕
下一节我们将介绍利用LineBuffer计算图像的sobel图像