UARTトランスミッタ
UART送信機(トランスミッタ)設計メモ。
uart_txモジュール
パラメータ
input clk
input reset
input tx_start
input s_tick
input (7:0) din
output tx_done_tick
output tx
ステータス
idle
start
data
stop
ASMDチャート
https://gyazo.com/66916db54b97a459056185960b486fd3
code:uart_tx.sv
// iverilog -g 2012 -s uart_tx_testbench uart_tx.sv baud_gen.sv uart_tx_testbench.sv && ./a.out
module uart_tx(
input logic clk,
input logic reset,
input logic tx_start,
input logic s_tick,
output logic tx_done_tick,
output logic tx
);
localparam DBIT = 8;
localparam SB_TICK = 16;
typedef enum {idle, start, data, stop} tx_state;
tx_state tx_state_reg, tx_state_next;
logic tx_reg, tx_next;
assign tx = tx_reg;
always_ff @(posedge clk, posedge reset) begin
if (reset)
begin
tx_state_reg <= idle;
s_reg <= 0;
n_reg <= 0;
b_reg <= 0;
tx_reg <= 1;
end
else
begin
tx_state_reg <= tx_state_next;
s_reg <= s_next;
n_reg <= n_next;
b_reg <= b_next;
tx_reg <= tx_next;
end
end
always_comb begin
tx_done_tick = 0;
tx_state_next = tx_state_reg;
s_next = s_reg;
n_next = n_reg;
b_next = b_reg;
tx_next = tx_reg;
case (tx_state_reg)
idle: begin
if (tx_start) begin
s_next = 0;
b_next = din;
tx_state_next = start;
end
end
start: begin
tx_next = 0;
if (s_tick) begin
if (s_reg == 15)
begin
s_next = 0;
n_next = 0;
tx_state_next = data;
end
else
s_next = s_reg + 1;
end
end
data: begin
tx_next = b_reg & 8'b00000001;
if (s_tick) begin
if (s_reg == 15)
begin
s_next = 0;
b_next = b_reg >> 1;
if (n_reg == (DBIT - 1))
tx_state_next = stop;
else
n_next = n_reg + 1;
end
else
s_next = s_reg + 1;
end
end
stop: begin
tx_next = 1;
if (s_tick == 1) begin
if (s_reg == (SB_TICK - 1))
begin
tx_state_next = idle;
tx_done_tick = 1;
end
else
s_next = s_reg + 1;
end
end
endcase
end
endmodule
code:uart_tx_testbench.sv
`timescale 1ns/1ps
module uart_tx_testbench();
logic clk, reset;
logic tx_start, s_tick;
logic tx_done_tick, tx;
baud_gen bg (
.clk(clk),
.reset(reset),
.dvsr(11'd651), // 100MHz / (16サンプリング * 9600Hz)
.tick(s_tick)
);
uart_tx dut (
.clk(clk),
.reset(reset),
.tx_start(tx_start),
.s_tick(s_tick),
.din(din),
.tx_done_tick(tx_done_tick),
.tx(tx)
);
initial begin
$dumpfile("uart_tx.vcd");
$dumpvars(0, dut);
clk = 0;
tx_start = 0;
din = 8'd0;
// 9600Hzの1周期が約10400ナノ秒
// データ送信開始(1回目)
din = 8'h55;
tx_start = 1;
tx_start = 0;
// データ送信開始(2回目)
din = 8'hAA;
tx_start = 1;
tx_start = 0;
end
// 5nsごとにclkを反転することで100MHzのクロックを生成
clk <= ~clk;
endmodule
実行して波形を表示してみる。
$ iverilog -g 2012 -s uart_tx_testbench uart_tx.sv baud_gen.sv uart_tx_testbench.sv && ./a.out
txの信号を眺めてみると、なんとなーく 0x55 (0b01010101) と 0xAA (0b10101010) が出力されてる気がする。ちゃんとした動作確認はあとで実機でやろう。
https://gyazo.com/71f4a5fd42d5093cabd30cffc93df0e1