当前位置:   article > 正文

IC/FPGA设计——跨时钟域处理之握手(1)

单比特握手跨时钟域电路图

点击上方“蓝字”,学习更多干货!

在数字电路中,跨时钟域处理是个很庞大的问题,因此将会作为一个专题来陆续分享。今天先来从处理单bit跨时钟域信号同步问题来入手。

01

握手(handshake)是用来处理单bit信号的跨时钟域传递的一个有效的方法。在从快时钟向慢时钟传递时,由于输入信号变化较快,输出一侧可能跟不上输入的变化,从而导致“漏采“现象。

图1 “漏采”现象演示

在图1中,由于两个时钟的速度差距,来自快时钟域的脉冲信号还未到达慢时钟的采样边沿便消失了,导致了“漏采”。

在这种情况下,如何让脉冲信号准确无误地传递过去呢?一个方法是将脉冲信号展宽,待输出一侧检测到信号并将其解析为脉冲信号后,再向输入一侧发送应答信号,表明接收到信号并且传输完成。这个过程被称之为“握手”。

02

先来看一个最基本的握手协议,下边是它的电路图。                                                     

图2   “握手”电路演示

在上图中 src_clk和dst_clk分别为输入和输出侧的时钟,src_pulse为输入的脉冲信号,dst_pulse为同步到输出端的脉冲信号。可以看到,脉冲信号被同步到输出端后,输出端便立即向输入端发送了应答信号,表示收到信号。而当输出端的应答信号同步到输入端后,输入端才可以同步下一个信号。以下为这个电路的verilog描述。

  1. module Sync_Pulse (
  2. input wire src_clk,
  3. input wire dst_clk,
  4. input wire rst_n,
  5. input wire src_pulse,
  6. output wire dst_pulse
  7. );
  8. reg req_state_dly1, req_state_dly2,dst_req_state,src_sync_req;
  9. reg ack_state_dly1,src_sync_ack;
  10. wire dst_sync_ack;
  11. always @ (posedge src_clk or negedge rst_n)
  12. begin
  13. if (rst_n == 1'b0)
  14. src_sync_req <= 1'b0;
  15. else if (src_pulse)
  16. src_sync_req <= 1'b1;
  17. else if (src_sync_ack)
  18. src_sync_req <= 1'b0;
  19. else;
  20. end
  21. always @ (posedge dst_clk or negedge rst_n)
  22. begin
  23. if (rst_n == 1'b0)
  24. begin
  25. req_state_dly1 <= 1'b0;
  26. req_state_dly2 <= 1'b0;
  27. dst_req_state <= 1'b0;
  28. end else begin
  29. req_state_dly1 <= src_sync_req;
  30. req_state_dly2 <= req_state_dly1;
  31. dst_req_state <= req_state_dly2;
  32. end
  33. end
  34. assign dst_sync_ack = req_state_dly2;
  35. always @ (posedge src_clk or negedge rst_n)
  36. begin
  37. if (rst_n == 1'b0)
  38. begin
  39. ack_state_dly1 <= 1'b0;
  40. src_sync_ack <= 1'b0;
  41. end
  42. else
  43. begin
  44. ack_state_dly1 <= dst_sync_ack;
  45. src_sync_ack <= ack_state_dly1;
  46. end
  47. end
  48. assign dst_pulse = dst_req_state & (~req_state_dly2);
  49. endmodule

03

上述电路虽然可以完整的同步信号,但是若在同步一个脉冲的过程中,输入端又接收到一个输入进来的脉冲,那么此时刚刚输入进来的脉冲将会同步失败。更糟糕的是该电路没有同步失败的反馈,导致使用者误以为正确同步了信号。鉴于此,将上述电路进行改进,当同步失败后将输出src_sync_fail信号来指示同步失败。以下为该电路的verilog描述(此代码来源于网络):

  1. module handshake_pulse_sync
  2. (
  3. src_clk , //source clock
  4. src_rst_n , //source clock reset (0: reset)
  5. src_pulse , //source clock pulse in
  6. src_sync_fail , //source clock sync state: 1 clock pulse if sync fail.
  7. dst_clk , //destination clock
  8. dst_rst_n , //destination clock reset (0:reset)
  9. dst_pulse //destination pulse out
  10. );
  11. //PARA DECLARATION
  12. //INPUT DECLARATION
  13. input src_clk ; //source clock
  14. input src_rst_n ; //source clock reset (0: reset)
  15. input src_pulse ; //source clock pulse in
  16. input dst_clk ; //destination clock
  17. input dst_rst_n ; //destination clock reset (0:reset)
  18. //OUTPUT DECLARATION
  19. output src_sync_fail ; //source clock sync state: 1 clock pulse if sync fail.
  20. output dst_pulse ; //destination pulse out
  21. //INTER DECLARATION
  22. wire dst_pulse ;
  23. wire src_sync_idle ;
  24. reg src_sync_fail ;
  25. reg src_sync_req ;
  26. reg src_sync_ack ;
  27. reg ack_state_dly1 ;
  28. reg ack_state_dly2 ;
  29. reg req_state_dly1 ;
  30. reg req_state_dly2 ;
  31. reg dst_req_state ;
  32. reg dst_sync_ack ;
  33. //--========================MODULE SOURCE CODE==========================--
  34. //--=========================================--
  35. // DST Clock :
  36. // 1. generate src_sync_fail;
  37. // 2. generate sync req
  38. // 3. sync dst_sync_ack
  39. //--=========================================--
  40. assign src_sync_idle = ~(src_sync_req | src_sync_ack );
  41. //report an error if src_pulse when sync busy ;
  42. always @(posedge src_clk or negedge src_rst_n)
  43. begin
  44. if(src_rst_n == 1'b0)
  45. src_sync_fail <= 1'b0 ;
  46. else if (src_pulse & (~src_sync_idle))
  47. src_sync_fail <= 1'b1 ;
  48. else
  49. src_sync_fail <= 1'b0 ;
  50. end
  51. //set sync req if src_pulse when sync idle ;
  52. always @(posedge src_clk or negedge src_rst_n)
  53. begin
  54. if(src_rst_n == 1'b0)
  55. src_sync_req <= 1'b0 ;
  56. else if (src_pulse & src_sync_idle)
  57. src_sync_req <= 1'b1 ;
  58. else if (src_sync_ack)
  59. src_sync_req <= 1'b0 ;
  60. end
  61. always @(posedge src_clk or negedge src_rst_n)
  62. begin
  63. if(src_rst_n == 1'b0)
  64. begin
  65. ack_state_dly1 <= 1'b0 ;
  66. ack_state_dly2 <= 1'b0 ;
  67. src_sync_ack <= 1'b0 ;
  68. end
  69. else
  70. begin
  71. ack_state_dly1 <= dst_sync_ack ;
  72. ack_state_dly2 <= ack_state_dly1 ;
  73. src_sync_ack <= ack_state_dly2 ;
  74. end
  75. end
  76. //--=========================================--
  77. // DST Clock :
  78. // 1. sync src sync req
  79. // 2. generate dst pulse
  80. // 3. generate sync ack
  81. //--=========================================--
  82. always @(posedge dst_clk or negedge dst_rst_n)
  83. begin
  84. if(dst_rst_n == 1'b0)
  85. begin
  86. req_state_dly1 <= 1'b0 ;
  87. req_state_dly2 <= 1'b0 ;
  88. dst_req_state <= 1'b0 ;
  89. end
  90. else
  91. begin
  92. req_state_dly1 <= src_sync_req ;
  93. req_state_dly2 <= req_state_dly1 ;
  94. dst_req_state <= req_state_dly2 ;
  95. end
  96. end
  97. //Rising Edge of dst_state generate a dst_pulse;
  98. assign dst_pulse = (~dst_req_state) & req_state_dly2 ;
  99. //set sync ack when src_req = 1 , clear it when src_req = 0 ;
  100. always @(posedge dst_clk or negedge dst_rst_n)
  101. begin
  102. if(dst_rst_n == 1'b0)
  103. dst_sync_ack <= 1'b0;
  104. else if (req_state_dly2)
  105. dst_sync_ack <= 1'b1;
  106. else
  107. dst_sync_ack <= 1'b0;
  108. end
  109. endmodule

从代码可以得知,在同步信号的过程中,src_sync_idle会拉低,此时若再有输入脉冲,则会输出同步失败信号。

仿真结果如下

图3 电路仿真结果

从仿真结果可以看到,该设计达到了同步信号要求。

对该部分有兴趣的,或者有问题想要探讨,欢迎点击“阅读原文”进行留言,也可以直接向公众号发送消息,欢迎大家的来信!

最后,创作不易,如果对你有帮助的话,点个“在看”再走呗!

IC/FPGA设计之分频器设计及Verilog代码(1)

IC/FPGA设计之分频器设计及Verilog代码(2)

IC/FPGA设计之复杂序列检测

你点的每个赞,我都认真当成了喜欢

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号