FPGA經典:Verilog傳奇與基於FPGA的數字圖像處理原理及應用

一 簡述算法

     最近惡補基礎知識,借了<<Verilog傳奇>>,《基於FPGA的嵌入式圖像處理系統設計》和<<基千FPGA的數字圖像處理原理及應用>>這三本書。express

<<Verilog傳奇>>是關於Verilog基礎知識的,總共九章。因爲書籍內容太多沒時間看,故通常都是瞭解整本書的大體內容,遇到問題時能回憶起在那看過,再返回來仔細研究。後面兩本書是圖像處理的FPGA應用,有不少基本的圖像處理操做,如常見的直方圖技術,各類濾波,圖像分割等。重點是圖像處理算法的FPGA映射,還有圖像仿真驗證平臺。編程

(一)<<Verilog傳奇>>總結:編程語言

第一章用來介紹Verilog語言的基本知識, 包括髮展歷史、設計流芯片結構和可綜合性等。 這裏的重點是幫你們創建Yerilog語言與其餘學科之間的聯繫。幫助你們掌握設計數字邏輯系統須要考量的有關內容。ide

第二章,除了介紹IEEE有關Verilog語言的標準體系及非RTL級的設計以外,還重 點說明了常量、 變量及結構化模塊的內容, 是學習Verilog語言的基礎。函數

第3、 四章, 分別介紹了用assign和always定義的組合邏輯電路的描述方法。 其中包含各類運算符操做的寫法, 以及條件、 多選的描述。 最後, 以多路選擇器爲例, 說明 瞭如何分析一個組合邏輯電路系統。學習

第五章, 介紹了時序邏輯電路系統的Verilog語言描述方法, 包括D觸發器及D觸 發器鏈的寫法。 本章還介紹瞭如何拆分組合電路以適應系統操做時間要求的概念。 在此基礎上, 介紹了三種系統速度與面積平衡的方法: 並行化設計流水線設計時分複用 設計測試

第六章, 結合工程實踐, 介紹了常常遇到的若干問題, 其中包括復位系統設計、 可變移位操做、 有限狀態機設計 多時鐘系統處理及循環操做的處理。spa

第七章, 介紹了與[P核設計有關的靈活編程問題。 其中涉及任務與函數的寫法、 利 用宏定義方法改變系統參數、 利用參數方法改變系統參數及生成塊方法改變系統結構。最後綜合運用這幾種方法, 給出了一個簡單的JP核一數字分頻系統 設計的例子。設計

第八章, 說明了Verilog語言中不可綜合的部分。 其一爲仿真所需的數據類型、複雜 運算和並行塊設計; 其二包含預編譯命令; 其三爲系統任務與函數。 本章還介紹了測試向量的概念及其編寫方法, 以及Yerilog語言與其餘語言接口的問題。

第九章, 以 「 直接數字式頻率合成器」 系統爲例, 綜合前面各章介紹的知識, 採用 了R OM查找表、 折線法和CORDIC算法分別進行了實現。本章不只但願讀者學會如何 綜合使用Yerilog語言, 還進一步介紹了部分算法與算法定點化的知識。

(二)<<Verilog傳奇>>閱讀建議

首先, 粗讀/跳讀第一章到第二章的第二講, 瞭解基本概念。 本書的基本假設是讀者都掌握了《數字電子技術》這一門課程。其次詳細閱讀第二章第三講到第五章,這是基礎內容。第六章,七章爲進階內容。第八章,是測試和驗證。第九章是一個複雜的例子, 重點是閱讀做者的思想、 設計過程及代碼風格。

因爲,我曾經學過Verilog語言,故直接從第六章,第七章開始。第六章(按鍵與復位,可變移位寬度的移位操做,有限狀態機及其代碼,多時鐘系統,循環控制),第七章(函數與任務,宏定義與宏判斷,參數,生成塊,數字分頻器核的設計)。今天下午看了函數與任務,後面詳細介紹。

(三)  <<基千FPGA的數字圖像處理原理及應用>>總結

重點講解圖像處理算法移植到FPGA中的基本思路和方法,突出工程應用。每一章均附有C/C++實現代碼,同時用按部就班、自頂向下的方式設計FPGA算法模塊, 針對每個模塊設計了詳細的實現框圖,確保讀者能理解算法設計的原理。

此外,每一個算法都配有Verilog實現方法,並給出仿真結果。本書還提出了一個通用的利用Modelsim和VS實現圖像處理的仿真測試平臺。這個仿真平臺是我學習的重點,在書本的第五章,系統仿真。主要是動手搭建視頻驗證的仿真平臺,給算法提供模擬的視頻源,聯合matlab查看算法處理效果。借鑑書本的思路,用在本身的圖像處理項目中。
本書內容概述以下:

(I)第1~5章是基礎章節, 重點介紹數字圖像處理和FPGA程序設計的基礎知識。
第1章簡單介紹了圖像處理的基礎知識, 包括圖像處理的發展示狀, 還地介紹了圖像從獲取到顯示存儲的基本流程。

第2章首先介紹了FPGA的發展示狀, 生產廠家及其開發流程。接着介紹了基千FPGA的圖像處理的基本開發流程。

第3章主要介紹了在FPGA中應用的編程語言。本章並無詳細介紹Verilog語法,而是從工程應用的角度介紹經常使用的設計方法和實例。

第4章主要介紹了把軟件算法映射到FPGA經常使用的技巧。首先介紹了應用較普遍的流水線設計方法, 接着介紹了FPGA硬件計算技術, 包括一些經常使用的計算轉換、查找表、浮點計算、C ordie計算等方法。最後介紹了在圖像處理中用途很是多的存儲器映射, 並提出了一些其餘設計技巧。

第5章首先簡要介紹了仿真測試軟件Modelsim的使用, 接着重點介紹了一個通用的視頻圖像處理仿真測試系統。這個測試系統包括完整的視頻模擬、視頻捕獲, 以及testbench設計, 並結合基於MFC 的VC上位機來實現測試系統的搭建。

(2)第6~10章主要介紹算法實現。
第6章介紹直方圖操做, 主要介紹幾種經常使用直方圖操做的FPGA實現: 直方圖統計、直方圖均衡、直方圖規定及直方圖線性拉伸。

第7章介紹基千圖像處理的線性濾波。首先, 介紹了均值濾波算法、高斯濾波算法、Sobel 算子及FFT等常見的幾種線性濾波原理。其次, 介紹了均值濾波算法和Sobel算子的FPGA實現。第8章主要介紹基千圖像處理的非線性濾波算法, 包括排序濾波的基本原理及其FPGA 實現方法。

第9章主要介紹基千圖像處理的形態學濾波算法, 包括形態學濾波的基本概念,包括形態學膨脹、形態學腐蝕、開運算及閉運算等。重點介紹了基千FPGA 的Tophat濾波的原理及實現方法。

第10章主要介紹基千圖像處理的常見的分割算法,包括全局闕值分割、局部自適應閥值分割及Canny 算子。重點介紹基千FPGA 的局部自適應闕值分割和Canny 算子的設計與實現。

第11 章主要介紹與視頻和圖像處理相關的輸入/輸出接口, 包括CameraLink、火線接口、USB 接口、千兆以太網等視頻輸入接口和CVT 標準,以及VGA, PAL, DVI,HDMI 等視頻輸出接口。其中, 給出了VGA 和PAL 接口的Verilog 代碼實現。


二  函數

函數,理解爲對於給定的輸入(一個或多個)進行處理後返回輸出值。在MATLAB中,有sum函數,max函數等。

在Verilog中,函數一是經常使用來計算數學公式的值。如波特率計算公式:divp10x = (10 * fsysclk) / (16 * baud)

二是函數可以被屢次調用,避免冗餘。

(一)函數的聲明與調用:

函數的聲明有兩種方式:

//express1
function[range] function_name(ports_list);
begin
   ...
end
endfunction
//example1
function [7:0] getbyte (input [15:0] address);
begin
. . .
getbyte = result_expression;
end
endfunction
//express2
function[range] function_name;
ports_list;
begin
   ...
end
endfunction
//example2
function [7:0] getbyte;
input [15:0] address;
begin
. . .
getbyte = result_expression;
end
endfunction

 函數只能有一個輸出,能夠經過多個信號的拼接完成多個信號輸出。

編寫函數代碼的原則:

(1)    函數定義只能模塊中完成,不能出如今過程塊(即always)。

(2)    函數至少一個輸入端口;不能包含輸出端口和雙向端口;

(3)    在函數結構中,不能使用任何形式的時間控制語句(#,wait)也不能使用disable停止語句。

(4)    函數定義不能出現always語句。

(5)    函數內部能夠調用函數,但不能調用任務;

(6)    函數調用便可在過程塊語句,也能夠在assign賦值語句出現;

(7)    函數調用語句不能單獨出現,只能做爲賦值語句的右端操做數;

下面用一個函數計算游泳池的面積,掌握函數的使用:

 

 下面是計算上圖的面積的Verilog代碼,體現了函數的聲明,調用。

 1 module function_total
 2 
 3   (
 4 
 5     input CLK, input RST,
 6 
 7     input[7:0] width,
 8 
 9     output reg[16:0]area
10 
11   );
12 
13  
14 
15 //Load other module(s)
16 
17  
18 
19 //Definition for Variables in the module
20 
21  
22 
23 //Functions for area calculation
24 
25 function[15:0] circle(input[7:0] diameter);
26 
27 begin
28 
29     circle = (24'd201 * {16'h0, diameter} * {16'h0, diameter}) / 256;
30 
31 end
32 
33 endfunction
34 
35  
36 
37 function[15:0] square(input[7:0] width);
38 
39 begin
40 
41     square = {8'h0, width} * {8'h0, width};
42 
43 end
44 
45 endfunction
46 
47  
48 
49 function[16:0] total(input[7:0] width);
50 
51 begin
52 
53     total = {2'h0, square(width)} + {2'h0, circle(width)};
54 
55 end
56 
57 endfunction
58 
59  
60 
61 //Logical
62 
63 always @(posedge CLK, negedge RST)
64 
65 begin
66 
67     if (!RST)
68 
69     //Reset
70 
71     begin
72 
73        area <= 17'h0000;
74 
75     end
76 
77     else
78 
79     //Data comes
80 
81     begin
82 
83         area <= total(width);
84 
85     end
86 
87 end
88 
89  
90 
91 endmodule
func_total

其中的Π/4 = (24'd201/256),diameter爲圓的直徑。代碼注意點:一是體現了函數中調用函數。二是信號位寬的變化。

square = {8'h0, width} * {8'h0, width};

//平方,則每一個變量前補充相同輸入變量位寬,即輸出square爲輸入位寬的兩倍。

total = {2'h0, square(width)} + {2'h0, circle(width)};

//爲避免相加溢出,位寬又擴寬兩位,僅僅把低17位的值賦給total。

三  任務

 

與函數的調用相似,任務的調用只有一種形式,如表7.2 所示。與函數的調用不一樣的是:任務的調用是在代碼裏單獨一行書寫的。

 

 

下面是幾點須要強調的規則:

(I) 任務的輸入、輸出端口和雙向端口數量不受限制,甚至能夠沒有輸入、輸出及

雙向端口;

(2)在任務定義的描述語句中,可使用出現不可綜合操做符合語句(使用最爲頻

繁的就是延遲控制語旬),但這樣會形成該任務不可綜合;

(3)在任務中既能夠調用其餘的任務或函數,也能夠調用自身;

(4) 在任務定義結構內不能出現initial always 過程塊;

(5)能夠在任務中中斷正在執行的任務,但其是不可綜合的;當任務被中斷後,程

序流程將返回到調用任務的地方繼續向下執行;

(6)任務調用語句只能出如今過程塊內;

(7)任務調用語句和一條普通的行爲描述語句的處理方法一致;

(8)當被調用輸入、 輸出或雙向端口時, 任務調用語句必須包含端口名列表, 且信號端口順序和類型必須和任務定義結構中的順序和類型一致; 須要說明的是, 任務的輸 出端口必須和寄存器類型的數據變量對應;

(9)綜合任務只能實現組合邏輯, 也就是說, 調用可綜合任務的時間爲 「 0"; 而在面向仿真的任務中能夠帶有時序控制,如時延,所以面向仿真的任務的調用時間不爲「 0」。

下面爲任務聲明及調用例子

 1 task total(input[7:0] width, output[l7:0J area); 
 2 begin 
 3 area <= {2'h0, square(width)} + {2'h0, circle(width)};
 4  end 
 5 endtask 
 6 
 7 always @(posedge CLK, negedge RST)
 8 begin
 9     if (!RST)
10     //Reset
11     begin
12        area <= 17'h0000;
13     end
14     else 
15     //Data comes
16     begin
17         total(width, area);//task call(調用)
18     end
19 end
Task example

爲了不屢次調用任務形成的地址衝突,添加automatic使任務成爲可重入的。這時在調用任務時,會自動給任務聲明變量分配動態地址空間,從 而有效避免了地址空間的衝突。

一個模塊裏的任務能夠在其餘模塊調用。

1 module module_main; 
2 task task_1...
3 task task_2...
4 endmodule
5 //other
6 module mainm1; 
7 m1.task_1(...)
8 m2.task_1(...)
9 endmodule

上面對於仿真驗證特別管用。

三 總結

 

 今天下午就看了一講,着重是本身看一遍,而後動手敲一下代碼,以後仿真驗證結果。計算游泳池面積的仿真代碼:

`timescale 1ns / 1ps        

module tb_top();
//========================================================
//parameters
parameter CLK_FREQ   = 50.000;//ddr reference clock frequency, unit: MHz
parameter CLK_PERIOD = 1000.0/CLK_FREQ; //unit: ns 

 // parameter  FREQ = 100_000_000 ;
 // parameter  BAUDRATE    = 115200  ;
//=======================================================
reg          clk;            // 50M
reg          rst_n         ;
reg [7:0] input_data;



wire[16:0] output_data;



//========================================================
GSR GSR(.GSRI(1'b1));

//==============================================  
//rst_n
initial 
begin
    rst_n = 1'b0;
    input_data = 0;
    #200;
    rst_n = 1'b1;
    input_data = 8'd1;//1+(pi/4)=1
        #200;
  
    input_data = 8'd4;//16+12=28
    #200;
     input_data = 8'd6;//36+28=64
     #200;
           #200;
  
    input_data = 8'd10;//100+78.5=178.5
    #200;
     rst_n = 1'b0;
     #200;
     $stop;
end


//----------------------------------------------------
//ref clk
initial 
begin
	clk = 1'b0;
end

always  #(CLK_PERIOD/2.0) clk = ~clk;

//==================================================
//TX
    function_total inst_function_total (.CLK(clk), .RST(rst_n), .width(input_data), .area(output_data));


          
endmodule

  

仿真結果以下所示:

後面還有不少要看,但以理解原理和動手實踐爲主。經過編代碼和仿真,可以感受更真實。

相關文章
相關標籤/搜索