边沿检测系统
系统介绍
摄像头复位引脚保持至少3ms时间的低电平后拉高使得摄像头处于硬件复位状态,同时SDRAM模块初始化完成,在摄像头复位引脚保持2ms高电平后开始通过SCCB或IIC通信协议写入115个不同的寄存器地址数据,写入数据成功后摄像头初始化模块产生初始化完成信号传入SDRAM模块中读缓存模块并保持高电平表示SDRAM模块可读状态。初始化完成之后在DVP摄像头传输模块产生的24Mhz频率时钟驱动下摄像头产生PCLK时钟信号通过DVP通信协议传输16位图像,每生成一个16位图像数据,DVP摄像头传输模块同时输出维持一个时钟周期的写请求信号输入到SDRAM模块中的写缓存模块。写缓存模块收到写请求信号后将16位图像数据依次写入不同的存储器逻辑单元地址,当写缓存模块中的图像数据满足一次突发读写数据长度条件后写入SDRAM存储器中。在图像数据写入SDRAM同时当VGA显示模块中扫描计数器为零及开始扫描初状态时产生输入图像信息请求信号,该信号输入到SDRAM模块中读缓存信号。当读缓存模块中的数据小于一次读写突发长度时输出读请求信号传入SDRAM控制模块,SDRAM在100Mhz频率时钟下输出数据16位数据传入到读缓存模块。读缓存的数据直接通过VGA模块后单通道图像数据传输到sobel边缘检测模块。该模块输入端口只输入去除其他图像数据的G通道6位数据, 将图像信息的3*3像素矩阵与sobel算子做卷积运算后得到的8位数据以RGB332格式实时显示到屏幕上。 系统信号连接设计图如下:
系统模块
边沿检测模块设计思路
FIFO求和模块
在学习算法模块之前要了解算法原理,设计FIFO求和模块,设计5*4矩阵输入到求和模块计算。此模块将三行数据累加求和并输出。将第一行的数据写入到FIFO_1中,第二行数据写入FIFO_2中,当第三行数据输入时读出第一与第二行数据,同时FIFO_1写入FIFO_2读出的第二行的数据,并且将这三行数据累加。信号波形图设计如下; FIFO求和模块设计图如下: 该模块的代码如下,可参考野火教程在此不做赘述。
module FIFO_SUM(
Clk ,
Rst_n ,
Pi_data ,
Pi_flag ,
Po_data ,
Po_flag
);
input Clk ;
input Rst_n ;
input [7:0] Pi_data ;
input Pi_flag ;
output [7:0] Po_data ;
output Po_flag ;
reg [10:0] cnt_col ;
reg [10:0] cnt_row ;
reg wr_en_1 ;
reg wr_en_2 ;
reg [7:0] wr_data_1 ;
reg [7:0] wr_data_2 ;
reg rd_en ;
wire [7:0] rd_data_1 ;
wire [7:0] rd_data_2 ;
reg mid_flag ;
reg sum_flag ;
reg [7:0] Po_data ;
reg Po_flag ;
parameter COL_MAX = 4 ;
parameter ROW_MAX = 5 ;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_col <= 1'b0;
else
if(Pi_flag && (cnt_col == COL_MAX - 1'b1))
cnt_col <= 1'b0;
else
if(Pi_flag)
cnt_col <= cnt_col + 1'b1;
else
cnt_col <= cnt_col;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_row <= 1'b0;
else
if((cnt_col == COL_MAX - 1'b1) && Pi_flag && (cnt_row == ROW_MAX - 1'b1))
cnt_row <= 1'b0;
else
if((cnt_col == COL_MAX - 1'b1) && Pi_flag )
cnt_row <= cnt_row + 1'b1;
else
cnt_row <= cnt_row;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
wr_en_1 <= 1'b0;
else
if((cnt_row == 0) && Pi_flag)
wr_en_1 <= 1'b1 ;
else
wr_en_1 <= mid_flag;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
wr_en_2 <= 1'b0;
else
if((cnt_row >= 1'b1) && ((cnt_row <= ROW_MAX - 2'd1)) && Pi_flag)
wr_en_2 <= 1'b1;
else
wr_en_2 <= 1'b0;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
wr_data_1 <= 1'b0;
else
if((cnt_row == 0) && Pi_flag)
wr_data_1 <= Pi_data;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
wr_data_2 <= 1'b0;
else
if((cnt_row >= 1'b1) && ((cnt_row <= ROW_MAX - 2'd1)) && Pi_flag)
wr_data_2 <= Pi_data;
else
wr_data_2 <= wr_data_2;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
rd_en <= 1'b0;
else
if(cnt_row >= 2'd2)
rd_en <= Pi_flag;
else
rd_en <= 1'b0;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
mid_flag <= 1'b0;
else
if(wr_en_2 && rd_en)
mid_flag <= 1'b1;
else
mid_flag <= 1'b0;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
sum_flag <= 1'b0;
else
sum_flag <= rd_en;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Po_data <= 1'b0;
else
Po_data <= rd_data_1 + rd_data_2 + Pi_data;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Po_flag <= 1'b0;
else
Po_flag <= sum_flag;
FIFO FIFO_inst_1 (
.clock ( Clk ),
.data ( wr_data_1 ),
.rdreq ( rd_en),
.wrreq ( wr_en_1 ),
.q ( rd_data_1 )
);
FIFO FIFO_inst_2 (
.clock ( Clk ),
.data ( wr_data_2 ),
.rdreq ( rd_en),
.wrreq ( wr_en_2 ),
.q ( rd_data_2 )
);
endmodule
sobel模块
sobel算子
将VGA输出的显示像素数据的单通道G输入到边缘检测模块中。处理模块运行流程图如图所示。模块中的两个算子如图所示,将两个算子与图像数据的三乘三矩阵相乘并相加得到的两个值and_b与and_a,将这两个值的平方根的和做开方运算得到compare,该值与阈值做比较,大于阈值则为0,小于阈值则为1。最终显示为只有黑白的图像数据,将计算后的图像数据以RGB332格式输出到显示硬件引脚上进行显示。SOBEL算子比其他的常用算子比如ROBERTS算子的计算简单,效率更高。但是准确率不高。模块设计如图所示。
sobel模块波形图如下所示,在此模拟了5*5矩阵与sobel算子卷积原理,与FIFO求和类似,增加计算标志位count_flag,在高电平下计算Gx=(A3-A1)+(B3-B1)*2+(C3-C1);
模拟矩阵:
模块设计代码如下:
LineBuffer、MAC_3、PA_3、SQRT分别为行缓存、相乘相加、求和、平方IP核。
module sobel_test(
input Clk ,
input Rst_n ,
input Po_flag ,
input [7:0] Po_data ,
input [7:0] Threshold ,
output reg [7:0] Out_data ,
output reg Out_flag
);
parameter A1 = 8'hff, A2 = 8'h00, A3 = 8'h01;
parameter A4 = 8'hfe, A5 = 8'h00, A6 = 8'h02;
parameter A7 = 8'hff, A8 = 8'h00, A9 = 8'h01;
parameter B1 = 8'h01, B2 = 8'h02, B3 = 8'h01;
parameter B4 = 8'h00, B5 = 8'h00, B6 = 8'h00;
parameter B7 = 8'hff, B8 = 8'hfe, B9 = 8'hff;
wire [7:0] count0;
wire [7:0] count1;
wire [7:0] count2;
wire [17:0] amass_a_0;
wire [17:0] amass_a_1;
wire [17:0] amass_a_2;
wire [17:0] amass_b_0;
wire [17:0] amass_b_1;
wire [17:0] amass_b_2;
wire [19:0] and_b;
wire [19:0] and_a;
wire [15:0] compare;
wire [7:0] shiftout;
LineBuffer LineBuffer_inst (
.clken ( Po_flag ),
.clock ( Clk ),
.shiftin ( Po_data ),
.shiftout ( shiftout ),
.taps0x ( count0 ),
.taps1x ( count1 ),
.taps2x ( count2 )
);
MAC_3 A0_inst(
.aclr3(!Rst_n),
.clock0(Clk),
.dataa_0(count2),
.datab_0(A1),
.datab_1(A2),
.datab_2(A3),
.result(amass_a_0)
);
MAC_3 A1_inst(
.aclr3(!Rst_n),
.clock0(Clk),
.dataa_0(count1),
.datab_0(A4),
.datab_1(A5),
.datab_2(A6),
.result(amass_a_1)
);
MAC_3 A2_inst(
.aclr3(!Rst_n),
.clock0(Clk),
.dataa_0(count0),
.datab_0(A7),
.datab_1(A8),
.datab_2(A9),
.result(amass_a_2)
);
MAC_3 B0_inst(
.aclr3(!Rst_n),
.clock0(Clk),
.dataa_0(count2),
.datab_0(B1),
.datab_1(B2),
.datab_2(B3),
.result(amass_b_0)
);
MAC_3 B1_inst(
.aclr3(!Rst_n),
.clock0(Clk),
.dataa_0(count1),
.datab_0(B4),
.datab_1(B5),
.datab_2(B6),
.result(amass_b_1)
);
MAC_3 B2_inst(
.aclr3(!Rst_n),
.clock0(Clk),
.dataa_0(count0),
.datab_0(B7),
.datab_1(B8),
.datab_2(B9),
.result(amass_b_2)
);
PA_3 pa0 (
.clock (Clk),
.data0x (amass_a_0),
.data1x (amass_a_1),
.data2x (amass_a_2),
.result (and_a)
);
PA_3 pb0 (
.clock (Clk),
.data0x (amass_b_0),
.data1x (amass_b_1),
.data2x (amass_b_2),
.result (and_b)
);
SQRT sqrt_inst (
.clk(Clk),
.radical(and_a * and_a + and_b * and_b),
.q(compare)
);
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Out_flag <= 1'b0;
else
Out_flag <= Po_flag;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Out_data <= 1'b0;
else
if(Po_flag)
Out_data <= (compare > Threshold) ? 0 : 255 ;
else
Out_data <= 0;
endmodule
对于负数的表示法:-1+1=0等价于h’ff+1=0,所以h’ff=-1。同理 h’fe+2=0,所以h’fe为-2。以此类推可以表示负数。
系统内模块测试情况
系统顶层文件
module DVP_SDRAM_VGA(
input wire Clk ,
input wire Rst_n ,
input wire Key_in1 ,
input wire Key_in2 ,
input wire Cmos_pclk ,
input wire Cmos_vsync ,
input wire Cmos_href ,
input wire [7:0] Cmos_data ,
output wire Cmos_xclk ,
output wire Cmos_sclk ,
inout wire Cmos_sda ,
output wire Cmos_pwdn ,
output wire Cmos_rst_n ,
output wire Sdram_clk ,
output wire Sdram_cke ,
output wire Sdram_cs_n ,
output wire Sdram_cas_n ,
output wire Sdram_ras_n ,
output wire Sdram_we_n ,
output wire [1:0] Sdram_ba ,
output wire [12:0] Sdram_addr ,
inout wire [15:0] Sdram_dq ,
output wire [1:0] Sdram_dqm ,
output wire [7:0] Vga_rgb ,
output wire Hsync ,
output wire Vsync ,
output wire Clk_vga ,
output wire Clk_blk ,
output wire Led ,
output wire SHCP ,
output wire STCP ,
output wire DS
);
reg [31:0] cnt ;
wire go ;
wire sys_rst_n ;
wire clk_cmos_24M ;
wire clk_100M ;
wire clk_shift_100M ;
wire clk_vga_24M ;
wire lock ;
wire init_done ;
wire wr_req ;
wire [15:0] data_cmos ;
wire pix_reg ;
wire [15:0] pix_data ;
wire wr_rst ;
wire [10:0] pix_x ;
wire [10:0] pix_y ;
wire rd_value_r ;
reg rd_value ;
wire po_flag ;
wire key_data1 ;
wire key_flag1 ;
wire key_data2 ;
wire key_flag2 ;
wire [7:0] change ;
reg [31:0] hex_data ;
assign Cmos_pwdn = 1'b0;
assign Cmos_rst_n = (cnt > 32'd175_000);
assign sys_rst_n = Rst_n && lock;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt <= 1'b0 ;
else
if(cnt < 32'd6500_001)
cnt <= cnt + 1'b1 ;
else
cnt <= cnt ;
assign go = (cnt == 32'd6500_000 ) ? 1'b1:1'b0;
assign rd_value_r = ((pix_x == 0) && (pix_y == 0))?1'b1:1'b0;
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
rd_value <= 1'b0;
else
if(rd_value_r)
rd_value <= 1'b1;
else
rd_value <= rd_value ;
HEX_8_top HEX_8_top_inst(
.Clk (Clk) ,
.Rst_n (Rst_n) ,
.Data_in ({24'd0,change}) ,
.SHCP (SHCP ) ,
.STCP (STCP ) ,
.DS (DS )
);
Key_shake Key_shake_inst1(
.Clk( Clk ),
.Rst_n( Rst_n ),
.Key_in( Key_in1 ),
.Key_flag( key_flag1 ),
.Key_data( key_data1 )
);
Key_shake Key_shake_inst2(
.Clk( Clk ),
.Rst_n( Rst_n ),
.Key_in( Key_in2 ),
.Key_flag( key_flag2 ),
.Key_data( key_data2 )
);
change change_inst(
.Clk (Clk ) ,
.Rst_n (Rst_n ) ,
.Key_data1 ( key_data1 ) ,
.Key_flag1 ( key_flag1 ) ,
.Key_data2 ( key_data2 ) ,
.Key_flag2 ( key_flag2 ) ,
.Change (change ) ,
.Led (Led )
);
pll pll_inst (
.areset ( !Rst_n ),
.inclk0 ( Clk ),
.c0 ( clk_cmos_24M ),
.c1 ( clk_100M ),
.c2 ( clk_shift_100M ),
.c3 ( clk_vga_24M ),
.locked ( lock )
);
OV7670_INIT_IIC OV7670_INIT_IIC_inst(
.Clk (Clk ) ,
.Rst_n (sys_rst_n ) ,
.Start (go ) ,
.Iic_clk (Cmos_sclk ) ,
.Sda (Cmos_sda ) ,
.Init_done (init_done )
);
CAMERA_OV7670_DVP CAMERA_OV7670_DVP_inst(
.Rst_n (sys_rst_n) ,
.Clk_cmos (clk_cmos_24M) ,
.Cmos_pclk (Cmos_pclk ) ,
.Cmos_vsync (Cmos_vsync) ,
.Cmos_href (Cmos_href ) ,
.Cmos_data (Cmos_data ) ,
.Cmos_data_value (wr_req ) ,
.Cmos_data_pixel (data_cmos) ,
.Xaddress () ,
.Yaddress () ,
.Wr_rst (wr_rst) ,
.Cmos_xclk (Cmos_xclk)
);
SDRAM_TOP SDRAM_TOP_inst(
.Clk (clk_100M) ,
.Rst_n (sys_rst_n) ,
.Clk_out (clk_shift_100M) ,
.Wr_fifo_wr_clk (Cmos_pclk) ,
.Wr_fifo_wr_req (wr_req) ,
.Wr_fifo_wr_data (data_cmos) ,
.Sdram_wr_b_addr (0) ,
.Sdram_wr_e_addr (640*480) ,
.Wr_burst_len (10'd512) ,
.Wr_rst (!sys_rst_n) ,
.Rd_fifo_rd_clk (clk_vga_24M) ,
.Rd_fifo_rd_req (vga_data_reg) ,
.Sdram_rd_b_addr (0) ,
.Sdram_rd_e_addr (640*480) ,
.Rd_burst_len (10'd512) ,
.Rd_rst (!sys_rst_n) ,
.Rd_value (rd_value) ,
.Rd_fifo_rd_data (pix_data) ,
.Rd_fifo_num () ,
.Sdram_clk (Sdram_clk ) ,
.Sdram_cke (Sdram_cke ) ,
.Sdram_cs_n (Sdram_cs_n ) ,
.Sdram_cas_n (Sdram_cas_n) ,
.Sdram_ras_n (Sdram_ras_n) ,
.Sdram_we_n (Sdram_we_n ) ,
.Sdram_ba (Sdram_ba ) ,
.Sdram_addr (Sdram_addr ) ,
.Sdram_dq (Sdram_dq ) ,
.Sdram_dqm (Sdram_dqm )
);
VGA_CTRL VGA_CTRL_inst(
.Clk (clk_vga_24M) ,
.Rst_n (sys_rst_n) ,
.Pix_data (pix_data) ,
.Disp_data (disp_data) ,
.Hsync (Hsync ) ,
.Vsync (Vsync ) ,
.Pix_x (pix_x) ,
.Pix_y (pix_y) ,
.Clk_vga (Clk_vga) ,
.Vga_blk (Clk_blk) ,
.Pix_reg (pix_reg)
);
wire [15:0] disp_data;
wire vga_data_reg;
wire [7:0] po_data ;
assign vga_data_reg = pix_reg;
assign Vga_rgb = po_data;
sobel_test sobel_test_inst(
.Clk (clk_vga_24M) ,
.Rst_n (sys_rst_n) ,
.Po_flag (pix_reg) ,
.Po_data ({2'd0,disp_data[10:5]}) ,
.Threshold (change) ,
.Out_data (po_data) ,
.Out_flag ()
);
endmodule
系统板级验证
阈值为12时系统运行结果图 阈值为20时系统运行结果图 原始摄像头采集图像系统运行结果图
|