Table of contents
foreword
The earliest FPGA-based : moving target detection (VGA display, schematic diagram + source code + hardware selection) , some netizens responded that VGA has a large screen, it is very inconvenient to do, and the function is too single.
Therefore, on the basis of the previous project, it is modified to TFT-LCD screen detection, and the detection results are output to the computer host computer through the serial port, so that everyone can do extended development.
First, look at the effect
Not much to say, first watch the video to see the effect.
FPGA-based moving target detection (LCD display-serial port output)
2. Hardware selection
Development board Altera: EP4CE6F17C8 (compatible with E10)
Camera: OV5640
Screen: TFT-LCD
cache data: SDRAM
board is self-made
3. System framework
Before the image acquisition of this system, because the frequency of the onboard crystal oscillator is inconsistent with that of the camera module and the TFT-LCD module, it is necessary to design the phase-locked loop module to output a clock signal consistent with that of the OV5640 camera before the system works. After the clock is input, configure the registers according to the manual of OV5640, so that the working mode of OV5640 meets the design requirements of this system. The image collected by the CMOS sensor enters the image processing module, and outputs the grayscale of the current frame for writing into SDRAM. At the same time, read out the gray level of the previous frame from SDRAM (one clock cycle difference from the current output) and re-enter the image processing module for frame difference image processing (that is, processing related to moving target detection).
In this system, when the selection function is satisfied, the real-time performance is required, so only one video stream is selected to be input. And according to the different clock domains, an asynchronous FIFO is designed to complete the data transmission buffer. Finally, the processing result is displayed on the screen through the ILI9488 driver module, and the detection information is output to the host computer through the serial port.
4. Program module
Code framework: This design basically uses pure Verilog design, using less IP, such as: PLL, FIFO. The code is accompanied by comments, which is highly readable and easy for everyone to transplant, participate in competitions, and complete the project.
Some module simulations:
1. Top-level module of the system
module dmk_photo_uart(
input clk,
input rst_n, //KEY4(o) 即OK按键作为复位
//CMOS Port
inout cmos_scl, //cmos i2c clock
inout cmos_sda, //cmos i2c data
input cmos_vsync, //cmos vsync
input cmos_href, //cmos hsync refrence,data valid
input cmos_pclk, //cmos pxiel clock
output cmos_xclk, //cmos externl clock
input [7:0] cmos_db, //cmos data
output cmos_rst_n, //cmos reset
output cmos_pwdn, //cmos power down
//LCD ILI9488 Port
output WR,
output RD,
output CS,
output RS,
output BL_cnt,
output [15:0] data,
output RESET,
//LED
output [3:0] led,
//uart
input uart_rxd, //uart 串行数据接收
output uart_txd, //uart 串行数据发送
//SDRAM Port
output sdram_clk, //sdram clock
output sdram_cke, //sdram clock enable
output sdram_cs_n, //sdram chip select
output sdram_we_n, //sdram write enable
output sdram_cas_n, //sdram column address strobe
output sdram_ras_n, //sdram row address strobe
output[1:0] sdram_dqm, //sdram data enable
output[1:0] sdram_ba, //sdram bank address
output[12:0] sdram_addr, //sdram address
inout[15:0] sdram_dq //sdram data
);
// parameter CMOS_H_PIXEL = 24'd640 ; //CMOS水平方向像素个数,用于设置SDRAM缓存大小
// parameter CMOS_V_PIXEL = 24'd480 ; //CMOS垂直方向像素个数,用于设置SDRAM缓存大小
parameter CMOS_H_PIXEL = 24'd480 ; //CMOS水平方向像素个数,用于设置SDRAM缓存大小
parameter CMOS_V_PIXEL = 24'd320 ; //CMOS垂直方向像素个数,用于设置SDRAM缓存大小
parameter Diff_Threshold = 8'd40 ; //帧差检测阈值
assign cmos_rst_n = 1'b1;
assign cmos_pwdn = 1'b0;
wire clk_ref;
wire clk_refout;//sdram控制器100M工作时钟、给SDRAM芯片的100M时钟
wire clk_lcd_w; //LCD驱动模块工作时钟,12.5MHz
wire pll_lock_w;
wire sys_rst_n;
wire lcd_init_done;
//PLL模块
sys_pll u_sys_pll_0(
.areset (!rst_n),
.inclk0 (clk),
.c0 (clk_ref ),//sdram控制器100M 工作时钟
.c1 (clk_refout),//SDRAM芯片 100M 时钟
.c2 (cmos_xclk),//CMOS XCLK 24M 时钟
.c3 (clk_lcd_w),//LCD驱动模块工作时钟,12.5MHz
.locked (pll_lock_w)
);
//延迟复位模块
delay_reset u_delay_reset_0(
.clk (clk),
.rst_n (rst_n && pll_lock_w && lcd_init_done),
.reset_n (sys_rst_n)
);
//摄像头I2C配置模块
ov5640_config #(
.CMOS_H_PIXEL (CMOS_H_PIXEL),
.CMOS_V_PIXEL (CMOS_V_PIXEL)
) u_ov5640_config_0(
.rst_n (sys_rst_n),
.clk (clk),
.i2c_scl (cmos_scl),
.i2c_sda (cmos_sda)
);
wire cmos_frame_vsync;
wire cmos_frame_href;
wire cmos_frame_clken;
wire [15:0] cmos_frame_data;
//CMOS图像数据采集模块
cmos_capture_data u_cmos_capture_data( //系统初始化完成之后再开始采集数据
.rst_n (sys_rst_n && sdram_init_done),
.cam_pclk (cmos_pclk),
.cam_vsync (cmos_vsync),
.cam_href (cmos_href),
.cam_data (cmos_db),
.cmos_frame_vsync (cmos_frame_vsync ),
.cmos_frame_href (cmos_frame_href ),
.cmos_frame_valid (cmos_frame_clken ), //数据有效使能信号
.cmos_frame_data (cmos_frame_data ) //有效数据
);
//----------------------------------------------------
//Video Image processor module.
wire per_frame_vsync = cmos_frame_vsync;
wire per_frame_href = cmos_frame_href;
wire per_frame_clken = cmos_frame_clken;
wire [7:0] per_img_red = {
cmos_frame_data[15:11], cmos_frame_data[15:13]};
wire [7:0] per_img_green = {
cmos_frame_data[10:5], cmos_frame_data[10:9]};
wire [7:0] per_img_blue = {
cmos_frame_data[4:0], cmos_frame_data[4:2]};
wire post_frame_vsync;
wire post_frame_href;
wire post_frame_clken;
wire post_img_Bit;
wire [7:0] post_img_red;
wire [7:0] post_img_green;
wire [7:0] post_img_blue;
wire [15:0] post_frame_data ;
assign post_frame_data = {
post_img_red[7:3],post_img_green[7:2],post_img_blue[7:3]} ;
wire YCbCr_frame_vsync ;
wire YCbCr_frame_href ;
wire YCbCr_frame_clken ;
wire [7:0] YCbCr_img_Y_current; //当前帧灰度
wire [15:0] YCbCr_img_Y_pre; //前一帧灰度
wire target_detect;
Video_Image_Processor #(
.IMG_HDISP (CMOS_H_PIXEL),
.IMG_VDISP (CMOS_V_PIXEL)
) u_Video_Image_Processor
(
//global clock
.clk (cmos_pclk),
.rst_n (sys_rst_n && sdram_init_done),
//Image data prepred to be processd
.per_frame_vsync (per_frame_vsync),
.per_frame_href (per_frame_href),
.per_frame_clken (per_frame_clken),
.per_img_red (per_img_red),
.per_img_green (per_img_green),
.per_img_blue (per_img_blue),
//RGB2YCbCr output
.YCbCr_frame_vsync (YCbCr_frame_vsync),
.YCbCr_frame_href (YCbCr_frame_href ),
.YCbCr_frame_clken (YCbCr_frame_clken),
.YCbCr_img_Y_current (YCbCr_img_Y_current),
.YCbCr_img_Y_pre (YCbCr_img_Y_pre[7:0]),
//Image data has been processd
.post_frame_vsync (post_frame_vsync),
.post_frame_href (post_frame_href),
.post_frame_clken (post_frame_clken),
.post_img_red (post_img_red ),
.post_img_green (post_img_green),
.post_img_blue (post_img_blue ),
//User interface
.Diff_Threshold (Diff_Threshold),
.target_detect (target_detect)
);
//sdram read & write
wire wr1_wrreq;
wire [15:0] wr1_data;
wire rd1_rdreq;
wire [15:0] rd1_data;
assign wr1_wrreq = YCbCr_frame_clken;
assign wr1_data = {
8'd0,YCbCr_img_Y_current};
assign rd1_rdreq = YCbCr_frame_clken;
assign YCbCr_img_Y_pre = rd1_data;
//摄像头采集模块,dvp转avalon-st裸流
wire [15:0] data_w0;
wire valid_w0,ready_w0,sop_w0,eop_w0;
cmos_to_st_top #(
.WIDTH (CMOS_H_PIXEL),
.HEIGHT (CMOS_V_PIXEL),
.DWIDTH (16)
) u_cmos_to_st_top(
.clk (clk),
.rst_n (sys_rst_n && sdram_init_done),
.cmos_pclk (cmos_pclk),
.cmos_vsync (post_frame_vsync ),
.cmos_href (post_frame_href ),
.cmos_clken (post_frame_clken ),
.cmos_data (post_frame_data ),
// .cmos_vsync (YCbCr_frame_vsync ),
// .cmos_href (YCbCr_frame_href ),
// .cmos_clken (YCbCr_frame_clken ),
// .cmos_data ( {YCbCr_img_Y_current[7:3],YCbCr_img_Y_current[7:2],YCbCr_img_Y_current[7:3]} ),
.source_sop (sop_w0),
.source_valid (valid_w0),
.source_data (data_w0),
.source_eop (eop_w0),
.source_ready (ready_w0)
);
//TFTLCD模块
vip_ILI9488 u_vip_ILI9488_0(
.clk (clk),
.clk12p5M (clk_lcd_w),
.rst_n (rst_n),
//Avalon-ST Sink
.sink_sop (sop_w0),
.sink_valid (valid_w0),
.sink_data (data_w0),
.sink_eop (eop_w0),
.sink_ready (ready_w0),
.lcd_intdone (lcd_init_done),
//TFTLCD interface
.WR (WR),
.RD (RD),
.CS (CS),
.RS (RS),
.BL_cnt (BL_cnt),
.data (data),
.RESET (RESET)
);
wire wr_full_1/*synthesis keep*/;
wire wr_full_2;
wire rd_empty_1;
wire rd_empty_2/*synthesis keep*/;
//assign led = {wr_full_1,1'b0,1'b0,rd_empty_1};
//4port SDRAM控制器模块
Sdram_Control_4Port Sdram_Control_4Port(
.REF_CLK (clk_ref),
.OUT_CLK (clk_refout),
.RESET_N (sys_rst_n), //复位输入,低电平复位
.WR1_DATA (wr1_data), //写入端口1的数据输入端,16bit
.WR1 (wr1_wrreq), //写入端口1的写使能端,高电平写入
.WR1_ADDR (0), //写入端口1的写起始地址
.WR1_MAX_ADDR (CMOS_H_PIXEL*CMOS_V_PIXEL), //写入端口1的写入最大地址
.WR1_LENGTH (256), //一次性写入数据长度
.WR1_LOAD (~sys_rst_n), //写入端口1清零请求,高电平清零写入地址和fifo
.WR1_CLK (cmos_pclk ), //写入端口1 fifo写入时钟
.WR1_FULL (wr_full_1), //写入端口1 fifo写满信号
.WR1_USE (), //写入端口1 fifo已经写入的数据长度
.WR2_DATA ( ), //写入端口2的数据输入端,16bit
.WR2 (0), //写入端口2的写使能端,高电平写入
.WR2_ADDR (CMOS_H_PIXEL*CMOS_V_PIXEL), //写入端口2的写起始地址
.WR2_MAX_ADDR (CMOS_H_PIXEL*CMOS_V_PIXEL*2), //写入端口2的写入最大地址
.WR2_LENGTH (256), //一次性写入数据长度
.WR2_LOAD (~sys_rst_n), //写入端口2清零请求,高电平清零写入地址和fifo
.WR2_CLK (clk), //写入端口2 fifo写入时钟
.WR2_FULL (wr_full_2), //写入端口2 fifo写满信号
.WR2_USE (), //写入端口2 fifo已经写入的数据长度
.RD1_DATA (rd1_data), //读出端口1的数据输出端,16bit
.RD1 (rd1_rdreq), //读出端口1的读使能端,高电平读出
.RD1_ADDR (0), //读出端口1的读起始地址
.RD1_MAX_ADDR (CMOS_H_PIXEL*CMOS_V_PIXEL), //读出端口1的读出最大地址
.RD1_LENGTH (256), //一次性读出数据长度
.RD1_LOAD (~sys_rst_n), //读出端口1 清零请求,高电平清零读出地址和fifo
.RD1_CLK (cmos_pclk), //读出端口1 fifo读取时钟
.RD1_EMPTY (rd_empty_1), //读出端口1 fifo读空信号
.RD1_USE (), //读出端口1 fifo已经还可以读取的数据长度
.RD2_DATA (), //读出端口2的数据输出端,16bit
.RD2 (0), //读出端口2的读使能端,高电平读出
.RD2_ADDR (CMOS_H_PIXEL*CMOS_V_PIXEL), //读出端口2的读起始地址
.RD2_MAX_ADDR (CMOS_H_PIXEL*CMOS_V_PIXEL*2), //读出端口2的读出最大地址
.RD2_LENGTH (256), //一次性读出数据长度
.RD2_LOAD (~sys_rst_n), //读出端口2清零请求,高电平清零读出地址和fifo
.RD2_CLK (clk), //读出端口2 fifo读取时钟
.RD2_EMPTY (rd_empty_2), //读出端口2 fifo读空信号
.RD2_USE (), //读出端口2 fifo已经还可以读取的数据长度
.SA (sdram_addr), //SDRAM 地址线,
.BA (sdram_ba), //SDRAM bank地址线
.CS_N (sdram_cs_n), //SDRAM 片选信号
.CKE (sdram_cke), //SDRAM 时钟使能
.RAS_N (sdram_ras_n), //SDRAM 行选中信号
.CAS_N (sdram_cas_n), //SDRAM 列选中信号
.WE_N (sdram_we_n), //SDRAM 写请求信号
.DQ (sdram_dq), //SDRAM 双向数据总线
.SDR_CLK (sdram_clk),
.DQM (), //SDRAM 数据总线高低字节屏蔽信号
.Sdram_Init_Done(sdram_init_done)
);
assign sdram_dqm = 2'b00;
///串口波特率
parameter CLK_FREQ = 50000000;
parameter UART_BPS = 9600;
wire [7:0] uart_tx_data ;
wire uart_tx_en ;
wire uart_tx_done ;
uart_tx_ctrl uart_tx_ctrl(
.clk (clk),
.rst_n (rst_n),
.target_detect (target_detect),
.uart_tx_en (uart_tx_en),
.uart_tx_data (uart_tx_data),
.uart_tx_done (uart_tx_done)
);
// 串口 发送
uart_send #(
.CLK_FREQ (CLK_FREQ),
.UART_BPS (UART_BPS)
)
rj45_1_send_mode1(
.sys_clk (clk),
.sys_rst_n (rst_n),
.uart_din (uart_tx_data ),
.uart_en (uart_tx_en ),
.uart_txd (uart_txd),
.tx_flag (),
.tx_done (uart_tx_done)
);
// 串口 接收
uart_recv #(
.CLK_FREQ (CLK_FREQ),
.UART_BPS (UART_BPS)
)
rs485_1_recv(
.sys_clk (clk),
.sys_rst_n (rst_n),
.uart_rxd (uart_rxd),
.uart_done ( ),
.uart_data ( ),
.uart_valid ( )
);
assign led[0] = target_detect;
assign led[1] = target_detect;
assign led[3] = uart_txd ;
endmodule
2. Image processing top-level module
`timescale 1ns/1ns
module Video_Image_Processor #(
parameter [9:0] IMG_HDISP = 10'd480, //640*480
parameter [9:0] IMG_VDISP = 10'd320
)
(
//global clock
input clk, //cmos video pixel clock
input rst_n, //global reset
//Image data prepred to be processd
input per_frame_vsync, //Prepared Image data vsync valid signal
input per_frame_href, //Prepared Image data href vaild signal
input per_frame_clken, //Prepared Image data output/capture enable clock
input [7:0] per_img_red, //Prepared Image red data to be processed
input [7:0] per_img_green, //Prepared Image green data to be processed
input [7:0] per_img_blue, //Prepared Image blue data to be processed
output YCbCr_frame_vsync,
output YCbCr_frame_href,
output YCbCr_frame_clken,
output [7:0] YCbCr_img_Y_current, //输出当前帧的灰度,用于写入SDRAM
input [7:0] YCbCr_img_Y_pre, //同时从SDRAM中读出前一帧的灰度,与当前输出相差一个时钟周期
//Image data has been processd
output post_frame_vsync, //Processed Image data vsync valid signal
output post_frame_href, //Processed Image data href vaild signal
output post_frame_clken, //Processed Image data output/capture enable clock
output [7:0] post_img_red, //Processed Image red data to be processed
output [7:0] post_img_green, //Processed Image green data to be processed
output [7:0] post_img_blue, //Processed Image blue data to be processed
//user interface
input [7:0] Diff_Threshold, //Frame Difference Threshold for move detect
output target_detect
);
assign YCbCr_frame_vsync = post0_frame_vsync;
assign YCbCr_frame_href = post0_frame_href ;
assign YCbCr_frame_clken = post0_frame_clken;
assign YCbCr_img_Y_current = post0_img_Y ;
//-------------------------------------
//Convert the RGB888 format to YCbCr444 format.
wire post0_frame_vsync;
wire post0_frame_href ;
wire post0_frame_clken;
wire [7:0] post0_img_Y ;
wire [7:0] post0_img_Cb ;
wire [7:0] post0_img_Cr ;
VIP_RGB888_YCbCr444 u_VIP_RGB888_YCbCr444
(
//global clock
.clk (clk), //cmos video pixel clock
.rst_n (rst_n), //system reset
//Image data prepred to be processd
.per_frame_vsync (per_frame_vsync), //Prepared Image data vsync valid signal
.per_frame_href (per_frame_href), //Prepared Image data href vaild signal
.per_frame_clken (per_frame_clken), //Prepared Image data output/capture enable clock
.per_img_red (per_img_red), //Prepared Image red data input
.per_img_green (per_img_green), //Prepared Image green data input
.per_img_blue (per_img_blue), //Prepared Image blue data input
//Image data has been processd
.post_frame_vsync (post0_frame_vsync), //Processed Image frame data valid signal
.post_frame_href (post0_frame_href), //Processed Image hsync data valid signal
.post_frame_clken (post0_frame_clken), //Processed Image data output/capture enable clock
.post_img_Y (post0_img_Y), //Processed Image brightness output
.post_img_Cb (post0_img_Cb), //Processed Image blue shading output
.post_img_Cr (post0_img_Cr) //Processed Image red shading output
);
//--------------------------------------
//frame difference
wire post1_frame_vsync; //Processed Image data vsync valid signal
wire post1_frame_href; //Processed Image data href vaild signal
wire post1_frame_clken; //Processed Image data output/capture enable clock
wire post1_img_Bit; //Processed Image Bit flag outout(1: Value, 0:inValid)
VIP_Frame_Difference u_VIP_Frame_Difference(
//global clock
.clk (clk), //cmos video pixel clock
.rst_n (rst_n), //global reset
//Image data prepred to be processd
.per_frame_vsync (post0_frame_vsync), //Prepared Image data vsync valid signal
.per_frame_href (post0_frame_href), //Prepared Image data href vaild signal
.per_frame_clken (post0_frame_clken), //Prepared Image data output/capture enable clock
.per_img_Y (post0_img_Y), //Prepared Image brightness input
.YCbCr_img_Y_pre (YCbCr_img_Y_pre),
//Image data has been processd
.post_frame_vsync (post1_frame_vsync), //Processed Image data vsync valid signal
.post_frame_href (post1_frame_href), //Processed Image data href vaild signal
.post_frame_clken (post1_frame_clken), //Processed Image data output/capture enable clock
.post_img_Bit (post1_img_Bit), //Processed Image Bit flag outout(1: Value, 0:inValid)
//User interface
.Diff_Threshold (Diff_Threshold) //Sobel Threshold for image edge detect
);
//--------------------------------------
//Bit Image Process with Erosion before Dilation Detector.
wire post2_frame_vsync; //Processed Image data vsync valid signal
wire post2_frame_href; //Processed Image data href vaild signal
wire post2_frame_clken; //Processed Image data output/capture enable clock
wire post2_img_Bit; //Processed Image Bit flag outout(1: Value, 0:inValid)
VIP_Bit_Erosion_Detector
#(
.IMG_HDISP (IMG_HDISP), //640*480
.IMG_VDISP (IMG_VDISP)
)
u_VIP_Bit_Erosion_Detector
(
//global clock
.clk (clk), //cmos video pixel clock
.rst_n (rst_n), //global reset
//Image data prepred to be processd
.per_frame_vsync (post1_frame_vsync), //Prepared Image data vsync valid signal
.per_frame_href (post1_frame_href), //Prepared Image data href vaild signal
.per_frame_clken (post1_frame_clken), //Prepared Image data output/capture enable clock
.per_img_Bit (post1_img_Bit), //Processed Image Bit flag outout(1: Value, 0:inValid)
//Image data has been processd
.post_frame_vsync (post2_frame_vsync), //Processed Image data vsync valid signal
.post_frame_href (post2_frame_href), //Processed Image data href vaild signal
.post_frame_clken (post2_frame_clken), //Processed Image data output/capture enable clock
.post_img_Bit (post2_img_Bit) //Processed Image Bit flag outout(1: Value, 0:inValid)
);
//--------------------------------------
//Bit Image Process with Dilation after Erosion Detector.
wire post3_frame_vsync; //Processed Image data vsync valid signal
wire post3_frame_href; //Processed Image data href vaild signal
wire post3_frame_clken; //Processed Image data output/capture enable clock
wire post3_img_Bit; //Processed Image Bit flag outout(1: Value, 0:inValid)
VIP_Bit_Dilation_Detector
#(
.IMG_HDISP (IMG_HDISP), //640*480
.IMG_VDISP (IMG_VDISP)
)
u_VIP_Bit_Dilation_Detector
(
//global clock
.clk (clk), //cmos video pixel clock
.rst_n (rst_n), //global reset
//Image data prepred to be processd
.per_frame_vsync (post2_frame_vsync), //Prepared Image data vsync valid signal
.per_frame_href (post2_frame_href), //Prepared Image data href vaild signal
.per_frame_clken (post2_frame_clken), //Prepared Image data output/capture enable clock
.per_img_Bit (post2_img_Bit), //Processed Image Bit flag outout(1: Value, 0:inValid)
//Image data has been processd
.post_frame_vsync (post3_frame_vsync), //Processed Image data vsync valid signal
.post_frame_href (post3_frame_href), //Processed Image data href vaild signal
.post_frame_clken (post3_frame_clken), //Processed Image data output/capture enable clock
.post_img_Bit (post3_img_Bit) //Processed Image Bit flag outout(1: Value, 0:inValid)
);
wire [9:0] rectangular_up ;
wire [9:0] rectangular_down ;
wire [9:0] rectangular_left ;
wire [9:0] rectangular_right ;
wire rectangular_flag ;
//检测运动目标所在的矩形区域
VIP_detect_rectangular
#(
.IMG_HDISP (IMG_HDISP), //640*480
.IMG_VDISP (IMG_VDISP)
)
u_VIP_detect_rectangular
(
//global clock
.clk (clk), //cmos video pixel clock
.rst_n (rst_n), //global reset
//Image data prepred to be processd
.per_frame_vsync (post3_frame_vsync), //Prepared Image data vsync valid signal
.per_frame_href (post3_frame_href), //Prepared Image data href vaild signal
.per_frame_clken (post3_frame_clken), //Prepared Image data output/capture enable clock
.per_img_Bit (post3_img_Bit), //Processed Image Bit flag outout(1: Value, 0:inValid)
//检测出的矩形边界
.rectangular_up (rectangular_up ),
.rectangular_down (rectangular_down ),
.rectangular_left (rectangular_left ),
.rectangular_right (rectangular_right),
.rectangular_flag (rectangular_flag)
);
//在输入视频上叠加检测出的矩形框
VIP_Video_add_rectangular
#(
.IMG_HDISP (IMG_HDISP), //640*480
.IMG_VDISP (IMG_VDISP)
)
u_VIP_Video_add_rectangular
(
//global clock
.clk (clk), //cmos video pixel clock
.rst_n (rst_n), //global reset
//Image data prepred to be processd
.per_frame_vsync (per_frame_vsync), //Prepared Image data vsync valid signal
.per_frame_href (per_frame_href), //Prepared Image data href vaild signal
.per_frame_clken (per_frame_clken), //Prepared Image data output/capture enable clock
.per_img_red (per_img_red), //Prepared Image red data input
.per_img_green (per_img_green), //Prepared Image green data input
.per_img_blue (per_img_blue), //Prepared Image blue data input
//检测出的矩形边界
.rectangular_up (rectangular_up ),
.rectangular_down (rectangular_down ),
.rectangular_left (rectangular_left ),
.rectangular_right (rectangular_right),
.rectangular_flag (rectangular_flag),
.post_frame_vsync (post_frame_vsync), //Prepared Image data vsync valid signal
.post_frame_href (post_frame_href), //Prepared Image data href vaild signal
.post_frame_clken (post_frame_clken), //Prepared Image data output/capture enable clock
.post_img_red (post_img_red), //Prepared Image red data input
.post_img_green (post_img_green), //Prepared Image green data input
.post_img_blue (post_img_blue) //Prepared Image blue data input
);
assign target_detect = rectangular_flag;
endmodule
3. LCD driver top module
//功能:Avalon-ST视频流接口的ILI9488驱动模块
module vip_ILI9488(
input clk,
input clk12p5M,
input rst_n,
//Avalon-ST Sink
input sink_sop,
input sink_valid,
input [15:0] sink_data,
input sink_eop,
output sink_ready,
//Conduit
output lcd_intdone,
//TFTLCD interface
output WR,
output RD,
output CS,
output RS,
output BL_cnt,
output [15:0] data,
output RESET
);
wire sop_w0,eop_w0,valid_w0,ready_w0;
wire [15:0] data_w0;
wire sop_w1;
wire [15:0] data_w1;
wire fifo_empty_w,fifo_rd_w;
wire [7:0] wrusedw_w;
wire pixelReady;
reg valid_r1;
assign fifo_rd_w = !fifo_empty_w && pixelReady;
assign sink_ready = (wrusedw_w <= 8'd200);
always@(posedge clk12p5M or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
valid_r1 <= 1'b0;
end
else
begin
valid_r1 <= fifo_rd_w;
end
end
vip_ili9488_dcfifo u_vip_ili9488_dcfifo_0 (
.aclr(!rst_n),
.data({
sink_sop,sink_data}),
.rdclk(clk12p5M),
.rdreq(fifo_rd_w),
.wrclk(clk),
.wrreq(sink_valid),
.q({
sop_w1,data_w1}),
.rdempty(fifo_empty_w),
.wrusedw(wrusedw_w)
);
ILI9488 u_ILI9488_0(
.clk12p5M(clk12p5M),
.rst_n(rst_n),
.x_start(10'd0),//横坐标
.x_end(10'd479),
.y_start(10'd0),
.y_end(10'd319),//纵坐标
.color(data_w1), //RGB565
.sop(sop_w1),
.write_en(valid_r1), //high active
.write_ready(pixelReady),//write_en拉高后必须等待write_ready为高才表示
.lcd_intdone(lcd_intdone),//TFTLCD 初始化完成标志,高有效
.WR(WR),
.RD(RD),
.CS(CS),
.RS(RS),
.BL_cnt(BL_cnt),
.data(data),
.RESET(RESET)
);
endmodule
4. SDRAM controller top module
module Sdram_Control_4Port(
// HOST Side
REF_CLK,
OUT_CLK,
RESET_N,
// CLK, //
//CLK_18, //
// FIFO Write Side 1
WR1_DATA,
WR1,
WR1_ADDR,
WR1_MAX_ADDR,
WR1_LENGTH,
WR1_LOAD,
WR1_CLK,
WR1_FULL,
WR1_USE,
// FIFO Write Side 2
WR2_DATA,
WR2,
WR2_ADDR,
WR2_MAX_ADDR,
WR2_LENGTH,
WR2_LOAD,
WR2_CLK,
WR2_FULL,
WR2_USE,
// FIFO Read Side 1
RD1_DATA,
RD1,
RD1_ADDR,
RD1_MAX_ADDR,
RD1_LENGTH,
RD1_LOAD,
RD1_CLK,
RD1_EMPTY,
RD1_USE,
// FIFO Read Side 2
RD2_DATA,
RD2,
RD2_ADDR,
RD2_MAX_ADDR,
RD2_LENGTH,
RD2_LOAD,
RD2_CLK,
RD2_EMPTY,
RD2_USE,
// SDRAM Side
SA,
BA,
CS_N,
CKE,
RAS_N,
CAS_N,
WE_N,
DQ,
DQM,
SDR_CLK,
// user inter
Sdram_Init_Done
);
`include "Sdram_Params.h"
// HOST Side
input REF_CLK; //System Clock
input OUT_CLK;
input RESET_N; //System Reset
// FIFO Write Side 1
input [`DSIZE-1:0] WR1_DATA; //Data input
input WR1; //Write Request
input [`ASIZE-1:0] WR1_ADDR; //Write start address
input [`ASIZE-1:0] WR1_MAX_ADDR; //Write max address
input [8:0] WR1_LENGTH; //Write length
input WR1_LOAD; //Write register load & fifo clear
input WR1_CLK; //Write fifo clock
output WR1_FULL; //Write fifo full
output [15:0] WR1_USE; //Write fifo usedw
// FIFO Write Side 2
input [`DSIZE-1:0] WR2_DATA; //Data input
input WR2; //Write Request
input [`ASIZE-1:0] WR2_ADDR; //Write start address
input [`ASIZE-1:0] WR2_MAX_ADDR; //Write max address
input [8:0] WR2_LENGTH; //Write length
input WR2_LOAD; //Write register load & fifo clear
input WR2_CLK; //Write fifo clock
output WR2_FULL; //Write fifo full
output [15:0] WR2_USE; //Write fifo usedw
// FIFO Read Side 1
output [`DSIZE-1:0] RD1_DATA; //Data output
input RD1; //Read Request
input [`ASIZE-1:0] RD1_ADDR; //Read start address
input [`ASIZE-1:0] RD1_MAX_ADDR; //Read max address
input [8:0] RD1_LENGTH; //Read length
input RD1_LOAD; //Read register load & fifo clear
input RD1_CLK; //Read fifo clock
output RD1_EMPTY; //Read fifo empty
output [15:0] RD1_USE; //Read fifo usedw
// FIFO Read Side 2
output [`DSIZE-1:0] RD2_DATA; //Data output
input RD2; //Read Request
input [`ASIZE-1:0] RD2_ADDR; //Read start address
input [`ASIZE-1:0] RD2_MAX_ADDR; //Read max address
input [8:0] RD2_LENGTH; //Read length
input RD2_LOAD; //Read register load & fifo clear
input RD2_CLK; //Read fifo clock
output RD2_EMPTY; //Read fifo empty
output [15:0] RD2_USE; //Read fifo usedw
// SDRAM Side
output [11:0] SA; //SDRAM address output
output [1:0] BA; //SDRAM bank address
output [1:0] CS_N; //SDRAM Chip Selects
output CKE; //SDRAM clock enable
output RAS_N; //SDRAM Row address Strobe
output CAS_N; //SDRAM Column address Strobe
output WE_N; //SDRAM write enable
inout [`DSIZE-1:0] DQ; //SDRAM data bus
output [`DSIZE/8-1:0] DQM; //SDRAM data mask lines
output SDR_CLK; //SDRAM clock
assign SDR_CLK=OUT_CLK;
wire CLK=REF_CLK;
output Sdram_Init_Done;
// Internal Registers/Wires
// Controller
reg [`ASIZE-1:0] mADDR; //Internal address
reg [8:0] mLENGTH; //Internal length
reg [`ASIZE-1:0] rWR1_ADDR; //Register write address
reg [`ASIZE-1:0] rWR1_MAX_ADDR; //Register max write address
reg [8:0] rWR1_LENGTH; //Register write length
reg [`ASIZE-1:0] rWR2_ADDR; //Register write address
reg [`ASIZE-1:0] rWR2_MAX_ADDR; //Register max write address
reg [8:0] rWR2_LENGTH; //Register write length
reg [`ASIZE-1:0] rRD1_ADDR; //Register read address
reg [`ASIZE-1:0] rRD1_MAX_ADDR; //Register max read address
reg [8:0] rRD1_LENGTH; //Register read length
reg [`ASIZE-1:0] rRD2_ADDR; //Register read address
reg [`ASIZE-1:0] rRD2_MAX_ADDR; //Register max read address
reg [8:0] rRD2_LENGTH; //Register read length
reg [1:0] WR_MASK; //Write port active mask
reg [1:0] RD_MASK; //Read port active mask
reg mWR_DONE; //Flag write done, 1 pulse SDR_CLK
reg mRD_DONE; //Flag read done, 1 pulse SDR_CLK
reg mWR,Pre_WR; //Internal WR edge capture
reg mRD,Pre_RD; //Internal RD edge capture
reg [9:0] ST; //Controller status
reg [1:0] CMD; //Controller command
reg PM_STOP; //Flag page mode stop
reg PM_DONE; //Flag page mode done
reg Read; //Flag read active
reg Write; //Flag write active
reg [`DSIZE-1:0] mDATAOUT; //Controller Data output
wire [`DSIZE-1:0] mDATAIN; //Controller Data input
wire [`DSIZE-1:0] mDATAIN1; //Controller Data input 1
wire [`DSIZE-1:0] mDATAIN2; //Controller Data input 2
wire CMDACK; //Controller command acknowledgement
// DRAM Control
reg [`DSIZE/8-1:0] DQM; //SDRAM data mask lines
reg [11:0] SA; //SDRAM address output
reg [1:0] BA; //SDRAM bank address
reg [1:0] CS_N; //SDRAM Chip Selects
reg CKE; //SDRAM clock enable
reg RAS_N; //SDRAM Row address Strobe
reg CAS_N; //SDRAM Column address Strobe
reg WE_N; //SDRAM write enable
wire [`DSIZE-1:0] DQOUT; //SDRAM data out link
wire [`DSIZE/8-1:0] IDQM; //SDRAM data mask lines
wire [11:0] ISA; //SDRAM address output
wire [1:0] IBA; //SDRAM bank address
wire [1:0] ICS_N; //SDRAM Chip Selects
wire ICKE; //SDRAM clock enable
wire IRAS_N; //SDRAM Row address Strobe
wire ICAS_N; //SDRAM Column address Strobe
wire IWE_N; //SDRAM write enable
// FIFO Control
reg OUT_VALID; //Output data request to read side fifo
reg IN_REQ; //Input data request to write side fifo
wire [15:0] write_side_fifo_rusedw1;
wire [15:0] read_side_fifo_wusedw1;
wire [15:0] write_side_fifo_rusedw2;
wire [15:0] read_side_fifo_wusedw2;
// DRAM Internal Control
wire [`ASIZE-1:0] saddr;
wire load_mode;
wire nop;
wire reada;
wire writea;
wire refresh;
wire precharge;
wire oe;
wire ref_ack;
wire ref_req;
wire init_req;
wire cm_ack;
wire active;
/*
Sdram_PLL sdram_pll1 (
.inclk0(REF_CLK),
.c0(CLK),
.c1(SDR_CLK),
.c2(CLK_18)
);
*/
control_interface control1 (
.CLK(CLK),
.RESET_N(RESET_N),
.CMD(CMD),
.ADDR(mADDR),
.REF_ACK(ref_ack),
.CM_ACK(cm_ack),
.NOP(nop),
.READA(reada),
.WRITEA(writea),
.REFRESH(refresh),
.PRECHARGE(precharge),
.LOAD_MODE(load_mode),
.SADDR(saddr),
.REF_REQ(ref_req),
.INIT_REQ(init_req),
.CMD_ACK(CMDACK),
.Sdram_Init_Done(Sdram_Init_Done)
);
command command1(
.CLK(CLK),
.RESET_N(RESET_N),
.SADDR(saddr),
.NOP(nop),
.READA(reada),
.WRITEA(writea),
.REFRESH(refresh),
.LOAD_MODE(load_mode),
.PRECHARGE(precharge),
.REF_REQ(ref_req),
.INIT_REQ(init_req),
.REF_ACK(ref_ack),
.CM_ACK(cm_ack),
.OE(oe),
.PM_STOP(PM_STOP),
.PM_DONE(PM_DONE),
.SA(ISA),
.BA(IBA),
.CS_N(ICS_N),
.CKE(ICKE),
.RAS_N(IRAS_N),
.CAS_N(ICAS_N),
.WE_N(IWE_N)
);
sdr_data_path data_path1(
.CLK(CLK),
.RESET_N(RESET_N),
.DATAIN(mDATAIN),
.DM(2'b00),
.DQOUT(DQOUT),
.DQM(IDQM)
);
Sdram_WR_FIFO write_fifo1(
.data(WR1_DATA),
.wrreq(WR1),
.wrclk(WR1_CLK),
.aclr(WR1_LOAD),
.rdreq(IN_REQ&WR_MASK[0]),
.rdclk(CLK),
.q(mDATAIN1),
.wrfull(WR1_FULL),
.wrusedw(WR1_USE),
.rdusedw(write_side_fifo_rusedw1)
);
Sdram_WR_FIFO write_fifo2(
.data(WR2_DATA),
.wrreq(WR2),
.wrclk(WR2_CLK),
.aclr(WR2_LOAD),
.rdreq(IN_REQ&WR_MASK[1]),
.rdclk(CLK),
.q(mDATAIN2),
.wrfull(WR2_FULL),
.wrusedw(WR2_USE),
.rdusedw(write_side_fifo_rusedw2)
);
assign mDATAIN = (WR_MASK[0]) ? mDATAIN1 :
mDATAIN2 ;
Sdram_RD_FIFO read_fifo1(
.data(mDATAOUT),
.wrreq(OUT_VALID&RD_MASK[0]),
.wrclk(CLK),
.aclr(RD1_LOAD),
.rdreq(RD1),
.rdclk(RD1_CLK),
.q(RD1_DATA),
.wrusedw(read_side_fifo_wusedw1),
.rdempty(RD1_EMPTY),
.rdusedw(RD1_USE)
);
Sdram_RD_FIFO read_fifo2(
.data(mDATAOUT),
.wrreq(OUT_VALID&RD_MASK[1]),
.wrclk(CLK),
.aclr(RD2_LOAD),
.rdreq(RD2),
.rdclk(RD2_CLK),
.q(RD2_DATA),
.wrusedw(read_side_fifo_wusedw2),
.rdempty(RD2_EMPTY),
.rdusedw(RD2_USE)
);
always @(posedge CLK)
begin
SA <= (ST==SC_CL+mLENGTH) ? 12'h200 : ISA;
BA <= IBA;
CS_N <= ICS_N;
CKE <= ICKE;
RAS_N <= (ST==SC_CL+mLENGTH) ? 1'b0 : IRAS_N;
CAS_N <= (ST==SC_CL+mLENGTH) ? 1'b1 : ICAS_N;
WE_N <= (ST==SC_CL+mLENGTH) ? 1'b0 : IWE_N;
PM_STOP <= (ST==SC_CL+mLENGTH) ? 1'b1 : 1'b0;
PM_DONE <= (ST==SC_CL+SC_RCD+mLENGTH+2) ? 1'b1 : 1'b0;
DQM <= {
(`DSIZE/8){
1'b0}}; //( active && (ST>=SC_CL) ) ? ( ((ST==SC_CL+mLENGTH) && Write)? 2'b11 : 2'b00 ) : 2'b11 ;
mDATAOUT<= DQ;
end
assign DQ = oe ? DQOUT : `DSIZE'hzzzz;
assign active = Read | Write;
always@(posedge CLK or negedge RESET_N)
begin
if(RESET_N==0)
begin
CMD <= 0;
ST <= 0;
Pre_RD <= 0;
Pre_WR <= 0;
Read <= 0;
Write <= 0;
OUT_VALID <= 0;
IN_REQ <= 0;
mWR_DONE <= 0;
mRD_DONE <= 0;
end
else
begin
Pre_RD <= mRD;
Pre_WR <= mWR;
case(ST)
0: begin
if({
Pre_RD,mRD}==2'b01)
begin
Read <= 1;
Write <= 0;
CMD <= 2'b01;
ST <= 1;
end
else if({
Pre_WR,mWR}==2'b01)
begin
Read <= 0;
Write <= 1;
CMD <= 2'b10;
ST <= 1;
end
end
1: begin
if(CMDACK==1)
begin
CMD<=2'b00;
ST<=2;
end
end
default:
begin
if(ST!=SC_CL+SC_RCD+mLENGTH+1)
ST<=ST+1;
else
ST<=0;
end
endcase
if(Read)
begin
if(ST==SC_CL+SC_RCD+1)
OUT_VALID <= 1;
else if(ST==SC_CL+SC_RCD+mLENGTH+1)
begin
OUT_VALID <= 0;
Read <= 0;
mRD_DONE <= 1;
end
end
else
mRD_DONE <= 0;
if(Write)
begin
if(ST==SC_CL-1)
IN_REQ <= 1;
else if(ST==SC_CL+mLENGTH-1)
IN_REQ <= 0;
else if(ST==SC_CL+SC_RCD+mLENGTH)
begin
Write <= 0;
mWR_DONE<= 1;
end
end
else
mWR_DONE<= 0;
end
end
// Internal Address & Length Control
always@(posedge CLK or negedge RESET_N)
begin
if(!RESET_N)
begin
rWR1_ADDR <= WR1_ADDR;
rWR1_MAX_ADDR <= WR1_MAX_ADDR;
rWR2_ADDR <= WR2_ADDR;
rWR2_MAX_ADDR <= WR2_MAX_ADDR;
rRD1_ADDR <= RD1_ADDR;
rRD1_MAX_ADDR <= RD1_MAX_ADDR;
rRD2_ADDR <= RD2_ADDR;
rRD2_MAX_ADDR <= RD2_MAX_ADDR;
rWR1_LENGTH <=WR1_LENGTH;
rRD1_LENGTH <=RD1_LENGTH;
rWR2_LENGTH <=WR2_LENGTH;
rRD2_LENGTH <=RD2_LENGTH;
end
else
begin
// Write Side 1
if(WR1_LOAD)
begin
rWR1_ADDR <= WR1_ADDR;
rWR1_LENGTH <= WR1_LENGTH;
end
else if(mWR_DONE&WR_MASK[0])
begin
if(rWR1_ADDR<rWR1_MAX_ADDR-rWR1_LENGTH)
rWR1_ADDR <= rWR1_ADDR+rWR1_LENGTH;
else
rWR1_ADDR <= WR1_ADDR;
end
// Write Side 2
if(WR2_LOAD)
begin
rWR2_ADDR <= WR2_ADDR;
rWR2_LENGTH <= WR2_LENGTH;
end
else if(mWR_DONE&WR_MASK[1])
begin
if(rWR2_ADDR<rWR2_MAX_ADDR-rWR2_LENGTH)
rWR2_ADDR <= rWR2_ADDR+rWR2_LENGTH;
else
rWR2_ADDR <= WR2_ADDR;
end
// Read Side 1
if(RD1_LOAD)
begin
rRD1_ADDR <= RD1_ADDR;
rRD1_LENGTH <= RD1_LENGTH;
end
else if(mRD_DONE&RD_MASK[0])
begin
if(rRD1_ADDR<rRD1_MAX_ADDR-rRD1_LENGTH)
rRD1_ADDR <= rRD1_ADDR+rRD1_LENGTH;
else
rRD1_ADDR <= RD1_ADDR;
end
// Read Side 2
if(RD2_LOAD)
begin
rRD2_ADDR <= RD2_ADDR;
rRD2_LENGTH <= RD2_LENGTH;
end
else if(mRD_DONE&RD_MASK[1])
begin
if(rRD2_ADDR<rRD2_MAX_ADDR-rRD2_LENGTH)
rRD2_ADDR <= rRD2_ADDR+rRD2_LENGTH;
else
rRD2_ADDR <= RD2_ADDR;
end
end
end
// Auto Read/Write Control
always@(posedge CLK or negedge RESET_N)
begin
if(!RESET_N)
begin
mWR <= 0;
mRD <= 0;
mADDR <= 0;
mLENGTH <= 0;
RD_MASK <= 0;
WR_MASK <= 0;
end
else if(Sdram_Init_Done)
begin
if( (mWR==0) && (mRD==0) && (ST==0) &&
(WR_MASK==0) && (RD_MASK==0) &&
(WR1_LOAD==0) && (RD1_LOAD==0) &&
(WR2_LOAD==0) && (RD2_LOAD==0) )
begin
// Read Side 1
if( (read_side_fifo_wusedw1 < rRD1_LENGTH) )
begin
mADDR <= rRD1_ADDR;
mLENGTH <= rRD1_LENGTH;
WR_MASK <= 2'b00;
RD_MASK <= 2'b01;
mWR <= 0;
mRD <= 1;
end
// Read Side 2
else if( (read_side_fifo_wusedw2 < rRD2_LENGTH) )
begin
mADDR <= rRD2_ADDR;
mLENGTH <= rRD2_LENGTH;
WR_MASK <= 2'b00;
RD_MASK <= 2'b10;
mWR <= 0;
mRD <= 1;
end
// Write Side 1
else if( (write_side_fifo_rusedw1 >= rWR1_LENGTH) && (rWR1_LENGTH!=0) )
begin
mADDR <= rWR1_ADDR;
mLENGTH <= rWR1_LENGTH;
WR_MASK <= 2'b01;
RD_MASK <= 2'b00;
mWR <= 1;
mRD <= 0;
end
// Write Side 2
else if( (write_side_fifo_rusedw2 >= rWR2_LENGTH) && (rWR2_LENGTH!=0) )
begin
mADDR <= rWR2_ADDR;
mLENGTH <= rWR2_LENGTH;
WR_MASK <= 2'b10;
RD_MASK <= 2'b00;
mWR <= 1;
mRD <= 0;
end
end
if(mWR_DONE)
begin
WR_MASK <= 0;
mWR <= 0;
end
if(mRD_DONE)
begin
RD_MASK <= 0;
mRD <= 0;
end
end
end
endmodule
5. Host computer sending module
module uart_tx_ctrl(
input clk,
input rst_n,
input target_detect,
output reg uart_tx_en ,
output reg [7:0] uart_tx_data,
input uart_tx_done
);
wire [ 7:0] string_data [15:0]; //待发送字符串
assign string_data[0] = "I";
assign string_data[1] = "n";
assign string_data[2] = "t";
assign string_data[3] = "r";
assign string_data[4] = "u";
assign string_data[5] = "d";
assign string_data[6] = "e";
assign string_data[7] = "r";
assign string_data[8] = 8'h21; // '!'
assign string_data[9] = 8'h0A; // '\n'
reg [4:0] ctrl_state ;
reg [3:0] cmd_byte_cnt;
//状态机,
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ctrl_state <= 5'd0;
cmd_byte_cnt <= 4'd0;
uart_tx_en <= 1'b0;
uart_tx_data <= 8'd0;
end
else begin
case(ctrl_state)
//Idle,无数据发送状态
5'd0: begin
cmd_byte_cnt <= 4'd0;
uart_tx_en <= 1'b0;
uart_tx_data <= 8'd0;
if(target_detect == 1'b1) begin //有目标出现
ctrl_state <= 5'd1;
end
else begin
ctrl_state <= 5'd0;
end
end
//开始发送串口数据
5'd1: begin
uart_tx_en <= 1'b1; //拉高发送使能
uart_tx_data <= string_data[cmd_byte_cnt];
ctrl_state <= 5'd2; //等待发送完成
end
//等待字节发送完成
5'd2: begin
uart_tx_en <= 1'b0;
if(uart_tx_done) begin // 字节发送完成
if(cmd_byte_cnt < 4'd9) begin
ctrl_state <= 5'd1; //字符串继续发送
cmd_byte_cnt <= cmd_byte_cnt + 1'b1;
end
else begin
ctrl_state <= 5'd0; //字符串继续发送
cmd_byte_cnt <= 4'd0;
end
end
end
default: begin
ctrl_state <= 5'd0;
end
endcase
end
end
endmodule
5. Obtaining engineering and kits
1. Project acquisition
A: Click to download directly: Based on FPGA: moving target detection (LCD display + serial port output, complete project).zip
B: Private message me or add email to get it (complete schematic diagram + source code project + key module simulation) (in addition, a VGA display based on FPGA single-target motion detection will be given as a gift)
2. Suite
I find it troublesome to debug. I have several sets of debugged kits in my hand. If necessary, I can buy them. You can see the phenomenon after powering on, which is convenient. If you need to add my email: [email protected].