Altifigence Academy

63 / 63 · Khái niệm

Thực hành tổng hợp: bộ phát UART và thời gian khung

Kết hợp bộ đếm chia tần, thanh ghi dịch và điều khiển luồng để tạo khung 8N1, rồi kiểm chứng các ranh giới bit.

Chốt đặc tả khung trước

Kiến thức cần có: bộ đếm, thanh ghiThanh ghi Mạch lưu trạng thái nhiều bit. Thanh ghi đồng bộ trong khóa học lưu đầu vào đã quy định tại cạnh clock. Tìm hiểu thêm dịch, valid/ready và resetReset Điều khiển đưa trạng thái về giá trị đầu đã định. Phải quy định đồng bộ hay bất đồng bộ và ưu tiên so với các điều khiển khác. Tìm hiểu thêm đồng bộ.

Định dạng 8N1 của UARTUART Thiết bị truyền thông nối tiếp bằng bit start, dữ liệu và bit stop mà không cần đường đồng hồ riêng. Hai phía phải thống nhất baud rate và định dạng khung. gồm 1 bit start, 8 bit dữ liệu, không parity và 1 bit stop. idle và stop bằng 1, start bằng 0; dữ liệu được gửi từ LSBLSB Bit có trọng số nhỏ nhất. Cần kiểm tra cả hướng ký hiệu và quy tắc chỉ mục. Tìm hiểu thêm. Mọi bit có cùng độ dài. Bài thực hành chỉ xét phát và giả sử bên cung cấp dữ liệu dùng cùng đồng hồ.

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\%

Với đồng hồ 48MHz và mục tiêu 115200 baud, có thể chọn hệ số chia nguyên D=417. Tốc độ thực tế khoảng 115108 baud, sai số khoảng -0.080%. Phải xem đặc tả thiết bị để đánh giá sai số cho phép tính cả bên nhận.

Trải 0x53 theo thứ tự truyền thực tế

0x53 được viết là 01010011, nhưng trên đường truyền các bit đi từ thấp đến cao theo thứ tự 1, 1, 0, 0, 1, 0, 1, 0. Mỗi ô trong hình là một khoảng bit gồm D chu kỳ, không phải một chu kỳ đồng hồ hệ thống. Các khoảng idle trước và sau được vẽ mỗi khoảng một ô để so sánh.

UART 8N1 · 0x53 · LSB first
Xem dữ liệu dạng sóng
Dữ liệu dạng sóng: mỗi ký tự là một khoảng; dấu chấm giữ trạng thái trước; p là một chu kỳ đồng hồ.
Tín hiệuDạng sóngGiá trị bus
tx101.0.10101.
phase234523452345idle → start → d0 → d1 → d2 → d3 → d4 → d5 → d6 → d7 → stop → idle

Từ start đến hết stop là đúng 10D chu kỳ. Các bit 1 hoặc 0 liên tiếp vẫn chiếm riêng một khoảng bit; không có chuyển mức trên đường truyền không có nghĩa bit biến mất.

Chốt một byte dữ liệu đúng một lần

Triển khai dưới đây yêu cầu CLKS_PER_BIT là hằng số từ 1 trở lên. Khi busy, mạch không nhận đầu vào và chỉ dùng data đã chốt lúc bắt đầu khung. Mạch không tạo bit-clock làm đồng hồ mới, mà dùng bộ đếm trong miền đồng hồ gốc để điều khiển thời điểm chuyển bit.

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

Gọi cạnh nhận đầu vào là E0; tx đổi thành start=0 tại đó. Sau đó, mạch chuyển sang bit tiếp theo sau đúng mỗi D chu kỳ. Bit stop bắt đầu ở E0+9D; busy hạ và done phát trong một chu kỳ ở E0+10D. Khoảng stop cuối cũng phải đủ D chu kỳ.

Vì triển khai này giữ in_ready=0 cho đến ngay trước cạnh kết thúc, khung tiếp theo sớm nhất được nhận tại cạnh sau đó. Khoảng cách nhận các khung liên tiếp vì vậy là 10D+110D+1 chu kỳ. Khoảng idle một chu kỳ này cũng là một phần của hoạt động bình thường.

Dự đoán chuỗi bit bằng tay

Các bit dữ liệu của 8'h53 từ LSB là 1,1,0,0,1,0,1,0. Toàn bộ khung có thứ tự sau:

Thứ tựstartd0d1d2d3d4d5d6d7stop
tx0110010101

Khi kiểm chứng, không được chỉ đếm số lần tx đổi mức, vì các bit liên tiếp cùng giá trị không có chuyển mức. Lấy mốc từ đầu khung, lấy mẫu giữa từng khoảng bit để đối chiếu bit dự kiến, đồng thời kiểm tra độ dài start và stop. Để kiểm thử đơn vị nhanh, hãy dùng cả các giá trị D nhỏ như 1, 2, 3.

Mở rộng bằng cách kết nối FIFO

FIFOFIFO Hàng đợi lấy ra dữ liệu được đưa vào trước. Quy tắc đầy, rỗng và cho phép đọc/ghi đồng thời là một phần của hợp đồng hoạt động. Tìm hiểu thêm đọc qua thanh ghi cập nhật dout và dout_valid ngay sau cạnh nhận pop. Mạch tiếp theo dùng cùng đồng hồ lấy mẫu phản hồi tại cạnh lênCạnh lên Khoảnh khắc clock chuyển 0 sang 1, khác với mức cao chỉ cả khoảng CLK=1. Tìm hiểu thêm kế tiếp. Nếu đưa dout vào UART ngay tại cạnh nhận pop, đó có thể vẫn là giá trị cũ. Hãy dùng bộ đệm một ô lưu byte trả về cùng trạng thái pending, rồi kết nối để truyền đúng một lần khi UART ready.

Kiểm chứng cuối cùng cần bao gồm 00·FF·01·80·55·53, đầu vào thay đổi khi busy, khung liên tiếp và reset giữa khung. Chính sách reset là hủy truyền và đưa tx về idle=1. Bên nhận vẫn có thể thấy một khung hợp lệ, vì vậy chỉ dựa vào định dạng khung UART thì không thể bảo đảm phát hiện truyền bị ngắt. Nếu bắt buộc phải loại bỏ dữ liệu bị ảnh hưởng, hãy quy định một hợp đồng hệ thống phối hợp reset của bên nhận với bên phát hoặc gửi tín hiệu hủy riêng đến bên nhận.

Đọc thêm: Microchip — EUSART và định dạng khung 8N1

Tự thử

CLKS_PER_BIT=4 và dữ liệu được nhận ở E0. Hãy xác định cạnh bắt đầu d0, bắt đầu stop và phát done. Nếu có in_valid=1 mới ở E40, byte tiếp theo có được nhận ngay tại cạnh đó không?

Đọc giải thích

d0 bắt đầu ở E4, stop ở E36 và done xuất hiện ngay sau E40. Ngay trước E40, busy=1 nên in_ready=0; byte mới chưa được nhận. Bên gửi phải giữ valid và data, và byte tiếp theo có thể được nhận ở E41. Mỗi khung dài 40 chu kỳ, khoảng cách nhận tối thiểu là 41 chu kỳ.

Lựa chọn áp dụng cho trình duyệt này. Có thể đổi ở chân trang bất cứ lúc nào.