Altifigence Academy

63 / 63 · 개념

종합 실습: UART 송신기와 프레임 타이밍

분주 카운터·시프트 레지스터·흐름 제어를 결합해 8N1 프레임을 만들고 비트 경계를 검증합니다.

프레임 형식과 비트 길이를 먼저 정합니다

선수 지식: 카운터, 시프트 레지스터레지스터 여러 비트의 상태를 저장하는 회로입니다. 이 과정의 동기식 레지스터는 클록 에지에서 정해진 입력을 저장합니다. 자세히 보기, valid/ready, 동기식 리셋리셋 상태를 미리 정한 초기값으로 되돌리는 제어입니다. 동기식인지 비동기식인지, 다른 제어보다 우선하는지를 함께 정해야 합니다. 자세히 보기.

UARTUART 별도의 클록 선 없이 시작 비트·데이터·정지 비트로 직렬 통신하는 장치입니다. 송수신 측이 baud rate와 프레임 형식에 합의해야 합니다.의 8N1 형식은 시작 비트 1개, 데이터 비트 8개, 정지 비트 1개로 구성되며 패리티 비트는 없습니다. 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\%

48MHz에서 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 first
파형 데이터 보기
파형 데이터: 각 문자는 한 구간, 점은 이전 상태 유지, p는 클록 한 주기입니다.
신호파형버스 값
tx101.0.10101.
phase234523452345idle → start → d0 → d1 → d2 → d3 → d4 → d5 → d6 → d7 → stop → idle

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에 보내면 이전 값일 수 있습니다. 반환된 바이트를 보관하는 1칸 버퍼와 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클록입니다.

선택은 이 브라우저에만 적용됩니다. 언제든 푸터에서 변경할 수 있습니다.