您好,登錄后才能下訂單哦!
本篇文章為大家展示了怎么進行UART傳輸實現FPGA,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
??????圖2 34 FPGA發送一幀串口數據(考慮波特率)
??如果圖2 34考慮 115200 的波特率,結果如圖2 34所示,每一位數據都保持 434 個時鐘,為此 Verilog 可以這樣表示,如代碼2 11所示:
????????? 代碼2 11
1. reg [10:0]D1;
2. reg [8:0]C1;
3. always @( posedge CLOCK)
4. case( i)
5. 0,1,2,3,4,5,6,7,8,9,10:
6. if( C1 == 9’ d434 -1 ) begin C1 <= 9’ d0; i <= i + 1’ b1; endelse begin TXD <= D1[i]; C1 <= C1 + 1'b1; end
7. ......
8. endcase
??如代碼2 11所示,步驟 1~8 不再保持一個時鐘,換之每個步驟都保持 434 個時鐘,因此每位 TXD 的發送數據也保持 8.68us。
??除此此外,串口傳輸協議不僅可以自定義波特率,串口傳輸協議也可以自定義一幀數據的位寬,自定義內容如表2 8所示:
?????? 表2 8 自定義一幀數據
??如表2 8所示,可以自定義的數據其中便包含數據位,默認下為 1 字節,自定義內容則是 5~9 位,校驗位也可以設置為有或者無( 默認下是有),停止位也可以增至 2 位(默認下是 1 位)。
??????????圖2 35 TX 功能模塊的建模圖
??如圖2 35所示,該模塊的左方有問答信號,還有 8 位的 iData,至于右方則是 TXD 頂層信號。此外,一幀數據的波特率為 115200 bps。
?????????? 代碼 2 12 TX 功能模塊代碼
1. //****************************************************************************//
2. //# @Author: 碎碎思
3. //# @Date: 2019-04-21 21:14:51
4. //# @Last Modified by: zlk
5. //# @WeChat Official Account: OpenFPGA
6. //# @Last Modified time: 2019-08-04 02:48:17
7. //# Description:
8. //# @Modification History: 2014-05-10 13:42:27
9. //# Date By Version Change Description:
10. //# ========================================================================= #
11. //# 2014-05-10 13:42:27
12. //# ========================================================================= #
13. //# | | #
14. //# | OpenFPGA | #
15. //****************************************************************************//
16. module tx_funcmod
17. (
18. input CLOCK, RESET,
19. output TXD,
20. input iCall,
21. output oDone,
22. input [7:0]iData
23. );
24. parameter B115K2 = 9'd434; // formula : ( 1/115200 )/( 1/50E+6 )
25.
26. reg [3:0]i;
27. reg [8:0]C1;
28. reg [10:0]D1;
29. reg rTXD;
30. reg isDone;
31.
32. always @( posedge CLOCK or negedge RESET )
33. if( !RESET )
34. begin
35. i <= 4'd0;
36. C1 <= 9'd0;
37. D1 <= 11'd0;
38. rTXD <= 1'b1;
39. isDone <= 1'b0;
40. end
41. else if( iCall )
42. case( i )
43.
44. 0:
45. begin D1 <= { 2'b11 , iData , 1'b0 }; i <= i + 1'b1; end
46.
47. 1,2,3,4,5,6,7,8,9,10,11:
48. if( C1 == B115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
49. else begin rTXD <= D1[i - 1]; C1 <= C1 + 1'b1; end
50.
51. 12:
52. begin isDone <= 1'b1; i <= i + 1'b1; end
53.
54. 13:
55. begin isDone <= 1'b0; i <= 4'd0; end
56.
57. endcase
58.
59. assign TXD = rTXD;
60. assign oDone = isDone;
61.
62. endmodule
??第16~24行為相關的出入端聲明,第 9 行則是波特率為 115200 的常量聲明。
??第26~40行為相關的寄存器聲明以及復位操作。
??第41~62行為部分核心操作。第 41 行的 if( iCall ) 表示該模塊不使能就不工作。步驟 0 用來準備發送數據,其中 2’b11 是停止位與校驗位(隨便填),1’b0 則是起始位。步驟 1~11用來發送一幀數據。步驟 12~13 用來反饋完成信號并返回步驟。
??這樣發送模塊就完成了,理想時序如下圖所示:
????????圖2 36 串口發送模塊功能邏輯示意圖
??由上圖可知,串口發送模塊是“定時發送”的過程。波特率模塊產生的時間間隔是通過計數器實現的,由圖2 37可知,每隔一定時間波特率模塊就會產生一個高脈沖給TX_Pin_Out引腳。
??串口發送的框圖如圖2 37所示:
??????????圖2 37 串口模塊RTL框圖
??對于FPGA實現UART的RX模塊功能主要就是電平采集。那么它到底是如何實現采集的呢?
???????????圖 2 38 RX模塊電平采集示意圖
??說到底,在發送模塊中一位數據發送的時間間隔是通過波特率進行控制的,同理,在接受模塊中采集一位數據的間隔同樣也要通過波特率進行控制,具體如上圖所示。
??上圖中,數據采集都是在“每位數據的中間”進行著。RX_Pin_In 輸入一幀數據,當檢測到低電平(起始位), 在第 0 位數據,采取忽略的態度,然后接下來的 8 位數據位都被采集,最后校驗位和停止位,卻是采取了忽略的操作。有一點必須好好注意,串口傳輸數據“從最低位開始,到最高位結束”。
??因為 Verilog 無法描述理想以外的時序, 對此所有時序活動都必須看成理想時序。
??????圖2 39 FPGA接收一幀波特率為115200的數據
??當FPGA接收一幀數據為波特率115200之際,情況差不多如圖2 41所示。50Mhz是FPGA的時鐘源,也是一幀數據的采集時鐘, RXD 則是一幀數據的輸入端。波特率為 115200的一位數據經過 50Mhz 的時鐘量化以后,每一位數據大約保持 8.68us,即 434 個時鐘。串口傳輸沒有自己的時鐘信號,所以我們必須利用 FPGA 的時鐘源“跟蹤”每一位數據。對此, FPGA 只能借用計數器“同步跟蹤”而已,至于 Verilog 則可以這樣描述,結果如代碼2 13所示:
?????????? 代碼2 13
1. 0,1,2,3,4,5,6,7,8,9,10: //同步跟蹤中 ...
2. if( C1 == 434 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
3. else C1 <= C1 + 1'b1;
??如代碼2 13所示,所謂同步跟蹤,就是利用計數器估計每一位數據 … 期間,步驟 0~10表示每一位數據,至于 C1 計數 434 個時鐘則是同步跟蹤中。其中-1考慮了步驟之間的跳轉所耗掉的時鐘。
????????? ?圖2 40 讀取起始位
??知道串口的一幀數據都是從拉低的起始位開始,然而為了完美尾行,亦即實現精密控時,起始位的讀取往往都是關鍵。如圖2 40所示,當我們在第一個時鐘讀取(采集)起始位的時候,由于 Verilog 的讀取只能經過讀取過去值而已,余下起始位還有 433 個時鐘需要我們跟蹤,為此 Verilog 可以這樣描述,結果如代碼2 14所示:
??????????? 代碼2 14
1. 0:
2. if( RXD == 1'b0 ) begin i <= i + 1'b1; C1 <= C1 + 4'd1; end
3. 1: // stalk start bit
4. if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
5. else C1 <= C1 + 1'b1;
??如代碼2 14所示,步驟 0 用來檢測起始位,如果 RXD 的電平為拉低狀態, C1 立即遞增以示同步跟蹤已經用掉一個時鐘,同樣也可以看成 i 進入下一個步驟用掉一個時鐘。然而步驟 1 是用來跟蹤余下的 433 個時鐘,但是計數器 C1 不是從 0 開始計數,而是從 1開始計算,因為 C1 在步驟已經遞增的緣故。
??????????圖2 41 讀取一幀數據當中的數據位
??一幀數據的跟蹤結果與讀取結果如圖2 41所示 … 除了起始位,我們使用了兩個步驟采集并跟蹤之余,接下來便用 8 個步驟數據一邊跟蹤一邊采集所有數據位,然而采集的時候則是 1/4 周期,即每位數據的第 108 個時鐘。最后的校驗位及結束位則是跟蹤而已。
??對此, Verilog 可以這樣表示,結果如代碼2 15所示:
?????????????代碼2 15
1. 0:
2. if( RXD == 1'b0 ) begin i <= i + 1'b1; C1 <= C1 + 4'd1; end
3.
4. 1: // start bit
5. if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
6. else C1 <= C1 + 1'b1;
7.
8. 2,3,4,5,6,7,8,9: //stalk and count 1~8 data's bit , sample data at 1/2 for bps
9. begin
10. if( C1 == SAMPLE ) D1[i-2] <= RXD;
11. if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
12. else C1 <= C1 + 1'b1;
13. end
14.
15. 10,11: // parity bit & stop bit
16. if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
17. else C1 <= C1 + 1'b1;
18.
19. 12:
20. begin isDone <= 1'b1; i <= i + 1'b1; end
21.
22. 13:
23. begin isDone <= 1'b0; i <= 4'd0; end
??如代碼2 15所示,步驟 0~1 用來采集與跟蹤起始位,步驟 2~9 則用來跟蹤數據位,并且采集為 1/4 周期。步驟 10~11 則用來跟蹤校驗位于結束位。
????????????圖2 42 RX功能模塊的建模圖
??圖2 42是 RX 功能模塊的建模圖,左方鏈接至頂層信號 RXD,右方則是問答信號還有 8位的 oData。
????????????代碼2 16 RX模塊實現代碼
1. //****************************************************************************//
2. //# @Author: 碎碎思
3. //# @Date: 2019-04-21 22:46:15
4. //# @Last Modified by: zlk
5. //# @WeChat Official Account: OpenFPGA
6. //# @Last Modified time: 2019-08-04 03:21:38
7. //# Description:
8. //# @Modification History: 2014-05-10 13:44:28
9. //# Date By Version Change Description:
10. //# ========================================================================= #
11. //# 2014-05-10 13:44:28
12. //# ========================================================================= #
13. //# | | #
14. //# | OpenFPGA | #
15. //****************************************************************************//
16. module rx_funcmod
17. (
18. input CLOCK, RESET,
19. input RXD,
20. input iCall,
21. output oDone,
22. output [7:0]oData
23. );
24. parameter BPS115K2 = 9'd434, SAMPLE = 9'd108;
25.
26. reg [3:0]i;
27. reg [8:0]C1;
28. reg [7:0]D1;
29. reg isDone;
30.
31. always @ ( posedge CLOCK or negedge RESET )
32. if( !RESET )
33. begin
34. i <= 4'd0;
35. C1 <= 9'd0;
36. D1 <= 8'd0;
37. isDone <= 1'b0;
38. end
39. else if( iCall )
40. case( i )
41.
42. 0:
43. if( RXD == 1'b0 ) begin i <= i + 1'b1; C1 <= C1 + 4'd1; end
44.
45. 1: // start bit
46. if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
47. else C1 <= C1 + 1'b1;
48.
49. 2,3,4,5,6,7,8,9: //stalk and count 1~8 data's bit , sample data at 1/2 for bps
50. begin
51. if( C1 == SAMPLE ) D1[i-2] <= RXD;
52. if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
53. else C1 <= C1 + 1'b1;
54. end
55.
56. 10,11: // parity bit & stop bit
57. if( C1 == BPS115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
58. else C1 <= C1 + 1'b1;
59.
60. 12:
61. begin isDone <= 1'b1; i <= i + 1'b1; end
62.
63. 13:
64. begin isDone <= 1'b0; i <= 4'd0; end
65.
66. endcase
67.
68. assign oDone = isDone;
69. assign oData = D1;
70.
71. endmodule
??第 16~24 行是相關的出入端聲明,第 24 行則是波特率為 115200 的常量聲明,其外還有采集的周期。
??第 26~38 行是相關的寄存器聲明,第 32~38 行則是這些寄存器的復位操作。
??第 39~46 行是核心操作。第 39 行的 if( iCall ) 表示該模塊不使能便不工作。步驟 0~1 用來判斷與跟蹤起始位;
??步驟 2~9 用來跟蹤并且讀取當中的數據位;步驟 10 至 11 則是用來跟蹤校驗位與停止位而已。步驟 12~13 則用來反饋完成信號,以示一次性的接收工作已經完成。
??第 68~69 行是輸出驅動聲明。
上述內容就是怎么進行UART傳輸實現FPGA,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。