UART通信用のサンプリングクロック生成機
#fpga #uart #verilog
システムクロックからUART通信サンプリング用のクロックを生成するボーレート生成機 ( baud_gen ) モジュール。
clk: システムクロック
reset: リセット
tick: 生成されたサンプリング用クロック
dvsr: Divisor。システムクロックを分周するためのカウンタの上限値。以下の式で求める
dvsr = システムクロック / サンプリング回数 * ボーレート
例
UARTのボーレートが9600Hz
1周期あたりのサンプリング回数が16回
システムクロックが100MHz
の場合、
dvsr = 100,000,000(100Mhz) / 16(サンプリング回数) * 9600(ボーレート)
dvsr = 651 となる
code:baud_gen.sv
module baud_gen(
input clk, reset,
input 10:0 dvsr,
output tick
);
logic 10:0 n_reg;
logic 10:0 n_next;
always_ff @(posedge clk, posedge reset)
if (reset)
n_reg <= 0;
else
n_reg <= n_next;
assign n_next = (n_reg == dvsr) ? 0 : n_reg + 1;
assign tick = (n_reg == 1);
endmodule
code:baud_gen_testbench.sv
`timescale 1ns/1ps
// iverilog -g 2012 -s baud_gen_testbench baud_gen.sv baud_gen_testbench.sv && ./a.out
module baud_gen_testbench();
logic clk, reset, tick;
baud_gen bg (
.clk(clk),
.reset(reset),
.dvsr(11'd651), // 100MHz / (16サンプリング * 9600Hz)
.tick(tick)
);
initial begin
$dumpfile("baud_gen.vcd");
$dumpvars(0, bg);
clk = 0;
reset = 1; #10
reset = 0; #10
// 50万タイムスケール後に終了する
#500000 $finish;
end
// 5nsごとにclkを反転することで100MHzのクロックを生成
always #5
clk <= ~clk;
endmodule
動作確認
$ iverilog -g 2012 -s baud_gen_testbench baud_gen.sv baud_gen_testbench.sv && ./a.out
で実行後、GTKWaveで波形を確認。6.5マイクロ秒(9600Hz * 16サンプリング)ごとにtickが立ってるのでちゃんと動いてそうな気がする (see: UARTのボーレートの計算方法)
https://gyazo.com/fe00263ca366c7b048da220783135084