我是靠谱客的博主 玩命板栗,最近开发中收集的这篇文章主要介绍Uart串口收发回环验证,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Uart串口收发回环验证

    • 接受模块
    • 发送模块
    • 波特率设置模块
    • 顶层模块
    • TB
    • Modelsim仿真结果
    • 板级验证
    • 总结

本次所做的项目比较复杂(对我本人来讲),设计一个Uart IP核,在其基础,封装axi接口,使其成为面向AXI口的IP,再例化个microblaze作为主机,使microblaze与Uart之间通过AXI总线进行通信。具体模块图如下,包含主机microblaze,主接口模块,从接口模块,从机Uart。

在这里插入图片描述
本文首先介绍Uart基本模块。该顶层模块包含接受模块、发送模块、发送波特率设置模块、接受波特率设置模块。为了方便验证,我们将接受模块与发送模块连接,采用回环的形式。

接受模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/05/24 16:58:41
// Design Name: 
// Module Name: uart_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_rx(
    clk,
    rst_n,
    Rs232_rx,
    bps_clk,
    rx_data,
    rx_int,
    bps_start
    );
    input clk;
    input rst_n;
    input bps_clk;
    input Rs232_rx;
    output [7:0] rx_data;
    output reg rx_int;
    output reg bps_start;
    
    reg Rs232_rx0,Rs232_rx1,Rs232_rx2,Rs232_rx3;
    wire neg_edge;
    reg [3:0] num;
    
    reg [7:0] rx_data_t1; 
    reg [7:0] rx_data_t2;
     
    always@(posedge clk or negedge rst_n)
        if(!rst_n) begin 
            Rs232_rx0 <= 1'b1;
            Rs232_rx1 <= 1'b1;
            Rs232_rx2 <= 1'b1;
            Rs232_rx3 <= 1'b1;
        end
        else begin
            Rs232_rx0 <= Rs232_rx;
            Rs232_rx1 <= Rs232_rx0;
            Rs232_rx2 <= Rs232_rx1;
            Rs232_rx3 <= Rs232_rx2;    
        end
    assign neg_edge = Rs232_rx3 & Rs232_rx2 & ~Rs232_rx1 & ~Rs232_rx0;
    
    always@(posedge clk or negedge rst_n)
    if(!rst_n) begin
        bps_start <= 1'b0;
        rx_int <= 1'b0;
    end
    else if (neg_edge) begin 
        bps_start <= 1'b1;
        rx_int <= 1'b1;
    end
    else if (num == 4'd10) begin
        bps_start <= 1'b0;
        rx_int <= 1'b0;  
    end 
   
   always@(posedge clk or negedge rst_n)
   if(!rst_n) begin
        rx_data_t1 <= 8'd0; 
        rx_data_t2 <=8'd0;
        num <= 4'd0;
   end
   else if(rx_int) begin 
    if (bps_clk) begin 
        num <= num+1'b1;
        case(num)
            4'd1: rx_data_t1[0] <= Rs232_rx;
            4'd2: rx_data_t1[1] <= Rs232_rx;
            4'd3: rx_data_t1[2] <= Rs232_rx;
            4'd4: rx_data_t1[3] <= Rs232_rx;
            4'd5: rx_data_t1[4] <= Rs232_rx;
            4'd6: rx_data_t1[5] <= Rs232_rx;
            4'd7: rx_data_t1[6] <= Rs232_rx;
            4'd8: rx_data_t1[7] <= Rs232_rx;
            default:;
        endcase 
     end
   end       
  else if(num >= 4'd9) begin 
    num <= 4'd0;
    rx_data_t2 <= rx_data_t1;
  end
 assign  rx_data = rx_data_t2;  
             
endmodule

发送模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/05/24 15:39:09
// Design Name: 
// Module Name: uart_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_tx(
    clk,
    rst_n,
    tx_int,
    rx_data,
    bps_clk,
    Rs232_tx,
    bps_start
    );
    input clk;
    input rst_n;
    input tx_int;
    input [7:0] rx_data;
    input bps_clk;
    output Rs232_tx;
    output bps_start;
    
    reg tx_int0;
    reg tx_int1;
    reg tx_int2;
    wire neg_edge;
    
    (* keep = "true" *) reg en;
    reg [3:0] num;
    reg bps_start_t;
    //reg [7:0] rx_data_t;
    
    reg Rs232_tx_t;
   
    
    always@(posedge clk or negedge rst_n)
        if(!rst_n) begin 
            tx_int0 <= 1'b0;
            tx_int1 <= 1'b0;
            tx_int2 <= 1'b0;
        end
        else begin
            tx_int0 <= tx_int;
            tx_int1 <= tx_int0;
            tx_int2 <= tx_int1;
        end   
    assign neg_edge = tx_int2 & ~tx_int1;
     
    always@(posedge clk or negedge rst_n)
        if(!rst_n) begin 
            en <= 1'b0;
            bps_start_t <= 1'b0;
        end
        else if (neg_edge) begin
            en <= 1'b1;
            bps_start_t <= 1'b1;
            //rx_data_t <= rx_data;
        end    
        else if (num == 4'd10) begin
            en <= 1'b0;
            bps_start_t <= 1'b0;  
        end
    assign bps_start = bps_start_t;
    
    always@(posedge clk or negedge rst_n)
        if(!rst_n) begin 
            Rs232_tx_t <= 1'b1;
            num <= 12'd0;
        end
        else if (en) begin 
            if (bps_clk) begin 
                case (num) 
                    4'd0: Rs232_tx_t <= 1'b0;
                    4'd1: Rs232_tx_t <= rx_data[0];
                    4'd2: Rs232_tx_t <= rx_data[1];
                    4'd3: Rs232_tx_t <= rx_data[2];
                    4'd4: Rs232_tx_t <= rx_data[3];
                    4'd5: Rs232_tx_t <= rx_data[4];
                    4'd6: Rs232_tx_t <= rx_data[5];
                    4'd7: Rs232_tx_t <= rx_data[6];
                    4'd8: Rs232_tx_t <= rx_data[7];
                    4'd9: Rs232_tx_t <= 1'b1;
                    default: Rs232_tx_t <= 1'b1;
                endcase
                num <= num +1'b1;  
            end   
        end        
        else if(num == 4'd10) begin
             num <= 1'b0;       
        end      
        
        assign Rs232_tx = Rs232_tx_t;
        
                     
endmodule

波特率设置模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/05/24 15:06:47
// Design Name: 
// Module Name: speed_set
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module speed_set(
    bps_start,
    clk,
    rst_n,
    bps_clk
    );
    input bps_start;
    input clk;
    input rst_n;
    output reg bps_clk;
    (* keep = "true" *) reg [12:0] cnt;
    
    `define BPS_NUM 5207
    `define BPS_NUM_2 2306
    
 
    always@(posedge clk or negedge rst_n)
    if (!rst_n)
        cnt <= 13'd0;
    else if (cnt == `BPS_NUM ||  !bps_start)
        cnt <= 13'd0;
    else 
        cnt <= cnt + 1'b1;
        
        
    always@(posedge clk or negedge rst_n)
    if(!rst_n)
        bps_clk <= 1'b0;
    else if (cnt == `BPS_NUM_2)
        bps_clk <= 1'b1;
    else 
        bps_clk <= 1'b0;
        

endmodule

顶层模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/05/27 10:00:56
// Design Name: 
// Module Name: uart_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_top(
    clk_p,
    clk_n,
    rst_n,
    Rx,
    Tx
    );
    input clk_p;
    input clk_n;
    input rst_n;
    input Rx;
    output Tx;
    
    wire clk_50m;
    wire bps_clk_tx;
    wire bps_clk_rx;
    wire bps_start_tx;
    wire bps_start_rx;
    wire [7:0] rx_data;
    wire int;
    
    
    clk_wiz_0 instance_name
       (
        // Clock out ports
        .clk_50m(clk_50m),     // output clk_50m
        // Status and control signals
        .resetn(rst_n), // input resetn
       // Clock in ports
        .clk_in1_p(clk_p),    // input clk_in1_p
        .clk_in1_n(clk_n));    // input clk_in1_n
    
    
    speed_set speed_tx(
        .bps_start(bps_start_tx),
        .clk(clk_50m),
        .rst_n(rst_n),
        .bps_clk(bps_clk_tx)
        );        
    uart_tx uart_tx(
        .clk(clk_50m),
        .rst_n(rst_n),
        .tx_int(int),
        .rx_data(rx_data),
        .bps_clk(bps_clk_tx),
        .Rs232_tx(Tx),
        .bps_start(bps_start_tx)
        );
    speed_set speed_rx(
        .bps_start(bps_start_rx),
         .clk(clk_50m),
         .rst_n(rst_n),
         .bps_clk(bps_clk_rx)
         );
    uart_rx uart_rx(
        .clk(clk_50m),
        .rst_n(rst_n),
        .Rs232_rx(Rx),
        .bps_clk(bps_clk_rx),
        .rx_data(rx_data),
        .rx_int(int),
        .bps_start(bps_start_rx)
        );
endmodule

TB

`timescale 1ns / 1ps
`define clock_period 20
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/05/27 10:38:22
// Design Name: 
// Module Name: uart_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//



module Uart_tb;
    reg clk_p;
    reg clk_n;
    reg rst_n;
    reg Rx;
    wire Tx;
    
            
    uart_top uart_top(
         .clk_p(clk_p),
         .clk_n(clk_n),
         .rst_n(rst_n),
         .Rx(Rx),
         .Tx(Tx)
    );
    
    initial clk_p = 0;
    always #2.5 begin 
        clk_p = ~clk_p;
        clk_n = ~clk_p;
    end
    initial begin
        Rx = 1'b1; 
        rst_n = 1'b0;
        #(`clock_period*20);
        rst_n = 1'b1;
        #(`clock_period*52080);
        
        //起始位
        Rx = 1'b0;       
        #(`clock_period*5208);
        
        //数据位
        Rx = 1'b1;  
        #(`clock_period*5208);
        Rx = 1'b0; 
        #(`clock_period*5208);
        Rx = 1'b0; 
        #(`clock_period*5208);
        Rx = 1'b0; 
        #(`clock_period*5208);
        
        Rx = 1'b1; 
        #(`clock_period*5208);
        Rx = 1'b0; 
        #(`clock_period*5208);
        Rx = 1'b0; 
        #(`clock_period*5208);
        Rx = 1'b0; 
        #(`clock_period*5208);
        
        //停止位
        Rx = 1'b1; 
        #(`clock_period*5208); 
        
         Rx = 1'b1; 
         #(`clock_period*52080); 
    end
   
endmodule

Modelsim仿真结果

在这里插入图片描述

板级验证

在这里插入图片描述在这里插入图片描述

总结

本项目Uart设计没有什么难度,基本原理在看完Uart之后spe之后基本了解,再加上之前有点底子,在代码表写上很快完成。但由于Vivado工具使用不熟练,导致花费大量时间,尤其在debug调试之后生成ILA核,抓取的波形不知道怎么看,自己摸索始终不会,最终还是在 老同志的帮助下知道了怎么回事,一方面感谢,另一发方面感概其其奇妙之后,感觉在数字芯片这么难之下下,我们工程师(妄称)还是要多多交流,这样才能共同进步。终极学习法费曼学习法不是说了吗,学习最快的途径是教会一个外行人,你教别人的同时自己也在快速成长。另外自身而言,实在琢磨不出在,还是问问别人,又是你半天搞不出来,一问就回了,提高效率不是。
扯哪去了,回归正题。在前期写好代码之后,兴致勃勃地仿真还通过了,感觉没啥问题,直接上板子烧入,之后崩了,没有结果。前期以为串口工具有问题,想不到还真有问题,板子上USB口接错了,COM口出错,小白尽是犯这种低级错误啊。改完之后重新烧入,还是不行,心态有点炸。实在没办法请教了大神,让我用debug来找出代码那不对,刚开始我始终不以为意,认为仿真通过我写的代码肯定没问题,肯定是其他硬件问题。再加上我debug不会用,浪费了大量时间。在慢慢琢磨与请教之后,发现了问题(前方高能):
1.我在一个always进程中对一个变量赋值之前,没有对其进行复位(TX模块的bps_start_t),导致仿真出现红线未知态。不过这不是主要问题
2.也是tx模块中我竟然多num信号在两个进程中同时对其赋值,明显不过的代码错误,但是综合尽然通过了,什么鬼
总结:
在那个alway进程中间对所有变量赋值之前,现在Rst中对所有进行复位
不要感觉没有错误仿真通过就感觉代码没问题,万事大吉EDA也不是万能的,错误看完的看看警告。
对变量进行暂存再赋值是将reg型变量变为wire型。如果其他进程用到了就不需要转变,只是偶尔输出时需要转变。

最后

以上就是玩命板栗为你收集整理的Uart串口收发回环验证的全部内容,希望文章能够帮你解决Uart串口收发回环验证所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部