01FPGA圖像仿真方法概述
VHDL和Verilog代碼編寫后通常需要編寫激勵文件進行仿真以驗證代碼的可行性,通過仿真可以及時排查代碼存在的時序問題,有效提高代碼實現(xiàn)效率。
圖像數據量通常較大,1920×1080@60Hz分辨率的圖像通常需要1920×1080個8bit寄存器reg,因此在仿真中通常難以直接編寫語句生成相應的代碼,因此需要借助相應圖像格式文件的讀取操作和文件格式轉換工具輔助。
Matlab是圖像算法設計驗證常用工具,因此主要以Matlab為輔助工具,對FPGA圖像仿真方法進行介紹,通常采用以下3種方法:
1. .txt格式圖像仿真方法:Verilog代碼通常支持通過$readmemh、$readmemb、$fopen等語句讀取.txt文本文件,因此可以借助Matlab將圖像轉換為.txt格式圖像文本,編寫.txt文件讀取代碼實現(xiàn)FPGA圖像仿真;
2. .coe格式圖像仿真方法:EDA工具通常提供ROM IP核支持.coe格式文件存儲,因此可以借助Matlab將圖像轉換為.coe格式文件,將.coe文件存入ROM,通過操作ROM讀取圖像數據實現(xiàn)FPGA圖像仿真;
3. 圖像存儲模塊仿真方法:通過編寫圖像存儲.v或.vhdl模塊以供頂層文件讀取,由于圖像數據量較大,可以借助Matlab工具實現(xiàn)存儲模塊的編寫過程。
02.txt格式圖像仿真方法
通過讀取.txt格式圖像文件實現(xiàn)基于Verilog仿真步驟:
1. 利用Matlab轉換.jpg或者其他圖像為.txt格式數據;
2. 通過Vivado完成圖像讀取處理并生成.txt格式文件;
3. 利用Matlab轉換顯示Vivado處理后的.txt格式圖像。
2.1 Matlab生成.txt文件
通過Matlab將圖像按16進制轉換為.txt格式,文件夾中應包含輸入圖片cascatrix.jpg:
Matlab代碼如下:
%**********************************************************************
% -------------------------------------------------------------------
% Company: Cascatrix
% Engineer: Carson
%
% Create Date: 2023/01/19
% Design Name: rgb_hex
% Module Name: rgb_hex
% Tool Versions: v1.0
% Description: Convert RGB888 into .txt
%-------------------------------------------------------------------
%*********************************************************************/
clear;clear all;clc;
% Load image
image_in = imread('cascatrix.jpg');
% Create .txt file
FileName=['image_in','.txt'];
% Get image size
[row,col,n] = size(image_in);
% Write image into image_in.txt
FileImage = fopen(FileName,'w');
for x = 1:row
for y = 1:col
image_r = dec2hex(image_in(x,y,1));
image_g = dec2hex(image_in(x,y,2));
image_b = dec2hex(image_in(x,y,3));
[r_row,r_col]=size(image_r);
[g_row,g_col]=size(image_g);
[b_row,b_col]=size(image_b);
if r_col == 1
image_r =['0',image_r];
elseif r_col == 0
image_r ='00';
end
if g_col == 1
image_g =['0',image_g];
elseif g_col == 0
image_g ='00';
end
if b_col == 1
image_b =['0',image_b];
elseif b_col == 0
image_b ='00';
end
image_hex=[image_r,image_g,image_b,];
fprintf(FileImage,'%s ',image_hex);
end
end
fclose(FileImage);
rgb_hex代碼運行后生成.txt格式圖像image_in.txt:
2.2 VIVADO讀取與處理
利用Verilog $readmemh語句讀取image_in.txt文件:
cx_image.v模塊(將.txt文件放置在相應路徑):
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/01/19
// Design Name: Image_Base
// Module Name: cx_image
// Tool Versions: v1.0
// Description: Image read and generate display
//parameters
//////////////////////////////////////////////////////////////////////////////////
`define PIXEL_1920_1080
//`define PIXEL_1680_1050
//`define PIXEL_1280_1024
//`define PIXEL_1280_720
//`define PIXEL_1024_768
//`define PIXEL_800_600
//`define PIXEL_640_480
module cx_image(
inputwireclk,
outputreghsyn,
outputregvsyn,
outputwireen,
outputreg [23:0]data
);
//1920x1080 148.5Mhz
`ifdef PIXEL_1920_1080
parameter H_ACTIVE = 1920;// 行數據有效時間
parameter H_FRONT_PORCH = 88; // 行消隱前肩時間
parameter H_SYNC_TIME = 44; // 行同步信號時間
parameter H_BACK_PORCH = 148; // 行消隱后肩時間
parameter V_ACTIVE = 1080;// 列數據有效時間
parameter V_FRONT_PORCH = 4; // 列消隱前肩時間
parameter V_SYNC_TIME = 5; // 列同步信號時間
parameter V_BACK_PORCH = 36; // 列消隱后肩時間
`endif
//1680x1050 119Mhz
`ifdef PIXEL_1680_1050
parameter H_ACTIVE = 1680;// 行數據有效時間
parameter H_FRONT_PORCH = 48; // 行消隱前肩時間
parameter H_SYNC_TIME = 32; // 行同步信號時間
parameter H_BACK_PORCH = 80; // 行消隱后肩時間
parameter V_ACTIVE = 1050;// 列數據有效時間
parameter V_FRONT_PORCH = 3; // 列消隱前肩時間
parameter V_SYNC_TIME = 6; // 列同步信號時間
parameter V_BACK_PORCH = 21; // 列消隱后肩時間
`endif
//1280x1024 108Mhz
`ifdef PIXEL_1280_1024
parameter H_ACTIVE = 1280;// 行數據有效時間
parameter H_FRONT_PORCH = 48; // 行消隱前肩時間
parameter H_SYNC_TIME = 112; // 行同步信號時間
parameter H_BACK_PORCH = 248; // 行消隱后肩時間
parameter V_ACTIVE = 1024;// 列數據有效時間
parameter V_FRONT_PORCH = 1; // 列消隱前肩時間
parameter V_SYNC_TIME = 3; // 列同步信號時間
parameter V_BACK_PORCH = 38; // 列消隱后肩時間
`endif
//1280X720 74.25MHZ
`ifdef PIXEL_1280_720
parameter H_ACTIVE = 1280;// 行數據有效時間
parameter H_FRONT_PORCH = 110; // 行消隱前肩時間
parameter H_SYNC_TIME = 40; // 行同步信號時間
parameter H_BACK_PORCH = 220; // 行消隱后肩時間
parameter V_ACTIVE = 720; // 列數據有效時間
parameter V_FRONT_PORCH = 5; // 列消隱前肩時間
parameter V_SYNC_TIME = 5; // 列同步信號時間
parameter V_BACK_PORCH = 20; // 列消隱后肩時間
`endif
//1024x768 65Mhz
`ifdef PIXEL_1024_768
parameter H_ACTIVE = 1024;// 行數據有效時間
parameter H_FRONT_PORCH = 24; // 行消隱前肩時間
parameter H_SYNC_TIME = 136; // 行同步信號時間
parameter H_BACK_PORCH = 160; // 行消隱后肩時間
parameter V_ACTIVE = 768; // 列數據有效時間
parameter V_FRONT_PORCH = 3; // 列消隱前肩時間
parameter V_SYNC_TIME = 6; // 列同步信號時間
parameter V_BACK_PORCH = 29; // 列消隱后肩時間
`endif
//800x600 40Mhz
`ifdef PIXEL_800_600
parameter H_ACTIVE = 800;// 行數據有效時間
parameter H_FRONT_PORCH = 40 ;// 行消隱前肩時間
parameter H_SYNC_TIME = 128;// 行同步信號時間
parameter H_BACK_PORCH = 88 ;// 行消隱后肩時間
parameter V_ACTIVE = 600;// 列數據有效時間
parameter V_FRONT_PORCH = 1 ;// 列消隱前肩時間
parameter V_SYNC_TIME = 4 ;// 列同步信號時間
parameter V_BACK_PORCH = 23 ;// 列消隱后肩時間
`endif
//640x480 25.175Mhz
`ifdef PIXEL_640_480
parameter H_ACTIVE = 640; // 行數據有效時間
parameter H_FRONT_PORCH = 16 ; // 行消隱前肩時間
parameter H_SYNC_TIME = 96 ; // 行同步信號時間
parameter H_BACK_PORCH = 48 ; // 行消隱后肩時間
parameter V_ACTIVE = 480; // 列數據有效時間
parameter V_FRONT_PORCH = 10 ; // 列消隱前肩時間
parameter V_SYNC_TIME = 2 ; // 列同步信號時間
parameter V_BACK_PORCH = 33 ; // 列消隱后肩時間
`endif
parameter H_TOTAL_TIME = H_ACTIVE + H_FRONT_PORCH + H_SYNC_TIME + H_BACK_PORCH;
parameter V_TOTAL_TIME = V_ACTIVE + V_FRONT_PORCH + V_SYNC_TIME + V_BACK_PORCH;
reg h_act = 1'b0;
reg v_act = 1'b0;
reg [12:0] h_syn_cnt = 13'b0;
reg [12:0] v_syn_cnt = 13'b0;
reg [23:0] image [0 : H_ACTIVE*V_ACTIVE-1];
reg [31:0] image_cnt = 32'b0;
// 讀取.txt文件到image數組中
initial begin
$readmemh("D:/FPGA_Document/CX_Document/CX_Image/ 01_Image_process_base/image_src/image_in.txt", image);
end
// 行掃描計數器
always@(posedge clk)
begin
if(h_syn_cnt == H_TOTAL_TIME-1)
h_syn_cnt <= 13'b0;
else
h_syn_cnt <= h_syn_cnt + 1;
end
// 列掃描計數器
always@(posedge clk)
begin
if(h_syn_cnt == H_TOTAL_TIME-1)
begin
if(v_syn_cnt == V_TOTAL_TIME-1)
v_syn_cnt <= 13'b0;
else
v_syn_cnt <= v_syn_cnt + 1;
end
end
// 行同步控制
always@(posedge clk)
begin
if(h_syn_cnt < H_SYNC_TIME)
hsyn <= 1'b0;
else
hsyn <= 1'b1;
end
// 場同步控制
always@(posedge clk)
begin
if(v_syn_cnt < V_SYNC_TIME)
vsyn <= 1'b0;
else
vsyn <= 1'b1;
end
// 有效數據使能
assign en = h_act & v_act;
// 行有效數據控制
always@(posedge clk)
begin
if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH - 1)
h_act = 1'b1;
else if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE - 1)
h_act = 1'b0;
end
// 列有效數據控制
always@(posedge clk)
begin
if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH - 1 && h_syn_cnt == 0)
v_act = 1'b1;
else if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE - 1 && h_syn_cnt == 0)
v_act = 1'b0;
end
// 像素計數器
always@(posedge clk)
begin
if(h_act & v_act)
image_cnt <= image_cnt + 1;
else if(image_cnt == H_ACTIVE*V_ACTIVE - 1)
image_cnt <= 32'b0;
end
// 圖像數據
always@(posedge clk)
begin
if(h_act & v_act)
data <= image[image_cnt][23:0];
else
data <= 24'b0;
end
endmodule
利用Verilog $fopen和$fwrite生成.txt圖像文件:
cx_tb.v仿真模塊(生成圖像文件到相應路徑):
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/01/19
// Design Name: Image_Base
// Module Name: cx_tb
// Tool Versions: v1.0
// Description: Image output simulation
//////////////////////////////////////////////////////////////////////////////////
module cx_tb(
);
reg clk;
reg [31:0] pixel_cnt;
wire de;
wire [23:0] data;
integer image_txt;
parameter PIXEL_TOTAL = 1920*1080;
//parameter PIXEL_TOTAL = 1680*1050;
//parameter PIXEL_TOTAL = 1280*1024;
//parameter PIXEL_TOTAL = 1280*720;
//parameter PIXEL_TOTAL = 1024*768;
//parameter PIXEL_TOTAL = 800*600;
//parameter PIXEL_TOTAL = 640*480;
cx_image inst_cx_image
(
.clk (clk ),
.hsyn ( ),
.vsyn ( ),
.en (de ),
.data (data)
);
always #1 clk = ~clk;
initial
begin
clk = 1‘b0;
end
initial
begin
image_txt = $fopen("D:/FPGA_Document/CX_Document/CX _Image/01_Image_process_base/image_src/image_out.txt");
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
pixel_cnt <= 0;
end
else if(de)
begin
pixel_cnt = pixel_cnt + 1;
$fwrite(image_txt,"%h ",data);
end
end
always@(posedge clk)
begin
if(pixel_cnt == PIXEL_TOTAL)
begin
$display("CX: image_out.txt is output completed successfully! %t", $realtime, "ps");
$fclose(image_txt);
$stop;
end
end
endmodule
仿真波形結果:
在指定路徑生成處理后的.txt圖像文件image_out.txt:
2.3 Matlab顯示.txt文件
通過Matlab將處理后的.txt圖像image_out.txt顯示,并轉換為jpg或其他格式圖像,編寫hex_rgb.m文件:
Matlab代碼如下:
%**********************************************************************
% -------------------------------------------------------------------
% Company: Cascatrix
% Engineer: Carson
%
% Create Date: 2023/01/19
% Design Name: hex_rgb
% Module Name: hex_rgb
% Tool Versions: v1.0
% Description: Convert .txt into RGB888
%-------------------------------------------------------------------
%*********************************************************************/
clear;clear all;clc;
% Image resolution
row = 1080;
col = 1920;
n = 3;
% Create output image
image_out = uint8(zeros(row,col,n));
% Write data into output image
FileImage = fopen('image_out.txt','r');
for x = 1:row
for y = 1:col
RGB = fscanf(FileImage,'%s',1);
image_out(x,y,1) = uint8(hex2dec(RGB(1:2)));
image_out(x,y,2) = uint8(hex2dec(RGB(3:4)));
image_out(x,y,3) = uint8(hex2dec(RGB(5:6)));
end
end
fclose(FileImage);
% Show the output image
imshow(image_out),title('Image output');
% Create image in .jpg format
imwrite(image_out,'cascatrix_output.jpg');
運行結果:
生成cascatrix_output.jpg
03.coe格式圖像仿真方法
通過讀取.coe格式圖像文件實現(xiàn)FPGA仿真步驟:
1. 利用Matlab通過圖像獲取.coe格式數據;
2. 通過操作ROM讀取圖像并處理生成.txt格式文件;
3. 利用Matlab轉換顯示Vivado處理后的.txt格式圖像。
3.1 Matlab獲取.coe文件
利用Matlab獲取圖像數據并生成.coe文件:
Matlab代碼如下:
%**********************************************************************
% -------------------------------------------------------------------
% Company: Cascatrix
% Engineer: Carson
%
% Create Date: 2023/01/19
% Design Name: rgb_coe
% Module Name: rgb_coe
% Tool Versions: v1.0
% Description: Convert RGB888 into .coe
%-------------------------------------------------------------------
%*********************************************************************/
clear;clear all;clc;
% Load image
image_in = imread('cascatrix.jpg');
% Create .coe file
FileName=['image_in','.coe'];
% Get image size
[row,col,n] = size(image_in);
% Write image into image_in.coe
FileImage = fopen(FileName,'w');
% Format of image.coe
fprintf(FileImage,'memory_initialization_radix = 16; ');
fprintf(FileImage,'memory_initialization_vector = ');
for x = 1:row
for y = 1:col
image_r = dec2hex(image_in(x,y,1));
image_g = dec2hex(image_in(x,y,2));
image_b = dec2hex(image_in(x,y,3));
[r_row,r_col]=size(image_r);
[g_row,g_col]=size(image_g);
[b_row,b_col]=size(image_b);
if r_col == 1
image_r =['0',image_r];
elseif r_col == 0
image_r ='00';
end
if g_col == 1
image_g =['0',image_g];
elseif g_col == 0
image_g ='00';
end
if b_col == 1
image_b =['0',image_b];
elseif b_col == 0
image_b ='00';
end
if((x == row)&&(y == col))
image_hex=[image_r,image_g,image_b,';'];
else
image_hex=[image_r,image_g,image_b,','];
end
fprintf(FileImage,'%s ',image_hex);
end
end
fclose(FileImage);
rgb_coe代碼運行后生成.coe文件image_in.coe:
3.2 Vivado操作ROM
調用配置ROM IP核,通過操作ROM讀取圖像數據:
由于Vivado中ROM IP支持最大深度為1048576,無法完全存儲1920×1080=2073600的圖像數據,因此只能存儲1280×720=921600的圖像數據,上述.coe文件也應當由1280×720分辨率的圖像生成:
導入Matlab生成的image_in.coe文件為初始數據的,.coe文件內容一定要與上一步配置的接口寬度和深度相匹配,否則將會報錯:
完成所有配置后,cx_image.v調用ROM并讀取數據:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/01/15
// Design Name: Image_Base
// Module Name: cx_image
// Tool Versions: v1.0
// Description: Image read and generate display parameters
//
//////////////////////////////////////////////////////////////////////////////////
//`define PIXEL_1920_1080
//`define PIXEL_1680_1050
//`define PIXEL_1280_1024
`define PIXEL_1280_720
//`define PIXEL_1024_768
//`define PIXEL_800_600
//`define PIXEL_640_480
module cx_image(
inputwireclk,
outputreghs,
outputregvs,
outputwireen,
outputwire [23:0]data
);
//1920x1080 148.5Mhz
`ifdef PIXEL_1920_1080
parameter H_ACTIVE = 1920;// 行數據有效時間
parameter H_FRONT_PORCH = 88; // 行消隱前肩時間
parameter H_SYNC_TIME = 44; // 行同步信號時間
parameter H_BACK_PORCH = 148; // 行消隱后肩時間
parameter V_ACTIVE = 1080;// 列數據有效時間
parameter V_FRONT_PORCH = 4; // 列消隱前肩時間
parameter V_SYNC_TIME = 5; // 列同步信號時間
parameter V_BACK_PORCH = 36; // 列消隱后肩時間
`endif
//1680x1050 119Mhz
`ifdef PIXEL_1680_1050
parameter H_ACTIVE = 1680;// 行數據有效時間
parameter H_FRONT_PORCH = 48; // 行消隱前肩時間
parameter H_SYNC_TIME = 32; // 行同步信號時間
parameter H_BACK_PORCH = 80; // 行消隱后肩時間
parameter V_ACTIVE = 1050;// 列數據有效時間
parameter V_FRONT_PORCH = 3; // 列消隱前肩時間
parameter V_SYNC_TIME = 6; // 列同步信號時間
parameter V_BACK_PORCH = 21; // 列消隱后肩時間
`endif
//1280x1024 108Mhz
`ifdef PIXEL_1280_1024
parameter H_ACTIVE = 1280;// 行數據有效時間
parameter H_FRONT_PORCH = 48; // 行消隱前肩時間
parameter H_SYNC_TIME = 112; // 行同步信號時間
parameter H_BACK_PORCH = 248; // 行消隱后肩時間
parameter V_ACTIVE = 1024;// 列數據有效時間
parameter V_FRONT_PORCH = 1; // 列消隱前肩時間
parameter V_SYNC_TIME = 3; // 列同步信號時間
parameter V_BACK_PORCH = 38; // 列消隱后肩時間
`endif
//1280X720 74.25MHZ
`ifdef PIXEL_1280_720
parameter H_ACTIVE = 1280;// 行數據有效時間
parameter H_FRONT_PORCH = 110; // 行消隱前肩時間
parameter H_SYNC_TIME = 40; // 行同步信號時間
parameter H_BACK_PORCH = 220; // 行消隱后肩時間
parameter V_ACTIVE = 720; // 列數據有效時間
parameter V_FRONT_PORCH = 5; // 列消隱前肩時間
parameter V_SYNC_TIME = 5; // 列同步信號時間
parameter V_BACK_PORCH = 20; // 列消隱后肩時間
`endif
//1024x768 65Mhz
`ifdef PIXEL_1024_768
parameter H_ACTIVE = 1024;// 行數據有效時間
parameter H_FRONT_PORCH = 24; // 行消隱前肩時間
parameter H_SYNC_TIME = 136; // 行同步信號時間
parameter H_BACK_PORCH = 160; // 行消隱后肩時間
parameter V_ACTIVE = 768; // 列數據有效時間
parameter V_FRONT_PORCH = 3; // 列消隱前肩時間
parameter V_SYNC_TIME = 6; // 列同步信號時間
parameter V_BACK_PORCH = 29; // 列消隱后肩時間
`endif
//800x600 40Mhz
`ifdef PIXEL_800_600
parameter H_ACTIVE = 800;// 行數據有效時間
parameter H_FRONT_PORCH = 40 ;// 行消隱前肩時間
parameter H_SYNC_TIME = 128;// 行同步信號時間
parameter H_BACK_PORCH = 88 ;// 行消隱后肩時間
parameter V_ACTIVE = 600;// 列數據有效時間
parameter V_FRONT_PORCH = 1 ;// 列消隱前肩時間
parameter V_SYNC_TIME = 4 ;// 列同步信號時間
parameter V_BACK_PORCH = 23 ;// 列消隱后肩時間
`endif
//640x480 25.175Mhz
`ifdef PIXEL_640_480
parameter H_ACTIVE = 640; // 行數據有效時間
parameter H_FRONT_PORCH = 16 ; // 行消隱前肩時間
parameter H_SYNC_TIME = 96 ; // 行同步信號時間
parameter H_BACK_PORCH = 48 ; // 行消隱后肩時間
parameter V_ACTIVE = 480; // 列數據有效時間
parameter V_FRONT_PORCH = 10 ; // 列消隱前肩時間
parameter V_SYNC_TIME = 2 ; // 列同步信號時間
parameter V_BACK_PORCH = 33 ; // 列消隱后肩時間
`endif
parameter H_TOTAL_TIME = H_ACTIVE + H_FRONT_PORCH + H_SYNC_TIME + H_BACK_PORCH;
parameter V_TOTAL_TIME = V_ACTIVE + V_FRONT_PORCH + V_SYNC_TIME + V_BACK_PORCH;
reg h_act;
reg v_act;
reg [12:0] h_syn_cnt;
reg [12:0] v_syn_cnt;
reg [19:0] image_cnt;
// 有效數據控制
assign en = h_act & v_act;
// 行掃描計數器
always@(posedge clk)
begin
if(h_syn_cnt == H_TOTAL_TIME - 1)
h_syn_cnt <= 13'b0;
else
h_syn_cnt <= h_syn_cnt + 1'b1;
end
// 列掃描計數器
always@(posedge clk)
begin
if(h_syn_cnt == H_TOTAL_TIME - 1)
begin
if(v_syn_cnt == V_TOTAL_TIME-1)
v_syn_cnt <= 13'b0;
else
v_syn_cnt <= v_syn_cnt + 1'b1;
end
end
// 行同步控制
always@(posedge clk)
begin
if(h_syn_cnt < H_SYNC_TIME)
hs <= 1'b0;
else
hs <= 1'b1;
end
// 場同步控制
always@(posedge clk)
begin
if(v_syn_cnt < V_SYNC_TIME)
vs <= 1'b0;
else
vs <= 1'b1;
end
// 行有效控制
always@(posedge clk)
begin
if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH - 1)
h_act = 1'b1;
else if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE - 1)
h_act = 1'b0;
end
// 列有效控制
always@(posedge clk)
begin
if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH - 1 && h_syn_cnt == 0)
v_act = 1'b1;
else if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE - 1 && h_syn_cnt == 0)
v_act = 1'b0;
end
// 像素數計數器
always@(posedge clk)
begin
if(image_cnt == H_ACTIVE*V_ACTIVE - 1)
image_cnt <= 20'b0;
else if(h_act & v_act)
image_cnt <= image_cnt + 1'b1;
end
// 調用ROM IP
blk_mem inst_blk_mem
(
.clka (clk),
.ena (h_act & v_act),
.addra (image_cnt),
.douta (data)
);
endmodule
仿真文件仍沿用cx_tb.v,但圖像分辨率應改為1280×720,生成image_out.txt文件與仿真波形:
3.3 Matlab顯示.txt文件
采用2.3中.txt文件轉圖像的Matlab代碼hex_rgb.m,同樣可以得到圖像:
04圖像存儲模塊仿真方法
通過讀取.coe格式圖像文件實現(xiàn)FPGA仿真步驟:
1. 利用Matlab生成圖像存儲模塊.v文件;
2. 通過VIVADO讀取圖像并處理生成.txt格式文件;
3. 利用Matlab轉換顯示Vivado處理后的.txt格式圖像。
4.1 Matlab生成.v文件
利用Matlab獲取圖像數據并生成.v文件:
Matlab代碼如下:
%**********************************************************************
% -------------------------------------------------------------------
% Company: Cascatrix
% Engineer: Carson
%
% Create Date: 2023/01/19
% Design Name: rgb_v
% Module Name: rgb_v
% Tool Versions: v1.0
% Description: Convert RGB888 into .v
%-------------------------------------------------------------------
%*********************************************************************/
clear;clear all;clc;
% Load image
image_in = imread('cascatrix.jpg');
% Create .v file
FileName=['image_in','.v'];
% Get image size
[row,col,n] = size(image_in);
% Write image into image_in.v
FileImage = fopen(FileName,'w');
% Format of image.coe
fprintf(FileImage,'module image_rom ');
fprintf(FileImage,'( ');
fprintf(FileImage,'input clk, ');
fprintf(FileImage,'input[31:0]addr, ');
fprintf(FileImage,'inputen, ');
fprintf(FileImage,'output[23:0]dout ');
fprintf(FileImage,'); ');
fprintf(FileImage,'reg [23:0] DATA; ');
fprintf(FileImage,'assigndouta = DATA; ');
fprintf(FileImage,'always@(*) ');
fprintf(FileImage,'begin ');
fprintf(FileImage,'case(addra) ');
s=0;
for x = 1:row
for y = 1:col
image_R = dec2hex(image_in(x,y,1));
image_G = dec2hex(image_in(x,y,2));
image_B = dec2hex(image_in(x,y,3));
[rm,rn]=size(image_R);
[gm,gn]=size(image_G);
[bm,bn]=size(image_B);
if rn == 1
image_R =['0',image_R];
elseif rn == 0
image_R ='00';
end
if gn == 1
image_G =['0',image_G];
elseif gn == 0
image_G ='00';
end
if bn == 1
image_B =['0',image_B];
elseif bn == 0
image_B ='00';
end
image_hex=[': DATA<=24','''','h',image_R,image_G,image_B,';'];
fprintf(FileImage,'%d %s ',(x-1)*col + y -1,image_hex);
end
end
fprintf(FileImage,' default: DATA<= 0; ');
fprintf(FileImage,'endcase ');
fprintf(FileImage,'end ');
fprintf(FileImage,'endmodule ');
fclose(FileImage);
rgb_v代碼運行后生成.v文件image_in.v:
4.2 Vivado讀取與處理
將生成的圖像存儲image.v模塊在cx_image調用:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/01/15
// Design Name: Image_Base
// Module Name: cx_image
// Tool Versions: v1.0
// Description: Image read and generate display parameters
//
//////////////////////////////////////////////////////////////////////////////////
`define PIXEL_1920_1080
//`define PIXEL_1680_1050
//`define PIXEL_1280_1024
//`define PIXEL_1280_720
//`define PIXEL_1024_768
//`define PIXEL_800_600
//`define PIXEL_640_480
module cx_image(
inputwireclk,
outputreghs,
outputregvs,
outputwireen,
outputwire [23:0]data
);
//1920x1080 148.5Mhz
`ifdef PIXEL_1920_1080
parameter H_ACTIVE = 1920;// 行數據有效時間
parameter H_FRONT_PORCH = 88; // 行消隱前肩時間
parameter H_SYNC_TIME = 44; // 行同步信號時間
parameter H_BACK_PORCH = 148; // 行消隱后肩時間
parameter V_ACTIVE = 1080;// 列數據有效時間
parameter V_FRONT_PORCH = 4; // 列消隱前肩時間
parameter V_SYNC_TIME = 5; // 列同步信號時間
parameter V_BACK_PORCH = 36; // 列消隱后肩時間
`endif
//1680x1050 119Mhz
`ifdef PIXEL_1680_1050
parameter H_ACTIVE = 1680;// 行數據有效時間
parameter H_FRONT_PORCH = 48; // 行消隱前肩時間
parameter H_SYNC_TIME = 32; // 行同步信號時間
parameter H_BACK_PORCH = 80; // 行消隱后肩時間
parameter V_ACTIVE = 1050;// 列數據有效時間
parameter V_FRONT_PORCH = 3; // 列消隱前肩時間
parameter V_SYNC_TIME = 6; // 列同步信號時間
parameter V_BACK_PORCH = 21; // 列消隱后肩時間
`endif
//1280x1024 108Mhz
`ifdef PIXEL_1280_1024
parameter H_ACTIVE = 1280;// 行數據有效時間
parameter H_FRONT_PORCH = 48; // 行消隱前肩時間
parameter H_SYNC_TIME = 112; // 行同步信號時間
parameter H_BACK_PORCH = 248; // 行消隱后肩時間
parameter V_ACTIVE = 1024;// 列數據有效時間
parameter V_FRONT_PORCH = 1; // 列消隱前肩時間
parameter V_SYNC_TIME = 3; // 列同步信號時間
parameter V_BACK_PORCH = 38; // 列消隱后肩時間
`endif
//1280X720 74.25MHZ
`ifdef PIXEL_1280_720
parameter H_ACTIVE = 1280;// 行數據有效時間
parameter H_FRONT_PORCH = 110; // 行消隱前肩時間
parameter H_SYNC_TIME = 40; // 行同步信號時間
parameter H_BACK_PORCH = 220; // 行消隱后肩時間
parameter V_ACTIVE = 720; // 列數據有效時間
parameter V_FRONT_PORCH = 5; // 列消隱前肩時間
parameter V_SYNC_TIME = 5; // 列同步信號時間
parameter V_BACK_PORCH = 20; // 列消隱后肩時間
`endif
//1024x768 65Mhz
`ifdef PIXEL_1024_768
parameter H_ACTIVE = 1024;// 行數據有效時間
parameter H_FRONT_PORCH = 24; // 行消隱前肩時間
parameter H_SYNC_TIME = 136; // 行同步信號時間
parameter H_BACK_PORCH = 160; // 行消隱后肩時間
parameter V_ACTIVE = 768; // 列數據有效時間
parameter V_FRONT_PORCH = 3; // 列消隱前肩時間
parameter V_SYNC_TIME = 6; // 列同步信號時間
parameter V_BACK_PORCH = 29; // 列消隱后肩時間
`endif
//800x600 40Mhz
`ifdef PIXEL_800_600
parameter H_ACTIVE = 800;// 行數據有效時間
parameter H_FRONT_PORCH = 40 ;// 行消隱前肩時間
parameter H_SYNC_TIME = 128;// 行同步信號時間
parameter H_BACK_PORCH = 88 ;// 行消隱后肩時間
parameter V_ACTIVE = 600;// 列數據有效時間
parameter V_FRONT_PORCH = 1 ;// 列消隱前肩時間
parameter V_SYNC_TIME = 4 ;// 列同步信號時間
parameter V_BACK_PORCH = 23 ;// 列消隱后肩時間
`endif
//640x480 25.175Mhz
`ifdef PIXEL_640_480
parameter H_ACTIVE = 640; // 行數據有效時間
parameter H_FRONT_PORCH = 16 ; // 行消隱前肩時間
parameter H_SYNC_TIME = 96 ; // 行同步信號時間
parameter H_BACK_PORCH = 48 ; // 行消隱后肩時間
parameter V_ACTIVE = 480; // 列數據有效時間
parameter V_FRONT_PORCH = 10 ; // 列消隱前肩時間
parameter V_SYNC_TIME = 2 ; // 列同步信號時間
parameter V_BACK_PORCH = 33 ; // 列消隱后肩時間
`endif
parameter H_TOTAL_TIME = H_ACTIVE + H_FRONT_PORCH + H_SYNC_TIME + H_BACK_PORCH;
parameter V_TOTAL_TIME = V_ACTIVE + V_FRONT_PORCH + V_SYNC_TIME + V_BACK_PORCH;
reg h_act;
reg v_act;
reg [12:0] h_syn_cnt;
reg [12:0] v_syn_cnt;
reg [31:0] image_cnt;
// 有效數據控制
assign en = h_act & v_act;
// 行掃描計數器
always@(posedge clk)
begin
if(h_syn_cnt == H_TOTAL_TIME - 1)
h_syn_cnt <= 13'b0;
else
h_syn_cnt <= h_syn_cnt + 1'b1;
end
// 列掃描計數器
always@(posedge clk)
begin
if(h_syn_cnt == H_TOTAL_TIME - 1)
begin
if(v_syn_cnt == V_TOTAL_TIME-1)
v_syn_cnt <= 13'b0;
else
v_syn_cnt <= v_syn_cnt + 1'b1;
end
end
// 行同步控制
always@(posedge clk)
begin
if(h_syn_cnt < H_SYNC_TIME)
hs <= 1'b0;
else
hs <= 1'b1;
end
// 場同步控制
always@(posedge clk)
begin
if(v_syn_cnt < V_SYNC_TIME)
vs <= 1'b0;
else
vs <= 1'b1;
end
// 行有效控制
always@(posedge clk)
begin
if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH - 1)
h_act = 1'b1;
else if(h_syn_cnt == H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE - 1)
h_act = 1'b0;
end
// 列有效控制
always@(posedge clk)
begin
if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH - 1 && h_syn_cnt == 0)
v_act = 1'b1;
else if(v_syn_cnt == V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE - 1 && h_syn_cnt == 0)
v_act = 1'b0;
end
// 像素數計數器
always@(posedge clk)
begin
if(image_cnt == H_ACTIVE*V_ACTIVE - 1)
image_cnt <= 32’b0;
else if(h_act & v_act)
image_cnt <= image_cnt + 1'b1;
end
// 圖像像素值存儲模塊
image inst_rom_image
(
.clk (clk),
.en (h_act & v_act),
.addr (image_cnt),
.dout (data)
);
endmodule
仿真文件仍采用cx_tb.v,生成image_out.txt文件與仿真波形:
4.3 Matlab顯示.txt文件
采用2.3中.txt文件轉圖像的Matlab代碼hex_rgb.m,同樣可以得到圖像:
-
FPGA
+關注
關注
1626文章
21667瀏覽量
601864 -
matlab
+關注
關注
182文章
2963瀏覽量
230170 -
Verilog
+關注
關注
28文章
1343瀏覽量
109986 -
數字圖像處理
+關注
關注
7文章
103瀏覽量
18905 -
圖像仿真
+關注
關注
0文章
2瀏覽量
5226
原文標題:FPGA數字圖像處理仿真方法
文章出處:【微信號:Carlinx FPGA,微信公眾號:Carlinx FPGA】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論