tag 标签: 跨时钟域

相关博文
  • 热度 30
    2017-6-7 21:59
    5717 次阅读|
    0 个评论
    4、处理跨时钟域时要注意哪些问题 4.1)同步器前不能有组合逻辑电路 如上图,在前一个时钟域的dff输出和后一个时钟域输入之间不能有组合逻辑,原因是组合逻辑会造成毛刺现象,后一级时钟域的dff很可能敲到毛刺,进而引入错误。 4.2)避免重收敛(reconvergence)和分叉(divergence) 重收敛的含义是,A时钟域的多根信号分别进行同步,同步到B时钟域,然后在B时钟域从新做逻辑汇聚成一根信号。这种同步的方式有一个很大的问题,你无法预期同步后的多根信号和之前还是一致的,例如,两根信号之前都是1,但是在同步后可能变成很多的情况。所以再重新汇聚肯定会出问题。例如下图中的状态机,在A时钟域可能是S1状态,但是同步后可能就变成了S2状态了。其实重收敛的问题可以避免,就是采用格雷码编码,避免一个时刻多个数据跳变。 如下图的格雷码编码再解码,就可以解决上述的一些问题。 分叉的含义与之相反,在A时钟域的单根信号被分别同步到B时钟域的多根信号,这同样会面临同步不一致的情况,有的被同步成1,有的被同步成0。 4.3)避免将cmd和data分开进行同步,而要绑定到一块采用异步fifo实现 Cmd和data经过异步fifo处理后的延迟可能会发生变化,所以应当避免将他们分开进行同步,而要绑定到一块进行同步{cmd,data}。 最后提一下异步复位同步释放电路,这种电路在soc中也广泛被使用。
  • 热度 26
    2015-10-5 16:05
    1658 次阅读|
    0 个评论
    距离上次的博客已经有段时间了,这写些日子一直在调SDRAM的模块以及文档的书写,SDRAM的子模块比较多,包括init(初始化模块)、refresh(刷新模块)、write(写模块)、read(读模块),使用起来相比之前的USB控制模块、今天的GEN_FRAME(以下均表示为成帧模块)都稍显复杂一些。好了,接下来介绍我们今天的主角:成帧模块。成帧模块的作用有两个: 1.完成时钟域的转换 :将缓存到sdram中的数据读出发送给USB,sdram芯片可以达到的时钟频率范围大致为24MHZ-256MHZ,该时钟由FPGA给出,具体的时钟还要看FPGA稳定工作可以达到的时钟。另一方面,USB控制器的时钟有USB芯片给出,为48MHZ。数据在不同时钟域间的传输就要用到时钟域的转换。 2.给数据加下帧头: 发送数据之前,首先给数据加上一行帧头,表明我的一行数据开始发送,该帧头包含了图像的列信息,然后将加了帧头的数据发送给USB控制模块,由它通过USB芯片发给上位机。   (一)跨时钟域的转换 下面我们来谈谈今天主角中的主角: 跨时钟域的转换 1,不做时钟域的转换有什么危害?2.单bit的信号与多bit的信号的处理方式有何不同? 带着这两个疑问我们来看。我们在做项目的时候不免会遇到两个模块的时钟不同的情况,A用的时钟是48MHZ,B用到的时钟是133MHZ( 这里的48跟133只是说明时钟不同 )。 以 单bit的信号 为例,都以上升沿采样: A.现在有一个由133MHZ产生的脉冲信号(一个时钟周期)flag,通过接口传给A(48MHZ),A要检测到它,可是现象是,你133MHZ太快了(太短),A的上升沿根本采不到它(也有概率可以采得到)。 B.反过来呢?A(48MHZ)的信号传给B(133MHZ),由于A的时钟频率比B慢,根本不会存在B采不到A信号的情况,但是还会有问题(就是不能让你好好传),亚稳态。 解释一下亚稳态: a.概念:指触发器无法在某个规定时间段内达到一个可确认的状态。(是不是还是有点不懂,没事看下面)。 b.什么情况会导致亚稳态:在同步系统中,建立时间、保持时间不满足就可能会产生,此时的输出端(Q端)在有效的时钟沿之后比较长时间处于不确定状态,毛刺、振荡或者是一个固定的某一电压(却不是D端的电压),这段时间成为决断时间,之后稳定在0、1上,但是这是随机的,跟输入没有必然的关系。 说了这么多,什么意思?就是每个频率的时钟都有自己的一个规则(建立时间、保持时间),我的地盘听我的,到了我的地盘就要按我的规矩办事,你不按我的规则来可以,后果就是,我随便给你输出一个值,这个值是什么,看心情,用了这个数据出不出问题就不是我的事了。 c.如何解决:1.减低时钟频率。2.将寄存器打两拍再使用。 跨时钟域的处理        A比较惨,A的情况包含了B,即包含采不到的情况,又存在亚稳态的问题,下面给出A的处理过程。有没有发现今天的图非常少,先上图。   将数据打三拍,一共四个寄存器,通过一个or门,时钟域转换为48MHZ,再延时两拍得到稳定的标志位。通过or门产生的信号会有毛刺,打两拍还可以起到去毛刺的作用。                另外,多bit同频率,异相位的时钟域切换,使用双口ram进行同步(同频异相),不同频不同相时钟转换使用异步FIFO做同步。成帧模块用到了异步FIFO做处理。 (二)GEN_FRAME模块描述 1模块框图            1. SDRAM存储一帧数据后使能read_start信号,GEN_FRAME将帧头发给USB W_FIFO,同时SDRAM向GEN_FRAME的内部FIFO写入一行数据。 2. SDRAM写完一行数据后等待写下一行的命令(read_req),GEN_FRAME继续向USB W_FIFO写入数据(w_flag有效),直到写完一行后等待。当PC将W_FIFO中数据读完,即flag_C==0时,read_req有效。 3. 当read_req有效时,下一行开始传输,GEN_FRAME中的FIFO同时进行读写(SDRAM向GEN_FRAME中的FIFO中写,同时将GEN_FRAME中的数据读出到USB W_FIFO)。 4. 直到读完一帧图像后(即行计数row_cnt计满),read_req无效,w_flag无效,停止读写。 2接口定义   3关键信号时序      A) 读 GEN_frame 数据到 USB W_FIFO ①  Sdram 存完一帧数据后发送 read_start 信号,经夸时钟域处理后得到 read_start_48 ,在此信号后检测到 flag_C 为 0 (即 W_FIFO 为空),因此要将 read_start_48 做延展,得到 read_start_buf ,取它的下降沿为读一帧数据开始。 ②  检测到 read_start_buf 的下降沿后将 w_usb_flag_reg 拉高,同时 w_usb_cnt 开始计数,由于数据给出客观上延时一拍才能读到,所以讲使能信号延时一拍发出,即 w_usb_flag 。该信号为传入下一级的使能信号。 ③  一行数据读出后,继续检测 flag_C=0 时, F_read_req( 向 GEN FIFO 发送读请求 ) , r_fifo_en 与 w_usb_flag 一致,同时读出 fifo 中的数据 r_fifo_data 。 注意:根据同步 fifo 的经验,这里的 r_fifo_en 本应该提前数据一拍给出,但上面写到同时读出 fifo 数据。没错,根据代码发现,异步 fifo 的读使能 r_fifo_en 与读数据 r_fifo_data 居然是同一时刻给出来!!!!! ④  每读完一行数据我们的行计数 gen_cnt_row 要加一。这里的行计数是由 w_usb_flag_reg 的下降沿来触发目的是保证不要丢数据。 ⑤  最终 GEN_FRAME 输出数据 w_data 根据行号来选择, gen_cnt_row=0 选择 zhen_data ,否则选择 fifo_data 。 注意:这里面的 gen_cnt_row 要记到 row_cnt+1 (帧头)。 B)sdram 向 GEN_FRAME FIFO 中写数据 ①   利用 sdram 时钟检测 flag_C 的下降沿,产生 read_req ,并输出到 sdram 控制模块中。 ②  检测到 read_req 为高时, sdram 将数据传入 GEN 模块, cnt_data 开始计数,计数器由 SD_data_v 使能信号控制(读 sdram 被刷新打断,数据会被打断),计数到 499 停止。 ③  写入 fifo 的数据为 512 个 16bit 的数据,数据只有 500 个,所以要补 12 个 16bit 的数据零, cnt_12 从 cnt_data==499 时开始计数,计到 11 为止。 将 SD_data_v 与 cnt_12_flag 作或操作,时序赋值给 w_fifo_en 。数据时序赋值给 w_fifo_data 。分别为写入 fifo 的使能信号与数据信号。 
  • 热度 20
    2013-9-3 00:21
    1720 次阅读|
    0 个评论
     对于数据采集接收的一方而言,所谓源同步信号,即传输待接收的数据和时钟信号均由发送方产生。FPGA应用中,常常需要产生一些源同步接口信号传输给外设芯片,这对FPGA内部产生时钟或数据的逻辑和时序都有较严格的要求。而对于一些FPGA采集信号的应用中,常常也有时钟和数据均来自外设芯片的情况,此时对数据和时钟的采集也同样需要关注FPGA内部的逻辑和时序。当然,无论何种情况,目的只有一个,保证信号稳定可靠的被传送或接收。          对于一个如图1所示的某视频芯片产生的源同步信号,当FPGA对其进行采集同步到另一个时钟域时,特权同学通常的做法有两种,特权同学称之为脉冲边沿检测采集法和异步FIFO采集法。下面简单的对这两种方法做一些讨论和说明。       图1     脉冲边沿检测采集法 脉冲边沿检测采集法,顾名思义,一定是应用了经典的脉冲边沿检测法来帮助或者直接采集信号。对于脉冲边沿检测法,大家可以参考特权同学的《深入浅出玩转FPGA》或者用gooogle摆渡一下。而这里尤其需要提醒大家注意的是,著名的奈奎斯特采样定理告诉我们:要从采样信号中无失真的恢复原信号,采样频率应大于两倍信号最高频率。而特权同学通过实践得出的结论与此相仿:若想稳定有效的采集到脉冲(数字信号)变化的边沿,采样频率应大于被采样脉冲最大频率的3倍。注意是要大于3倍,甚至若是可能尽量采用4倍以上的采样频率才能够达到稳定的状态。至于为什么,我想深谙此道(脉冲边沿检测法)的聪明人看完结论就已经明白了,无需特权同学再废话解释一番。          而具体的做法也很简单,把图1理想化就如图2所示。其中,待采集信号时钟Tx Clock,待采集数据使能信号Enable Signal,待采集数据总线Data Bus。FPGA内部信号采集时钟为Rx Clock,该时钟为待采集时钟的4倍。       图2            采用脉冲边沿检测法,使用Rx Clock去采集Tx Clock,Rx Clock reg1和Rx Clock reg2分别为第一级和第二级Tx Clock锁存信号。Tx Clock上升沿对应的一个有效指示信号Tx Clock pos每个Tx Clock时钟周期产生一个Rx Clock脉宽的有效高电平使能信号。从图3中可以看到,此时若用Tx Clock pos作为FPGA内部采样使能信号,虽然Tx Clock pos处于第7个Tx Clock,但是真正采集Data Bus其实已经是第8个Tx Clock上升沿了。很明显,第8个Tx Clock上升沿对准的不是Data Bus的稳定信号中央,数据很可能采集到错误值。       图3            因此,通过上面的分析,还是可以采取一些变通的方式来保证第8个Tx Clock上升沿采集到Data Bus的中央值。如图4所示,采用同样的方式对Data Bus做两级信号锁存,那么第8个Tx Clock上升沿就能够在Data Bus reg2的中央采集数据了。这样做只有一点小问题,相应的需要多付出2组寄存器来锁存Data Bus。         图4     异步FIFO 采集法          再说异步FIFO采集法,其实这种方法没什么新奇,只不过充分利用异步FIFO的同步特性来完成跨时钟域的数据交互。但是其中还是有几个非常关键的要点需要提醒设计者注意,无论如何FIFO的输入端数据和时钟信号(包括控制信号,如有效使能信号等)必须符合FIFO的数据锁存有效建立和保持时间,这个最重要的条件除了需要靠数据源端来保证外,还需要靠数据锁存端(FPGA内部)设计者做好时序上的约束和分析,否则到源端再nice的波形恐怕都无法保证能够可靠的被FIFO锁存。          异步FIFO的基本通讯时序波形如图5所示。我们关心的是FIFO的写入。由图中不难发现,写入时钟wrclk的每个上升沿会判断写入请求信号wrreq是否有效,若是有效则FIFO会相应的锁存当前的写入数据data。简单来看,从基本时序上分析,wrclk的上升沿需要对准wrreq和data的中央,这是外部传输过来的源信号必须满足的基本关系。无论如何,即便是绞尽脑汁,也要想办法让这个基本关系得到保证,否则,后面的rdclk、rdreq配合的再默契恐怕都不能得到稳定的q输出。         图5            原型开发的前期,设计者必须首先验证写入信号的关系,哪怕是不惜动用示波器(⊙﹏⊙b汗,连示波器都没有不要混了),源端给到FPGA输入端口的信号很多时候不是那么尽善尽美的,实践出真知,测试结果说了算。当然了,实在没有先进武器又想打胜仗的朋友恐怕只有不停的用代码测试采集到最稳定的数据了,这有点碰运气的成分在里面,不是非常推荐。          类似与开篇提到的应用,特权同学的实际信号采集如图6所示,把写入时钟Tx Clock和写入请求信号Enable Signal都先用同步时钟Rx Clock打了一拍,然后再输入FIFO中,而数据总线Data Bus则直接送往FIFO。这样从最终检测来看,能够保证时钟的上升沿对准数据和控制信号的中央,相对稳定和安全的把数据送往FIFO中。       图6          工程实践中往往不是一招一式的生搬硬套理论,一定要抓住最关键的设计要点,并采取各种有效的手段保证设计的实现。
  • 热度 21
    2013-9-3 00:19
    2598 次阅读|
    0 个评论
    附录(相关设计技巧): 1. 慢时钟域到快时钟域的同步及上升(下降)沿检测电路 同步和上升沿检测电路 :(注意输入B是被反向过的)   时序图 : 代码实现为 :先将发送时钟域过来的信号用寄存器打两拍,然后将输出信号A和再打一拍的反向信号B相与(如果是 下降沿检测 ,则将输出信号A反向和再打一拍的同向信号B相与)。   拓展 :如果将先将发送时钟域过来的信号用寄存器打两拍,然后将输出信号A和再打一拍的信号B相一或,就得到的是 上升沿和下降沿都检测 的逻辑。   2. 脉冲检测(将脉冲信号转换为电平信号,pulse-toggle-circuit) 基本电路为:   时序图:   代码实现为: always@(posedge clk1 or negedge nrst) begin if(!nrst) Q = 0; else  Q = D; end   assign D = Data ? Q_bar : Q;   拓展: 。。。   3.  完整握手流程 完整握手流程为:   时序图:   代码实现为:     4. 部分握手流程I(完整握手流程的简化版)  部分握手流程I为:   时序图:   说明: 省去了完整握手流程里面的最后一步,也就是ACK信号自动会把自己de-assert,而不是要等检测到REQ信号de-assert之后了。   In the first partial handshake scheme, Circuit A asserts its request signal and the  Circuit B acknowledges it with a single clock-wide pulse . In this case, Circuit B does not care when Circuit A drops its request signal. However, to make this technique work, Circuit A must  drop its request signal for at least one clock cycle  otherwise Circuit B  cannot distinguish between the previous and the new request .(A发出的REQ信号必须至少无效持续一个时钟周期,否则B无法辨别两个响铃的REQ信号)   With this handshake,  Circuit B uses a level synchronizer  for the request signal and  Circuit A uses a pulse synchronizer  for the acknowledge signal. In this handshake protocol the acknowledge pulses only occur when Circuit B detects the request signal. This allows Circuit A to control the spacing of the pulses into the synchronizer by controlling the timing of its request signal.   5.  部分握手流程II(完整握手流程的简化版) 部分握手流程II为:   时序图:   说明: 省去了完整握手流程里面的最后两步,两个信号在assert保持一段时间以后都是自动de-assert,不在相互检测。   In this second partial handshake scheme, Circuit A asserts it request with a  single clock-wide pulse  and Circuit B acknowledges it with a single clock-wide pulse. In this case, both circuits need to save state to indicate that the request is pending.   This type of handshake uses pulse synchronizers but  if one circuit has a clock that is twice as fast as the other, that circuit can use an edge-detect synchronizer instead . (如果有一个时钟域的时钟比另外一个时钟域的时钟快两倍以上,则可以使用边沿检测同步电路来代替握手电路)   6. Basic Data Path Design 基本电路为:   时序图:     说明: A design using  full handshake  signaling has a large window of time for the receiving circuit to sample the signal bus and is  not very efficient. The same design can use a  partial handshake  instead of the full handshake to  speed up  the transfer.   7. Advanced Data Path Design 基本电路为:     时序图:     代码实现为:  
  • 热度 16
    2013-9-3 00:19
    1274 次阅读|
    0 个评论
    1. 亚稳态的概念说明 是指 触发器 无法在某个规定时间段内达到一个可确认的状态。当一个触发器进入亚稳态引时,既无法预测该单元的输出电平,也无法预测何时输出才能稳定在某个正确的电平上。在这个稳定期间,触发器输出一些中间级电平,或者可能处于振荡状态,并且这种无用的输出电平可以沿信号通道上的各个触发器级联式传播下去。   在 同步系统 中,如果触发器的setup time / hold time不满足,就可能产生亚稳态,此时触发器输出端Q在有效时钟沿之后比较长的一段时间处于不确定的状态,在这段时间里Q端毛刺、振荡、固定的某一电压值,而不是等于数据输入端D的值。这段时间称为决断时间(resolution time)。经过resolution time之后Q端将稳定到0或1上,但是究竟是0还是1,是随机的,与输入没有必然的关系。   在跨时钟域的设计中,由于时钟的不同步,及其容易产生亚稳态。   常用的同步方法是使用两级寄存器来进行同步:   2. 多时钟设计的命名规则 不同时钟域的时钟和模块以及模块输入输出信号命名,应当加上适当的前缀以区分。如控制部分uclk,视频处理部分vclk,NVM接口部分mclk。这样既便于区分,也便于在后端做时序约束和分析时的处理(比如某些命令的批量处理,set_false_path -from { u* })。   3. 多时钟设计的模块划分 将整体的多时钟设计分割成多个单个独立时钟的功能模块和负责模块间同步的同步模块,这样非常利于后端的时序分析,程序结构也更加清晰。   4. 快时钟域到慢时钟域的同步 常见问题:快时钟域的信号持续时间太短,慢时钟域采不到   解决方法1: 将快时钟域传递的信号持续时间延长,使其大于慢时钟域的一个时钟周期。   解决方法2:使用握手信号(反馈信号)   5. 跨时钟域传递多个相关信号(如enable和load信号) 5.1 问题1: 传递两个同时需要的信号(b_load和b_en)   解决方法:只传递一个信号(b_lden)   5.2 问题2:传递两个前后顺序控制的信号(ben1和ben2)   解决方法:只传递一个信号(ben1)   5.3 问题3:传递两个编码控制信号(bdec 和bdec )   解决方法1:产生一个ready信号(bden_n)来指示数据的有效性   解决方法2:使用one-hot key信号结合状态机来处理接收到的信号 Note :    6. 数据的同步 There are  far too many opportunities  for  multi-bit data changes  to be  incorrectly sampled  using synchronizers.   6.1 握手信号(但是要牺牲一定的时间) Data can be passed between clock domains using  two  or  three handshake control signals , depending on the application and the paranoia of the design engineer. The biggest disadvantage to using handshaking is the  latency  required to pass and recognize all of the handshaking signals for each data word that is transferred.   For many open-ended data-passing applications,  a simple two-line handshaking sequence is sufficient . The sender places data onto a data bus and then  synchronizes a "data_valid " signal to the receiving clock domain. When the "data_valid" signal is recognized in the new clock domain, the receiver clocks the data into a register in the new clock domain (the data should have been stable for at least two rising clock edges in the sending clock domain) and then passes an " acknowledge " signal  through a synchronizer  to the sender. When the sender recognizes the synchronized "acknowledge" signal, the sender can change the value being driven onto the data bus.   Under some circumstances, it might be useful to  use a third control signal, "ready", sent through a synchronizer from the receiver to the sender to indicate that the receiver is indeed "ready" to receive data.  The "ready" signal should not be asserted while the "data_valid" signal is true. When the "data_valid" signal is de-asserted, a "ready" signal can be passed to the sender. Of course, with the added handshake signal comes the penalty of longer latency to synchronize and recognize the third control signal.   6.2 FIFO One of the most popular methods of passing data between clock domains is to use a FIFO.  A dual port memory is used for the FIFO storage . One port is controlled by the sender which puts data into the memory as fast a one data word (or one data bit for serial applications) per write clock. The other port is controlled by the receiver, which pulls data out of memory one data word per read clock.  Two control signals are used to indicate if the FIFO is empty, full or partially full .  Two additional control signals are frequently used to indicate if the FIFO is almost full or almost empty.   In theory,  placing data into a shared memory with one clock  and  removing the data from the shared memory with another clock  seems like an easy and ideal solution to passing data between clock domains. For the most part it is, but generating accurate full and empty flags can be challenging.  
相关资源