Development Environment.
Program : Quartus Prime 18.1 Lite Edition, Tera-term.
Tool : Modelsim 10.5b Starter Edition.
FPGA : Cyclone V
Hardware Devices : De1-SoC Board, FT232BL.
Language : Verilog2001.
Objective.
Outputs ASCII code on the LED of De1-SoC board when you type characters on the keyboard.
Why?
UART(Universal Asynchronous Receiver/Transmitter)는 일반적으로 컴퓨터나 주변 기기에서 직렬 통신을 위해 사용되고 있는 범용 비동기식 송수신 장치이며 주로 컴퓨터와 마이크로 컨트롤러, 센서, 모뎀의 데이터 송수신에 활용된다. 통신 프로토콜에 대한 이해를 바탕으로 UART를 설계하고 데이터의 송수신을 확인함으로써 시리얼 통신 방식을 익히고자 한다.
Design Steps.
1. UART overview.
2. UART TX. (TX Data Hard Coding)
3. UART RX.
4. UART. (Internal Loopback Test)
5. UART 7-SEGMENT.
1. UART overview.
직렬 통신(Serial Communication)이란 한 번에 하나의 비트를 전송하는 병렬 통신과 반대로 디지털 장치들 간에 데이터를 비트 단위로 연속적으로 전송하는 통신 방식을 말한다. UART, SPI, I2C, USB가 이에 해당하며 그 중 UART(Universal Asynchronous Receiver/Transmitter)는 비동기식 통신 프로토콜로 컴퓨터와 주변 장치들간 데이터의 송수신에 활용되며 주로 마이크로컨트롤러, 센서, 모뎀 등에 적용된다. UART의 Data Frame은 아래와 같다.
UART는 송신부와 수신부 사이에 Clock Signal을 공유하지 않는 특징을 가지고 있다. 대신에 START, STOP Bit를 사용함으로써 데이터의 시작과 끝을 정의한다. 해당 프로젝트에서는 Serial Communication의 Bit Rate를 115200bps로 설정하였다. De1-SoC Board의 Default 주파수는 50MHz로 1 Cycle에 20ns의 주기를 가진다. 1초에 115200Bit를 전송할 수 있으므로 8680ns (1/115200 = 0.00000868s = 0.00868ms = 8.68us) 마다 1-Bit를 전송할 수 있게 된다.
2. UART TX. (TX Data Hard Coding)
1) Objective.
UART TX의 목표는 FT232BL 칩을 연결하여 임의로 지정한 TX(ASCII X, 0x58, 0x01011000)값이 Tera-term에 출력되도록 하는 것이다. UART TX의 Block Diagram은 아래와 같이 그릴 수 있다.
2) Design Block.
먼저 카운터를 설계한다. 그 이유는 8680ns 마다 1-Bit를 전송하므로 20ns의 주기를 가진 Clock을 초기화하지 않고 434 Cycle 동안 유지할 필요가 있기 때문이다. 다음으로 Data Frame에 맞게 Data, START, STOP Bit를 정의해 줄 Finite State Machine을 설계한다. FSM은 다음과 같다.
3) Verilog Coding.
// 115200bps, ASCII hardcoding data 'X' 01011000, 0x58
module UART_TX(
input clk ,
input reset_n ,
output tx
);
parameter IDLE = 0 ,
START = 1 ,
D0 = 2 ,
D1 = 3 ,
D2 = 4 ,
D3 = 5 ,
D4 = 6 ,
D5 = 7 ,
D6 = 8 ,
D7 = 9 ,
STOP = 10;
reg [8:0] count = 0;
reg [3:0] current_state = 0, next_state;
reg tx_data;
wire bit_clear = (count == 433);
wire bit_stop = (current_state == STOP && count == 0);
//counter
always@(posedge clk, negedge reset_n)begin
if(!reset_n)
count <= 0;
else if(bit_clear)
count <= 0;
else
count <= count + 1;
end
//state transfer
always@(posedge clk, negedge reset_n)begin
if(!reset_n)
current_state <= IDLE;
else
current_state <= next_state;
end
//next state logic
always@(*)begin
next_state = current_state;
case(current_state)
IDLE : if(bit_clear) next_state = START ;
START : if(bit_clear) next_state = D0 ;
D0 : if(bit_clear) next_state = D1 ;
D1 : if(bit_clear) next_state = D2 ;
D2 : if(bit_clear) next_state = D3 ;
D3 : if(bit_clear) next_state = D4 ;
D4 : if(bit_clear) next_state = D5 ;
D5 : if(bit_clear) next_state = D6 ;
D6 : if(bit_clear) next_state = D7 ;
D7 : if(bit_clear) next_state = STOP ;
STOP : if(bit_clear) next_state = IDLE ;
default : if(bit_clear) next_state = IDLE ;
endcase
end
//output logic
always@(*)begin
case(current_state)
IDLE : tx_data = 1'b1;
START : tx_data = 1'b0;
D0 : tx_data = 1'b0;
D1 : tx_data = 1'b0;
D2 : tx_data = 1'b0;
D3 : tx_data = 1'b1;
D4 : tx_data = 1'b1;
D5 : tx_data = 1'b0;
D6 : tx_data = 1'b1;
D7 : tx_data = 1'b0;
STOP : tx_data = 1'b1;
default : tx_data = 1'b1;
endcase
end
assign tx = tx_data;
endmodule
UART의 Data Frame은 기본적으로 IDLE 상태에서 1, START 상태에서 0, STOP 상태에서 1의 값을 가진다. Test Bench 작성과 파형 확인을 위한 Tcl도 작성한다.
`timescale 1 ns / 1 ns
module tb_uart_tx();
reg clk ;
reg reset_n ;
wire tx ;
uart_tx Uart_tx_0 (
.clk (clk ),
.reset_n (reset_n ),
.tx (tx )
);
initial begin
clk = 1'b1;
forever #10 clk = ~clk;
end
initial begin
reset_n = 1'b1;
@(posedge clk);
reset_n = 1'b0;
@(posedge clk);
reset_n = 1'b1;
end
endmodule
vlib work
vlog uart_tx.v tb_uart_tx.v
vsim work.tb_uart_tx
view wave
add wave -radix unsigned /clk
add wave -radix unsigned /reset_n
add wave -radix unsigned /tx
add wave -radix unsigned /tb_uart_tx/Uart_tx_0/count
add wave -radix unsigned /tb_uart_tx/Uart_tx_0/cst
run 300us
4) Simulation.
5) Verification with Tera-term.
3. UART RX.
1) Objective.
TX Data를 수신하는 UART RX 모듈을 설계한다.
2) Falling Edge Detection.
UART의 Data Frame은 기본적으로 IDLE과 STOP에서 1, START에서 0의 Value를 가진다. Clock Signal이 존재하지 않는 비동기식 시스템에서 START Bit를 시작하고 데이터의 수신을 감지할 수 있는 Falling Edge Detection을 구현했다.
//falling edge detection
assign f_det = ~dly0 & dly1;
always@(posedge clk, negedge reset_n) begin
if(!reset_n) begin
dly0 <= 0;
dly1 <= 0;
end else begin
dly0 <= rx;
dly1 <= dly0;
end
end
3) Mid-Capture.
신호가 변하는 Edge보다 데이터의 중간 값을 Capture하는 것이 TX에서 전송된 Data를 안정적으로 수신할 수 있다. START에서 D0로 넘어가기 전 bit_capture 신호를 추가하였다. START 상태가 217 Cycle 동안 유지되면 counter 초기화 후, D0 상태로 진입하고 그 때부터 다시 434 Cycle을 반복하며 Data Bit의 중간 값을 Capture한다.
//counter
wire bit_clear = (count == 433);
wire bit_midcap = (count == 216) && (cst == START);
wire bit_start = f_det & (cst == IDLE);
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
count <= 9'b0;
else if(bit_clear)
count <= 9'b0;
else if(bit_midcap)
count <= 9'b0;
else if(bit_start)
count <= 9'b0;
else
count <= count + 9'b1;
end
4) FSM.
5) Verilog Coding.
module UART_RX(
input clk ,
input reset_n ,
input rx ,
output reg [7:0] rx_data
);
parameter IDLE = 0 ,
START = 1 ,
D0 = 2 ,
D1 = 3 ,
D2 = 4 ,
D3 = 5 ,
D4 = 6 ,
D5 = 7 ,
D6 = 8 ,
D7 = 9 ,
STOP = 10;
reg [8:0] count = 0;
reg [3:0] current_state = 0;
reg [3:0] next_state;
reg delay_0;
reg delay_1;
//falling edge detection
always@(posedge clk, negedge reset_n)begin
if(!reset_n)begin
delay_0 <= 0;
delay_1 <= 0;
end else begin
delay_0 <= rx;
delay_1 <= delay_0;
end
end
wire f_edge_det = ~delay_0 & delay_1;
wire bit_start = (f_edge_det && current_state == IDLE);
wire bit_capture = (current_state == START && count == 216);
wire bit_clear = (count == 433);
//counter
always@(posedge clk, negedge reset_n)begin
if(!reset_n)
count <= 0;
else if(bit_start)
count <= 0;
else if(bit_capture)
count <= 0;
else if(bit_clear)
count <= 0;
else
count <= count + 1;
end
// state transfer
always@(posedge clk, negedge reset_n)begin
if(!reset_n)
current_state <= IDLE;
else
current_state <= next_state;
end
// next state logic
always@(*)begin
next_state = current_state;
case(current_state)
IDLE : if(bit_start) next_state = START;
START : if(bit_capture) next_state = D0 ;
D0 : if(bit_clear) next_state = D1 ;
D1 : if(bit_clear) next_state = D2 ;
D2 : if(bit_clear) next_state = D3 ;
D3 : if(bit_clear) next_state = D4 ;
D4 : if(bit_clear) next_state = D5 ;
D5 : if(bit_clear) next_state = D6 ;
D6 : if(bit_clear) next_state = D7 ;
D7 : if(bit_clear) next_state = STOP ;
STOP : if(bit_clear) next_state = IDLE ;
default : next_state = IDLE ;
endcase
end
//output logic
always@(posedge clk, negedge reset_n)begin
if(!reset_n)
rx_data <= 0;
else if(bit_clear) begin // keep the value of UART_TX hard-coding data
case(current_state) // default value 1 at IDLE, STOP and 0 at START
D0 : rx_data[0] <= rx;
D1 : rx_data[1] <= rx;
D2 : rx_data[2] <= rx;
D3 : rx_data[3] <= rx;
D4 : rx_data[4] <= rx;
D5 : rx_data[5] <= rx;
D6 : rx_data[6] <= rx;
D7 : rx_data[7] <= rx;
endcase
end
end
endmodule
4. UART. (Internal Loop-Back Test, Only for Simulation)
1) Objective.
위에서 설계한 UART RX module이 UART TX의 데이터을 제대로 수신하는지 시뮬레이션을 통해 확인하려고 한다. UART TX와 RX를 하나의 모듈에 Instantiation하고 Interanl Loop-Back으로 결과를 확인한다. Block Diagram은 아래와 같다.
2) Verilog Coding.
module UART(
input clk ,
input reset_n ,
output [7:0] rx_data
);
wire rxtx;
UART_TX UART_TX_u0(
.clk (clk ),
.reset_n (reset_n ),
.tx (rxtx )
);
UART_RX UART_RX_u0(
.clk (clk ),
.reset_n (reset_n ),
.rx (rxtx ),
.rx_data (rx_data )
);
endmodule
`timescale 1 ns / 1 ns
module tb_UART();
reg clk ;
reg reset_n ;
wire [7:0] rx_data ;
UART UART_u0(
.clk (clk ),
.reset_n (reset_n ),
.rx_data (rx_data )
);
initial fork
clk_gen();
reset_gen();
join
task clk_gen;
begin
clk = 1'b0;
forever #10 clk = ~clk;
end
endtask
task reset_gen;
begin
reset_n = 1'b1;
end
endtask
parameter IDLE = 0 ,
START = 1 ,
D0 = 2 ,
D1 = 3 ,
D2 = 4 ,
D3 = 5 ,
D4 = 6 ,
D5 = 7 ,
D6 = 8 ,
D7 = 9 ,
STOP = 10;
reg [8*8-1:0] nstate_tx;
always@(UART_u0.UART_TX_u0.next_state)begin
case(UART_u0.UART_TX_u0.next_state)
IDLE : nstate_tx = "IDLE ";
START : nstate_tx = "START ";
D0 : nstate_tx = "D0 ";
D1 : nstate_tx = "D1 ";
D2 : nstate_tx = "D2 ";
D3 : nstate_tx = "D3 ";
D4 : nstate_tx = "D4 ";
D5 : nstate_tx = "D5 ";
D6 : nstate_tx = "D6 ";
D7 : nstate_tx = "D7 ";
STOP : nstate_tx = "STOP ";
default : nstate_tx = "IDLE ";
endcase
end
reg [8*8-1:0] nstate_rx;
always@(UART_u0.UART_RX_u0.next_state)begin
case(UART_u0.UART_RX_u0.next_state)
IDLE : nstate_rx = "IDLE ";
START : nstate_rx = "START ";
D0 : nstate_rx = "D0 ";
D1 : nstate_rx = "D1 ";
D2 : nstate_rx = "D2 ";
D3 : nstate_rx = "D3 ";
D4 : nstate_rx = "D4 ";
D5 : nstate_rx = "D5 ";
D6 : nstate_rx = "D6 ";
D7 : nstate_rx = "D7 ";
STOP : nstate_rx = "STOP ";
default : nstate_rx = "IDLE ";
endcase
end
endmodule
vlib work
vlog UART.v tb_UART.v UART_TX.v UART_RX.v
vsim work.tb_UART
view wave
add wave -radix unsigned /clk
add wave -radix unsigned /reset_n
add wave -radix unsigned /UART_u0/UART_TX_u0/tx
add wave -radix ASCII /nstate_tx
add wave -radix unsigned /UART_u0/UART_RX_u0/rx
add wave -radix ASCII /nstate_rx
add wave -radix unsigned /UART_u0/UART_RX_u0/bit_start
add wave -radix ASCII /rx_data
add wave -radix unsigned /UART_u0/UART_TX_u0/bit_stop
run 300us
3) Simulation.
Simulation을 통해서 UART RX 모듈이 UART TX 모듈 데이터의 중간 값을 제대로 Capture하여 rx_data로 출력한다는 것을 확인하였고 이러한 Internal Loop-Back Test를 통해 설계한 UART 모듈이 정상적으로 동작함을 확인할 수 있었다.
4. UART 7-SEGMENT.
1) Objective.
키보드로 입력한 문자의 ASCII Code 값이 LED에 출력되는지 확인한다. PC와 연결한 FT232BL 칩에서 TX 데이터를 전송하고 UART RX 모듈이 데이터를 수신하고 출력으로 LED를 동작시킨다. (추가적으로 Tera-term을 통해 입력 데이터 확인) Block Diagram은 아래와 같다.
2) 7-Segment controller.
UART RX에서 수신한 ASCII(Hexadecimal) 값을 LED에 출력하기 위해 입력에 따른 세그먼트의 출력 0 ~ F를 정의한다.
module uart_7seg_controller(
input [3:0] inp_data,
output reg seg_a,
output reg seg_b,
output reg seg_c,
output reg seg_d,
output reg seg_e,
output reg seg_f,
output reg seg_g
);
// cathode
always@(*) begin
case(inp_data)
4'b0000 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1111110;
4'b0001 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b0110000;
4'b0010 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1101101;
4'b0011 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1111001;
4'b0100 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b0110011;
4'b0101 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1011011;
4'b0110 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1011111;
4'b0111 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1110000;
4'b1000 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1111111;
4'b1001 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1111011;
4'b1010 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b0110011;
4'b1011 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1011011;
4'b1100 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1011111;
4'b1101 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1110000;
4'b1110 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1001111;
4'b1111 : {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g}= ~7'b1000111;
endcase
end
endmodule
3)Verilog Coding.
module uart_rx_seg(
input clk,
input reset_n,
input rx,
output seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g,
output seg_h, seg_i, seg_j, seg_k, seg_l, seg_m, seg_n
);
localparam IDLE = 0;
localparam START = 1;
localparam MID = 2;
localparam D0 = 3;
localparam D1 = 4;
localparam D2 = 5;
localparam D3 = 6;
localparam D4 = 7;
localparam D5 = 8;
localparam D6 = 9;
localparam D7 = 10;
localparam STOP0 = 11;
localparam STOP1 = 12;
reg dly0, dly1;
reg [8:0] count = 9'b0;
reg [3:0] cst = 4'b0;
reg [3:0] nst;
reg [7:0] rx_data;
assign f_det = ~dly0 & dly1;
always@(posedge clk, negedge reset_n) begin
if(!reset_n) begin
dly0 <= 0;
dly1 <= 0;
end else begin
dly0 <= rx;
dly1 <= dly0;
end
end
wire bit_clear = (count == 433);
wire bit_midcap = (count == 216) && (cst == START);
wire bit_start = f_det && (cst == IDLE);
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
count <= 9'b0;
else if(bit_clear)
count <= 9'b0;
else if(bit_midcap)
count <= 9'b0;
else if(bit_start)
count <= 9'b0;
else
count <= count + 9'b1;
end
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
cst <= IDLE;
else
cst <= nst;
end
always@(*) begin
case(cst)
IDLE : if(bit_start ) nst = START ; else nst = IDLE ;
START : if(bit_midcap) nst = MID ; else nst = START ;
MID : if(bit_clear ) nst = D0 ; else nst = MID ;
D0 : if(bit_clear ) nst = D1 ; else nst = D0 ;
D1 : if(bit_clear ) nst = D2 ; else nst = D1 ;
D2 : if(bit_clear ) nst = D3 ; else nst = D2 ;
D3 : if(bit_clear ) nst = D4 ; else nst = D3 ;
D4 : if(bit_clear ) nst = D5 ; else nst = D4 ;
D5 : if(bit_clear ) nst = D6 ; else nst = D5 ;
D6 : if(bit_clear ) nst = D7 ; else nst = D6 ;
D7 : if(bit_clear ) nst = STOP0 ; else nst = D7 ;
STOP0 : if(bit_clear ) nst = STOP1 ; else nst = STOP0 ;
STOP1 : if(bit_clear ) nst = IDLE ; else nst = STOP1 ;
endcase
end
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
rx_data <= 8'b0;
else if(count == 0) begin
case(cst)
D0 : rx_data[0] <= rx;
D1 : rx_data[1] <= rx;
D2 : rx_data[2] <= rx;
D3 : rx_data[3] <= rx;
D4 : rx_data[4] <= rx;
D5 : rx_data[5] <= rx;
D6 : rx_data[6] <= rx;
D7 : rx_data[7] <= rx;
endcase
end
end
uart_7seg_controller uUart_7seg_controller_0(
.inp_data (rx_data[3:0] ),
.seg_a (seg_a ),
.seg_b (seg_b ),
.seg_c (seg_c ),
.seg_d (seg_d ),
.seg_e (seg_e ),
.seg_f (seg_f ),
.seg_g (seg_g )
);
uart_7seg_controller uUart_7seg_controller_1(
.inp_data (rx_data[7:4] ),
.seg_a (seg_h ),
.seg_b (seg_i ),
.seg_c (seg_j ),
.seg_d (seg_k ),
.seg_e (seg_l ),
.seg_f (seg_m ),
.seg_g (seg_n )
);
endmodule
`timescale 1 ns / 1 ns
module tb_uart_rx_seg();
reg clk;
reg reset_n;
reg rx;
wire seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g;
wire seg_h, seg_i, seg_j, seg_k, seg_l, seg_m, seg_n;
uart_rx_seg uUart_rx_seg_0(
.clk (clk ),
.reset_n (reset_n ),
.rx (rx ),
.seg_a (seg_a ),
.seg_b (seg_b ),
.seg_c (seg_c ),
.seg_d (seg_d ),
.seg_e (seg_e ),
.seg_f (seg_f ),
.seg_g (seg_g ),
.seg_h (seg_h ),
.seg_i (seg_i ),
.seg_j (seg_j ),
.seg_k (seg_k ),
.seg_l (seg_l ),
.seg_m (seg_m ),
.seg_n (seg_n )
);
initial begin
clk = 1'b0;
forever #10 clk = ~clk;
end
initial begin
reset_n = 1'b1;
end
initial begin
rx = 1'b1; // IDLE
#20000 rx = 1'b0; // START
// ASCII 'X'
# 8680 rx = 1'b0; // D0
# 8680 rx = 1'b0; // D1
# 8680 rx = 1'b0; // D2
# 8680 rx = 1'b1; // D3
# 8680 rx = 1'b1; // D4
# 8680 rx = 1'b0; // D5
# 8680 rx = 1'b1; // D6
# 8680 rx = 1'b0; // D7
# 8680 rx = 1'b1; // STOP0
# 8680 rx = 1'b1; // STOP1
# 8680 rx = 1'b1;
# 8680 rx = 1'b1; // IDLE
# 8680 rx = 1'b0; // START
// ASCII 'A'
# 8680 rx = 1'b1; // D0
# 8680 rx = 1'b0; // D1
# 8680 rx = 1'b0; // D2
# 8680 rx = 1'b0; // D3
# 8680 rx = 1'b0; // D4
# 8680 rx = 1'b0; // D5
# 8680 rx = 1'b1; // D6
# 8680 rx = 1'b0; // D7
# 8680 rx = 1'b1; // STOP0
# 8680 rx = 1'b1; // STOP1
end
endmodule
vlib work
vlog uart_rx_seg.v tb_uart_rx_seg.v uart_7seg_controller.v
vsim work.tb_uart_rx_seg
view wave
add wave -radix unsigned /clk
add wave -radix unsigned /reset_n
add wave -radix unsigned /rx
add wave -radix unsigned /tb_uart_rx_seg/uUart_rx_seg_0/count
add wave -radix unsigned /tb_uart_rx_seg/uUart_rx_seg_0/cst
add wave -radix unsigned /tb_uart_rx_seg/uUart_rx_seg_0/bit_clear
add wave -radix unsigned /tb_uart_rx_seg/uUart_rx_seg_0/bit_midcap
add wave -radix unsigned /tb_uart_rx_seg/uUart_rx_seg_0/bit_start
add wave -radix bin /tb_uart_rx_seg/uUart_rx_seg_0/rx_data
add wave -radix ascii /tb_uart_rx_seg/uUart_rx_seg_0/rx_data
run 250us
4) Simulation.
5) Verification with De1-SoC Board & Tera-term.
module uart_rx_seg(
input clk,
input reset_n,
input rx,
output seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g,
output seg_h, seg_i, seg_j, seg_k, seg_l, seg_m, seg_n,
output tx
);
localparam IDLE = 0;
localparam START = 1;
localparam MID = 2;
localparam D0 = 3;
localparam D1 = 4;
localparam D2 = 5;
localparam D3 = 6;
localparam D4 = 7;
localparam D5 = 8;
localparam D6 = 9;
localparam D7 = 10;
localparam STOP0 = 11;
localparam STOP1 = 12;
reg dly0, dly1;
reg [8:0] count = 9'b0;
reg [3:0] cst = 4'b0;
reg [3:0] nst;
reg [7:0] rx_data;
assign tx = rx;
assign f_det = ~dly0 & dly1;
always@(posedge clk, negedge reset_n) begin
if(!reset_n) begin
dly0 <= 0;
dly1 <= 0;
end else begin
dly0 <= rx;
dly1 <= dly0;
end
end
wire bit_clear = (count == 433);
wire bit_midcap = (count == 216) && (cst == START);
wire bit_start = f_det && (cst == IDLE);
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
count <= 9'b0;
else if(bit_clear)
count <= 9'b0;
else if(bit_midcap)
count <= 9'b0;
else if(bit_start)
count <= 9'b0;
else
count <= count + 9'b1;
end
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
cst <= IDLE;
else
cst <= nst;
end
always@(*) begin
case(cst)
IDLE : if(bit_start ) nst = START ; else nst = IDLE ;
START : if(bit_midcap) nst = MID ; else nst = START ;
MID : if(bit_clear ) nst = D0 ; else nst = MID ;
D0 : if(bit_clear ) nst = D1 ; else nst = D0 ;
D1 : if(bit_clear ) nst = D2 ; else nst = D1 ;
D2 : if(bit_clear ) nst = D3 ; else nst = D2 ;
D3 : if(bit_clear ) nst = D4 ; else nst = D3 ;
D4 : if(bit_clear ) nst = D5 ; else nst = D4 ;
D5 : if(bit_clear ) nst = D6 ; else nst = D5 ;
D6 : if(bit_clear ) nst = D7 ; else nst = D6 ;
D7 : if(bit_clear ) nst = STOP0 ; else nst = D7 ;
STOP0 : if(bit_clear ) nst = STOP1 ; else nst = STOP0 ;
STOP1 : if(bit_clear ) nst = IDLE ; else nst = STOP1 ;
endcase
end
always@(posedge clk, negedge reset_n) begin
if(!reset_n)
rx_data <= 8'b0;
else if(count == 0) begin
case(cst)
D0 : rx_data[0] <= rx;
D1 : rx_data[1] <= rx;
D2 : rx_data[2] <= rx;
D3 : rx_data[3] <= rx;
D4 : rx_data[4] <= rx;
D5 : rx_data[5] <= rx;
D6 : rx_data[6] <= rx;
D7 : rx_data[7] <= rx;
endcase
end
end
uart_7seg_controller uUart_7seg_controller_0(
.inp_data (rx_data[3:0] ),
.seg_a (seg_a ),
.seg_b (seg_b ),
.seg_c (seg_c ),
.seg_d (seg_d ),
.seg_e (seg_e ),
.seg_f (seg_f ),
.seg_g (seg_g )
);
uart_7seg_controller uUart_7seg_controller_1(
.inp_data (rx_data[7:4] ),
.seg_a (seg_h ),
.seg_b (seg_i ),
.seg_c (seg_j ),
.seg_d (seg_k ),
.seg_e (seg_l ),
.seg_f (seg_m ),
.seg_g (seg_n )
);
endmodule
'Verilog Projects' 카테고리의 다른 글
Morse Code Generator. (0) | 2023.12.17 |
---|---|
Avalon Bus : GPIO (0) | 2023.11.12 |
Avalon Bus : PWM (0) | 2023.11.12 |
Avalon Bus Modeling. (1) | 2023.11.12 |
8-Bit Multiplier. (0) | 2023.10.28 |