UART 发送和接收数据不启动(Vivado)

UART Transmit and receive data does not start (Vivado)

我不明白为什么当我将时钟频率从 50MHz 设置为 100MHz 时,通过在测试台中将 clk 周期更改为 5,我的输出发送和接收数据保持为 0 . 任何人都可以启发我吗?我需要我的时钟频率为 100MHz。非常感谢您的帮助。

测试平台

`timescale 1ns / 1ps
 
 
module uart_tx_test();
parameter       periodCLK_2     = 5;

parameter       perioddump      = 10;
parameter       delay           = 1;
parameter       delay_in        = 2;

reg           CLK_TB  = 0       ;
reg           RSTN           ;
reg [7:0] data = 0;
reg clk = 0;
reg enable = 0;

wire tx_busy;
wire rdy;
wire [7:0] rxdata;

wire loopback;
reg rdy_clr = 0;

uart test_uart(.din(data),
           .wr_en(enable),
           .clk_50m(clk),
           .tx(loopback),
           .tx_busy(tx_busy),
           .rx(loopback),
           .rdy(rdy),
           .rdy_clr(rdy_clr),
           .dout(rxdata));

initial begin
    // $dumpfile("uart.vcd");
    $dumpvars(0, uart_tx_test);
    enable <= 1'b1;
    #2 enable <= 1'b0;
end

always begin
    #5 clk = ~clk; //I set period to 5; period was 1 previously.
end 

always @(posedge rdy) begin
    #2 rdy_clr <= 1;
    #2 rdy_clr <= 0;
    if (rxdata != data) begin
        $display("FAIL: rx data %x does not match tx %x", rxdata, data);
        $finish;
    end else begin
        if (rxdata == 8'hff) begin
            $display("SUCCESS: all bytes verified");
            $finish;
        end
        data <= data + 1'b1;
        enable <= 1'b1;
        #2 enable <= 1'b0;
    end
end

endmodule

设计来源

module uart(
    input wire [7:0] din,
    input wire wr_en,
    input wire clk_50m,
    output wire tx,
    output wire tx_busy,

    input wire rx,
    input wire rdy_clr,
    output wire rdy,
    output wire [7:0] dout
);

wire rxclk_en, txclk_en;

baud_rate_gen uart_baud(
    .clk_50m(clk_50m),
    .rxclk_en(rxclk_en),
    .txclk_en(txclk_en)
);

transmitter uart_tx(
    .tx(tx),
    .din(din),
    .clk_50m(clk_50m),
    .clken(txclk_en),
    .wr_en(wr_en),
    .tx_busy(tx_busy)
);

receiver uart_rx(
    .rx(rx),
    .data(dout),
    .clk_50m(clk_50m),
    .clken(rxclk_en),
    .rdy(rdy),
    .rdy_clr(rdy_clr)
);

endmodule
/*
 * Hacky baud rate generator to divide a 50MHz clock into a 9600 baud
 * rx/tx pair where the rx clcken oversamples by 16x.
 */
module baud_rate_gen(input wire clk_50m,
             output wire rxclk_en,
             output wire txclk_en);

parameter RX_ACC_MAX = 100000000 / (9600 * 16);
parameter TX_ACC_MAX = 100000000 / 9600;
parameter RX_ACC_WIDTH = $clog2(RX_ACC_MAX);
parameter TX_ACC_WIDTH = $clog2(TX_ACC_MAX);
reg [RX_ACC_WIDTH - 1:0] rx_acc = 0;
reg [TX_ACC_WIDTH - 1:0] tx_acc = 0;

assign rxclk_en = (rx_acc == 5'd0);
assign txclk_en = (tx_acc == 9'd0);

always @(posedge clk_50m) begin
    if (rx_acc == RX_ACC_MAX[RX_ACC_WIDTH - 1:0])
        rx_acc <= 0;
    else
        rx_acc <= rx_acc + 5'b1;
end

always @(posedge clk_50m) begin
    if (tx_acc == TX_ACC_MAX[TX_ACC_WIDTH - 1:0])
        tx_acc <= 0;
    else
        tx_acc <= tx_acc + 9'b1;
end

endmodule
module transmitter(
    input wire [7:0] din,
    input wire wr_en,
    input wire clk_50m,
    input wire clken,
    output reg tx,
    output wire tx_busy
);

initial begin
     tx = 1'b1;
end

parameter STATE_IDLE    = 2'b00;
parameter STATE_START   = 2'b01;
parameter STATE_DATA    = 2'b10;
parameter STATE_STOP    = 2'b11;

reg [7:0] data = 8'h00;
reg [2:0] bitpos = 3'h0;
reg [1:0] state = STATE_IDLE;

always @(posedge clk_50m) begin
    case (state)
    STATE_IDLE: begin
        if (wr_en) begin
            state <= STATE_START;
            data <= din;
            bitpos <= 3'h0;
        end
    end
    STATE_START: begin
        if (clken) begin
            tx <= 1'b0;
            state <= STATE_DATA;
        end
    end
    STATE_DATA: begin
        if (clken) begin
            if (bitpos == 3'h7)
                state <= STATE_STOP;
            else
                bitpos <= bitpos + 3'h1;
            tx <= data[bitpos];
        end
    end
    STATE_STOP: begin
        if (clken) begin
            tx <= 1'b1;
            state <= STATE_IDLE;
        end
    end
    default: begin
        tx <= 1'b1;
        state <= STATE_IDLE;
    end
    endcase
end

assign tx_busy = (state != STATE_IDLE);

endmodule
module receiver(
    input wire rx,
    input wire rdy_clr,
    input wire clk_50m,
    input wire clken,
    output reg rdy,
    output reg [7:0] data
);

initial begin
    rdy = 0;
    data = 8'b0;
end

parameter RX_STATE_START    = 2'b00;
parameter RX_STATE_DATA     = 2'b01;
parameter RX_STATE_STOP     = 2'b10;

reg [1:0] state = RX_STATE_START;
reg [3:0] sample = 0;
reg [3:0] bitpos = 0;
reg [7:0] scratch = 8'b0;

always @(posedge clk_50m) begin
    if (rdy_clr)
        rdy <= 0;

    if (clken) begin
        case (state)
        RX_STATE_START: begin
            /*
            * Start counting from the first low sample, once we've
            * sampled a full bit, start collecting data bits.
            */
            if (!rx || sample != 0)
                sample <= sample + 4'b1;

            if (sample == 15) begin
                state <= RX_STATE_DATA;
                bitpos <= 0;
                sample <= 0;
                scratch <= 0;
            end
        end
        RX_STATE_DATA: begin
            sample <= sample + 4'b1;
            if (sample == 4'h8) begin
                scratch[bitpos[2:0]] <= rx;
                bitpos <= bitpos + 4'b1;
            end
            if (bitpos == 8 && sample == 15)
                state <= RX_STATE_STOP;
        end
        RX_STATE_STOP: begin
            /*
             * The baud clock may not be running at exactly the
             * same rate as the transmitter.  If we thing that
             * we're at least half way into the stop bit, allow
             * transition into handling the next start bit.
             */
            if (sample == 15 || (sample >= 8 && !rx)) begin
                state <= RX_STATE_START;
                data <= scratch;
                rdy <= 1'b1;
                sample <= 0;
            end else begin
                sample <= sample + 4'b1;
            end
        end
        default: begin
            state <= RX_STATE_START;
        end
        endcase
    end
end

endmodule



您需要相应地调整所有其他延迟。将所有 #2 更改为 #10,然后您将看到 SUCCESS: all bytes verified 消息。

您的原始时钟延迟为 #1,您的其他输入信号脉冲(enablerdy_clr)的宽度足以让您的 uart 设计模块正确采样.例如,在 clk 的第一个姿势上,您的设计正确地将 enable 输入采样为 1,这启动了 TX 状态机。

当您将延迟从 #1 更改为 #5 时,时钟周期增加了 5 倍。但是,您的 enable 脉冲保持与以前相同的宽度,这意味着设计将 enable 采样为 0,而不是 1。因此您的 TX 状态机保持在 IDLE 状态。通过将 enable 延迟从 #2 更改为 #10,您可以将 enable 正确采样为 1.

您可以通过转储 VCD 文件并查看设计中的波形轻松地向自己证明这一点。


您可以用 parameter 替换数字延迟,以便更轻松地更改为不同的频率。


注意:您说 clk 延迟最初是 #1。这使 clk 信号的周期为 2ns,即 500MHz,而不是 50MHz。