新聞中心

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

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

作者: 時(shí)間:2015-11-19 來(lái)源:網(wǎng)絡(luò) 收藏

  原始代碼驗(yàn)證

本文引用地址:http://butianyuan.cn/article/283059.htm

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

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

  因?yàn)樵趯⒋a復(fù)制到word的過(guò)程中,會(huì)有一定的格式兼容問(wèn)題,所以文中部分格式不是太規(guī)范,望各位理解,另外,完整的代碼,小梅哥也以pdf的形式提供了,感興趣的朋友可以下載學(xué)習(xí)。

  本仿真模型的第一句話“`timescale 1ns/1ps”為仿真精度及時(shí)間的說(shuō)明,定義時(shí)間精度為1ps,時(shí)間單位為1ns,那么我們?cè)诖a編寫的過(guò)程中,如果寫成“#200”則表示延時(shí)200ns,因?yàn)闀r(shí)間精度為1ps,因此我們還可以進(jìn)一步提高延時(shí)精度,如“#200.1”表示延時(shí)200.1ns。一般的測(cè)試文件(testbench)中,這句話作為第一句話,必寫,當(dāng)然,時(shí)間精度和單位我們可以根據(jù)自己的需求更改,如寫成“`timescale 1us/1ns”或者“`timescale 1ns/1ns”等都是可以的。

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

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

    

 

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

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

  因?yàn)楸痉抡婺P蛯?shí)質(zhì)上就是一個(gè)串口收發(fā)模塊,因此也需要有收發(fā)波特率發(fā)生器,這里小梅哥為了省事,直接調(diào)用了特權(quán)同學(xué)的波特率發(fā)生器模塊,來(lái)作為我仿真模型的波特率發(fā)生器。因?yàn)樵摬ㄌ芈拾l(fā)生器本身也屬于待測(cè)試部分,小梅哥之所以敢放心的調(diào)用,是因?yàn)槭孪任乙呀?jīng)通過(guò)仿真,確定了該波特率發(fā)生器功能的正確性。第21行至33行為分別例化得到發(fā)送波特率發(fā)生器和接收波特率發(fā)生器的代碼。

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

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

  這里需要注意的是,打印出來(lái)的接收數(shù)據(jù)和發(fā)送數(shù)據(jù)是針對(duì)仿真模型來(lái)說(shuō)的,send data是仿真模型發(fā)送出去的數(shù)據(jù),對(duì)應(yīng)待測(cè)模塊應(yīng)該接收到的數(shù)據(jù)。receive data則是仿真模型接收到的數(shù)據(jù),對(duì)應(yīng)待測(cè)模塊發(fā)送的數(shù)據(jù)。

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

  以上對(duì)小梅哥寫的串口仿真模型進(jìn)行了介紹,在實(shí)際使用中,只需要將該模型與待測(cè)模塊按照如下圖所示的方式連接起來(lái)即可。

    

 

  這里,小梅哥使用一個(gè)testbench文件作為頂層,將這兩個(gè)部分連接起來(lái),同時(shí)產(chǎn)生my_uart_top工作所需的時(shí)鐘和復(fù)位信號(hào)。該文件詳細(xì)代碼如下:

  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

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

 


上一頁(yè) 1 2 3 下一頁(yè)

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

評(píng)論


相關(guān)推薦

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

關(guān)閉