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 採樣模組
  1. `define BPS_115200
  2. `define CLK_PERIORD 20 // define periord is 20ns(50MHz)
  3. `define BPS_SET 1152 // define baudrate is 115200bps
  4.  
  5. `define BPS_PARA (10_000_000/`CLK_PERIORD/`BPS_SET)
  6. // bit width count = 1/115200/20(ns)
  7. // = 1000_000_000/115200/20(sec)
  8. // = 10_000_000/CLK_PERIORD/BPS_SET;
  9. `define BPS_PARA_2 (`BPS_PARA/2)
  10. // BPS_PARA/2;
  11. // sample frequency is 2 * baud-rate
  12.  
  13. //-----------------------------------------------------------
  14. // function : bit width counter
  15. // input : ext_clk (clock) 50MHz
  16. // : ext_rst_n (reset)
  17. // output : cnt
  18. //-----------------------------------------------------------
  19. reg[12:0] cnt; // sample counter
  20. reg[2:0] uart_ctrl; // uart baud-rate select register
  21.  
  22. always @ (posedge clk or negedge rst_n)
  23. if(!rst_n) cnt <= 13'd0;
  24. else if((cnt == `BPS_PARA) || !bps_start)
  25. cnt <= 13'd0; // clear sample counter
  26. else cnt <= cnt+1'b1; // counting sample
  27.  
  28. //-----------------------------------------------------------
  29. // function : bit sample counter (middle of bit)
  30. // input : ext_clk (clock) 50MHz
  31. // : ext_rst_n (reset)
  32. // output : clk_bps_r
  33. //-----------------------------------------------------------
  34. reg clk_bps_r; // baud-rate register
  35.  
  36. always @ (posedge clk or negedge rst_n)
  37. if(!rst_n) clk_bps_r <= 1'b0;
  38. else if(cnt == `BPS_PARA_2)
  39. clk_bps_r <= 1'b1; // sample on middle of clock
  40. else clk_bps_r <= 1'b0;
  41.  
  42. assign clk_bps = clk_bps_r;
Rx 的模組
  1. //-----------------------------------------------------------
  2. // function : bit debounce
  3. // input : ext_clk (clock) 50MHz
  4. // : ext_rst_n (reset)
  5. // output : neg_uart_rx
  6. //-----------------------------------------------------------
  7. reg uart_rx0,uart_rx1,uart_rx2,uart_rx3; // regiter for receiver
  8. wire neg_uart_rx; // sample data at falling edge
  9.  
  10. always @ (posedge clk or negedge rst_n)
  11. if(!rst_n) begin
  12. uart_rx0 <= 1'b0;
  13. uart_rx1 <= 1'b0;
  14. uart_rx2 <= 1'b0;
  15. uart_rx3 <= 1'b0;
  16. end
  17. else begin
  18. uart_rx0 <= uart_rx;
  19. uart_rx1 <= uart_rx0;
  20. uart_rx2 <= uart_rx1;
  21. uart_rx3 <= uart_rx2;
  22. end
  23.  
  24. // falling edge to debounce 40ns-80ns noise
  25. // neg_uart_rx active when data receiving
  26. assign neg_uart_rx = uart_rx3 & uart_rx2 & ~uart_rx1 & ~uart_rx0;
  27.  
  28. //-----------------------------------------------------------
  29. // function : bit debounce
  30. // input : ext_clk (clock) 50MHz
  31. // : ext_rst_n (reset)
  32. // output : neg_uart_rx
  33. //-----------------------------------------------------------
  34. reg bps_start_r; // bit start receive
  35. reg[3:0] num; // bit shift times
  36.  
  37. always @ (posedge clk or negedge rst_n)
  38. if(!rst_n) begin
  39. bps_start_r <= 1'bz;
  40. rx_int <= 1'b0;
  41. end
  42. else if(neg_uart_rx) begin // receive falling edge trigger
  43. bps_start_r <= 1'b1; // start receiver
  44. rx_int <= 1'b1; // enable receiver interrput
  45. end
  46. else if(num == 4'd9) begin // receiver complete
  47. bps_start_r <= 1'b0; // clear start flag
  48. rx_int <= 1'b0; // disable receiver interrupt
  49. end
  50.  
  51. assign bps_start = bps_start_r;
  52.  
  53. //-----------------------------------------------------------
  54. // function : receive UART data and store to
  55. // input : ext_clk (clock) 50MHz
  56. // : ext_rst_n (reset)
  57. // output : rx_data_r
  58. //-----------------------------------------------------------
  59. reg[7:0] rx_data_r; // receiver buffer unteil next receive
  60. reg[7:0] rx_temp_data; // receiver data buffer
  61.  
  62. always @ (posedge clk or negedge rst_n)
  63. if(!rst_n) begin
  64. rx_temp_data <= 8'd0;
  65. num <= 4'd0;
  66. rx_data_r <= 8'd0;
  67. end
  68. else if(rx_int) begin // receivr handle
  69. if(clk_bps) begin // read data and store
  70. // receive 1 start bit, 8 data bits and 1-2 stop bits
  71. num <= num+1'b1;
  72. case (num)
  73. 4'd1: rx_temp_data[0] <= uart_rx; // store bit 0
  74. 4'd2: rx_temp_data[1] <= uart_rx; // store bit 1
  75. 4'd3: rx_temp_data[2] <= uart_rx; // store bit 2
  76. 4'd4: rx_temp_data[3] <= uart_rx; // store bit 3
  77. 4'd5: rx_temp_data[4] <= uart_rx; // store bit 4
  78. 4'd6: rx_temp_data[5] <= uart_rx; // store bit 5
  79. 4'd7: rx_temp_data[6] <= uart_rx; // store bit 6
  80. 4'd8: rx_temp_data[7] <= uart_rx; // store bit 7
  81. default: ;
  82. endcase
  83. end
  84. else if(num == 4'd9) begin // check data valid
  85. num <= 4'd0; // clear data counter
  86. rx_data_r <= rx_temp_data; // store to rx_data
  87. end
  88. end
  89.  
  90. assign rx_data = rx_data_r;
  91.  
Tx 的模組
  1. //-----------------------------------------------------------
  2. // function : bit debounce
  3. // input : ext_clk (clock) 50MHz
  4. // : ext_rst_n (reset)
  5. // output : neg_rx_int
  6. //-----------------------------------------------------------
  7. reg rx_int0,rx_int1,rx_int2; // rx_int fall edge register
  8. wire neg_rx_int; // rx_int fall edge trigger
  9.  
  10. always @ (posedge clk or negedge rst_n)
  11. if(!rst_n) begin
  12. rx_int0 <= 1'b0;
  13. rx_int1 <= 1'b0;
  14. rx_int2 <= 1'b0;
  15. end
  16. else begin
  17. rx_int0 <= rx_int;
  18. rx_int1 <= rx_int0;
  19. rx_int2 <= rx_int1;
  20. end
  21.  
  22. // capture falling edge, neg_rx_int hold 1 clock
  23. assign neg_rx_int = ~rx_int1 & rx_int2;
  24.  
  25. //-----------------------------------------------------------
  26. // function : Enable and start data transmit
  27. // input : ext_clk (clock) 50MHz
  28. // : ext_rst_n (reset)
  29. // output : bps_start_t
  30. //-----------------------------------------------------------
  31. reg[7:0] tx_data; // Transmit data buffer
  32. reg bps_start_t; // Start Transmit data
  33. reg tx_en; // Transmit enable
  34. reg[3:0] num; // Transmit bit count
  35.  
  36. always @ (posedge clk or negedge rst_n)
  37. if(!rst_n) begin
  38. bps_start_t <= 1'bz;
  39. tx_en <= 1'b0;
  40. tx_data <= 8'd0;
  41. end
  42. else if(neg_rx_int) begin // receive complete and ready to trnsmit
  43. bps_start_t <= 1'b1; // start transmit
  44. tx_data <= rx_data; // store receive data to
  45. tx_en <= 1'b1; // enable data transmit
  46. end
  47. else if(num == 4'd10) begin // transmit complete
  48. bps_start_t <= 1'b0; // stop transmit
  49. tx_en <= 1'b0; // disable data transmit
  50. end
  51.  
  52. assign bps_start = bps_start_t;
  53.  
  54. //-----------------------------------------------------------
  55. // function : bit debounce
  56. // input : ext_clk (clock) 50MHz
  57. // : ext_rst_n (reset)
  58. // output : neg_uart_rx
  59. //-----------------------------------------------------------
  60. reg uart_tx_t;
  61.  
  62. always @ (posedge clk or negedge rst_n)
  63. if(!rst_n) begin
  64. num <= 4'd0;
  65. uart_tx_t <= 1'b1;
  66. end
  67. else if(tx_en) begin
  68. if(clk_bps) begin
  69. num <= num+1'b1;
  70. case (num)
  71. 4'd0: uart_tx_t <= 1'b0; // start transmot
  72. 4'd1: uart_tx_t <= tx_data[0]; // send bit 0
  73. 4'd2: uart_tx_t <= tx_data[1]; // send bit 1
  74. 4'd3: uart_tx_t <= tx_data[2]; // send bit 2
  75. 4'd4: uart_tx_t <= tx_data[3]; // send bit 3
  76. 4'd5: uart_tx_t <= tx_data[4]; // send bit 4
  77. 4'd6: uart_tx_t <= tx_data[5]; // send bit 5
  78. 4'd7: uart_tx_t <= tx_data[6]; // send bit 6
  79. 4'd8: uart_tx_t <= tx_data[7]; // send bit 7
  80. 4'd9: uart_tx_t <= 1'b1; // end transmit
  81. default: uart_tx_t <= 1'b1;
  82. endcase
  83. end
  84. else if(num == 4'd10) num <= 4'd0; // reset
  85. end
  86.  
  87. assign uart_tx = uart_tx_t;

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

留言

這個網誌中的熱門文章

EC 所需知識 - SMBUS

EC 所需知識 - KBC

EC 所需知識 - LPC