欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

FPGA学习之路——URAT Verilog程序设计

程序员文章站 2022-04-01 22:05:05
...

FPGA学习之路——URAT Verilog程序设计

UART(Universal Asynchronous Receiver Transmitter,通用异步收发器)是广泛使用的异步串行数据通信协议。
UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。

  • Tx—数据发送接口
  • Rx—数据接收接口

两个设备间将TX与RX相连,RX与TX相连即可正常工作。最常用到的就是我们电脑上的USB那就是个最典型的UART接口。
FPGA学习之路——URAT Verilog程序设计

UART传输时序

UART传输时序图如下图所示
FPGA学习之路——URAT Verilog程序设计
发送数据过程: 空闲状态,线路位于高电平;当接收到发送数据指令后,拉低线路一个数据位的时间T,接着数据按低位到高位依次发送,数据发送完毕后,接着发送奇偶校验位和停止位(停止位为高电平),一帧数据发送完毕。
接收数据过程: 空闲状态,线路处于高电平;当检测到线路的下降沿(线路点位由高电位变为低电位)时说明线路有数据传输,按规定的波特率从低位到高位接收数据,数据接收完毕后,接着接收并比较奇偶校验位是否正确,若正确则通知后续设备准备接收或存入缓存。

因为UART是异步传输,没有同步时钟。所以为了保证数据传输的正确性,UART采用16倍数据波特率的时钟进行采样。每个数据有16个时钟采样,取中间的采样值。
UART的接收数据时序为:当检测到数据的下降沿时,表明线路上有数据在传输,这时计数子CNT开始计数,当计数器为24=16+8(去除开始的拉低数据,在第0位数据中间采样)时,采样的值为第0位数据;当计数子的值为40时,采样的为第一位数据,以此类推。若进行奇偶校验,则当计数子的值为152时,采样的值即为奇偶位;当计数子的值为168时,采样的值“1”表示停止位,表示一帧数据接收完成。

假设数据的波特率为b,那么时钟频率就是16b。以b=115200,系统时钟为50MHz为例,则分频系数为50,000,000/(16115200)=27.127,取整为27。分频器Verilog HDL代码如下:

module clkdiv(clk,rst,clkout);
input clk;
input rst;
output clkout;

reg clkout;
reg [15:0] cnt;

always @(negedge rst)begin
    clkout<=1'd1;
    cnt<=16'd0;
end

always @(posedge clk)begin
    if(cnt==16'd12)begin
        clkout<=1'd1;
        cnt<=cnt+16'd1;
    end
    else if(cnt==16'd26)begin
        clkout<=1'd0;
        cnt<=16'd0;
    end
    else begin
        cnt<=cnt+16'd1;
    end
end
endmodule

编码过程中需注意,若部分寄存器不通过rst赋初值,如代码块中的cnt和clk_out,则Vivado会报错,Vivado版本为2018.3,目前我也只想到引入rst进行赋值的方法解决。
更:可以在定义寄存器时直接赋初值。如reg [7:0]cnt =8’d0;
此外,UART发送和接受模块中部分代码如下,完整代码我稍后上传至CSDN,有需的朋友可以下载参考。
上升沿检测代码,其中wrsig发送命令,上升沿有效。该部分代码完成了wrsig的上升沿检测。

always @(posedge clk)begin
    wrsigbuf<=wrsig;
    wrsigrise<=(~wrsigbuf)&wrsig;
end

启动数据发送进程的代码,需满足发送命令有效且线路空闲的条件

always @(posedge clk)begin
    if(wrsigrise && (~idle))begin    //发送命令有效且线路空闲,启动数据发送进程
        send<=1'd1;
    end
    else if(cnt == 8'd176)begin      //一帧数据发送结束
        send<=1'd0;
    end
end

数据发送进程中的部分代码,设计思路在上文中已表述,其中paritymode为常数0,用于奇偶校验;datain为待传输的数据;presult存放数据校验的结果;cnt为32—112的被省略。在cnt为144时发送奇偶校验位,然后拉高电平,表示传输过程结束。接收进程编码思路与发送进程类似,此处不表。

always @(posedge clk)begin
    if(send == 1'd1)begin
        case(cnt)
        8'd0:
            begin
                tx<=1'd0;
                idle<=1'd1;
                cnt<=cnt+8'd1;
            end
         8'd16:
            begin
                tx<=datain[0];
                presult<=datain[0]^paritymode;
                idle<=1'b1;
                cnt<=cnt+8'd1;
            end
        ……
		8'd128:
			begin
				tx <= datain[7];
				presult <= datain[7]^presult;
				idle <= 1'b1;
				cnt <= cnt + 8'd1;
			end
		8'd144:
		    begin
		      tx<=presult;
		      idle <= 1'b1;
			  cnt <= cnt + 8'd1;
		    end
		8'd160:
		    begin
		      tx<=1'd1;
		      idle<=1'd1;
		      cnt<=cnt+1'd1;
		    end
		8'd176:
		  begin
		      tx<=1'd1;
		      idle<=1'd0;
		      cnt<=cnt+8'd1;
		  end
		 default:
             begin
                cnt<=cnt+8'd1;
             end                   
         endcase
    end
    else begin
        tx<=1'd1;
        cnt<=8'd0;
        idle<=1'b0;
    end
end

本文搭建的系统结构图如下,clkdiv为分频模块;testuart为激励产生模块,输出待发送的数据和发送使能;uarttx为uart发送模块,输入为分频后的时钟、待发送的数据和发送使能,输出为数据信号tx和idle,idle为线路指示状态,高为线路忙,低为空闲;uartrx为uart接收模块,输入为分频后的时钟和数据信号,输出为数据、数据出错指示和帧出错指示。
FPGA学习之路——URAT Verilog程序设计

本文搭建系统的仿真结果如下图所示:
FPGA学习之路——URAT Verilog程序设计
从图中我们可以看到,接受数据与发送数据结果相同。若接收数据的奇偶校验位与收到的奇偶校验位不符,则dataerror为1。若接收帧的第11位即停止位不为1,则帧发生错误,frameerror为1。文中结果均未发生错误。

项目下载链接:https://download.csdn.net/download/qq_42334072/12376984

参考资料:《VERILOG HDL应用程序设计实例精讲》