<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 手機與無線通信 > 牛人業(yè)話 > 小梅哥和你一起深入學習FPGA之串口調(diào)試(一)(上)

          小梅哥和你一起深入學習FPGA之串口調(diào)試(一)(上)

          作者: 時間:2015-11-19 來源:網(wǎng)絡 收藏

            原始代碼驗證

          本文引用地址:http://www.ex-cimer.com/article/283059.htm

            前面,通對設計代碼的一個簡單分析,弄清楚了特權(quán)同學設計代碼的基本架構(gòu)和思路。那么看過特權(quán)同學教學視頻的都知道,該代碼能夠?qū)崿F(xiàn)一個字節(jié)的數(shù)據(jù)收發(fā)測試。那么這里,小梅哥就先對該設計進行一個仿真,通過仿真來分析此設計的性能。

            仿真的思路很簡單,就是通過模擬串口發(fā)送過程,給該設計模塊發(fā)送數(shù)據(jù),由前面分析可知,該設計模塊接收到數(shù)據(jù)后,會立即將數(shù)據(jù)發(fā)送出去,因此我們還需要對串口發(fā)送出來的數(shù)據(jù)進行分析,這里,熟悉Uart協(xié)議的,我們可以直接觀察發(fā)送波形。當然,為了更加直觀,我們也可以設計一個模擬串口接收數(shù)據(jù)的仿真模型,通過該模塊來讀取串口發(fā)送出來的數(shù)據(jù)??紤]到看這篇文章的大多是初學者,為了讓大家能夠更好的查看我們的仿真結(jié)果,同時教大家進行仿真模型的設計,小梅哥還是自己編寫了一個虛擬的串口仿真模型。驗證時,只需要將該仿真模型掛接到串口模塊上,則該模型便能夠自動的給串口模塊發(fā)送數(shù)據(jù),同時接收串口發(fā)送過來的數(shù)據(jù)。并會實時的將發(fā)送的數(shù)據(jù)和接收的數(shù)據(jù)打印出來,實際在觀察仿真結(jié)果時,我們便只需要觀看打印的結(jié)果就可以了。該串口仿真模型的代碼如下所示:

            以下是代碼片段:

            1 `timescale 1ns/1ps

            2

            3 module Uart_module ( uart_rx , uart_tx , send_state );

            4

            5 input uart_rx ;

            6 output reg uart_tx ;

            7 output reg send_state ;

            8

            9 reg Clk;

            10 reg Rst_n ;

            11

            12 wire Mid_Flag_send ;

            13 wire Mid_Flag_Receive ;

            14

            15 reg Receive_Baud_Start ;

            16 reg [ 7 : 0] rx_data ;

            17

            18 initial Clk = 1;

            19 always #10 Clk = ~Clk;

            20

            21 speed_select speed_select_Send (

            22 . clk( Clk),

            23 . rst_n ( Rst_n ),

            24 . bps_start ( 1'b1 ),

            25 . clk_bps ( Mid_Flag_send )

            26 );

            27

            28 speed_select speed_select_receive (

            29 . clk( Clk),

            30 . rst_n ( Rst_n ),

            31 . bps_start ( Receive_Baud_Start ),

            32 . clk_bps ( Mid_Flag_Receive )

            33 );

            34

            35 initial begin

            36 Rst_n = 0;

            37 uart_tx = 1;

            38 send_state = 0;

            39 #300 Rst_n = 1;

            40

            41 $display ( "Set Baud As 9600bps" );

            42 #200 ; Uart_Send ( 8'hb6 );

            43 #20 ; Uart_Send ( 8'he7 );

            44 #80 ; Uart_Send ( 8'hf0 );

            45 #500 ; Uart_Send ( 8'h02 );

            46 #300 ; Uart_Send ( 8'hb4 );

            47 #40 ; Uart_Send ( 8'he5 );

            48 #90 ; Uart_Send ( 8'hb0 );

            49 #1000 ; Uart_Send ( 8'h32 );

            50 #2000000 ;

            51 $stop ;

            52 end

            53

            54 task Uart_Send ;

            55 input [ 7: 0] Data ;

            56 begin

            57 send_state = 1;

            58 @( posedge Mid_Flag_send) #0.1 uart_tx = 0;

            59 @( posedge Mid_Flag_send) #0.1 uart_tx = Data [0];

            60 @( posedge Mid_Flag_send) #0.1 uart_tx = Data [1];

            61 @( posedge Mid_Flag_send) #0.1 uart_tx = Data [2];

            62 @( posedge Mid_Flag_send) #0.1 uart_tx = Data [3];

            63 @( posedge Mid_Flag_send) #0.1 uart_tx = Data [4];

            64 @( posedge Mid_Flag_send) #0.1 uart_tx = Data [5];

            65 @( posedge Mid_Flag_send) #0.1 uart_tx = Data [6];

            66 @( posedge Mid_Flag_send) #0.1 uart_tx = Data [7];

            67 @( posedge Mid_Flag_send) #0.1 uart_tx = 1;

            68 $display ( "Uart_Send Data = %0h" , Data );

            69 send_state = 0;

            70 end

            71 endtask

            72

            73 initial begin

            74 forever begin

            75 @( negedge uart_rx )

            76 begin

            77 Receive_Baud_Start = 1;

            78 @( posedge Mid_Flag_Receive);

            79 @( posedge Mid_Flag_Receive) rx_data [0] = uart_rx ;

            80 @( posedge Mid_Flag_Receive) rx_data [1] = uart_rx ;

            81 @( posedge Mid_Flag_Receive) rx_data [2] = uart_rx ;

            82 @( posedge Mid_Flag_Receive) rx_data [3] = uart_rx ;

            83 @( posedge Mid_Flag_Receive) rx_data [4] = uart_rx ;

            84 @( posedge Mid_Flag_Receive) rx_data [5] = uart_rx ;

            85 @( posedge Mid_Flag_Receive) rx_data [6] = uart_rx ;

            86 @( posedge Mid_Flag_Receive) rx_data [7] = uart_rx ;

            87 @( posedge Mid_Flag_Receive) Receive_Baud_Start = 0;

            88 $display ( "Uart_receive Data = %0h" , rx_data );

            89 end

            90 end

            91 end

            92

            93 endmodule

            94

            因為在將代碼復制到word的過程中,會有一定的格式兼容問題,所以文中部分格式不是太規(guī)范,望各位理解,另外,完整的代碼,小梅哥也以pdf的形式提供了,感興趣的朋友可以下載學習。

            本仿真模型的第一句話“`timescale 1ns/1ps”為仿真精度及時間的說明,定義時間精度為1ps,時間單位為1ns,那么我們在代碼編寫的過程中,如果寫成“#200”則表示延時200ns,因為時間精度為1ps,因此我們還可以進一步提高延時精度,如“#200.1”表示延時200.1ns。一般的測試文件(testbench)中,這句話作為第一句話,必寫,當然,時間精度和單位我們可以根據(jù)自己的需求更改,如寫成“`timescale 1us/1ns”或者“`timescale 1ns/1ns”等都是可以的。

            該模塊作為一個仿真模型,就是虛擬了一個串口收發(fā)儀器,既然是一個串口收發(fā)儀器,則必然有串口發(fā)送端口和串口接收端口,因此在模塊名后面定義了三個端口。這與一般的testbench不同,一般的testbench作為仿真時的頂層,不需要端口,因此模塊名后就直接以“;”結(jié)束。該模塊的三個端口“uart_rx , uart_tx , send_state”分別為串口接收端口、串口發(fā)送端口、串口發(fā)送狀態(tài)信號。串口收發(fā)端口不用說,大家也已經(jīng)知道了,串口發(fā)送狀態(tài)信號主要作為指示信號,指示當前仿真模型正在進行數(shù)據(jù)的發(fā)送過程。

            第9行至第16行為測試文件中信號的定義,以前我們總是理解說這些信號就是待測試模塊的端口,需要在測試文件中定義。那么這里小梅哥更喜歡換一種方式來理解:我們自己的設計,本設計中即特權(quán)的串口模塊,是一個功能未知的黑盒子,這個黑盒子有一些信號線引出,有的信號線是作為輸入的,即需要外部輸入一定的信號作為激勵,而有的信號線是作為輸出的,能夠輸出一些數(shù)據(jù),當然還有一些信號線是既能夠作為輸入,又能夠作為輸出的,即三態(tài)。我們要想知道這個黑盒子的功能,就需要給這個黑盒子的輸入信號線接上信號源,通過給這些輸入信號線一定的激勵,觀察其輸出端口上的響應,從而獲知該黑盒子的功能。那么在這里,對于待測試模塊的輸入端口,我們就接上信號發(fā)生器,對于輸出端口,我們就接上示波器或者邏輯分析儀,這樣,我們就能夠通過信號發(fā)生器給輸入端口產(chǎn)生一定的激勵,然后通過示波器觀察輸出端口的輸出了。即如下圖所示:

              

           

            那么,我們的testbench主要實現(xiàn)信號發(fā)生器的功能,既然是信號發(fā)生器那么就一定有數(shù)據(jù)信號輸出,這個數(shù)據(jù)信號輸出就可以連接到我們的待測模塊上。待測試模塊的輸出端口,連接到我們的示波器或者邏輯分析儀的探頭上,這樣就實現(xiàn)了一個完整的測試系統(tǒng),那么我們信號發(fā)生器的信號源,可能命名叫做,a,b,c,d,e……. 而我們示波器的探頭則命名為探頭1,探頭2……接下來就好理解了,在testbench,我們將信號發(fā)生器的輸出信號定義為reg型,而示波器的探頭定義為wire型。我們信號發(fā)生器的輸出信號線和示波器的探頭線都可以任意命名,實際使用時一一對應連接到待測試模塊的端口上,也可以就直接與待測模塊的各個端口名保持一致。本設計中,小梅哥讓testbench中的信號與待測模塊的端口保持一致。

            第18行和19行為產(chǎn)生50MHz時鐘的語句。

            因為本仿真模型實質(zhì)上就是一個串口收發(fā)模塊,因此也需要有收發(fā)波特率發(fā)生器,這里小梅哥為了省事,直接調(diào)用了特權(quán)同學的波特率發(fā)生器模塊,來作為我仿真模型的波特率發(fā)生器。因為該波特率發(fā)生器本身也屬于待測試部分,小梅哥之所以敢放心的調(diào)用,是因為事先我已經(jīng)通過仿真,確定了該波特率發(fā)生器功能的正確性。第21行至33行為分別例化得到發(fā)送波特率發(fā)生器和接收波特率發(fā)生器的代碼。

            第54行至71行為發(fā)送一個完整字節(jié)的數(shù)據(jù)(自動添加起始位和停止位)的代碼,該部分寫成任務的形式,方便調(diào)用。當我們需要發(fā)送一個字節(jié)的數(shù)據(jù)時,例如,發(fā)送8'hb6,只需要寫“Uart_Send ( 8'hb6 )”即可,該任務便將自動執(zhí)行,將數(shù)據(jù)發(fā)送出去。在一個字節(jié)的數(shù)據(jù)發(fā)送完成后,同時使用系統(tǒng)任務$display來打印當前發(fā)送的數(shù)據(jù)是多少,以方便我們直觀的觀察仿真運行過程。至于$display這個系統(tǒng)任務中各個部分的含義,請讀者自行閱讀verilog的語法書。代碼的42至49行便是調(diào)用此任務進行了多次數(shù)據(jù)的發(fā)送。

            73行至91行為模擬串口接收部分,通過對串口模塊發(fā)送出來的數(shù)據(jù)進行接收,并將接收到的數(shù)據(jù)用$display函數(shù)打印出來。我們只需要閱讀發(fā)送數(shù)據(jù)和接收數(shù)據(jù)后打印出來的信息,即可判斷通信是否成功,待測模塊功能是否正常。

            這里需要注意的是,打印出來的接收數(shù)據(jù)和發(fā)送數(shù)據(jù)是針對仿真模型來說的,send data是仿真模型發(fā)送出去的數(shù)據(jù),對應待測模塊應該接收到的數(shù)據(jù)。receive data則是仿真模型接收到的數(shù)據(jù),對應待測模塊發(fā)送的數(shù)據(jù)。

            我們所編寫的測試文件,一定要是可控的,即在所有事務完成后,將仿真停下來,否則,仿真會一直進行下去,導致出現(xiàn)大量冗余波形,影響我們對仿真結(jié)果的分析。因此在第51行,當所有測試已經(jīng)完成后,使用系統(tǒng)任務$stop將仿真停下來。

            以上對小梅哥寫的串口仿真模型進行了介紹,在實際使用中,只需要將該模型與待測模塊按照如下圖所示的方式連接起來即可。

              

           

            這里,小梅哥使用一個testbench文件作為頂層,將這兩個部分連接起來,同時產(chǎn)生my_uart_top工作所需的時鐘和復位信號。該文件詳細代碼如下:

            1 `timescale 1ns /1ns

            2

            3 module Uart_tb ;

            4

            5 reg Clk;

            6 reg Rst_n ;

            7

            8 wire uart_rx ;

            9 wire uart_tx ;

            10 wire send_state ;

            11

            12 my_uart_top u1 (

            13 . clk( Clk),

            14 . rst_n ( Rst_n ),

            15 . rs232_rx ( uart_tx ),

            16 . rs232_tx ( uart_rx )

            17 );

            18

            19 Uart_module u2 (

            20 . uart_rx ( uart_rx ),

            21 . uart_tx ( uart_tx ),

            22 . send_state ( send_state )

            23 );

            24

            25 initial begin

            26 Clk = 1;

            27 Rst_n = 0;

            28 #200 ;

            29 Rst_n = 1;

            30 end

            31

            32 always #10 Clk = ~Clk;

            33

            34 endmodule

            35

            該代碼實在簡單,只是實現(xiàn)了一個啟動時的初始化和50MHz時鐘的產(chǎn)生,因此小梅哥就不做任何分析了。

           


          上一頁 1 2 3 下一頁

          關(guān)鍵詞: FPGA 串口調(diào)試

          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();