串口回環工程現象: https://www.bilibili.com/BV1Af4y117H4?p=18
至簡設計系列_串口回環工程
--作者:小黑同學
本案例的編號為:000900000237,如果有疑問,請按編號在下面貼子查找答案:MDY案例交流【匯總貼】_FPGA-明德揚科教 (mdy-edu.com)
本文為明德揚原創及錄用文章,轉載請注明出處!
串行接口簡稱串口,也稱串行通訊接口或者串行通信接口,是采用串行通信方式的擴展接口。串行接口是指數據一位一位地順序傳送,其特點是通信線路簡單,只要一對傳輸線就可以實現雙向通信(可以直接利用電話線作為傳輸線),從而大大降低了成本,特別適合用于遠距離通信,但傳送速度較慢。一條信息的各位數據被逐位按順序傳送的通信方式稱作串行通信。串行通信的特點是:數據位的傳送,按位順序進行,最少只需要一根傳輸線即可完成;成本低,但傳送速度慢。串行通信的距離可以從幾米到幾千米;根據信息的傳送方向,串行通信可以進一步分為單工、半雙工和全雙工三種。
串口的出現是在1980年前后,數據傳輸率是115kbps~230kbps。串口出現的初期是為了實現連接計算機外設的目的,初期串口一般用來連接鼠標和外置Modem以及老式攝像頭和寫字板等設備。串口也可以應用于兩臺計算機(或設備)之間的互聯及數據傳輸。由于串口不支持熱插拔及傳輸速率較低,部分新主板和大部分便攜電腦已開始取消該接口。串口多用于工業控制和測量設備以及部分通信設備中。
本練習要求實現串口回環功能,具體功能要求如下
1、 上位機于FPGA之間通過串口進行通信,規定波特率為9600,數據位為8bit,無奇偶校驗位,停止位為1。
2、 FPGA內部有一個可保存128字節的FIFO。
3、 FPGA從上位機接收到數據后,將數據保存到FIFO中。
4、 當FIFO保存的數據超過60個數據時,啟動發送數據操作:讀取FIFO的數據,將數據返回給上位機。
5、 在啟動發送數據操作過程中,如果FIFO變空,結束發送操作,等待下一次的啟動。
注意:上位機接收到的數據與發送的數據相同,不能多也不能少。
1.1.3 系統結構框圖
系統結構框圖如下所示:

圖二
1.1.4模塊功能串口接收模塊實現功能
1、 將輸入數據進行同步化處理。
2、 解析串口時序,將有效數據進行串并轉換。
Ø 數據處理模塊實現功能
1、 包含一個FIFO,用來存儲接收到的數據。
2、 滿足發送條件后,讀出FIFO的數據送給下游模塊。
Ø 串口發送模塊實現功能
1、 將接收到的數據進行并串轉換,發送給上位機。
1.1.5頂層信號
1.1.6參考代碼
下面是本工程的頂層代碼:
-
module mdyUartLoopBack(
-
rst_n ,
-
clk ,
-
rx_uart,
-
tx_uart
-
);
-
parameter BPS = 5208;
-
-
input rst_n ;
-
input clk ;
-
input rx_uart ;
-
output tx_uart ;
-
-
wire [7:0] uart_in ;
-
wire uart_in_vld ;
-
wire [7:0] uart_out ;
-
wire uart_out_vld;
-
wire rdy ;
-
-
uart_rx#(.BPS(BPS)) uart_rx(
-
.clk (clk ),
-
.rst_n (rst_n ),
-
.din (rx_uart ),
-
.dout (uart_in ),
-
.dout_vld(uart_in_vld)
-
);
-
uart_tx#(.BPS(BPS)) uart_tx(
-
.clk (clk ),
-
.rst_n (rst_n ),
-
.din (uart_out ),
-
.din_vld (uart_out_vld),
-
.rdy (rdy ),
-
.dout (tx_uart )
-
);
-
data_handle u_data_handle(
-
.clk (clk ),
-
.rst_n (rst_n ),
-
.din (uart_in ),
-
.din_vld (uart_in_vld ),
-
.dout (uart_out ),
-
.dout_vld(uart_out_vld),
-
.rdy (rdy )
-
);
-
- endmodule
1.2 串口接收模塊設計1.2.1 接口信號
1.2.2 設計思路
UART異步串行口簡介
數據通信的基本方式可分為并行通信和串行通信兩種:
并行通信:是指利用多條數據線將一個資料的各位同時傳送。特點是傳輸速度快,適合用于短距離通信,但要求通信速率較高的應用場合。
串行通信:是指利用一條傳輸線將資料一位位的順序傳送。特點是通信線路簡單,利用簡單的線纜就可以實現通信,減低成本,適用于遠距離通信,但傳輸速度慢的應用場合。
在FPGA看來,串口只有兩根線,一根線用于接收,一根線用于發送。

Ø UART異步串行口的傳輸格式
異步通信以一個字符為傳輸單位,通信中兩個字符間的時間間隔是不固定的,然而在同一個字符中的兩個相鄰位代碼間的時間間隔是固定的。
通信協議(通信規程):是指通信雙方約定的一些規則。在使用異步串行口傳送一個字符的信息時,對資料格式有如下規定:規定有空閑位、起始位、數據位、奇偶校驗位、停止位。通訊時序圖如下:

每一個數據位的寬度等于傳送波特率的倒數。微機異步串行通信中,常用的波特率為110,150,300,600,1200,2400,4800,9600 ,19200,38400,115200等。代表每個碼元傳輸的速率。在二進制數據傳輸中,波特率和比特率相同都是為每個比特數據傳輸的速率,其倒數為1bit數據的寬度,也就是1bit數據持續的時間。確定這一時間,就可用FPGA構造計數器實現比特周期的延時,從而實現特定波特率的數據傳輸。
Ø 開始前,線路處于空閑狀態,送出連續“1”。傳送開始時首先發一個“0”作為起始位,然后出現在通信線上的是字符的二進制編碼數據。
Ø 每個字符的數據位長可以約定為5 位、6 位、7 位或8 位。
Ø 后面是奇偶校驗位,顧名思義,檢驗位適用于數據校驗。分為奇校驗和偶校驗。奇校驗需要保證傳輸數據總共有奇數個邏輯高電平,偶校驗則需要保證傳輸數據有偶數個邏輯高電平。即“奇偶”指的是數據中(包括該校驗位)1的個數。例如:傳輸的數據是01000011,如果校驗方式是奇校驗,則校驗位為0 ,若是偶校驗則校驗位是1.傳輸中校驗位不是必須項,雙方可以約定不要校驗位,或者使用奇/偶校驗方式。
Ø 最后是表示停止位的“1”信號,這個停止位可以約定持續1 位、1.5 位或2 位的時間寬度。由于每臺設備有其自己的時鐘,很可能再通信中兩臺設備間出現小小的不同步。因此停止位不僅僅是表示傳輸的結束,并且提供一個校正時鐘同步的機會,讓從機可以正確的識別下一輪數據的起始位。停止位的位數越多,不同時鐘同步的容忍程度就越大,但是數據傳輸速率也越慢。
Ø 至此一個字符傳送完畢,線路又進入空閑,持續為“1”。經過一段隨機的時間后,下一個字符開始傳送才又發出起始位。
Ø 架構設計
上位機發送的數據會按照上圖所示串口的時序圖的順序過來,因此我們需要按照其對應的格式進行接收。發送8位數據data前,串口接收數據線會先變0并持續一段時間(起始位),然后發送data[0]、data[1],以此類推直至發送完data[7],發送每位數據時都會持續一段時間,發送完畢后數據線會變為1并持續一段時間(結束位)。至此,完成數據的發送。可以看出每段有效信號的開始前和結束后,都會有特殊信號:有效數據開始前會有一段變0的信號,用以告知FPGA開始傳送數據;結束后會有一段變1的信號,告知FPGA此數據傳送結束。
由上面時序分析可知,當我們檢測到數據線從高電平(空閑位)變為低電平(起始位)就表示開始數據的傳輸了,因此需要進行下降沿的檢測,檢測方法如下:

該檢測方法主要利用D觸發器打拍來實現。
din:輸入串口數據。
din_ff0:輸入串口數據經過一級緩存之后的信號,目的是為了將異步信號同步化。
din_ff1:輸入串口數據經過二級緩存之后的信號,目的是為了減少亞穩態造成的影響。
din_ff2:輸入串口數據經過三級緩存之后的信號,目的是為了檢測信號的下降沿。
flag_add:接收狀態指示信號,當在時鐘上升沿檢測到din_ff1等于0并且din_ff2等于1的時候表示檢測到了下降沿,此時將flag_add信號拉高,表示進入到接收狀態。
根據串口時序,可以提出兩個計數器的架構,如下圖所示:

該架構由兩個計數器組成:時鐘計數器cnt和數據計數器data_num。
時鐘計數器cnt:用于計數發送1bit數據所需要的時間,加一條件為flag_add,表示進入接收狀態時就開始計數;結束條件為數5208個,開發板晶振時鐘是50M,對應周期為20ns,每位數據的持續時間為104166ns/20ns=5208.3個時鐘周期,近似為5208個時鐘周期。
數據計數器data_num:用于對接收的每一比特數據進行計數,加一條件為end_cnt,表示接收到1bit的數據就加一;結束條件為數9個,一個起始位加上八個數據位,共9位,數完就清零。
Ø 注意事項
1、 串口接收模塊中的數據計數器一定不要把停止位也數上去,否則在接受的數據的時候會出錯。感興趣的同學可以使用signaltap抓取信號進行分析(仿真沒有用)。
2、 由于工程中串口的每1bit數據傳輸所需要的時間是近似值,也就是存在誤差,因此串口接收在采集數據的時候,需要在數據的中間時刻進行采樣,這樣才能保證數據的正確性。
1.2.3參考代碼
下面是使用明德揚的計數器模板等寫出來的本模塊代碼。
-
always @ (posedge clk or negedge rst_n) begin
-
if(!rst_n) begin
-
din_ff0 <= 1'b1;
-
din_ff1 <= 1'b1;
-
din_ff2 <= 1'b1;
-
end
-
else begin
-
din_ff0 <= din;
-
din_ff1 <= din_ff0;
-
din_ff2 <= din_ff1;
-
end
-
end
-
-
always @ (posedge clk or negedge rst_n)begin
-
if(!rst_n) begin
-
flag_add <= 1'b0;
-
end
-
else if(din_ff2 & ~din_ff1) begin
-
flag_add <= 1'b1;
-
end
-
else if(data_num==4'd8&&end_cnt) begin
-
flag_add <= 1'b0;
-
end
-
end
-
-
always @ (posedge clk or negedge rst_n)begin
-
if(!rst_n)begin
-
cnt <= 0;
-
end
-
else if(add_cnt)begin
-
if(end_cnt)begin
-
cnt <= 0;
-
end
-
else begin
-
cnt <= cnt+1'b1;
-
end
-
end
-
else begin
-
cnt <= 0;
-
end
-
end
-
assign add_cnt = flag_add;
-
assign end_cnt = add_cnt && cnt == BPS-1;
-
-
-
-
always @(posedge clk or negedge rst_n) begin
-
if (rst_n==0) begin
-
data_num <= 0;
-
end
-
else if(add_data_num) begin
-
if(end_data_num)
-
data_num <= 0;
-
else
-
data_num <= data_num+1 ;
-
end
-
end
-
assign add_data_num = end_cnt;
-
assign end_data_num = add_data_num && data_num == 9-1 ;
-
-
always @ (posedge clk or negedge rst_n)begin
-
if(!rst_n) begin
-
dout <= 8'd0;
-
end
-
else if(add_cnt && cnt==BPS_P-1 && data_num!=0) begin
-
dout<={din,{dout[7:1]}};
-
end
-
else begin
-
dout<=dout;
-
end
-
end
-
-
always @ (posedge clk or negedge rst_n)begin
-
if(!rst_n) begin
-
dout_vld <= 1'b0;
-
end
-
else if(add_data_num && data_num == 4'd8) begin
-
dout_vld <= 1'b1;
-
end
-
else begin
-
dout_vld <= 1'b0;
-
end
-
end
- endmodule
1.3 數據處理模塊設計1.3.1接口信號
1.3.2 設計思路
FIFO原理簡介
FIFO(first input first output),即先進先出的數據緩存器,本質上還是RAM,與普通存儲器的區別:沒有外部讀寫地址線,這樣使用起來非常簡單。特點就是只能順序寫入數據,順序讀出數據,其數據地址由內部讀寫指針自動加一完成,不能像普通存儲器那樣可以由地址線決定讀取或寫入某個指定的地址。
FIFO根據讀寫時鐘的區別,分為同步FIFO和異步FIFO。同步FIFO讀寫共用一個相同的時鐘;異步FIFO讀寫可以使用不同的時鐘。由于異步FIFO內部存在同步化電路,因此資源占用要比同步FIFO大。
再FPGA中,FIFO的使用主要有兩種場合,應用于緩存和跨時鐘域處理。FIFO本身就是存儲器,自然可以用作數據的緩存,只不過在選擇上需要跟普通的RAM區分開。又由于異步FIFO的存在,可以使得其寫側和讀側時鐘不同,因此又可用作跨時鐘域處理。
更多關于FIFO的內容,可以關注明德揚FIFO專題課,或者是明德揚免費的FIFO課程
Ø 架構設計
按照功能要求,本模塊需要對接收的數據進行存儲,當存夠60個的時候開始發送,下面是本模塊的架構圖。

本模塊大致分為三部分:FIFO的寫控制電路、FIFO、FIFO的讀控制電路。
寫控制電路:只要輸入數據有效,就將數據寫進FIFO,主要信號為寫數據data和寫使能wrreq。
FIFOip核:存儲數據。
讀控制電路:當FIFO內部有60個數據、FIFO非空并且下游模塊準備好接收數據的時候,就開始讀。主要信號為輸出數據q、FIFO有效數據量指示信號usedw、空指示信號empty、讀使能rdreq。
1.3.3參考代碼
-
assign data = din ;
-
assign wrreq = din_vld ;
-
-
-
my_fifo u_my_fifo (
-
.clock(clk ),
-
.data (data ),
-
.rdreq(rdreq),
-
.wrreq(wrreq),
-
.empty(empty),
-
.q (q ),
-
.usedw(usedw)
-
);
-
-
-
always@(*)begin
-
if(rd_flag && empty==1'b0 && rdy)
-
rdreq = 1'b1;
-
else
-
rdreq = 1'b0;
-
end
-
-
always@(posedge clk or negedge rst_n)begin
-
if(rst_n==1'b0)begin
-
rd_flag <= 1'b0;
-
end
-
else if(rd_flag==1'b0 && usedw>=60) begin
-
rd_flag <= 1'b1;
-
end
-
else if(rd_flag==1'b1 && empty)begin
-
rd_flag <= 1'b0;
-
end
-
end
-
-
always @(posedge clk or negedge rst_n)begin
-
if(rst_n==1'b0)begin
-
dout <= 0;
-
end
-
else begin
-
dout <= q;
-
end
-
end
-
-
always @(posedge clk or negedge rst_n)begin
-
if(rst_n==1'b0)begin
-
dout_vld <= 1'b0;
-
end
-
else begin
-
dout_vld <= rdreq;
-
end
-
end
-
-
- endmodul
1.4 串口發送模塊設計1.4.1接口信號
1.4.2設計思路
串口發送就是要按照串口的時序,對數據進行并串轉換,在介紹架構之前,先來描述一下本模塊一些重要的信號的含義:
工作狀態指示信號tx_flag:初始狀態為0,表示處于空閑狀態,當檢測到輸入數據有效的時候,該信號變為1,表示處于工作狀態,當數據發送完之后,重新拉低,進入空閑狀態,等待下一個數據的輸入。
數據鎖存信號tx_data_tmp:位寬為8bit,初始狀態為0,當模塊處于空閑狀態,并且輸入數據有效的時候,就接收輸入的數據進行鎖存。由于輸入數據在串口發送的時間內都需要用到,因此為了防止數據發生變化,導致串口發送出現問題,所以引入此信號進行數據的鎖存。
準備好接收指示信號rdy:當接收到輸入數據,或者模塊處于發送狀態的時候,此信號為1,表示不能接收數據,其他情況為1,表示準備好接收數據了。由于上游模塊數據輸出速率要比串口發送模塊發送的速度快得多,所以需要此信號來控制上游模塊的輸出,當串口發送模塊收到有效數據的時候,需要立刻把此信號拉高,所以需要用組合邏輯產生。
我們可以得到兩個計數器組成的計數器架構,如下圖所示:

該架構由兩個計數器組成:時鐘計數器cnt和數據計數器data_num。
時鐘計數器cnt:用于計數發送1bit數據所需要的時間,加一條件為tx_flag,表示進入工作狀態時就開始計數;結束條件為數5208個,開發板晶振時鐘是50M,對應周期為20ns,每位數據的持續時間為104166ns/20ns=5208.3個時鐘周期,近似為5208個時鐘周期。
數據計數器data_num:用于對接收的每一比特數據進行計數,加一條件為end_cnt,表示發送1bit的數據就加一;結束條件為數10個,一個起始位加上八個數據位,再加上一個結束位,共10位,數完就清零。
使用明德揚的計數器等模板,可以很快速很熟練地寫出此模塊代碼。
-
always @(posedge clk or negedge rst_n)begin
-
if(rst_n==1'b0)begin
-
tx_flag <= 1'b0;
-
end
-
else if(tx_flag==1'b0 && din_vld) begin
-
tx_flag <= 1'b1;
-
end
-
else if(tx_flag && data_num==9 && cnt==BPS-1)begin
-
tx_flag <= 1'b0;
-
end
-
end
-
-
-
always @ (posedge clk or negedge rst_n)begin
-
if(!rst_n)begin
-
cnt <=0;
-
end
-
else if(tx_flag)begin
-
if(cnt==BPS-1)begin
-
cnt<=14'd0;
-
end
-
else begin
-
cnt <=cnt+1'b1;
-
end
-
end
-
else begin
-
cnt<=0;
-
end
-
end
-
assign add_cnt = tx_flag;
-
assign end_cnt = add_cnt && cnt==BPS-1;
-
-
-
always @ (posedge clk or negedge rst_n) begin
-
if(!rst_n) begin
-
tx_data_tmp <=8'd0;
-
end
-
else if(tx_flag==1'b0 && din_vld) begin
-
tx_data_tmp <= din;
-
end
-
end
-
-
-
always @(posedge clk or negedge rst_n) begin
-
if (rst_n==0) begin
-
data_num <= 0;
-
end
-
else if(add_data_num) begin
-
if(end_data_num)
-
data_num <= 0;
-
else
-
data_num <= data_num+1 ;
-
end
-
end
-
assign add_data_num = end_cnt;
-
assign end_data_num = add_data_num && data_num == 10-1 ;
-
-
-
-
always @ (posedge clk or negedge rst_n) begin
-
if(!rst_n) begin
-
dout <= 1'b1;
-
end
-
else if(tx_flag)begin
-
if(data_num==0)begin
-
dout<=1'b0;
-
end
-
else if(data_num==9)begin
-
dout<=1'b1;
-
end
-
else begin
-
dout <= tx_data_tmp[data_num-1];
-
end
-
end
-
else begin
-
dout<=1'b1;
-
end
-
end
-
-
always @(*)begin
-
if(din_vld || tx_flag)
-
rdy = 1'b0;
-
else
-
rdy = 1'b1;
-
end
-
- endmodule
1.5 效果和總結
下圖是該工程的現象
由于該工程在不同開發板上的上板效果是相同的,所以就統一展示。下圖為串口調試助手的界面,下方一欄中是要發送的數據:010203040506,共6個字節,點擊手動發送10次之后,串口調試助手接收到的數據將在上方空白區域顯示。

由于該項目的上板現象是動態的,想觀看完整現象的朋友可以看一下現象演示的視頻。
感興趣的朋友也可以訪問明德揚論壇(http://www.fpgabbs.cn/)進行FPGA相關工程設計學習,也可以看一下我們往期的文章:
明德揚是一家專注于FPGA領域的專業性公司,公司主要業務包括開發板、教育培訓、項目承接、人才服務等多個方向。點撥開發板——學習FPGA的入門之選。
MP801開發板——千兆網、ADDA、大容量SDRAM等,學習和項目需求一步到位。網絡培訓班——不管時間和空間,明德揚隨時在你身邊,助你快速學習FPGA。周末培訓班——明天的你會感激現在的努力進取,升職加薪明德揚來助你。就業培訓班——七大企業級項目實訓,獲得豐富的項目經驗,高薪就業。專題課程——高手修煉課:提升設計能力;實用調試技巧課:提升定位和解決問題能力;FIFO架構設計課:助你快速成為架構設計師;時序約束、數字信號處理、PCIE、綜合項目實踐課等你來選。項目承接——承接企業FPGA研發項目。人才服務——提供人才推薦、人才代培、人才派遣等服務。
MP801開發板——千兆網、ADDA、大容量SDRAM等,學習和項目需求一步到位。網絡培訓班——不管時間和空間,明德揚隨時在你身邊,助你快速學習FPGA。周末培訓班——明天的你會感激現在的努力進取,升職加薪明德揚來助你。就業培訓班——七大企業級項目實訓,獲得豐富的項目經驗,高薪就業。專題課程——高手修煉課:提升設計能力;實用調試技巧課:提升定位和解決問題能力;FIFO架構設計課:助你快速成為架構設計師;時序約束、數字信號處理、PCIE、綜合項目實踐課等你來選。項目承接——承接企業FPGA研發項目。人才服務——提供人才推薦、人才代培、人才派遣等服務。
【設計教程下載】

【設計視頻教程】
https://www.bilibili.com/BV1Af4y117H4?p=17
