Altifigence Academy

63 / 63 · 概念

綜合實作:UART 傳送器與資料框時序

結合分頻計數器、移位暫存器與流量控制建立 8N1 資料框,驗證位元邊界。

先固定資料框規格

先備知識:計數器、移位暫存器暫存器儲存多個位元的狀態。本課程中的同步暫存器會在時脈邊緣儲存指定的輸入。 詳細內容、valid/ready 與同步重設重設將狀態回復至規格指定的初始值。必須一併定義它是同步或非同步,以及是否優先於其他控制訊號。 詳細內容。

UARTUART不使用獨立時脈線,而以起始位元、資料位元與停止位元進行序列通訊。收發雙方必須約定 baud rate 與訊框格式。 8N1 為一個起始位、八個資料位、無 parity、一個停止位。Idle、stop 為 1,start 為 0,資料從 LSBLSB是位權最低的位元。須同時確認表示方向與索引規則。 詳細內容 起送;每位維持相同長度。本練習只處理傳送,假設資料來源同時脈。

Bactual=fclkD,ϵ=Bactual−BtargetBtarget×100%B_{\mathrm{actual}}=\frac{f_{\mathrm{clk}}}{D},\qquad \epsilon=\frac{B_{\mathrm{actual}}-B_{\mathrm{target}}}{B_{\mathrm{target}}}\times100\%

48 MHz 目標 115200 baud,可選整數分頻 D=417。實際約 115108 baud,誤差約 −0.080%。包含接收端的允許總誤差,須依裝置規格確認。

把 0x53 展成實際傳送順序

0x53 表示為 01010011,但線路從低位依序送 1,1,0,0,1,0,1,0。圖中一格不是一個系統時脈,而是 D 個時脈組成的一個位元期間。前後 idle 各畫一格供比較。

UART 8N1 · 0x53 · LSB 先傳
查看波形資料
波形資料:每個字元表示一個區間;句點保持先前狀態;p 表示一個時脈週期。
訊號波形匯流排值
tx101.0.10101.
階段234523452345閒置 → 起始 → d0 → d1 → d2 → d3 → d4 → d5 → d6 → d7 → 停止 → 閒置

Start 到 stop 結束恰為 10D 個時脈。連續的 1 或 0 仍各佔一個位元期間,沒有電位轉換不表示少了一位。

一個資料位元組只擷取一次

以下實作契約要求 CLKS_PER_BIT 為至少 1 的常數。Busy 時不接受輸入,只使用資料框開始時擷取的 data。不建立新 bit-clock,而是在原時脈內以計數器控制移動時點。

SystemVerilog
module uart_tx #(
    parameter int unsigned CLKS_PER_BIT = 417,
    localparam int CW = (CLKS_PER_BIT <= 1) ? 1 : $clog2(CLKS_PER_BIT)
) (
    input  logic       clk, rst,
    input  logic       in_valid,
    output logic       in_ready,
    input  logic [7:0] in_data,
    output logic       tx, busy, done
);
    logic [9:0] frame;
    logic [3:0] bits_left;
    logic [CW-1:0] ticks_left;
    assign in_ready = !busy;

    always_ff @(posedge clk) begin
        if (rst) begin
            tx         <= 1'b1;
            busy       <= 1'b0;
            done       <= 1'b0;
            bits_left  <= 4'd0;
            ticks_left <= '0;
        end else begin
            done <= 1'b0;
            if (!busy) begin
                if (in_valid) begin
                    frame      <= {1'b1, in_data, 1'b0};
                    tx         <= 1'b0;
                    busy       <= 1'b1;
                    bits_left  <= 4'd10;
                    ticks_left <= CW'(CLKS_PER_BIT-1);
                end
            end else if (ticks_left != 0) begin
                ticks_left <= ticks_left - 1'b1;
            end else if (bits_left == 4'd1) begin
                tx   <= 1'b1;
                busy <= 1'b0;
                done <= 1'b1;
            end else begin
                frame      <= {1'b1, frame[9:1]};
                tx         <= frame[1];
                bits_left  <= bits_left - 1'b1;
                ticks_left <= CW'(CLKS_PER_BIT-1);
            end
        end
    end
endmodule

接受輸入的邊緣 E0,tx 變為 start=0,之後每隔恰好 D 個時脈切到下一位。E0+9D 開始 stop,E0+10D 解除 busy、產生一週期 done。最後的 stop 也必須維持 D 週期。

本實作在結束邊緣前 in_ready 都為 0,因此下一框最快到再下一邊緣接受,連續框的接受間隔為 10D+110D+1 個時脈。這個額外一時脈 idle 間隔也是正常行為的一部分。

手動預測位元序列

8'h53 從 LSB 起為 1,1,0,0,1,0,1,0,完整資料框如下。

順序startd0d1d2d3d4d5d6d7stop
tx0110010101

驗證不能只計 tx 改變次數,因連續同值位元不會切換。以框起點為基準,取樣各位元區間中央並與預期比較,也檢查 start、stop 長度。快速單元驗證可用 D=1、2、3 等小值。

延伸設計:連接 FIFO

暫存讀取 FIFOFIFO是先進先出的佇列。滿、空,以及是否允許同時讀寫的規則,都是行為契約的一部分。 詳細內容 在 pop 接受邊緣後更新 dout、dout_valid,同時脈下級在再下一上升緣上升緣是時脈由 0 變成 1 的瞬間。它與表示整段 CLK=1 期間的高準位不同。 詳細內容取樣回應。若在 pop 接受的同一邊緣把 dout 送給 UART,可能是舊值。應加入保存回傳位元組的單格緩衝及 pending 狀態,在 UART ready 時恰好傳一次。

最終驗證包含 00、FF、01、80、55、53,busy 中改變的輸入、連續框,以及框中 reset。Reset 政策為中止傳送,tx 返回 idle=1;接收器仍可能看到有效框,因此僅憑 UART 框格式無法保證偵測到傳送中止。若必須丟棄受影響的資料,應明確約定系統行為:讓接收器的 reset 與傳送器連動,或向接收器提供獨立的中止訊號。

延伸閱讀:Microchip — EUSART and 8N1 framing

自己試試看

CLKS_PER_BIT=4,E0 接受資料。求 d0 起點、stop 起點與 done 邊緣。E40 有新的 in_valid=1,該邊緣會接受下一位元組嗎?

查看解說

D0 在 E4 後開始,stop 在 E36,done 在 E40 後。E40 前 busy=1、in_ready=0,新位元組尚未接受。傳送端須保持 valid、data,下一位元組可在 E41 接受。每框 40 個時脈,最小接受間隔 41 個。

此選擇適用於本瀏覽器,隨時可從頁尾變更。