본문 바로가기

Verilog Projects

UART.

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 Data format

 

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.

LSB first, 0101 1000

 

5) Verification with Tera-term.

pin planner, programer, 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.

ASCII 'X'
ASCII 'A'

 

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