代码注释有些匆忙,如有错误注释还请批评,仅作参考
UART
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
审核编辑 :李倩
全部0条评论
快来发表一下你的评论吧 !