FPGA sample - 如何使用 UART loopback 驗證

在範例中,使用 Intel MAX 10 core board 上的 CP1202 , 把系統的 USB 資料轉成 UART 的資料, 再由 FPGA 的 RX 接收, 再由 TX 傳送給系統的 USB.

硬體方塊圖
在硬體方面,只需要把 intel MAX 10 core board 的 mini USB 連接到 Notebook 就完成了. 因為在 intel MAX 10 core board 內有 CP2102 是一個 USB COM 的晶片, 所以當 intel MAX 10 core board 連接到 notebook, 就會建立一個 COM.


Notebook 就可以透過 COM 和 intel MAX 10 core board 溝通.

FPGA 程式碼方塊圖
Notebook 由 Termite 應用程式輸入資料,經過 USB COM(CP2102) 傳送到 FPGA Rx 程式模組, 經過 40ns (2 clock) 除雜訊功能,開始接收資料, start 由高阻抗變成高電位, int 也同樣變成高電位.啟動 Rx Config 採樣模組,在採樣點(資料位元的中心點), bps 就會變成高電位, Rx 模組讀取資料放到 Rx data 陣列. 直到資料接收完整, start 變成低電位, int 也同時變成低電位.

當 int 變成高電位,Tx 模組經過 20ns (1 clock) 除雜訊功能,開始計數接收資料,直到資料接收完整,啟動 Tx Config 傳送定位模組, 在資料定位點(資料位元的結束點), bps 會變成高電位,Tx 模組傳送資料到 notebook.



Rx/Tx Config 採樣模組
 
`define BPS_115200
`define CLK_PERIORD  20 // define periord is 20ns(50MHz)
`define BPS_SET    1152 // define baudrate is 115200bps

`define BPS_PARA   (10_000_000/`CLK_PERIORD/`BPS_SET)
       // bit width count = 1/115200/20(ns)
       // = 1000_000_000/115200/20(sec)
       // = 10_000_000/CLK_PERIORD/BPS_SET;
`define BPS_PARA_2   (`BPS_PARA/2)
       // BPS_PARA/2;
       // sample frequency is 2 * baud-rate

//-----------------------------------------------------------
// function      : bit width counter
// input       : ext_clk (clock) 50MHz
//       : ext_rst_n (reset)
// output     : cnt
//-----------------------------------------------------------
reg[12:0] cnt;    // sample counter
reg[2:0] uart_ctrl;   // uart baud-rate select register

always @ (posedge clk or negedge rst_n)
 if(!rst_n)     cnt <= 13'd0;
 else if((cnt == `BPS_PARA) || !bps_start)
       cnt <= 13'd0;  // clear sample counter
 else      cnt <= cnt+1'b1; // counting sample

//-----------------------------------------------------------
// function      : bit sample counter (middle of bit)
// input       : ext_clk (clock) 50MHz
//       : ext_rst_n (reset)
// output     : clk_bps_r
//-----------------------------------------------------------
reg clk_bps_r;    // baud-rate register

always @ (posedge clk or negedge rst_n)
 if(!rst_n)     clk_bps_r <= 1'b0;
 else if(cnt == `BPS_PARA_2)
       clk_bps_r <= 1'b1; // sample on middle of clock
 else      clk_bps_r <= 1'b0;

assign clk_bps = clk_bps_r;
Rx 的模組
//-----------------------------------------------------------
// function     : bit debounce
// input      : ext_clk (clock) 50MHz
//      : ext_rst_n (reset)
// output    : neg_uart_rx
//-----------------------------------------------------------
reg uart_rx0,uart_rx1,uart_rx2,uart_rx3; // regiter for receiver
wire neg_uart_rx;  // sample data at falling edge

always @ (posedge clk or negedge rst_n)
 if(!rst_n) begin
  uart_rx0 <= 1'b0;
  uart_rx1 <= 1'b0;
  uart_rx2 <= 1'b0;
  uart_rx3 <= 1'b0;
 end
 else begin
  uart_rx0 <= uart_rx;
  uart_rx1 <= uart_rx0;
  uart_rx2 <= uart_rx1;
  uart_rx3 <= uart_rx2;
 end

// falling edge to debounce 40ns-80ns noise
// neg_uart_rx active when data receiving
assign neg_uart_rx = uart_rx3 & uart_rx2 & ~uart_rx1 & ~uart_rx0;

//-----------------------------------------------------------
// function     : bit debounce
// input      : ext_clk (clock) 50MHz
//       : ext_rst_n (reset)
// output     : neg_uart_rx
//-----------------------------------------------------------
reg bps_start_r;   // bit start receive
reg[3:0] num;    // bit shift times

always @ (posedge clk or negedge rst_n)
 if(!rst_n) begin
  bps_start_r <= 1'bz;
  rx_int <= 1'b0;
 end
 else if(neg_uart_rx) begin // receive falling edge trigger
  bps_start_r <= 1'b1; // start receiver
  rx_int <= 1'b1;   // enable receiver interrput
 end
 else if(num == 4'd9) begin // receiver complete
  bps_start_r <= 1'b0; // clear start flag
  rx_int <= 1'b0;   // disable receiver interrupt
 end

assign bps_start = bps_start_r;

//-----------------------------------------------------------
// function     : receive UART data and store to
// input      : ext_clk (clock) 50MHz
//       : ext_rst_n (reset)
// output     : rx_data_r
//-----------------------------------------------------------
reg[7:0] rx_data_r;   // receiver buffer unteil next receive
reg[7:0] rx_temp_data;  // receiver data buffer

always @ (posedge clk or negedge rst_n)
 if(!rst_n) begin
  rx_temp_data <= 8'd0;
  num <= 4'd0;
  rx_data_r <= 8'd0;
 end
 else if(rx_int) begin // receivr handle
   if(clk_bps) begin // read data and store
        // receive 1 start bit, 8 data bits and 1-2 stop bits
    num <= num+1'b1;
    case (num)
     4'd1: rx_temp_data[0] <= uart_rx; // store bit 0
     4'd2: rx_temp_data[1] <= uart_rx; // store bit 1
     4'd3: rx_temp_data[2] <= uart_rx; // store bit 2
     4'd4: rx_temp_data[3] <= uart_rx; // store bit 3
     4'd5: rx_temp_data[4] <= uart_rx; // store bit 4
     4'd6: rx_temp_data[5] <= uart_rx; // store bit 5
     4'd7: rx_temp_data[6] <= uart_rx; // store bit 6
     4'd8: rx_temp_data[7] <= uart_rx; // store bit 7
     default: ;
    endcase
   end
   else if(num == 4'd9) begin  // check data valid
    num <= 4'd0;    // clear data counter
    rx_data_r <= rx_temp_data; // store to rx_data
   end
 end

assign rx_data = rx_data_r;

Tx 的模組
//-----------------------------------------------------------
// function     : bit debounce
// input      : ext_clk (clock) 50MHz
//      : ext_rst_n (reset)
// output    : neg_rx_int
//-----------------------------------------------------------
reg rx_int0,rx_int1,rx_int2; // rx_int fall edge register
wire neg_rx_int;   // rx_int fall edge trigger

always @ (posedge clk or negedge rst_n)
 if(!rst_n) begin
  rx_int0 <= 1'b0;
  rx_int1 <= 1'b0;
  rx_int2 <= 1'b0;
 end
 else begin
  rx_int0 <= rx_int;
  rx_int1 <= rx_int0;
  rx_int2 <= rx_int1;
 end

// capture falling edge, neg_rx_int hold 1 clock
assign neg_rx_int = ~rx_int1 & rx_int2;

//-----------------------------------------------------------
// function     : Enable and start data transmit
// input      : ext_clk (clock) 50MHz
//      : ext_rst_n (reset)
// output    : bps_start_t
//-----------------------------------------------------------
reg[7:0] tx_data;   // Transmit data buffer
reg bps_start_t;   // Start Transmit data
reg tx_en;    // Transmit enable
reg[3:0] num;   // Transmit bit count

always @ (posedge clk or negedge rst_n)
 if(!rst_n) begin
  bps_start_t <= 1'bz;
  tx_en <= 1'b0;
  tx_data <= 8'd0;
 end
 else if(neg_rx_int) begin  // receive complete and ready to trnsmit
  bps_start_t <= 1'b1;  // start transmit
  tx_data <= rx_data;  // store receive data to
  tx_en <= 1'b1;   // enable data transmit
 end
 else if(num == 4'd10) begin // transmit complete
  bps_start_t <= 1'b0;  // stop transmit
  tx_en <= 1'b0;   // disable data transmit
 end

assign bps_start = bps_start_t;

//-----------------------------------------------------------
// function     : bit debounce
// input      : ext_clk (clock) 50MHz
//      : ext_rst_n (reset)
// output    : neg_uart_rx
//-----------------------------------------------------------
reg uart_tx_t;

always @ (posedge clk or negedge rst_n)
 if(!rst_n) begin
  num <= 4'd0;
  uart_tx_t <= 1'b1;
 end
 else if(tx_en) begin
   if(clk_bps) begin
    num <= num+1'b1;
    case (num)
     4'd0: uart_tx_t <= 1'b0;   // start transmot
     4'd1: uart_tx_t <= tx_data[0]; // send bit 0
     4'd2: uart_tx_t <= tx_data[1]; // send bit 1
     4'd3: uart_tx_t <= tx_data[2]; // send bit 2
     4'd4: uart_tx_t <= tx_data[3]; // send bit 3
     4'd5: uart_tx_t <= tx_data[4]; // send bit 4
     4'd6: uart_tx_t <= tx_data[5]; // send bit 5
     4'd7: uart_tx_t <= tx_data[6]; // send bit 6
     4'd8: uart_tx_t <= tx_data[7]; // send bit 7
     4'd9: uart_tx_t <= 1'b1;  // end transmit
     default: uart_tx_t <= 1'b1;
    endcase
   end
   else if(num == 4'd10) num <= 4'd0;  // reset
 end

assign uart_tx = uart_tx_t;

範例程式位於 Github 的 FPGA-Bus-Uart-Loopback-sample

留言

這個網誌中的熱門文章

EC 所需知識 - SMBUS

EC 所需知識 - KBC

EC 所需知識 - LPC