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

南方菜鳥發表於2021-07-24

一 簡述

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

<<Verilog傳奇>>是關於Verilog基礎知識的,總共九章。由於書籍內容太多沒時間看,故一般都是瞭解整本書的大致內容,遇到問題時能回憶起在那看過,再返回來仔細研究。後面兩本書是影像處理的FPGA應用,有很多基本的影像處理操作,如常見的直方圖技術,各種濾波,影像分割等。重點是影像處理演算法的FPGA對映,還有影像模擬驗證平臺。

(一)<<Verilog傳奇>>總結:

第一章用來介紹Verilog語言的基本知識, 包括髮展歷史、設計流晶片結構和可綜合性等。 這裡的重點是幫大家建立Yerilog語言與其他學科之間的聯絡。幫助大家掌握設計數字邏輯系統需要考量的有關內容。

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

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

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

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

第七章, 介紹了與[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程式碼,體現了函式的宣告,呼叫。

FPGA經典:Verilog傳奇與基於FPGA的數字影像處理原理及應用
 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”。

下面為任務宣告及呼叫例子

FPGA經典:Verilog傳奇與基於FPGA的數字影像處理原理及應用
 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

  

模擬結果如下所示:

後面還有很多要看,但以理解原理和動手實踐為主。通過編程式碼和模擬,能夠感覺更真實。

 



 





 




 

 

 

 

 

 

 



 

相關文章