1、UART通信協議 UART:Universal Asynchronous Receiver/Transmitter,通用異步接收/發送裝置,所謂異步,就是說發送和接受不能同時進行,是單工的。對于UART的verilog設計,簡單的說就是需要“波特率發生器”與“數據傳輸時序”兩個模塊,如下: (1)波特率 在UART通信協議中很重要的一個定義,就是“波特率”,即傳輸數據時的速率。波特率一般有以下這些: (2)數據傳輸時序 對于UART數據傳輸的協議,如下所示。其中奇偶校驗位與停止位不是必須的。而“起始位、資料位、停止位”則是必須的。一般資料位為8 bits。
具體的時序圖如下所示。A-b為起始位,b-c為資料位,c-d為停止位。 2、UART硬件設計 UART是計算機中串行通信端口的關鍵部分。在計算機中,UART相連于產生兼容RS232規范信號的電路。RS232標準定義邏輯“1”信號相對于地為-3到-15伏,而邏輯“0”相對于地為3到15伏。所以,當一個微控制器中的UART相連于PC時,它需要一個RS232驅動器來轉換電平。 如下圖所示,UART硬件電路灰常的簡單,只需要一塊電平轉換芯片即可。電平轉換芯片一般用Max3232、Max232,SP3232等,其中Maxim公司的電平轉換芯片比較常用。跟PC和處理器相連接的,只要相應的TXD、RXD兩根信號線即可。 3、UART Verilog設計 基于FPGA的UART設計,其實在單片機中沒有這么一說。單片機中早已有了UART的IP,我們只要調用函數即可,但FPGA中,純硬件設計電路上,我們想要使用串口來調試,那我們就必須了解徹底UART通信協議,必須自己動手寫UART的硬核。利用硬件描述語言,相當的方便。 UART驅動代碼的編寫,算是比較簡單的設計了。Bingo當年用VHDL編寫串口通信,后來學了Verilog,重新來過,最后修改串口,改善得到穩定的版本,經過多次測試,上萬數據傳輸未出現過錯誤,已應用于多個項目中,在此獻丑,希望對你有用。 以下是相關的下載信息: (1)串口調試助手 http://www./lib/detail.aspx?id=86809 (2)uart_io_test工程 http://www./lib/detail.aspx?id=86812 (3)uart_fifo_design工程 http://www./lib/detail.aspx?id=86813 對于基于FPGA的Verilog設計UART通信接口的代碼分析,如下所示: (1)波特率發生器 如果您看過前面章節,那您是否還記得“第九章 為所欲為——教你什么才是真正的任意分頻”?此處我們為了達到標準的頻率,最大極限的不想出現任何誤差,Bingo利用自己設計的“相位控制分頻原理”,來完成此模塊的設計。具體的分頻原理請看第九章,此處不再做累贅的闡述,謝謝。 關于本模塊的主要代碼,如下: /************************************************* * Module Name : clk_generator.v * Engineer : Crazy Bingo * Target Device : EP2C8Q208C8 * Tool versions : Quartus II 11.0 * Create Date : 2011/01/27 * Revision : v1.0 * Description : **************************************************/ module clk_generator ( input clk, input rst_n, output clk_bps, output clk_smp ); //------------------------------------------ /************clk_smp = 16*clk_bps************ Freq_Word1 <= 32'd25770; Freq_Word1 <= 32'd412317; //300 bps Freq_Word1 <= 32'd51540; Freq_Word2 <= 32'd824634; //600 bps Freq_Word1 <= 32'd103079; Freq_Word2 <= 32'd1649267; //1200 bps Freq_Word1 <= 32'd206158; Freq_Word2 <= 32'd3298535; //2400 bps Freq_Word1 <= 32'd412317; Freq_Word2 <= 32'd6597070; //4800 bps Freq_Word1 <= 32'd824634; Freq_Word2 <= 32'd13194140; //9600 bps Freq_Word1 <= 32'd1649267; Freq_Word2 <= 32'd26388279; //19200 bps Freq_Word1 <= 32'd3298535; Freq_Word2 <= 32'd52776558; //38400 bps Freq_Word1 <= 32'd3693672; Freq_Word2 <= 32'd59098750; //43000 bps Freq_Word1 <= 32'd4810363; Freq_Word2 <= 32'd76965814; //56000 bps Freq_Word1 <= 32'd4947802; Freq_Word2 <= 32'd79164837; //57600 bps Freq_Word1 <= 32'd9895605; Freq_Word2 <= 32'd158329674; //115200bps Freq_Word1 <= 32'd10995116; Freq_Word2 <= 32'd175921860; //128000bps Freq_Word1 <= 32'd21990233; Freq_Word2 <= 32'd351843721; //256000bps *****************************************************/ //only want to generate beautiful clk for bsp and sample reg [31:0] bps_cnt1; reg [31:0] bps_cnt2; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin bps_cnt1 <= 0; bps_cnt2 <= 0; end else begin bps_cnt1 <= bps_cnt1 + 32'd9895605; //Bps=115200bps bps_cnt2 <= bps_cnt2 + 32'd158329674; //Bps=115200bps*16 end end //------------------------------------------ //clk_bps sync bps generater reg clk_bps_r0,clk_bps_r1,clk_bps_r2; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin clk_bps_r0 <= 0; clk_bps_r1 <= 0; clk_bps_r2 <= 0; end else begin if(bps_cnt1 < 32'h7FFF_FFFF) clk_bps_r0 <= 0; else clk_bps_r0 <= 1; clk_bps_r1 <= clk_bps_r0; clk_bps_r2 <= clk_bps_r1; end end assign clk_bps = ~clk_bps_r2 & clk_bps_r1; //------------------------------------------ //clk_smp sync receive bps generator reg clk_smp_r0,clk_smp_r1,clk_smp_r2; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin clk_smp_r0 <= 0; clk_smp_r1 <= 0; clk_smp_r2 <= 0; end else begin if(bps_cnt2 < 32'h7FFF_FFFF) clk_smp_r0 <= 0; else clk_smp_r0 <= 1; clk_smp_r1 <= clk_smp_r0; clk_smp_r2 <= clk_smp_r1; end end assign clk_smp = ~clk_smp_r2 & clk_smp_r1; endmodule 代碼中Bingo設置了多個選項的bps,根據您的需要,可以直接修改代碼,來達到自己的要求。本模塊的功能主要功能是生成兩個時鐘: a) clk_bps : UART TXD信號線數據發送的波特率 b) clk_smp: UART RXD信號線數據接受的采樣速率,以對已波特率的16倍速度采樣,捕獲數據的中點,在數據最穩態讀取數據,達到最大限制的穩定。 (2)TXD發送模塊 這部分代碼比較簡單,因為FPGA是主控,只要根據固定的時序給數據即可。Bingo設計了一個狀態機來完成時序,狀態機代碼如下: always@(posedge clk or negedge rst_n) begin if(!rst_n) begin txd_state <= T_IDLE; txd_flag_r <= 0; txd <= 1'b1; end else begin case(txd_state) T_IDLE: begin txd <= 1; txd_flag_r <= 0; if(txd_en == 1) txd_state <= T_SEND; else txd_state <= T_IDLE; end T_SEND: begin if(clk_bps == 1) begin if(txd_cnt < 4'd9) txd_cnt <= txd_cnt + 1'b1; else begin txd_cnt <= 0; txd_state <= T_IDLE; txd_flag_r <= 1; end case(txd_cnt) 4'd0: txd <= 0; 4'd1: txd <= txd_data[0]; 4'd2: txd <= txd_data[1]; 4'd3: txd <= txd_data[2]; 4'd4: txd <= txd_data[3]; 4'd5: txd <= txd_data[4]; 4'd6: txd <= txd_data[5]; 4'd7: txd <= txd_data[6]; 4'd8: txd <= txd_data[7]; 4'd9: txd <= 1; endcase end end endcase end End 數據發送的狀態機設計如下: 同時,為了軟件調試,數據識別等的方便,Bingo在此模塊設置了數據發送標志位。此部分主要參考了Bingo“第七章 你想干嘛——邊沿檢測技術”的方法,此處不再做累贅闡述,若有不懂請看上文。此部分代碼如下: //------------------------------------- //Capture the falling of data transfer over reg txd_flag_r0,txd_flag_r1; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin txd_flag_r0 <= 0; txd_flag_r1 <= 0; end else begin txd_flag_r0 <= txd_flag_r; txd_flag_r1 <= txd_flag_r0; end end assign txd_flag = txd_flag_r1 & ~txd_flag_r0; (3)RXD發送模塊 由于接收數據的時候,主控是PC,從機是FPGA,因此FPGA需要采樣數據。以上波特率發生器中講到過,采樣時鐘clk_bps = 16*clk_bps。FPGA硬件描述,通過計數,當采樣到RXD數據起始位信號有效時,0-7-15開始計數,,其中7為數據的中點,最穩定的時刻。因此在此時采樣數據,能夠達到最穩定的效果。Bingo設計代碼如下: always@(posedge clk or negedge rst_n) begin if(!rst_n) begin smp_cnt <= 0; rxd_cnt <= 0; rxd_data <= 0; rxd_state <= R_IDLE; end else if(clk_smp == 1) begin case(rxd_state) R_IDLE: begin rxd_cnt <= 0; if(rxd_sync == 1'b0) begin smp_cnt <= smp_cnt + 1'b1; if(smp_cnt == 4'd7) //8 clk_smp enable rxd_state <= R_SAMPLE; end else smp_cnt <= 0; end R_SAMPLE: begin smp_cnt <= smp_cnt +1'b1; if(smp_cnt == 4'd7) begin rxd_cnt <= rxd_cnt +1'b1; if(rxd_cnt == 4'd7) rxd_state <= R_IDLE; case(rxd_cnt) 3'd0: rxd_data[0] <= rxd_sync; 3'd1: rxd_data[1] <= rxd_sync; 3'd2: rxd_data[2] <= rxd_sync; 3'd3: rxd_data[3] <= rxd_sync; 3'd4: rxd_data[4] <= rxd_sync; 3'd5: rxd_data[5] <= rxd_sync; 3'd6: rxd_data[6] <= rxd_sync; 3'd7: rxd_data[7] <= rxd_sync; endcase end end endcase end end
同樣,發送部分狀態機如下如下所示:
|
|
來自: lixinhecom > 《UART》