国产精品免费无遮挡无码永久视频-国产高潮视频在线观看-精品久久国产字幕高潮-国产精品99精品无码视亚

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

發(fā)布時(shí)間:2016-1-26 11:52    發(fā)布者:designapp
關(guān)鍵詞: FPGA , 串口調(diào)試
大家好,這幾天在各個(gè)論壇上,經(jīng)常就有人在向我咨詢基于FPGA的串口通信代碼,大部分都是在網(wǎng)上下載一個(gè)現(xiàn)成的代碼,但是在使用中就遇到了各種問題,于是就發(fā)到了論壇上來求助。在閱讀了他們的代碼之后,我發(fā)現(xiàn)幾乎出自同一個(gè)版本(目前確定為特權(quán)同學(xué)的基于EPM240入門實(shí)驗(yàn)的代碼)。他們?cè)谡{(diào)試這個(gè)代碼的時(shí)候,經(jīng)常存在這樣幾個(gè)問題:1、部分人對(duì)該串口通訊模塊完全不理解,對(duì)每句話,甚至每個(gè)模塊的功能都不理解;2、部分人采用最原始的畫波形的方式來對(duì)該模塊進(jìn)行仿真,結(jié)果無法得到仿真結(jié)果;3、部分人不會(huì)使用modelsim對(duì)該設(shè)計(jì)進(jìn)行仿真;4、絕大部分人不會(huì)編寫testbench;5、下板測(cè)試無法進(jìn)行正確的字符串收發(fā)。在公司內(nèi)部,我將這種現(xiàn)象和幾位老師交流之后,夏宇聞老師建議我專門針對(duì)該代碼寫一個(gè)由原理到代碼,由仿真到板級(jí)的調(diào)試筆記。爭取用最通俗,也是最笨的辦法,手把手的教會(huì)大家來調(diào)試這個(gè)代碼。

本調(diào)試筆記主要由五個(gè)部分組成:原始代碼分析;原始代碼驗(yàn)證;對(duì)原始代碼進(jìn)行修改;對(duì)修改后的代碼進(jìn)行驗(yàn)證;對(duì)修改后的設(shè)計(jì)進(jìn)行板級(jí)驗(yàn)證。每個(gè)部分,小梅哥都會(huì)用圖文結(jié)合的方式,教大家一步一步的來進(jìn)行。
原始代碼分析

該代碼來自小梅哥最崇拜的大神,特權(quán)同學(xué)。當(dāng)時(shí)小梅哥也是看著特權(quán)同學(xué)的書和視頻教程一步一步走過來的。特權(quán)同學(xué)的代碼實(shí)現(xiàn)了單字節(jié)的收發(fā)測(cè)試,沒有對(duì)連續(xù)字節(jié)的收發(fā)進(jìn)行測(cè)試。特權(quán)同學(xué)當(dāng)時(shí)也說過,這個(gè)只是一個(gè)簡單的實(shí)驗(yàn),離實(shí)際工業(yè)應(yīng)用還有一定的距離。考慮到論壇上很多小伙伴都希望能夠?qū)崿F(xiàn)連續(xù)字節(jié)的收發(fā)功能,因此小梅哥就在特權(quán)同學(xué)的代碼上進(jìn)行了修改。修改后的代碼,輸入時(shí)鐘可以在一定范圍內(nèi)選擇任意頻率,目前已經(jīng)支持5種波特率選擇(9600、19200、38400、57600、115200),實(shí)際小梅哥還做過更高波特率的測(cè)試,目前實(shí)測(cè)在115200波特率的速率下可以實(shí)現(xiàn)超過9999999次連續(xù)無間斷的收發(fā)。這里,小梅哥首先將特權(quán)同學(xué)設(shè)計(jì)架構(gòu)在這里列出來,以給讀者一個(gè)直觀的印象。
  


由上圖可知,特權(quán)同學(xué)的UART串口設(shè)計(jì)主要包含了四個(gè)模塊:串口發(fā)送模塊(my_uart_tx)、串口接收模塊(my_uart_rx)、串口接收波特率發(fā)生器(speed_rx)和串口發(fā)送波特率發(fā)生器(speed_tx),其中,串口發(fā)送波特率發(fā)生器主要用來產(chǎn)生串口發(fā)送模塊發(fā)送數(shù)據(jù)時(shí)所需的波特率時(shí)鐘,串口接收波特率發(fā)生器主要用來產(chǎn)生串口接收模塊接收數(shù)據(jù)時(shí)的波特率時(shí)鐘,串口發(fā)送模塊主要負(fù)責(zé)在指定波特率的速率下將待發(fā)送字節(jié)發(fā)送出去,串口接收模塊則主要負(fù)責(zé)接收來自其他設(shè)備發(fā)送過來的串口數(shù)據(jù)。
my_uart_top模塊即串口收發(fā)頂層模塊實(shí)現(xiàn)了各個(gè)模塊間的信號(hào)連接功能,通過該頂層模塊的連接,實(shí)現(xiàn)了將串口接收到的數(shù)據(jù)再發(fā)送出去的功能,即我們測(cè)試串口通信最常用的一種方式——回環(huán)測(cè)試。特權(quán)同學(xué)該實(shí)驗(yàn)的各個(gè)端口和內(nèi)部信號(hào)的意義如表1所示:



該實(shí)驗(yàn)的內(nèi)容為,串口接收模塊在檢測(cè)到發(fā)送設(shè)備發(fā)送過來的數(shù)據(jù)起始位時(shí),接收中斷信號(hào)置1,該信號(hào)則作為啟動(dòng)串口接收波特率發(fā)送器的控制信號(hào),然后在每個(gè)波特率時(shí)鐘上升沿到來時(shí)讀取串口接收端口(rs232_rx)上的數(shù)據(jù)。一幀(字節(jié))數(shù)據(jù)接收完成后,接收中斷信號(hào)拉低,停止波特率發(fā)生器工作,接收完成,系統(tǒng)進(jìn)入等待狀態(tài),等待下一次的數(shù)據(jù)到來。

同時(shí),接收中斷信號(hào)的下降沿也作為串口發(fā)送模塊的發(fā)送使能信號(hào),因?yàn)橐坏┙邮罩袛嘈盘?hào)的下降沿出現(xiàn),就表明接收模塊完成了一次數(shù)據(jù)的接收,此時(shí),就開始使能串口發(fā)送波特率發(fā)生器,串口發(fā)送模塊則在波特率時(shí)鐘的上升沿到來時(shí)依次將接收模塊接收到的數(shù)據(jù)的每一位(發(fā)送模塊自動(dòng)添加起始位和停止位)依次發(fā)送出去,當(dāng)數(shù)據(jù)發(fā)送完成之后,停止串口發(fā)送波特率發(fā)生器的使能,模塊進(jìn)入等待狀態(tài),等待下一次接收中斷信號(hào)下降沿的到來。

這里,我們首先對(duì)該設(shè)計(jì)的波特率發(fā)生器模塊進(jìn)行分析。該模塊相對(duì)簡單,代碼如下所示:

以下是代碼片段:

1 module speed_select (
2 clk, rst_n ,
3 bps_start , clk_bps
4 );
5
6 input clk; // 50MHz
7 input rst_n ; //
8 input bps_start ; //
9 output clk_bps ; // clk_bps
10
11 /*
12 parameter bps9600 = 5207, // 9600bps
13 bps19200 = 2603, // 19200bps
14 bps38400 = 1301, // 38400bps
15 bps57600 = 867, // 57600bps
16 bps115200 = 433; // 115200bps
17
18 parameter bps9600_2 = 2603,
19 bps19200_2 = 1301,
20 bps38400_2 = 650,
21 bps57600_2 = 433,
22 bps115200_2 = 216;
23 */
24
25 //
26 `define BPS_PARA 5207 // 9600
27 `define BPS_PARA_2 2603 // 9600
28
29 reg[ 12 : 0] cnt ; //
30 reg clk_bps_r ; //
31
32 //---------------------------------------------------------
33 reg[ 2 : 0] uart_ctrl ; // uart
34 //---------------------------------------------------------
35
36 always @ ( posedge clk or negedge rst_n )
37 if(! rst_n ) cnt
38 else if(( cnt == `BPS_PARA ) || ! bps_start ) cnt
39 else cnt
40
41 always @ ( posedge clk or negedge rst_n )
42 if(! rst_n ) clk_bps_r
43 else if( cnt == `BPS_PARA_2 ) clk_bps_r
//clk_bps_r ,
44 else clk_bps_r
45
46 assign clk_bps = clk_bps_r ;
47
48 endmodule

該代碼的12-22行用注釋的方式告訴了我們,獲得不同波特率時(shí)波特率分頻計(jì)數(shù)器的值應(yīng)該為多少,以及波特率計(jì)數(shù)器計(jì)數(shù)到一半時(shí)的值為多少(該值作為對(duì)信號(hào)的采樣點(diǎn),因?yàn)橐话闱闆r下,一位數(shù)據(jù),在該位數(shù)據(jù)保持時(shí)間的中間時(shí)刻是最穩(wěn)定的)。26行和27行定義的兩個(gè)參數(shù)BPS_PARA和BPS_PARA_2分別就是波特率分頻計(jì)數(shù)器的最大值和中間值。實(shí)際使用時(shí),只需要根據(jù)你所需要的波特率,更改這兩個(gè)參數(shù)的值即可 。例如,選擇波特率為9600bps時(shí),設(shè)定BPS_PARA=5207,BPS_PARA_2=2603。關(guān)于這個(gè)值的計(jì)算,這里暫時(shí)不提,后文會(huì)有交代。

36行至39行為波特率分頻計(jì)數(shù)器的計(jì)數(shù)進(jìn)程,即波特率發(fā)生模塊沒有被使能(! bps_start)或者計(jì)數(shù)器計(jì)數(shù)到BPS_PARA后則將計(jì)數(shù)器清零,其它情況下則每來一個(gè)時(shí)鐘上升沿計(jì)數(shù)器自加1。通過此進(jìn)程,則可得到相對(duì)精準(zhǔn)的波特率定時(shí)。

41行至44行為數(shù)據(jù)采樣時(shí)刻的生成,上面提到過“一般情況下,一位數(shù)據(jù),在該位數(shù)據(jù)保持時(shí)間的中間時(shí)刻是最穩(wěn)定的”,因此這里我們?cè)谟?jì)數(shù)器計(jì)數(shù)到一半時(shí),產(chǎn)生一個(gè)時(shí)鐘周期的高脈沖,此脈沖作為采樣數(shù)據(jù)的使能信號(hào)。
               
以上為波特率發(fā)生器的代碼及分析,波特率發(fā)生模塊在例化時(shí)被分別例化為串口發(fā)送波特率發(fā)生器和串口接收波特率發(fā)生器。接下來我們?cè)賮矸治龃诮邮漳K的代碼。

1 module my_uart_rx (
2 clk, rst_n ,
3 rs232_rx , rx_data , rx_int ,
4 clk_bps , bps_start
5 );
6
7 input clk; // 50MHz
8 input rst_n ; //
9 input rs232_rx ; // RS232
10 input clk_bps ; // clk_bps
11 output bps_start ; //
12 output [ 7: 0] rx_data ; //
13 output rx_int ; // ,
14
15 //---------------------------------------------------------
16 reg rs232_rx0 , rs232_rx1 , rs232_rx2 , rs232_rx3 ; //
17 wire neg_rs232_rx ; //
18
19 always @ ( posedge clk or negedge rst_n ) begin
20 if(! rst_n ) begin
21 rs232_rx0
22 rs232_rx1
23 rs232_rx2
24 rs232_rx3
25 end
26 else begin
27 rs232_rx0
28 rs232_rx1
29 rs232_rx2
30 rs232_rx3
31 end
32 end
33 //
34 //
35 // 40ns
36 assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0; // neg_rs232_rx
37
38 //---------------------------------------------------------
39 reg bps_start_r ;
40 reg[ 3: 0] num; //
41 reg rx_int ; // ,
42
43 always @ ( posedge clk or negedge rst_n )
44 if(! rst_n ) begin
45 bps_start_r
46 rx_int
47 end
48 else if( neg_rs232_rx ) begin
// rs232_rx
49 bps_start_r
50 rx_int
51 end
52 else if( num==4'd12 ) begin //
53 bps_start_r
54 rx_int
55 end
56
57 assign bps_start = bps_start_r ;
58
59 //---------------------------------------------------------
60 reg[ 7 : 0] rx_data_r ; //
61 //---------------------------------------------------------
62
63 reg[ 7 : 0] rx_temp_data ; //
64
65 always @ ( posedge clk or negedge rst_n )
66 if(! rst_n ) begin
67 rx_temp_data
68 num
69 rx_data_r
70 end
71 else if( rx_int ) begin //
72 if( clk_bps ) begin
// , 8bit 1 2
73 num
74 case ( num)
75 4'd1:rx_temp_data[0]
76 4'd2:rx_temp_data [1]
77 4'd3:rx_temp_data [2]
78 4'd4:rx_temp_data [3]
79 4'd5:rx_temp_data [4]
80 4'd6:rx_temp_data [5]
81 4'd7:rx_temp_data [6]
82 4'd8:rx_temp_data [7]
83 default : ;
84 endcase
85 end
86 else if( num == 4'd12 ) begin
// 1+8+1(2)=11bit
87 num
88 rx_data_r
89 end
90 end
91
92 assign rx_data = rx_data_r ;
93
94 endmodule

第19行到第36行為起始位檢測(cè)部分,19到32行,實(shí)現(xiàn)了對(duì)rs232_rx端口上電平的連續(xù)四個(gè)時(shí)鐘周期的寄存,第36行則對(duì)這連續(xù)4個(gè)時(shí)鐘上升沿時(shí)的rs232_rx端口電平進(jìn)行邏輯操作,得出rs232_rx端口信號(hào)下降沿的到來。neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0,即后兩次寄存的狀態(tài)為低電平而前兩次寄存的裝填為高電平,則表明該端口上的信號(hào)發(fā)生了1->0的跳變,即有下降沿出現(xiàn)。neg_rs232_rx信號(hào)會(huì)產(chǎn)生一個(gè)周期的高脈沖。

第43行至第55行則根據(jù)neg_rs232_rx和num計(jì)數(shù)值來控制串口接收波特率發(fā)生器的工作和接收中斷信號(hào)。第65行至第90行則采用線性序列機(jī)的設(shè)計(jì)方式,進(jìn)行一個(gè)字節(jié)的數(shù)據(jù)的接收。

以上為對(duì)串口接收模塊的一個(gè)簡單分析,接下來,再進(jìn)行串口發(fā)送模塊的分析。

1 module my_uart_tx (
2 clk, rst_n ,
3 rx_data , rx_int , rs232_tx ,
4 clk_bps , bps_start
5 );
6
7 input clk; // 50MHz
8 input rst_n ; //
9 input clk_bps ; // clk_bps_r ,
10 input [ 7 : 0] rx_data ; //
11 input rx_int ;
12 output rs232_tx ; // RS232
13 output bps_start ; //
14
15 //---------------------------------------------------------
16 reg rx_int0 , rx_int1 , rx_int2 ; //rx_int
17 wire neg_rx_int ; // rx_int
18
19 always @ ( posedge clk or negedge rst_n ) begin
20 if(! rst_n ) begin
21 rx_int0
22 rx_int1
23 rx_int2
24 end
25 else begin
26 rx_int0
27 rx_int1
28 rx_int2
29 end
30 end
31
32 assign neg_rx_int = ~rx_int1 & rx_int2 ; // neg_rx_int
33
34 //---------------------------------------------------------
35 reg[ 7 : 0] tx_data ; //
36 //---------------------------------------------------------
37 reg bps_start_r ;
38 reg tx_en ; //
39 reg[ 3: 0] num;
40
41 always @ ( posedge clk or negedge rst_n ) begin
42 if(! rst_n ) begin
43 bps_start_r
44 tx_en
45 tx_data
46 end
47 else if( neg_rx_int ) begin //
48 bps_start_r
49 tx_data
50 tx_en
51 end
52 else if( num==4'd11 ) begin //
53 bps_start_r
54 tx_en
55 end
56 end
57
58 assign bps_start = bps_start_r ;
59
60 //---------------------------------------------------------
61 reg rs232_tx_r ;
62
63 always @ ( posedge clk or negedge rst_n ) begin
64 if(! rst_n ) begin
65 num
66 rs232_tx_r
67 end
68 else if( tx_en ) begin
69 if( clk_bps ) begin
70 num
71 case ( num)
72 4'd0 : rs232_tx_r
73 4'd1 : rs232_tx_r
74 4'd2 : rs232_tx_r
75 4'd3 : rs232_tx_r
76 4'd4 : rs232_tx_r
77 4'd5 : rs232_tx_r
78 4'd6 : rs232_tx_r
79 4'd7 : rs232_tx_r
80 4'd8 : rs232_tx_r
81 4'd9 : rs232_tx_r
82 default : rs232_tx_r
83 endcase
84 end
85 else if( num==4'd11 ) num
86 end
87 end
88
89 assign rs232_tx = rs232_tx_r ;
90
91 endmodule

代碼19行到30行對(duì)串口接收模塊的接收中斷信號(hào)進(jìn)行了3次寄存,第32行則通過對(duì)連續(xù)兩次寄存結(jié)果的判斷,來檢測(cè)接收中斷信號(hào)rx_int的下降沿。如果有下降沿到來,neg_rx_int信號(hào)則會(huì)產(chǎn)生一個(gè)時(shí)鐘周期的高脈沖信號(hào),第47行則通過對(duì)該信號(hào)的狀態(tài)判斷,來確定是否啟動(dòng)發(fā)送波特率發(fā)生器模塊。如果檢測(cè)到了該高脈沖,則使能串口發(fā)送(tx_en FPGA愛好者學(xué)習(xí)。
               
原始代碼驗(yàn)證

前面,通對(duì)設(shè)計(jì)代碼的一個(gè)簡單分析,弄清楚了特權(quán)同學(xué)設(shè)計(jì)代碼的基本架構(gòu)和思路。那么看過特權(quán)同學(xué)教學(xué)視頻的都知道,該代碼能夠?qū)崿F(xiàn)一個(gè)字節(jié)的數(shù)據(jù)收發(fā)測(cè)試。那么這里,小梅哥就先對(duì)該設(shè)計(jì)進(jìn)行一個(gè)仿真,通過仿真來分析此設(shè)計(jì)的性能。
仿真的思路很簡單,就是通過模擬串口發(fā)送過程,給該設(shè)計(jì)模塊發(fā)送數(shù)據(jù),由前面分析可知,該設(shè)計(jì)模塊接收到數(shù)據(jù)后,會(huì)立即將數(shù)據(jù)發(fā)送出去,因此我們還需要對(duì)串口發(fā)送出來的數(shù)據(jù)進(jìn)行分析,這里,熟悉Uart協(xié)議的,我們可以直接觀察發(fā)送波形。當(dāng)然,為了更加直觀,我們也可以設(shè)計(jì)一個(gè)模擬串口接收數(shù)據(jù)的仿真模型,通過該模塊來讀取串口發(fā)送出來的數(shù)據(jù)。考慮到看這篇文章的大多是初學(xué)者,為了讓大家能夠更好的查看我們的仿真結(jié)果,同時(shí)教大家進(jìn)行仿真模型的設(shè)計(jì),小梅哥還是自己編寫了一個(gè)虛擬的串口仿真模型。驗(yàn)證時(shí),只需要將該仿真模型掛接到串口模塊上,則該模型便能夠自動(dòng)的給串口模塊發(fā)送數(shù)據(jù),同時(shí)接收串口發(fā)送過來的數(shù)據(jù)。并會(huì)實(shí)時(shí)的將發(fā)送的數(shù)據(jù)和接收的數(shù)據(jù)打印出來,實(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的過程中,會(huì)有一定的格式兼容問題,所以文中部分格式不是太規(guī)范,望各位理解,另外,完整的代碼,小梅哥也以pdf的形式提供了,感興趣的朋友可以下載學(xué)習(xí)。

本仿真模型的第一句話“`timescale 1ns/1ps”為仿真精度及時(shí)間的說明,定義時(shí)間精度為1ps,時(shí)間單位為1ns,那么我們?cè)诖a編寫的過程中,如果寫成“#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ā)端口不用說,大家也已經(jīng)知道了,串口發(fā)送狀態(tài)信號(hào)主要作為指示信號(hào),指示當(dāng)前仿真模型正在進(jìn)行數(shù)據(jù)的發(fā)送過程。

第9行至第16行為測(cè)試文件中信號(hào)的定義,以前我們總是理解說這些信號(hào)就是待測(cè)試模塊的端口,需要在測(cè)試文件中定義。那么這里小梅哥更喜歡換一種方式來理解:我們自己的設(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)源,通過給這些輸入信號(hào)線一定的激勵(lì),觀察其輸出端口上的響應(yīng),從而獲知該黑盒子的功能。那么在這里,對(duì)于待測(cè)試模塊的輸入端口,我們就接上信號(hào)發(fā)生器,對(duì)于輸出端口,我們就接上示波器或者邏輯分析儀,這樣,我們就能夠通過信號(hào)發(fā)生器給輸入端口產(chǎn)生一定的激勵(lì),然后通過示波器觀察輸出端口的輸出了。即如下圖所示:
  


那么,我們的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……接下來就好理解了,在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àn)楸痉抡婺P蛯?shí)質(zhì)上就是一個(gè)串口收發(fā)模塊,因此也需要有收發(fā)波特率發(fā)生器,這里小梅哥為了省事,直接調(diào)用了特權(quán)同學(xué)的波特率發(fā)生器模塊,來作為我仿真模型的波特率發(fā)生器。因?yàn)樵摬ㄌ芈拾l(fā)生器本身也屬于待測(cè)試部分,小梅哥之所以敢放心的調(diào)用,是因?yàn)槭孪任乙呀?jīng)通過仿真,確定了該波特率發(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來打印當(dāng)前發(fā)送的數(shù)據(jù)是多少,以方便我們直觀的觀察仿真運(yùn)行過程。至于$display這個(gè)系統(tǒng)任務(wù)中各個(gè)部分的含義,請(qǐng)讀者自行閱讀verilog的語法書。代碼的42至49行便是調(diào)用此任務(wù)進(jìn)行了多次數(shù)據(jù)的發(fā)送。

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

這里需要注意的是,打印出來的接收數(shù)據(jù)和發(fā)送數(shù)據(jù)是針對(duì)仿真模型來說的,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ù)完成后,將仿真停下來,否則,仿真會(huì)一直進(jìn)行下去,導(dǎo)致出現(xiàn)大量冗余波形,影響我們對(duì)仿真結(jié)果的分析。因此在第51行,當(dāng)所有測(cè)試已經(jīng)完成后,使用系統(tǒng)任務(wù)$stop將仿真停下來。

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


這里,小梅哥使用一個(gè)testbench文件作為頂層,將這兩個(gè)部分連接起來,同時(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í)在簡單,只是實(shí)現(xiàn)了一個(gè)啟動(dòng)時(shí)的初始化和50MHz時(shí)鐘的產(chǎn)生,因此小梅哥就不做任何分析了。
本文地址:http://www.4huy16.com/thread-160364-1-1.html     【打印本頁】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問題,我們將根據(jù)著作權(quán)人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評(píng)論 登錄 | 立即注冊(cè)

廠商推薦

  • Microchip視頻專區(qū)
  • 技術(shù)熱潮席卷三城,2025 Microchip中國技術(shù)精英年會(huì)圓滿收官!
  • 電動(dòng)兩輪車設(shè)計(jì)生態(tài)系統(tǒng)
  • “芯”光璀璨,鵬城共賞——2025 Microchip中國技術(shù)精英年會(huì)深圳站回顧
  • Microchip第22屆中國技術(shù)精英年會(huì)——采訪篇
  • 貿(mào)澤電子(Mouser)專區(qū)

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號(hào) | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表