[Verilog] UART 컨트롤러를 만들어 보자 (2) - 보레이트 생성기 구현

pikamon·2022년 4월 27일
0

Verilog

목록 보기
8/12

Verilog HDL로 각 모듈을 하나씩 만들어 보자.


첫 번째로 보레이트 생성기를 만들어 보자.

0. 매크로 정의

먼저 각 모듈에서 사용할 매크로를 정의하자.

  • Defines.vh
`ifndef __DEFINES_VH__
`define __DEFINES_VH__

// States of state machine
`define STATE_RESET			3'b001
`define STATE_IDLE			3'b010
`define STATE_START_BIT		3'b011
`define STATE_DATA_BITS		3'b100
`define STATE_STOP_BIT		3'b101

// Main clocks
`define CLOCK_RATE_100MHZ	100000000

// Baudrates
`define BAUD_RATE_1200		1200
`define BAUD_RATE_9600		9600
`define BAUD_RATE_57600		57600
`define BAUD_RATE_115200	115200
`define BAUD_RATE_230400	230400
`define BAUD_RATE_460800	460800

// Oversampling rates
`define OVERSAMPLING_1		1
`define OVERSAMPLING_2		2
`define OVERSAMPLING_4		4
`define OVERSAMPLING_8		8
`define OVERSAMPLING_16		16

// Data bits
`define DATA_BITS_7 		7
`define DATA_BITS_8 		8

`endif /*__DEFINES_VH__*/

입력 클럭, 보레이트, 오버샘플링 등 사용자가 가변적으로 설정할 수 있는 값들을 따로 매크로 파일로 빼서 관리하도록 구성하였다.

1. RTL 구현

RTL 모듈을 만들어 보자.

  • BaudRateGenerator.v
`ifndef __BAUDRATE_GENERATOR_V__
`define __BAUDRATE_GENERATOR_V__

`include "inc/Defines.vh"

module BaudRateGenerator #(
        parameter CLOCK_RATE    = `CLOCK_RATE_100MHZ, // use 100MHz as default
        parameter BAUD_RATE     = `BAUD_RATE_115200,  // use 115200 as default
        parameter OVERSAMPLING  = `OVERSAMPLING_16    // use 16x as default
    )(
        input wire clk,   // main clock
        output reg rxClk, // baud rate for rx
        output reg txClk  // baud rate for tx
    );

    localparam MAX_RATE_RX  = CLOCK_RATE / (2 * BAUD_RATE * OVERSAMPLING);
    localparam MAX_RATE_TX  = CLOCK_RATE / (2 * BAUD_RATE);
    localparam RX_CNT_WIDTH = $clog2(MAX_RATE_RX);
    localparam TX_CNT_WIDTH = $clog2(MAX_RATE_TX);

    reg [RX_CNT_WIDTH - 1:0] rxCnt = 0;
    reg [TX_CNT_WIDTH - 1:0] txCnt = 0;

    initial begin
        rxClk = 1'b0;
        txClk = 1'b0;
    end

    always @ (posedge clk) begin
        // generate rx clock
        if (rxCnt == MAX_RATE_RX) begin
            rxCnt <= 0;
            rxClk <= ~rxClk;
        end else begin
            rxCnt <= rxCnt + 1'b1;
        end

        // generate tx clock
        if (txCnt == MAX_RATE_TX) begin
            txCnt <= 0;
            txClk <= ~txClk;
        end else begin
            txCnt <= txCnt + 1'b1;
        end
    end

endmodule

`endif /*__BAUDRATE_GENERATOR_V__*/

입력 클럭과 보레이트, 오버샘플링 값을 이용하여 rx, tx 클럭 주기를 계산한 후, 카운터를 이용하여 rx, tx 클럭을 분주시킨다.

2. Testbench 구현

위 모듈을 테스트하기 위한 테스트벤치를 만들어 보자.

  • BaudRateGenerator_tb.v
`timescale 10ns/1ns

`include "inc/Defines.vh"
`include "src/BaudRateGenerator.v"

module tbBaudRateGenerator();

	parameter CLOCK_RATE	= `CLOCK_RATE_100MHZ;
	parameter BAUD_RATE		= `BAUD_RATE_115200;
	parameter OVERSAMPLING	= `OVERSAMPLING_16;

	reg clk = 0;

    wire rxClk;
    wire txClk;

    BaudRateGenerator #(
        .CLOCK_RATE(CLOCK_RATE),
        .BAUD_RATE(BAUD_RATE),
        .OVERSAMPLING(OVERSAMPLING)
    ) test (
        .clk(clk),
        .rxClk(rxClk),
        .txClk(txClk)
    );

	initial begin
		$dumpfile("test.vcd");
		$dumpvars(-1, test);
    end

	always begin
		#0.5 clk = ~clk;
	end

	initial begin
		#1000 $finish;
	end

endmodule

10ns당 1회 분주하기 때문에 clk에 100MHz 클럭이 만들어진다. 이를 시뮬레이션 돌리면 이에 대한 rx, tx 클럭이 출력되는 것을 기대할 수 있다.

3. Makefile 정의

개발 편의를 위해 Makefile을 생성하였다.

  • Makefile
all: BaudRateGenerator

BaudRateGenerator: clean
	iverilog -o test.vvp testbench/BaudRateGenerator_tb.v
	vvp test.vvp
	gtkwave test.vcd

clean:
	rm -f test.vcd
	rm -f test.vvp

make만 입력하면 자동으로 clean 후 시뮬레이션을 돌릴 수 있다.

4. 실행 및 결과

make를 입력한다.

make

그러면 gtkwave가 실행되며, 아래와 같이 입출력을 확인할 수 있다.

1. rx 클럭 검증

먼저 rx 클럭부터 보자.

입력 클럭이 100MHz이고 보레이트 115200에 오버샘플링이 16x이기 때문에, rx 분주를 계산하는 공식은 아래와 같다.

rxClk = 100000000 / (2 * 115200 * 16) = 27.16

다시 말하면 clk이 27회 분주하면 rxClk이 토글되며, clk이 54회 분주하면 rxClk이 1회 분주한다.

rxClk이 LOW에서 HIGH로 갈 때까지의 clk 분주 개수를 세어보면 27개인 것을 알 수 있다.

따라서 입력 클럭에 맞춰 rx 클럭이 정상적으로 생성된 것을 볼 수 있다.

2. tx 클럭 검증

그다음 tx 클럭을 보자.

입력 클럭이 너무 촘촘해서 잘 안보이기 때문에, rx 클럭과 비교해보자.

rx 클럭이 16회 분주할 때마다 tx 클럭이 1회 분주하는지를 보면 되며,

위 그림을 통해 tx 클럭이 정상적으로 생성되는 것을 볼 수 있다.

profile
개발자입니당 *^^* 깃허브 https://github.com/pikamonvvs

0개의 댓글