代碼注釋有些匆忙,如有錯誤注釋還請批評,僅作參考
Uart比較簡單,所以僅對tx作比較詳細的注釋,但里面一些內容還是值得新手學習的
1開始位(低電平)+8位數據+1停止位(高電平,這里選的是一個周期高電平,也可兩個)(無校驗位)
1、prescale是完成一個bit需要主時鐘計數的次數(其和主時鐘以及波特率之間的關系參考網上文章)
2、進入uart模塊的異步信號,最好使用提供的同步器同步
3、異步復位信號最好使用提供的同步器同步
4、波特率任意選,只要時鐘夠大,能夠符合誤碼率計算即可,這里使用的是125Mhz
5、基本的思想就是移位
6、傳輸條件就是握手
7、如果使用Xlinx的片子,建議使用全局時鐘資源(IBUFG后面連接BUFG的方法是最基本的全局時鐘資源的使用方法)
8、這個完整的代碼就是使用IBUFG+BUFG
9、傳輸雖然簡單,但對于新手來講,還是有挺多的知識點值得學習的點
10、公眾號只是對代碼進行了簡單注釋
UART的發送數據模塊
// 歡迎大家關注公眾號:AriesOpenFPGA// Q群:808033307// Language: Verilog 2001// 代碼注釋有些匆忙,如有錯誤注釋還請批評,僅作參考// UART// 1開始位+8位數據+1停止位(無校驗)// prescale是完成一個bit需要主時鐘計數的次數(其和主時鐘以及波特率之間的關系參考網上文章)// 進入uart模塊的異步信號,最好使用提供的同步器同步// 異步復位信號最好使用提供的同步器同步// 波特率任意選,只要時鐘夠大,能夠符合誤碼率計算即可,這里使用的是125M// 基本的思想就是移位// 傳輸條件就是握手// 如果使用Xlinx的片子,建議使用全局時鐘資源(IBUFG后面連接BUFG的方法是最基本的全局時鐘資源的使用方法)// 這個完整的代碼就是使用IBUFG+BUFG// 傳輸雖然簡單,但對于新手來講,還是有挺多的知識點值得學習的// 公眾號只是對代碼進行了簡單注釋`timescale 1ns / 1ps/* AXI4-Stream UART */module uart_tx #(parameter DATA_WIDTH = 8)(input wire clk, // 系統時鐘input wire rst, // 復位信號/* AXI input */input wire [DATA_WIDTH-1:0] s_axis_tdata, // 輸入到這個模塊準備發送出去的數據input wire s_axis_tvalid, // 有數據要輸入到這個模塊output wire s_axis_tready, // 該模塊準備好接收數據output wire txd, // UART interfaceoutput wire busy, // Status 線忙input wire [15:0] prescale // Configuration 預分度);reg s_axis_tready_reg = 0;reg txd_reg = 1;reg busy_reg = 0;reg [DATA_WIDTH:0] data_reg = 0;reg [18:0] prescale_reg = 0;reg [3:0] bit_cnt = 0;assign s_axis_tready = s_axis_tready_reg;assign txd = txd_reg;assign busy = busy_reg;always @(posedge clk)beginif (rst)begins_axis_tready_reg <= 0; // 從機沒有準備好發送txd_reg <= 1; // 發送線拉高prescale_reg <= 0; //bit_cnt <= 0; // 位計數器初始化為0busy_reg <= 0; // 復位后為不忙狀態endelsebeginif (prescale_reg > 0)begins_axis_tready_reg <= 0;prescale_reg <= prescale_reg - 1;endelse if (bit_cnt == 0) //比特計數器為0begins_axis_tready_reg <= 1; // 從機把ready信號拉高busy_reg <= 0; // 忙信號拉低無效if (s_axis_tvalid) // 如果從機準備好接收數據begins_axis_tready_reg <= !s_axis_tready_reg; //prescale_reg <= (prescale << 3)-1; //bit_cnt <= DATA_WIDTH+1; // 一共10次計數data_reg <= {1'b1, s_axis_tdata}; //txd_reg <= 0; // 起始位0(起始位tx拉低,停止位拉高)busy_reg <= 1; // 開始傳輸后,傳輸線進入忙狀態endendelsebeginif (bit_cnt > 1) //beginbit_cnt <= bit_cnt - 1;prescale_reg <= (prescale << 3)-1; // 經過(prescale << 3)-1次的系統時鐘計數,完成一位的移位{data_reg, txd_reg} <= {1'b0, data_reg}; // 移位操作endelse if (bit_cnt == 1)beginbit_cnt <= bit_cnt - 1;prescale_reg <= (prescale << 3);txd_reg <= 1; // 停止位1endendendendendmodule
UART的接收模塊(不詳細講解)
Language: Verilog 20011ns / 1ps/*AXI4-Stream UART*/module uart_rx #(parameter DATA_WIDTH = 8)(input wire clk,input wire rst,AXI output */output wire [DATA_WIDTH-1:0] m_axis_tdata,output wire m_axis_tvalid,input wire m_axis_tready,UART interface */input wire rxd,Status */output wire busy,output wire overrun_error,output wire frame_error,Configuration */input wire [15:0] prescale);reg [DATA_WIDTH-1:0] m_axis_tdata_reg = 0;reg m_axis_tvalid_reg = 0;reg rxd_reg = 1;reg busy_reg = 0;reg overrun_error_reg = 0;reg frame_error_reg = 0;reg [DATA_WIDTH-1:0] data_reg = 0;reg [18:0] prescale_reg = 0;reg [3:0] bit_cnt = 0;assign m_axis_tdata = m_axis_tdata_reg;assign m_axis_tvalid = m_axis_tvalid_reg;assign busy = busy_reg;assign overrun_error = overrun_error_reg;assign frame_error = frame_error_reg;always @(posedge clk)beginif (rst) // 初始化各種參數beginm_axis_tdata_reg <= 0;m_axis_tvalid_reg <= 0;rxd_reg <= 1;prescale_reg <= 0;bit_cnt <= 0;busy_reg <= 0;overrun_error_reg <= 0;frame_error_reg <= 0;endelsebeginrxd_reg <= rxd;overrun_error_reg <= 0;frame_error_reg <= 0;if (m_axis_tvalid && m_axis_tready) // 準備有數據要發以及準被好發beginm_axis_tvalid_reg <= 0;endif (prescale_reg > 0) //beginprescale_reg <= prescale_reg - 1;endelse if (bit_cnt > 0)beginif (bit_cnt > DATA_WIDTH+1)beginif (!rxd_reg) // 實際的read為0時,開始計數bitbeginbit_cnt <= bit_cnt - 1;prescale_reg <= (prescale << 3)-1; //prescale是16位移3位減1位,因為prescale_regendelsebeginbit_cnt <= 0;prescale_reg <= 0;endendelse if (bit_cnt > 1)beginbit_cnt <= bit_cnt - 1;prescale_reg <= (prescale << 3)-1;data_reg <= {rxd_reg, data_reg[DATA_WIDTH-1:1]};endelse if (bit_cnt == 1)beginbit_cnt <= bit_cnt - 1;if (rxd_reg)beginm_axis_tdata_reg <= data_reg;m_axis_tvalid_reg <= 1;overrun_error_reg <= m_axis_tvalid_reg;endelsebeginframe_error_reg <= 1;endendendelsebeginbusy_reg <= 0;if (!rxd_reg)beginprescale_reg <= (prescale << 2)-2;bit_cnt <= DATA_WIDTH + 2;data_reg <= 0;busy_reg <= 1;endendendendendmodule
UART頂層
Language: Verilog 20011ns / 1ps/*AXI4-Stream UART*/module uart #(parameter DATA_WIDTH = 8)(input wire clk,input wire rst,/*AXI input*/input wire [DATA_WIDTH-1:0] s_axis_tdata,input wire s_axis_tvalid,output wire s_axis_tready,/*AXI output*/output wire [DATA_WIDTH-1:0] m_axis_tdata,output wire m_axis_tvalid,input wire m_axis_tready,/*UART interface*/input wire rxd,output wire txd,/*Status*/output wire tx_busy,output wire rx_busy,output wire rx_overrun_error,output wire rx_frame_error,/*Configuration*/input wire [15:0] prescale);uart_tx #(.DATA_WIDTH(DATA_WIDTH))uart_tx_inst (.clk(clk),.rst(rst),axi input.s_axis_tdata(s_axis_tdata),.s_axis_tvalid(s_axis_tvalid),.s_axis_tready(s_axis_tready),output.txd(txd),status.busy(tx_busy),configuration.prescale(prescale));uart_rx #(.DATA_WIDTH(DATA_WIDTH))uart_rx_inst (.clk(clk),.rst(rst),axi output.m_axis_tdata(m_axis_tdata),.m_axis_tvalid(m_axis_tvalid),.m_axis_tready(m_axis_tready),input.rxd(rxd),status.busy(rx_busy),.overrun_error(rx_overrun_error),.frame_error(rx_frame_error),configuration.prescale(prescale));endmodule
同步(異步復位)模塊
Language: Verilog-2001很常用的模塊1 ns / 1 ps/*Synchronizes an active-high asynchronous reset signal to a given clock byusing a pipeline of N registers.*/module sync_reset #(parameter N=2 // depth of synchronizer)(input wire clk,input wire rst,output wire sync_reset_out);reg [N-1:0] sync_reg = {N{1'b1}};assign sync_reset_out = sync_reg[N-1];always @(posedge clk or posedge rst) beginif (rst)sync_reg <= {N{1'b1}};elsesync_reg <= {sync_reg[N-2:0], 1'b0};endendmodule
同步(異步信號)模塊
// Language: Verilog-2001//很常用的模塊`timescale 1 ns / 1 ps/** Synchronizes an asyncronous signal to a given clock by using a pipeline of* two registers.*/module sync_signalparameter WIDTH=1, // width of the input and output signalsparameter N=2 // depth of synchronizer)(input wire clk,input wire [WIDTH-1:0] in,output wire [WIDTH-1:0] out);reg [WIDTH-1:0] sync_reg[N-1:0];/** The synchronized output is the last register in the pipeline.*/assign out = sync_reg[N-1];integer k;always @(posedge clk) beginsync_reg[0] <= in;for (k = 1; k < N; k = k + 1) beginsync_reg[k] <= sync_reg[k-1];endendendmodule
審核編輯 :李倩
-
Verilog
+關注
關注
30文章
1374瀏覽量
114529 -
uart
+關注
關注
22文章
1314瀏覽量
106650 -
代碼
+關注
關注
30文章
4968瀏覽量
73976
原文標題:Uart協議及Verilog代碼
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
UART的缺點介紹
UART、SPI、I2C 實戰對比:哪個更適合你的項目?
SPI、I2C、I2S、UART:通信協議解釋
SPI、I2C、I2S、UART:通信協議對比表
如何使用FPGA實現SRIO通信協議
多路UART數據轉發芯片 支持1主4從UART接口 UART擴展芯片
基于Hbird-e-sdk Linux環境下使用Uart0 對串口進行輸入的軟件代碼參考
蜂鳥E203與電腦實現UART通信實現代碼并實現上位機控制代碼分享
TI DMD代碼
JEDSD204B標準verilog實現-協議演進
芯知識|廣州唯創電子語音芯片UART通信協議解析:發碼長度與校驗碼計算
基于小凌派RK2206開發板:OpenHarmony如何使用IoT接口控制UART外設
FPGA Verilog HDL語法之編譯預處理
ElfBoard嵌入式教育科普|UART接口全面解析
Uart協議及Verilog代碼
評論