본문 바로가기

[Harman] 반도체 설계/Quartus

Quartus II project - Simple Uart Rx.

 

Internal Loop-Back : 이전에 설계했던 SimpleUartTx 의 ASCII code 'X' 를 Rx 가 제대로 수신하는지만 확인한다. (Simulation Only)


Clk : DE1 - SoC Board 의 default freqency 는 50Mhz 로 20ns 의 Clock Period 를 가진다. Bit Rate 115200bps 를 만족하기 위해선 1 Bit 를 전송할 때, 8680ns 가 필요하고 20ns 의 주기가 434 cycles 유지되어야 한다. 

f_det : Uart 는 기본적으로 IDLE 과 STOP 에서 1, START 에서 0 의 값을 가진다. Clock Signal 이 존재하는 않는 Asychronous system 에서 Data 의 송수신이 이뤄지기 위해 START 와 STOP 이 필요하고 START 를 알리는 F_det 을 설계했다.   

 

f_det


Cap : Tx 에서 전송된 DATA 를 안정적으로 받기 위해 DATA 의 중간 값을 Capture 한다. 이를 위해 START 에서 20ns 의 주기를 217 cycles 동안 유지하고 (4340ns) MID 상태를 추가했다. (clk_count == 216) 에서 Tx_cst 의 mid 값을 capture 하고 Rx_cst 는 다음 state 로 이동한다.   

 

Capture mid value


Data bit : 217 cycles 이 지나면 start bit capture (#4340), 이후에는 동일하게 434 count 를 진행하면서 d0, d1 ~ d7 를 capture 한다.

initial reset_n
reset_n = 1

module simple_uart_rx(
    input clk,
    input reset_n,
    input rx,
    output reg [7:0] rx_data
);
    localparam  idle = 0,
                start = 1,
                mid = 2,
                d0 = 3,
                d1 = 4,
                d2 = 5,
                d3 = 6,
                d4 = 7,
                d5 = 8,
                d6 = 9,
                d7 = 10,
                stop = 11,
                stop_1 = 12;

   reg rx_delay1, rx_delay2;
   reg [3:0] cst = 0;
   reg [3:0] nst;
   reg [8:0] clk_count = 9'd0;
   
   wire bit_clr = (clk_count == 433);
   wire bit_cap = ((clk_count == 216) && (cst == start));
   // capture mid value in start state
   
   // falling edge detected 
   always @(posedge clk, negedge reset_n) begin
      if(!reset_n) begin
         rx_delay1 <= 0;
         rx_delay2 <= 0;
      end
      else begin
         rx_delay1 <= rx;
         rx_delay2 <= rx_delay1;
      end
   end
   
   assign f_det = ~rx_delay1 & rx_delay2;
   
   // 217, 434 clk counter
   always @(posedge clk, negedge reset_n) begin
      if(!reset_n) begin
         clk_count <= 9'd0;      
      end
      else if((f_det && (cst == idle)) || bit_clr || bit_cap) begin
         clk_count <= 9'd0;
      end
      else begin
         clk_count <= clk_count + 9'd1;
      end
   end
   
   // state variation 
   always @(posedge clk, negedge reset_n) begin 
      if(!reset_n) begin
         cst <= idle;
      end
      else if(f_det && (cst == idle)) begin
      // line 60 : if f_det is '1' in idle state, move to start state
         cst <= start;
      end
      else if(!f_det && (cst == idle)) begin
      // line 63: keep its idle state if f_det is not '1'
         cst <= idle;
      end      
      else if(bit_clr || bit_cap) begin // bit_cap : idle -> start
         cst <= nst; // bit_clr
      end
   end
   
   // next state
   always @(*) begin 
      case (cst)
         idle : nst = idle; // line 63
         start : nst = mid; // line 60
         mid : nst = d0;
         d0 : nst = d1;
         d1 : nst = d2;
         d2 : nst = d3;
         d3 : nst = d4;
         d4 : nst = d5;
         d5 : nst = d6;
         d6 : nst = d7;
         d7 : nst = stop;
         stop : nst = stop_1; 
         default: nst = idle;
      endcase
   end
   
   // output
   always @(posedge clk, negedge reset_n) begin
      if (!reset_n)
         rx_data = 9'd0;
      else if (clk_count == 9'd0) begin
      // moore machine, prevent value changes in rx cst
         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

endmodule
`include "../simple_uart_rx/simple_uart_rx.v"
`include "../simple_uart_tx/simple_uart_tx.v"

module simple_uart(
   input clk,
   input reset_n,
   output [7:0] rx_data
);

   wire w_uart; 
   
   simple_uart_tx uSimple_uart_tx_0(
      .clk(clk),
      .reset_n(reset_n),
      .tx(w_uart)
   );
   
   simple_uart_rx uSimple_uart_rx_0(
      .clk(clk),
      .reset_n(reset_n),
      .rx(w_uart),
      .rx_data(rx_data)
   );
   
endmodule   
`timescale 1 ns / 1 ns 

module simple_uart_tb();

   reg clk;
   reg reset_n;
   wire [7:0] rx_data;
   
   simple_uart uSimple_uart(
      .clk(clk),
      .reset_n(reset_n),
      .rx_data(rx_data)
   );
   
   initial begin
      clk = 1'b1;
      forever #10 clk = ~clk;
   end
   
   initial begin
      reset_n = 1'b1;
   end
   
endmodule

 

Data 8bit 를 받은 후에, ASCII 'X' 를 출력하고 Value 를 유지한다.

 

 

hex : 0x58

 

// tcl file

vlib work
vlog simple_uart.v simple_uart_tb.v
vsim simple_uart_tb
view wave 
add wave -radix bin           /clk
add wave -radix unsigned      /uSimple_uart/uSimple_uart_rx_0/clk_count
add wave -radix bin           /reset_n
add wave -radix bin           /uSimple_uart/uSimple_uart_tx_0/tx
add wave -radix unsigned      /uSimple_uart/uSimple_uart_tx_0/cst
add wave -radix bin           /uSimple_uart/uSimple_uart_rx_0/rx
add wave -radix bin           /uSimple_uart/uSimple_uart_rx_0/f_det
add wave -radix unsigned      /uSimple_uart/uSimple_uart_rx_0/cst
add wave -radix bin           /rx_data

run 130 us