基于FPGA的UART全双工数据控制器

引言:

UART串行通讯协议是一种经典通讯协议,尽管在当前,它的通讯传输速度已经不能满足高数据量传输场景,但在传统的工业应用中还十分普遍广泛。在网上,一般所见到的可应用于FPGA设计的UART接口都遗留有编程语言的设计痕迹,无法实现FPGA上的多数据时序控制传输,因此本文提出了一种带有多标志位的UART控制器,可以满足数据流的双向全双工传递。但由于本人在设计上经验的缺失,本文采用的接收状态机与发送状态机的设置与控制存在有严重不足,希望本文的设计能够引起大家的思考。

1.UART协议

UART协议通过两根数据线实现上下位机数据的双向传递,在数据通讯开始之时,通讯双方需要约定通信所使用的波特率值。由于UART不使用时钟线,因此只有约定了波特率值的前提下,有效数据才可以被识别采集。在约定的波特率下,系统按照指定间隔对数据线上的数据进行采样,读取出有效数据位;而发送方按照指定间隔将数据的每位保持指定的时间,方便接收方进行等间隔采样。

在数据发送中,发送方先将TX线由高拉至低,然后按照从最低位到最高位的顺序将数据放置于TX线上。有效数据一般为6-10位,这需要通讯双方提前约定。当有效数据传输完毕后,可以选择添加一位的奇偶校检位,也可以选择不添加。当一帧数据被传送出去后,发送方将TX总线拉高,等待下一次数据发送。

在数据接收中,接收方检测到RX总线上的电平从高变为低时,就明确发送方开始发送数据。当这个低电平位结束后,数据按从最低位到最高位传送过来,接收方可以根据波特率设定诗律进行采样接收。

UART总线的数据收发时序如图1.1所示:

                                                                          图1.1   UART传输时序

2.UART模块总体设计

根据UART协议,要实现UART串行通讯,需要三个基本功能:波特率生成、接收数据采样、发送数据保持控制。

其中波特率生成是为了给系统生成一个采样保持时钟,以这个时钟为指示对数据线进行操作。但是,在FPGA设计中,不能使用专用时钟计数分频后的结果作为时钟。由于计数器分频后的时钟掺杂有组合逻辑,它有极大的可能存在有毛刺,而作为一个依靠边沿触发驱动电路工作的时钟,显然是不合适的。因此是实际设计中,分频后得到的波特率时钟应当作为电平控制信号而使用。

而接收数据采样将被集成在数据接收模块。该模块根据UART通信协议规定,利用状态机在波特率信号的指示下读取总线上的串行数据。当一帧信息被完整的接收后,该模块生成一个rd信号,告诉外部模块可以从接收缓冲区读取数据。

发送数据保持控制也是采用状态机实现功能的实现。当待发送数据被送至UART控制模块后,数据有效标志信号告诉数据发送模块开始工作,此时控制状态机从空闲状态变换至2开始状态,将TX总线的高电平拉低,然后逐位的发送数据,当数据发送完毕后,状态机回归空闲,将TX总线置高,等待下一次发送数据的到来。

本设计相较于网上其他设计,增添了写控制。读控制、发送数据有效位等三个控制信号,根据三个控制信号所携带的信息,足以实现数据连续接收发送的有效实现。

3.Verilog代码

3.1 顶层模块

module uart(
    clk,rst_n,data_wr,data_rd,tx,rx,rd,wr,data_v
    );
    input clk,rst_n;
    
    input rx;               //UART串行输入
    output tx;              //数据串行输出
    
    input[7:0]data_wr;      //数据写入UART模块
    output[7:0]data_rd;     //数据从UART中读出
    
    input data_v;           //写入数据有效信号
    output rd;              //数据可以从UART模块中读出
    output wr;              //数据可以写入UART模块
    //
    wire bps;//波特率时钟信号,作通讯电平判别
    //
    //波特率产生模块
    bps_crate U1(
        .clk(clk),
        .rst_n(rst_n),
        .bps(bps)
        );
    //
    //数据串行接收模块
    uart_rx U2(
        .clk(clk),
        .rst_n(rst_n),
        .bps(bps),
        .rx(rx),
        .data_rd(data_rd),
        .rd(rd)
        );
    //
    //数据串行发送模块
    uart_tx U3(
        .clk(clk),
        .rst_n(rst_n),
        .bps(bps),
        .data_v(data_v),
        .tx(tx),
        .data_wr(data_wr),
        .wr(wr)
        );
endmodule

3.2 波特率生成模块

module bps_crate(
    clk,rst_n,bps
    );
    //
    input clk, rst_n;
    output bps;
    //
    reg bps;
    reg[7:0]cnt;//分频计数器
    parameter division = 10;//调整分频常数确定波特率
    //
    always@(posedge clk or negedge rst_n)
        if(!rst_n)  
            begin
                cnt <= 8'd0;
                bps <= 1'b0;
            end
        else if(cnt == division)
            begin
                cnt <= 8'd0;
                bps <= 1'b1;
            end
        else
            begin
                cnt <= cnt + 8'd1;
                bps <= 1'b0;
            end
endmodule

3.3 接收模块

module uart_rx(
    clk,rst_n,bps,rx,data_rd,rd
    );
    ///
    input clk,rst_n;
    input bps;//波特率时钟
    input rx;//串行输入
    output[7:0]data_rd;//一帧接收数据
    output rd;//接收数据可读出
    ///
    reg[7:0]data_rd;
    reg rd;
    reg[3:0]state;//串行数据接收状态机
    ///
    parameter idle  = 4'd0;
    parameter bit_0 = 4'd1;
    parameter bit_1 = 4'd2;
    parameter bit_2 = 4'd3;
    parameter bit_3 = 4'd4;
    parameter bit_4 = 4'd5;
    parameter bit_5 = 4'd6;
    parameter bit_6 = 4'd7;
    parameter bit_7 = 4'd8;
    ///
    //状态机状态转移判定
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            begin
                state <= 4'd0;
            end
        else if(state == idle)
            begin
                if(bps&~rx)  state <= bit_0;
                else  state <= idle;
            end
        else if(state == bit_0)
            begin
                if(bps) state <= bit_1;
                else state <= bit_0;
            end
        else if(state == bit_1)
            begin
                if(bps) state <= bit_2;
                else state <= bit_1;
            end
        else if(state == bit_2)
            begin
                if(bps) state <= bit_3;
                else state <= bit_2;
            end
         else if(state == bit_3)
            begin
                if(bps) state <= bit_4;
                else state <= bit_3;
            end
        else if(state == bit_4)
            begin
                if(bps) state <= bit_5;
                else state <= bit_4;
            end
        else if(state == bit_5)
            begin
                if(bps) state <= bit_6;
                else state <= bit_5;
            end
        else if(state == bit_6)
            begin
                if(bps) state <= bit_7;
                else state <= bit_6;
            end
        else if(state == bit_7)
            begin
                if(bps) state <= idle;
                else state <= bit_7;
            end
        else
            state <= idle;
    
    //状态机
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            begin
                data_rd <= 8'd0;
                rd <= 1'b0;
            end
        else if(bps)
            case(state)
            idle : begin
                        data_rd <= 8'd0;
                        rd <= 1'b0;
                    end
            bit_0 : begin
                        data_rd[0] <= rx;
                    end
            bit_1 : begin
                        data_rd[1] <= rx;
                    end
            bit_2 : begin
                        data_rd[2] <= rx;
                    end
            bit_3 : begin
                        data_rd[3] <= rx;
                    end
            bit_4 : begin
                        data_rd[4] <= rx;
                    end
            bit_5 : begin
                        data_rd[5] <= rx;
                    end
            bit_6 : begin
                        data_rd[6] <= rx;
                    end
            bit_7 : begin
                        data_rd[7] <= rx;
                        rd <= 1'd1;
                    end 
            default : begin
                        data_rd <= 8'd0;
                        rd <= 1'd0;
                        end
            endcase
            
endmodule

3.4 发送模块

module uart_tx(
    clk,rst_n,bps,tx,data_wr,wr,data_v
    );
    ///
        input clk,rst_n;
        input bps;//波特率时钟
        output tx;//串行输出
        input data_v;
        input[7:0]data_wr;//一帧发送数据
        output wr;//发送数据可写入
        ///
        reg ready;//数据备好标志
        reg tx;
        reg[7:0]data;
        reg wr;
        reg[3:0]state;//串行数据接收状态机
        ///
        parameter idle  = 4'd0;
        parameter start = 4'd1;
        parameter bit_0 = 4'd2;
        parameter bit_1 = 4'd3;
        parameter bit_2 = 4'd4;
        parameter bit_3 = 4'd5;
        parameter bit_4 = 4'd6;
        parameter bit_5 = 4'd7;
        parameter bit_6 = 4'd8;
        parameter bit_7 = 4'd9;
        
        //有效数据输入标志上升沿检测模块
        reg flag;
        reg v1;
        always@(posedge clk or negedge rst_n)
            if(!rst_n)  v1 <= 1'b0;
            else  v1 <= data_v;
        always@(posedge clk or negedge rst_n)
            if(!rst_n)  flag <= 1'b0;
            else    flag <= data_v&~v1;
        
        //状态机状态转移判定
        always@(posedge clk or negedge rst_n)
            if(!rst_n)
                begin
                    state <= 4'd0;
                end
            else if(state == idle)
                begin
                    if(bps&ready)    state <= start;
                    else state <= idle;
                end
            else if(state == start)
                begin
                    if(bps) state <= bit_0;
                    else state <= start;
                end
            else if(state == bit_0)
                begin
                    if(bps) state <= bit_1;
                    else state <= bit_0;
                end
            else if(state == bit_1)
                begin
                    if(bps) state <= bit_2;
                    else state <= bit_1;
                end
            else if(state == bit_2)
                begin
                    if(bps) state <= bit_3;
                    else state <= bit_2;
                end
             else if(state == bit_3)
                begin
                    if(bps) state <= bit_4;
                    else state <= bit_3;
                end
            else if(state == bit_4)
                begin
                    if(bps) state <= bit_5;
                    else state <= bit_4;
                end
            else if(state == bit_5)
                begin
                    if(bps) state <= bit_6;
                    else state <= bit_5;
                end
            else if(state == bit_6)
                begin
                    if(bps) state <= bit_7;
                    else state <= bit_6;
                end
            else if(state == bit_7)
                begin
                    if(bps) state <= idle;
                    else state <= bit_7;
                end
            else
                state <= idle;
        
        //状态机
        always@(posedge clk or negedge rst_n)
            if(!rst_n)
                begin
                    ready <= 1'b0;
                    wr <= 1'b0;
                end
            else 
                case(state)
                idle : begin
                            wr <= 1'b1;
                            if(flag) ready <= 1'b1;
                            tx <= 1'b1;
                        end
                start : begin
                            ready <= 1'b0;
                            wr <= 1'b0;
                            tx <= 1'b0;
                        end
                bit_0 : begin
                            tx <= data_wr[0];
                        end
                bit_1 : begin
                            tx <= data_wr[1];
                        end
                bit_2 : begin
                            tx <= data_wr[2];
                        end
                bit_3 : begin
                            tx <= data_wr[3];
                        end
                bit_4 : begin
                            tx <= data_wr[4];
                        end
                bit_5 : begin
                            tx <= data_wr[5];
                        end
                bit_6 : begin
                            tx <= data_wr[6];
                        end
                bit_7 : begin
                            tx <= data_wr[7];
                        end 
                default : begin
                            tx <= 1'd0;
                            wr <= 1'd0;
                            end
                endcase
endmodule

4.总结

本设计是一个简单的UART控制器设计,由于设计中设定了一帧数据为8位,不存有铰检位,因此结构显得略微粗糙。本文设计主要解决的是变换数据的连续接收发送,相对于网上其他设计,可控性、可移植性有所提升。

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值