跨时钟传输——多比特
目錄
?跨時鐘傳輸中,亞穩態是如何形成的?
多比特的跨時鐘傳輸——數據準確性以及關聯性問題
如何解決多比特跨時鐘傳輸中的數據準確性問題?
?方法一:多比特信號合成單比特信號
?方法二:MUX/DMUX同步器
?方法三:格雷碼編碼方式
方法四:異步FIFO
方法五:握手機制
方法六:多周期路徑同步法,MCP
需要用到跨時鐘的場景:
1.單比特:單比特慢到快的跨時鐘傳輸(電平同步器、邊沿檢測同步電路)、單比特快到慢傳輸引起的數據丟失問題(脈沖同步/脈沖檢測)。
2.多比特:數據準確性和關聯性問題。
?跨時鐘傳輸中,亞穩態是如何形成的?
? ? ? Din在從CLOCK1時鐘域變到CLOCK2時鐘域時,如下圖所示,假如Din剛好在Clock2的采樣窗口變化,且不滿足建立保持時間,就會產生亞穩態,也就是Dout會在一個電壓范圍內浮動,如果在Dout浮動期間采樣Dout信號,那么采樣到的值可能是正確值,也可能不是。
多比特的跨時鐘傳輸——數據準確性以及關聯性問題
首先明確什么樣的多比特信號才是多比特信號?
多比特信號指的是一個變量的表示是由多個比特位構成,這些比特位之間是相互關聯的,比如位寬為32位的ADDR。
而像幾個獨立的單比特信號組合到一起,在同步之后也是各自起作用的,這樣的"多比特信號"就是偽多比特信號,依然可以采用每個比特打兩拍的方式去同步。
多比特信號為什么不可以采用打兩拍的方式同步?
如下圖所示,2比特信號data從aclk時鐘跨到bclk時鐘,data信號的兩個比特位同時發生變化,剛好發生在目標時鐘bclk的采樣沿,由于雙觸發同步具有隨機性,假設data的第一比特信號被正確采樣并同步,而第二比特信號的同步觸發器沒有采樣到,就會延遲一個周期,就會造成同步過去的數據發生錯誤,如上圖中,由于第二比特出現了延遲,導致生成了錯誤的2'b01的中間態信號。??
因此對于多比特信號按照打兩拍的方式進行跨時鐘傳輸,就會由于各個比特穿越時間不一致,而造成目標時鐘域出現一些中間態無意義數據,也就是數據的準確性和關聯性出現了問題
如何解決多比特跨時鐘傳輸中的數據準確性問題?
解決多比特的CDC問題有六種方法:
? ? ? ? ①多比特信號合成單比特信號
? ? ? ? ②MUX同步器
? ? ? ? ③格雷碼編碼
? ? ? ? ④異步FIFO
? ? ? ? ⑤握手機制
? ? ? ? ⑥多周期路徑同步MCP?
?方法一:多比特信號合成單比特信號
假如多比特信號之間存在邏輯關聯性,就可以將源時鐘信號合成一個單一的控制信號,然后進行兩級寄存器同步。如下圖所示,多比特信號經過logic電路合成單比特信號后要經過寄存器寄存一下,因為組合邏輯電路易產生毛刺。
?方法二:MUX/DMUX同步器
如果多比特信號無法融合成一個信號,那么方法一就不可用。那么就可以采用方法二:MUX同步器(MUX synchronizer)
使用MUX同步器要求被同步的數據跟隨一個使能信號,當使能信號有效時,數據才會被同步。
如下圖所示:(以慢到快為例)將使能信號從源時鐘過渡到目的時鐘后,作為MUX的選擇信號,當enable有效時再進行同步,保證了所有bit在同一個使能信號有效時刻同步,避免了多比特信號傳輸中的非關聯問題。
?可以看出,MUX同步器主要應用于帶有數據有效標志位的多比特CDC問題。
MUX同步器應用在慢到快的CDC時,數據長度應該至少為m+1個目標時鐘周期,m指的是同步器數量,此處為m=2。
將上述電路使用verilog語言描述:
module mux_syn(input clka,input clkb,input rst_n,input [3:0] data_in,input data_en,output reg data_out );reg data_en_ar;reg data_en_br;reg data_en_brr;reg [3:0] data_r;//先處理源時鐘下的信號 always@(posedge clka or negedge rst_n)beginif(!rst_n)begindata_r <= 4'b0;data_en_ar <= 1'b0;endelse begindata_r <= data_in;data_en_ar <= data_en;end end//處理目的時鐘下的信號 always@(posedge clkb or negedge rst_n)beginif(!rst_n)begindata_en_br <= 1'b0;data_en_brr <= 1'b0;endelse begindata_en_br <= data_en_ar;data_en_brr <= dada_en_br;end end//使用MUX輸出 always@(posedge clkb or negedge rst_n)beginif(!rst_n)begindata_out <= 4'b0;endelse if(data_en_brr)begindata_out <= data_r;end endendmoudle?方法三:格雷碼編碼方式
由于格雷碼相鄰兩位只有一位發生變化,相當于將多比特的CDC轉換成了單比特的CDC。在跨時鐘傳輸時可以大大降低發生亞穩態發生的概率。
但這種方法有使用限制:
1.由于格雷碼是相鄰兩位只有一位變化,因此格雷碼又能用在數據連續變化的情況下,一般用于計數器,比如異步fifo中的讀寫指針。
2.格雷碼的變化周期是2^N。因此,如果數據的取值范圍不是2^N,就無法使用格雷碼。
方法四:異步FIFO
異步fifo相當于將源時鐘數據緩存起來,然后目標時鐘從緩存中取數據,常用于數據流的跨時鐘傳輸,相對于握手機制,異步FIFO的傳輸速度較快。
異步FIFO的設計參考:https://blog.csdn.net/carrotbanana/article/details/126338269
方法五:握手機制
握手機制是一種閉環的數據同步方法,握手機制最基本的方法是數據鎖存和握手信號。在源時鐘域對數據進行鎖存,發出請求信號,用于指示目標時鐘域何時對總想數據進行采樣。在目的時鐘域產生應答信號用于指示源時鐘域何時更新寄存器中的數據。
?握手機制經典題目:分別編寫一個發送模塊和一個接收模塊,模塊的時鐘信號分別為clka和clkb,兩個時鐘頻率不相同。發送模塊循環發送0-7,每個數據傳輸網還曾后,間隔5個時鐘,發送下一個數據。在兩個模塊之間添加握手信號,保證數據傳輸不丟失。接口信號圖如下:req為請求信號,ack為應答信號。
?可以參考單比特中的握手機制(跨時鐘傳輸——單比特_carrotbanana的博客-CSDN博客),只不過這里將整個模塊拆分成了發送模塊和接收模塊。
發送模塊:
首先從數據發送開始,總線上放置data數據,然后req信號置1,在req為1期間,總線數據保持不變,以便能被接收模塊接收。
當接收模塊接收到數據后,會返回ack應答信號,該應答信號屬于接收時鐘域,因此需要將該應答信號同步到發送時鐘域,該信號是一個單比特信號,采用兩級同步器即可。
當接收時鐘域的兩級觸發器ack信號為01時,下一個采樣延,采集到的ack有效信號將變為11,表明握手傳輸完成,此時會撤銷req請求信號,并復位計數器,開始準備計數五個時鐘周期。
由于req請求信號已經撤銷,因此總線數據可以進行更新(本題中是數據加一操作),注意數據更新操作在ack兩級同步器為01的時刻開始更新,如果在ack為11的時候,更新會一直更新,因為11會持續五個時鐘周期。那么數據就會更新五次。
當計數器記滿五個時鐘周期,req信號重新變得有效,開始重新請求發送數據然后繼續循環往復。。。
module data_driver(input clka,input rst_n,input data_ack,output data_req,output [3:0] data );reg data_ack_r; reg data_ack_rr; reg [2:0] cnt;//應答信號同步,采用兩級同步器。 always@(posedge clka or negedge rst_n)beginif(!rst_n)begindata_ack_r<=4'b0;data_ack_rr<=4'b0;endelse begindata_ack_r<=data_ack;data_ack_rr<=data_ack_rr;end end//計數器計數:每發送一個數據,就要計數五個周期。 always@(posedge clka or negedge rst_n)beginif(!rst_n)begincnt<=3'b0;endelse if(data_req)begin //在data_req有效期間,數據不能變化,計數停止。cnt<=cnt;endelse if(data_ack_r && !data_ack_rr)begin //ack信號在clka時鐘域的兩個寄存器的值為01,的時候,說明下一個時刻,ack_rr信號將為1,也就是說下一個采樣時刻,完成握手傳輸,計數復位,準備計數。cnt<=3'b0;endelse begincnt<=cnt+1'b1;end end//發送數據請求,當計數器記滿五個周期時,請求發送信號置1,此外,握手機制的應答信號ACK有效時,請求信號會撤銷 always@(posedge clka or negedge rst_n)beginif(!rst_n)begindata_req<=1'b0;endelse if(data_ack_r && !data_ack_rr) //反饋信號ACK有效時,撤銷reqdata_req<=1'b0;else if(cnt==3'd4)begindata_req<=1'b1;end//數據發送:當req為1時,數據保持不變,當反饋信號回來時,說明上一次的傳輸已經完成,可以開始更新數據 always@(posedge clka or negedge rst_n)beginif(!rst_n)begindata<=4'b0;end if(data_req)begindata<=data;endelse if(data_ack_r && !data_ack_rr)begindata <= data+1'b1;end end endmodule接收模塊:當接收模塊接收到req有效信號后,將信號同步到接收時鐘域后,接收模塊開始采樣數據,并返回應答信號ack。
當接收模塊接收到的req信號變為0時,接收模塊撤回應答信號。
module data_receiver(input clkb,input rst_n,input data_req,input [3:0] data,output data_ack ); reg data_req_r; reg data_req_rr;//同步REQ信號 always@(posedge clkb or negedge rst_n)beginif(!rst_n)begindata_req_r<=1'b0;data_req_rr<=1'b0;endelse begindata_req_r<=data_req;data_req_rr<=data_req_r;end end//發送ACK信號,實際上ack信號就是req信號在clkb時鐘域上的一個寄存信號 always@(posedge clkb or negedge rst_n)beginif(!rst_n)begindata_ack<=1'b0;endelse if(data_req_rr)begindata_ack<=1'b1;endelsedata_ack<=1'b0; end//接受數據data reg [3:0] data_in_reg; always@(posedge clkb or negedge rst_n)beginif(!rst_n)begindata_in_reg<=4'b0000;endelse if(data_req_r && !data_req_rr)begindata_in_reg<=data;end endendmodule將發送模塊與接收模塊連接起來
module top(input clka,input clkb,input rst_n );wire ack; wire req; wire [3:0]data;data_drivrer data_driver( .clk(clka) .rst_n(rst_n) .data_ack(ack) .data_req(req) .data(data) ); data_receiver data_receiver( .clk(clkb) .rst_n(rst_n) .data_ack(ack) .data_req(req) .data(data) ); endmodule方法六:多周期路徑同步法,MCP
多周期路徑同步法將MUX同步與握手機制結合起來,被同步的數據同樣需要一個數據使能信號,數據信號與使能信號被同時同步到目標時鐘域,并將使能信號作為反饋信號,返回給源時鐘域,完成握手。
參考:
FPGA學習筆記——跨時鐘域(CDC)設計之多bit信號同步-pudn.com
FPGA邏輯設計回顧(5)多比特信號的CDC處理方式之MUX同步器 - 知乎
跨時鐘域的方法--多周期路徑 - 知乎
FPGA學習記錄——??途W刷題(二)-pudn.com
總結
以上是生活随笔為你收集整理的跨时钟传输——多比特的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 封装一个函数,山峰 高度不固定、纸张厚度
- 下一篇: latex 表格行间距设置