当前位置:   article > 正文

跨时钟域总结

跨时钟域

       亚稳态介绍:

        亚稳态是指在设计的正常运行过程中,信号在一定时间内不能达到稳定的0或者1的现象。由于同步系统中,数据与时钟存在固定的关系,其输入信号满足触发器的时序要求,即建立时间和保持时间,所以不会发送亚稳态现象;而对于异步系统,数据与时钟关系不固定,当出现不满足建立时间和保持时间的现象时,就会输出亚稳态,输出介于0和1之间的不定态。

         举例:输入信号(src_data_out)在源时钟域(src_clk)的亚稳态窗内发生了变化,在另一个时钟域(dest_clk)对该输入信号采样时,就会导致输出出现亚稳态(dest_data_out)。

        所谓亚稳态窗,就是建立时间+保持时间

        另:在异步复位中,如果复位信号不满足removal time和recovery time也会出现亚稳态。 

        而对于容易出现亚稳态现象的电路则需要进行跨时钟域处理。

        跨时钟域介绍:

         跨时钟域主要目的是保证数据从A时钟到B时钟的正确传递,其发生于多时钟域下,包含以下关系:

        1. 时钟频率不同;

        2. 时钟频率相同,但相位不同;

         跨时钟域信号的传输分为两类:

        1. 控制信号的传输(单bit信号)

        2. 数据信号的传输(多bit信号)

        其中,控制信号的传输分为从快时钟域到慢时钟域的传输,慢时钟域到快时钟域的传输。

        慢时钟域到快时钟域的传输——延迟打拍:

        此类传输可直接使用两级触发器进行缓存即可,因为理论上,快时钟域总会采集到慢时钟域的信号;在快时钟域下,对慢时钟域的信号进行连续缓存两次,可有效降低因建立时间和保持时间的不满足而导致的亚稳态问题。

  1. RTL code:
  2. module pulse_syn_slow2f(
  3. input clk_f,clk_s,rst_n,signal_slow,
  4. output signal_fast
  5. );
  6. reg signal_fast_r, signal_fast_rr;
  7. always @(posedge clk_f or negedge rst_n)begin
  8. if(!rst_n)begin
  9. signal_fast_r <= 1'b0;
  10. signal_fast_rr <= 1'b0;
  11. end
  12. else begin
  13. signal_fast_r <= signal_slow;
  14. signal_fast_rr <= signal_fast_r;
  15. end
  16. end
  17. //上升沿检测
  18. assign signal_fast = !signal_fast_rr && signal_fast_r;
  19. /*
  20. 下降沿检测
  21. assign signal_fast = signal_fast_rr && !signal_fast_r;
  22. */
  23. endmodule

         快时钟域到慢时钟域的传输——握手传输:

        此类情况,容易出现在慢时钟域中无法采集到快时钟域的信号,可采用握手传输的方式进行跨时钟域处理。

        原理:

        1. 在快时钟域下,对输入的脉冲信号进行检测,检测到输入的脉冲信号后,输出一个高电平信号,不急于将信号拉低,保持高电平状态;
        2. 在慢时钟域下,对快时钟域下输出的高电平信号进行延迟打拍采样;
        3. 在慢时钟域下,确认得到高电平信号后,输出反馈信号给快时钟域;
        4. 快时钟域对反馈信号进行延迟打拍采样,确认接收到反馈信号,拉低输出的高电平信号;

  1. RTL code:
  2. module pulse_syn_fast2s
  3. #(parameter pulse_init = 1'b0)(
  4. input rst_n,clk_fast,pulse_fast,clk_slow,
  5. output pulse_slow);
  6. wire clear_n;
  7. reg pulse_fast_r;
  8. //(1)快时钟域对脉冲信号检测,并不急于将信号拉低,保持输出信号为高电平状态
  9. always @(posedge clk_fast or negedge rst_n)begin
  10. if(!rst_n)
  11. pulse_fast_r <= pulse_init;
  12. else if(!clear_n)
  13. pulse_fast_r <= 1'b0;
  14. else if(pulse_fast)
  15. pulse_fast_r <= 1'b1;
  16. end
  17. //(2)慢时钟域下对信号进行延迟打拍采样
  18. reg [1:0] pulse_fast2s_r;
  19. always @(posedge clk_slow or negedge rst_n)begin
  20. if(!rst_n)
  21. pulse_fast2s_r <= 2'b0;
  22. else
  23. pulse_fast2s_r <= {pulse_fast2s_r[0],pulse_fast_r};
  24. end
  25. assign pulse_slow = pulse_fast2s_r[1];
  26. //(3)快时钟域下对慢时钟域的反馈信号延迟打拍采样
  27. reg [1:0] pulse_slow2f_r;
  28. always @(posedge clk_fast or negedge rst_n)begin
  29. if(!rst_n)
  30. pulse_slow2f_r <= 2'b0;
  31. else
  32. pulse_slow2f_r <= {pulse_slow2f_r[0],pulse_slow};
  33. end
  34. //(4)拉低快时钟域脉冲信号
  35. assign clear_n = ~(!pulse_fast && pulse_slow2f_r[1]);
  36. endmodule

        数据信号的传输(多bit信号)——异步FIFO:

        多位宽数据的异步传输问题,无论是从快时钟到慢时钟,还是从慢时钟到快时钟,
都可以用 FIFO 处理。

        异步FIFO系统框图:

        FIFO设计的几个关键点:

        1. FIFO空满的判断:

        增加1位标志位,因为FIFO是一种回卷式的读写,将标志位和地址位结合,可进行FIFO空满的判断;假设:读地址和写地址都指向同样的位置,即最高位相同,rdaddr==wraddr,可判断出FIFO此时的状态为读空;若读写地址的最高位不同,其余位相同,即rdaddr[N]==wraddr[N];  rdaddr[N-1:0]==wraddr[N-1:0]; 此时可判断出FIFO状态为写满;写地址比读地址大出一个FIFO深度。在读写吞吐量相同情况下,FIFO深度=写入数据个数-读出数据个数。

        FIFO满条件:                                                     

           FIFO空条件:

        2. 格雷码和二进制码的相互转换:

        因为格雷码本身的性质,即格雷码相邻两个状态之间只有单比特信号发生跳变,其余信号不变。因此,在FIFO中,地址总线可以先转换成格雷码,再进行两级触发器对格雷码地址进行同步,其误码概率与单比特信号的跨时钟域转换是一致的。

        格雷码转二进制:

  1. bin[3]=gray[3]
  2. bin[2]=gray[3]^gray[2]
  3. bin[1]=gray[3]^gray[2]^gray[1]
  4. bin[0]=gray[3]^gray[2]^gray[1]^gray[0]
  5. RTL code:
  6. integer i
  7. always @(*)
  8. for(i=0;i<=size;i=i+1)
  9. bin[i] = ^(gray>>i);

        二进制转格雷码:

  1. gray[3]=bin[3]
  2. gray[2]=bin[2]^bin[3]
  3. gray[1]=bin[1]^bin[2]
  4. gray[0]=bin[0]^bin[1]
  5. RTL code
  6. assign gray = (bin>>1)^bin;

        注意:先将a时钟的地址格雷码编码,再用b时钟采样格雷码地址进行两级触发器缓存,最后用b时钟对暂存的格雷码地址进行译码。

  1. RTL code
  2. module async_fifo_16x16(
  3. //fifo_write
  4. wr_clk,wr_en,almost_full,full,wr_data,wr_reset,
  5. //fifo_read
  6. rd_clk,rd_en,almost_empty,empty,rd_data,rd_reset
  7. );
  8. /*************** parameter ************************/
  9. parameter ADDR_WIDTH = 4;
  10. parameter DATA_WIDTH = 16;
  11. parameter ALMOST_FULL_GAP = 3;//离满还有 ALMOST_FULL_GAP时,almost_full有效
  12. parameter ALMOST_EMPTY_GAP = 3;//离空还有ALMOST_EMPTY_GAP时,almost_empty有效
  13. parameter FIFO_DEEP = 16;
  14. input wr_reset;//wr_clk 下的复位
  15. input wr_clk;
  16. input wr_en;
  17. input [DATA_WIDTH-1:0] wr_data;
  18. output almost_full;
  19. output full;
  20. input rd_reset;
  21. input rd_clk;
  22. input rd_en;
  23. output almost_empty;
  24. output empty;
  25. output [DATA_WIDTH-1:0] rd_data;
  26. /*********************** wire && reg ********************/
  27. wire [DATA_WIDTH-1:0] wr_addr;
  28. wire [DATA_WIDTH-1:0] rd_addr;
  29. wire [DATA_WIDTH-1:0] data_out_temp;//FIFO读出数据
  30. reg [ADDR_WIDTH:0] wr_gap;//写指针与读指针之间的间隔
  31. reg [ADDR_WIDTH:0] rd_gap;//读指针与写指针之间的间隔
  32. wire [DATA_WIDTH-1:0] rd_data;//fifo data output
  33. reg almost_full;//fifo almost full
  34. reg full;
  35. reg almost_empty;
  36. reg empty;
  37. reg [ADDR_WIDTH:0] waddr;//写地址,最高位为指针循环指示
  38. reg [ADDR_WIDTH:0] waddr_gray;//写地址格雷码
  39. reg [ADDR_WIDTH:0] waddr_gray_sync_dl;//写地址格雷码,同步到读时钟域
  40. reg [ADDR_WIDTH:0] waddr_gray_sync;
  41. reg [ADDR_WIDTH:0] raddr;//读地址,最高位为指针循环指示位
  42. reg [ADDR_WIDTH:0] raddr_gray;//读地址格雷码
  43. reg [ADDR_WIDTH:0] raddr_gray_sync_dl;//同步到写时钟域的读地址格雷码
  44. reg [ADDR_WIDTH:0] raddr_gray_sync;
  45. reg [ADDR_WIDTH:0] raddr_gray2bin;//读地址的二进制码
  46. reg [ADDR_WIDTH:0] waddr_gray2bin;//写地址的二进制码
  47. reg wen;//RAM写使能
  48. reg ren;//RAM读使能
  49. /************** 异步FIFO读/写地址的格雷码编码 ****************/
  50. //写控制逻辑
  51. //RAM写使能与地址
  52. assign wen = wr_en && (!full);
  53. //fifo write address generated
  54. always @(posedge wr_clk or posedge wr_reset)
  55. if(wr_reset)
  56. waddr <= {(ADDR_WIDTH+1){1'b0}};
  57. else if(wen)
  58. waddr <= waddr + 1'b1;
  59. assign wr_addr = waddr[ADDR_WIDTH-1:0];//写地址连接到RAM存储器
  60. //fifo write address : bin2gray
  61. always @(posedge wr_clk or posedge wr_reset)
  62. if(wr_reset)
  63. waddr_gray <= {(ADDR_WIDTH+1){1'b0}};
  64. else
  65. waddr_gray <= waddr ^ {1'b0,waddr[ADDR_WIDTH:1]};//原二进制码左移一位,高位补零,再与原二进制码进行异或
  66. //fifo read address gray sync to wr_clk
  67. always @(posedge wr_clk or posedge wr_reset)
  68. if(wr_reset)begin
  69. raddr_gray_sync <= {(ADDR_WIDTH+1){1'b0}};
  70. raddr_gray_sync_dl <= {(ADDR_WIDTH+1){1'b0}};
  71. end
  72. else begin
  73. raddr_gray_sync <= raddr_gray;
  74. raddr_gray_sync_dl <= raddr_gray_sync;
  75. end
  76. //读地址格雷码转变为二进制码
  77. always @(*)begin
  78. raddr_gray2bin = {
  79. raddr_gray_sync_dl[4],
  80. raddr_gray_sync_dl[4]^raddr_gray_sync_dl[3],
  81. raddr_gray_sync_dl[4]^raddr_gray_sync_dl[3]^raddr_gray_sync_dl[2],
  82. raddr_gray_sync_dl[4]^raddr_gray_sync_dl[3]^raddr_gray_sync_dl[2]^raddr_gray_sync_dl[1],
  83. raddr_gray_sync_dl[4]^raddr_gray_sync_dl[3]^raddr_gray_sync_dl[2]^raddr_gray_sync_dl[1]^raddr_gray_sync_dl[0]
  84. };
  85. end
  86. //写指针与读指针间隔计算
  87. /*wraddr和rdaddr最高位不等时,rdaddr[3:0]>wraddr[3:0],低4位直接相减即可*/
  88. /*wraddr和rdaddr最高位相等时,rdaddr[3:0]<wraddr[3:0],wraddr减去rdaddr得到
  89. 已经写入FIFO的数值,要得到还剩多少个就要满则必须由FIFO深度减去该值*/
  90. always @(*)begin
  91. if(raddr_gray2bin[4]^waddr[4])
  92. wr_gap = raddr_gray2bin[3:0]-waddr[3:0];
  93. else
  94. wr_gap = FIFO_DEEP + raddr_gray2bin - waddr;
  95. end
  96. //almost_full 信号产生
  97. always @(posedge wr_clk or posedge wr_reset)begin
  98. if(wr_reset)
  99. almost_full <= 1'b0;
  100. else begin
  101. if(wr_gap < ALMOST_FULL_GAP)begin
  102. almost_full <= 1'b1;
  103. end
  104. else
  105. almost_full <= 1'b0;
  106. end
  107. end
  108. //full 信号产生
  109. always @(posedge wr_clk or posedge wr_reset)
  110. if(wr_reset)
  111. full <= 1'b0;
  112. else
  113. full <= (!(|wr_gap)) || ((wr_gap==1)&wr_en);
  114. //异步FIFO读控制逻辑
  115. //RAM读使能
  116. assign ren = rd_en && (!empty);
  117. //FIFO读地址产生
  118. always @(posedge rd_clk or posedge rd_reset)
  119. if(rd_reset)
  120. raddr <= {(ADDR_WIDTH+1){1'b0}};
  121. else if(ren)
  122. raddr <= raddr + 1'b1;
  123. assign rd_addr = raddr[ADDR_WIDTH-1:0];//连接到FIFO内RAM存储器的读地址
  124. //写地址:bin2gray
  125. always @(posedge rd_clk or posedge rd_reset)
  126. if(rd_reset)
  127. raddr_gray <= {(ADDR_WIDTH+1){1'b0}};
  128. else
  129. raddr_gray <= raddr ^ {1'b0,raddr[ADDR_WIDTH:1]};
  130. //写地址同步到读时钟
  131. always @(posedge rd_clk or posedge rd_reset)begin
  132. if(rd_reset)begin
  133. waddr_gray_sync <= {(ADDR_WIDTH+1){1'b0}};
  134. waddr_gray_sync_dl <= {(ADDR_WIDTH+1){1'b0}};
  135. end
  136. else begin
  137. waddr_gray_sync <= waddr_gray;
  138. waddr_gray_sync_dl <= waddr_gray_sync;
  139. end
  140. end
  141. //写地址格雷码变成二进制
  142. always @(*)begin
  143. waddr_gray2bin = {
  144. waddr_gray_sync_dl[4],
  145. waddr_gray_sync_dl[4]^waddr_gray_sync_dl[3],
  146. waddr_gray_sync_dl[4]^waddr_gray_sync_dl[3]^waddr_gray_sync_dl[2],
  147. waddr_gray_sync_dl[4]^waddr_gray_sync_dl[3]^waddr_gray_sync_dl[2]^addr_gray_sync_dl[1],
  148. waddr_gray_sync_dl[4]^waddr_gray_sync_dl[3]^waddr_gray_sync_dl[2]^addr_gray_sync_dl[1]^waddr_gray_sync_dl[0]
  149. };
  150. end
  151. //读指针与写指针的间隔
  152. always @(*)
  153. rd_gap = waddr_gray2bin - raddr;
  154. //almost_empty信号产生
  155. always @(posedge rd_clk or posedge rd_reset)
  156. if(rd_reset)
  157. almost_empty <= 1'b1; //重置时,FIFO应为空
  158. else begin
  159. if(rd_gap < ALMOST_EMPTY_GAP)
  160. almost_empty <= 1'b1;
  161. else
  162. almost_empty <= 1'b0;
  163. end
  164. //产生empty信号
  165. always @(posedge rd_clk or posedge rd_reset)begin
  166. if(rd_reset)
  167. empty <= 1'b1;
  168. else
  169. empty <= (!(|rd_gap))||((rd_gap==1)&rd_en);
  170. end
  171. //例化FIFO内部RAM寄存器
  172. ram_16x16 ul(
  173. //port a
  174. .clka (wr_clk),
  175. .addra (wr_addr),
  176. .dina (wr_data),
  177. .wra(wen),
  178. //port b
  179. .clkb(rd_clk),
  180. .addrb(rd_addr),
  181. .doutb(rd_data),
  182. .rdb(ren)
  183. );
  184. endmodule

参考资料:

《FPGA深度解析》

《硬件架构的艺术》

《菜鸟教程——跨时钟域处理》

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/861032
推荐阅读
相关标签
  

闽ICP备14008679号