一步让你明白fpga数字信号处理
fpga数字信号处理
Verilog根本电路设计之一:单bit跨时钟域同步
\\\插播一条:
自己在今年整理一套单片机单片机相关论文800余篇(附送网盘链接)
论文制作思维导图
原理图+源代码+开题报告+正文+外文资料
想要的同学私信找我。
Verilog基本电路设计(包括:时钟域同步、无缝切换、异步FIFO、去抖滤波))
首先介绍异步信号的跨时钟域同步问题。一般分为单bit的控制信号同步,以及多bit的数据信号同步。多bit的信号同步会使用异步FIFO完成,而单bit的信号同步,又是时钟没缝切换电路以及异步FIFO电路的设计根底,这里先介绍单bit信号同步处理。clka域下的信号signal_a,向异步的clkb域传递时,会产生亚稳态问题。所有的亚稳态,归根结底就是setup/hold时长不满足导致。在同一个时钟域下的信号,综合以及布线工具能够在data路径或者clock路径上插入buffer使得每一个DFF的setup/hold时长都满足;但是当signal_a在clkb域下使用时,由于clka与clkb异步,它们的相位关系不确定,那么在clkb的时钟沿到来时,没法确定signal_a此时是否处于稳定没变化状态,也即setup/hold时长没法确定,从而产生亚稳态。这种异步信号在前后端流程里面是没法做时序分析的,也就是静态时序分析里常说的false_path。打消亚稳态,就是采用多级DFF来采样来自另一个时钟域的信号,级数越多,同步过来的信号越稳定。对于频次很高的设计,建议至少用三级DFF,而两级DFF同步则是所有异步信号处理的最根本要求。单bit的信号跨时钟域同步,又分成电平信号同步以及脉冲信号同步。电平信号,就是说clka下的信号signal_a在clkb看来,是一个很宽的信号,会保持多个clkb的时钟周期,一定能被clkb采到。这种情况,只须要使用clkb用至少两级DFF不间断抓signal_a即可,特别须要强调的是,此时signal_a必需是clka下的寄存器信号,假如signal_a是clka下的组合逻辑信号,一定要先在clka下用DFF抓一拍,再使用两级DFF向clkb传递。这是由于clka下的组合逻辑信号会有毛刺,在clka下使用时会由setup/hold时长保证毛刺不会被clka采到,但由于异步相位不确定,组合逻辑的毛刺却极有可能被clkb采到。电平信号的同步处
私信我绿色软件airuimcu
理,一般用于知道确定的时钟频率大小关系或者极慢时钟下的信号向极快时钟域传递时使用,简单处理如下:
always @ (posedge clkb or negedge rst_n)beginif (!rst_n) beginlevl_b_d1 levl_b_d2 levl_b_d3 endelse beginlevl_b_d1 levl_b_d2 levl_b_d3 endendassign puls_b_pos = levl_b_d2 & (~levl_b_d3);
assign puls_b_neg = levl_b_d3 & (~levl_b_d2);assign levl_b_out = levl_b_d2;
上面三个输出分别是经过同步之后,clkb下可以使用的0变1脉冲信号,1变0脉冲信号以及电平信号。再次强调:levl_a_in必须是clka的DFF信号!下面是更常见的,clka下的脉冲信号,同步到clkb时钟域下,它对于clka与clkb的时钟频率关系没有任何限制,快到慢,慢到快都没问题。其主要原理就是先把脉冲信号在clka下展宽,变成电平信号,再向clkb传递,当确认clkb已经“看见”信号同步过去之后,再清掉clka下的电平信号。脉冲信号同步处理电路,有两个地方使用了上面的电平信号同步处理原则,请仔细揣摩原因。详细见下面的RTL,其中省略了信号定义声明:
module sync_pulse (// inputrst_n, // system resetclka, // clockAclkb, // clockBpuls_a_in, // pulse input from clka// outputpuls_b_out, // pulse output in clkblevl_b_out // level output in clkb);parameter DLY = 1; //always @ (posedge clka or negedge rst_n)beginif (rst_n == 1'b0)signal_a else if (puls_a_in)signal_a else if (signal_b1_a2)signal_a else ;endalways @ (posedge clkb or negedge rst_n)beginif (rst_n == 1'b0)signal_b elsesignal_b endalways @ (posedge clkb or negedge rst_n)beginif (rst_n == 1'b0) beginsignal_b_b1 signal_b_b2 endelse beginsignal_b_b1 signal_b_b2 endendalways @ (posedge clka or negedge rst_n)beginif (rst_n == 1'b0) beginsignal_b1_a1 signal_b1_a2 endelse beginsignal_b1_a1 signal_b1_a2 endendassign puls_b_out = signal_b_b1 & (~signal_b_b2) ;assign levl_b_out = signal_b_b1 ;endmodule
下一篇讲时钟切换电路。留下一个思考题:clka下的同一个寄存器信号signal_a,电平宽度对clkb而言足够长,如果同时调用两个相同的电平同步模块向clkb时钟传递,分别得到levl_b1和levl_b2,那么在clkb时钟域下看到的lev_b1和levl_b2信号是否一样?这个问题是实际设计中一不小心就会犯错的,如果能够想明白正确回答这个问题,异步信号的理解就可以过关了。
Verilog基本电路设计之二:时钟无缝切换
时钟切换分成两种方式,普通切换和去毛刺无缝切换。普通切换,就是不关心切出的时钟是否存在毛刺,这种方式电路成本小。如果时钟切换时,使用此时钟的模块电路处于非工作状态,或者模块内电路被全局复位信号reset住的,即使切出毛刺也不会导致DFF误触发,这样的模块可以选择用此种切换方式。写法很简单 assign clk_o = sel_clkb ? clkb : clka ,当sel_clkb为1时选择clkb,否则选择clka。不过在实际设计中,建议直接调用库里的MUX单元set_dont_touch,不要采用这里的assign写法,因为这种写法最后综合得到的可能不是MUX而是复杂组合逻辑,给前后端流程的时钟约束和分析带来不便。无缝切换,就是切换时无毛刺时钟平稳过渡。在时钟切换中,只要出现比clka或者clkb频率更高的窄脉冲,不论是窄的高电平还是窄的低电平,都叫时钟毛刺。工作在切换后时钟clk_o下的电路模块,综合约束是在max{clka,clkb}频率下的,也就是说设计最后signoff的时候,只保证电路可以稳定工作的最高频率是max{clka,clkb},如果切换中出现更高频的时钟毛刺,电路可能出现无法预知的结果而出错。无缝切换,一般用在处于工作状态的模块需要调频或者切换时钟源,比如内部系统总线,CPU等。你刚用手机打完游戏后马上关屏听音乐,这两种场景中,CPU在满足性能前提下为了控制功耗,其工作频率会动态地从很高调至较低,此时就可能是在CPU一直处于工作状态下,通过无缝切换时钟源头实现的。在无缝切换电路中,切换信号sel_clkb可以是任意时钟域下的信号,包括但不限于clka或者clkb域,但是sel_clkb必须是一个DFF输出信号;clka与clkb的频率大小相位关系可以任意。无缝切换需要解决两个问题,一是异步切换信号的跨时钟域同步问题,这里需要使用《Verilog基本电路设计之一》里的同步电路原理消除亚稳态;二是同步好了的切换信号与时钟信号如何做逻辑,才能实现无毛刺。下面写出无缝切换电路的主体部分,忽略了内部信号的定义声明等。
module clk_switch (rst_n,clka,clkb,sel_clkb,clk_o);always @ (posedge clka or negedge rst_n)beginif (!rst_n) beginsel_clka_d0 sel_clka_d1
endelse beginsel_clka_d0 sel_clka_d1 endend// part2//always @ (posedge clka_n or negedge rst_n)always @ (posedge clka or negedge rst_n)beginif (!rst_n) beginsel_clka_dly1 sel_clka_dly2 sel_clka_dly3 endelse beginsel_clka_dly1 sel_clka_dly2 sel_clka_dly3 endend// part3//always @ (posedge clkb_n or negedge rst_n)always @ (posedge clkb or negedge rst_n)beginif (!rst_n) beginsel_clkb_d0 sel_clkb_d1 endelse beginsel_clkb_d0 sel_clkb_d1 endend// part4//always @ (posedge clkb_n or negedge rst_n)always @ (posedge clkb or negedge rst_n)beginif (!rst_n) beginsel_clkb_dly1 sel_clkb_dly2 sel_clkb_dly3 endelse beginsel_clkb_dly1 sel_clkb_dly2 sel_clkb_dly3 endend// part5clk_gate_xxx clk_gate_a ( .CP(clka), .EN(sel_clka_dly3), .Q(clka_g) .TE(1'b0) );clk_gate_xxx clk_gate_b ( .CP(clkb), .EN(sel_clkb_dly3), .Q(clkb_g) .TE(1'b0) );//assign clka_g = clka & sel_clka_dly3 ;//assign clkb_g = clkb & sel_clkb_dly3 ;assign clk_o = clka_g | clkb_g ;endmodule
上面是我认为比较合理的无缝切换电路,其他切换方式跟这个会有些许出入,但基本大同小异原理是一样的。有几点说明:1、抛开注释掉的电路不看,由于part5部分直接调用库里的clock gating cell,使得整个切换电路全部只需要用到时钟上升沿,无需额外定义反向时钟,精简了DC综合的时钟约束;直接调用gating cell的另一个好处是,前后端工具会自动检查gating cell的CP信号与EN信号的setup/hold时间,使得gating后的Q时钟输出无毛刺尖峰。TE端可以根据实际需要接上scan测试模式信号。如果使用part5部分的gating cell实现,前面的part1,2,3,4全部替换成注释掉的反相时钟也是没有问题。2、part2和part4部分,具体需要多少级DFF,甚至完全不要也是可以的,这就回到了《Verilog基本电路设计之一》里讨论的到底多少级DFF消除亚稳态才算合理的问题。时钟频率很低可能无所谓,如果时钟频率达到GHz,这部分建议至少保留三级DFF,因为三级DFF延时也仅仅只有3ns的时间裕度。没必要为了省这么几个DFF降低电路可靠性,在复杂IP以及大型SOC系统中,你会发现多几十个DFF,面积上可以忽略,系统可靠性和稳定性才是首要的。3、如果part5部分希望使用注释掉的两行“与”逻辑实现时钟gating,此时part1与part3使用正相或者反相时钟都可以,但是必须把part2和part4部分改为注释掉的反相时钟实现,目的是初步从RTL设计上避免“与”逻辑的毛刺,同时还需要后端配合,因为很多后端工具对时钟“与”逻辑的clock gating check未必会检查。用clk下降沿拍出的en信号,再跟clk做与逻辑得到的门控时钟,在RTL仿真阶段看到的一定不会有毛刺,但是布线完成后,如果clk相对en后移,那与逻辑得到的门控时钟就有毛刺了。这就是用与逻辑做门控的缺点,由于后端工具可能不会去检查这个与门的时序关系而导致出错。但直接调用库里的gating cell,工具天然就会去检查这个时序,免去人工确认的后顾之忧。最后,请大家仔细看看sel_clka_d0 和sel_clkb_d0 这两处逻辑,按理说,sel_clkb跟sel_clka_dly3以及sel_clkb_dly3之间相互都是异步的,而按照异步信号同步处理原则,两个不同时钟域下的信号是不允许直接做组合逻辑的,为什么这里可以这样使用?
Verilog基本电路设计之三:异步FIFO
FIFO用于为匹配读写速度而设置的数据缓冲buffer,当读写时钟异步时,就是异步FIFO。多bit的数据信号,并不是直接从写时钟域同步到读时钟域的,而是读写时钟域分别派遣了一个信使,去通知对方时钟域,当前本方所处的读写情况,来判断还能不能写以及可不可以读,这两个信使就是读写指针。在《Verilog基本电路设计之一》里已讨论过,即使单bit的异步信号,通过两个相同的同步电路,达到clkb域时都可能“长”的不是一个模样,更加不用说多bit的异步信号同时传递到clkb域会变成什么五花八门的模样了。这里读写指针不是单bit信号,它们如何向对方时钟域去同步呢?格雷码!它的特点是每次只有一个bit发生变化,这样就把多bit信号同步转变为了单bit信号同步,这也是为什么多bit的格雷码信号,可以类似于单bit信号那样,直接使用两级DFF去同步的根本原因。下面给出异步FIFO的主体部分,同样,省略了信号声明定义。module asyn_fifo (// inputaf_wclk , // async-FIFO clear in write clockaf_rclk , // async-FIFO clear in read clockrst_n, // system resetaf_wr_en, // async-FIFO write enableaf_rd_en, // async-FIFO read enableaf_dati, // async-FIFO data in//output af_full , // Async-FIFO full flagaf_empty, // Async-FIFO empty flagaf_dato // Async-FIFO data out);//------------------------- data input --------------------------assign nxt_wptr_wclk = (af_wr_en && !af_full) ? (wptr_wclk + 1'b1) : wptr_wclk ;assign nxt_wptr_gray = (nxt_wptr_wclk >> 1) ^ nxt_wptr_wclk ;always @ (posedge af_wclk or negedge rst_n)beginif (rst_n == 1'b0) beginwptr_wclk wptr_gray endelse beginwptr_wclk wptr_gray endendreg [31:0] ram[15:0] ; //always @ (posedge af_wclk)beginif (af_wr_en == 1'b1)ram[wptr_wclk[3:0]] else ;end//------------------------ data output ---------------------------assign nxt_rptr_rclk = (af_rd_en && !af_empty) ? (rptr_rclk + 1'b1) : rptr_rclk ;assign nxt_rptr_gray = (nxt_rptr_rclk >> 1) ^ nxt_rptr_rclk ;always @ (posedge af_rclk or negedge rst_n)beginif (rst_n == 1'b0) beginrptr_rclk rptr_gray endelse beginrptr_rclk rptr_gray endendassign af_dato = ram[rptr_rclk[3:0]] ;// sync read pointeralways @ (posedge af_wclk or negedge rst_n)beginif (rst_n == 1'b0) beginrptr_sp1 rptr_sp2 endelse beginrptr_sp1 rptr_sp2 endend// sync write pointeralways @ (posedge af_rclk or negedge rst_n)beginif (rst_n == 1'b0) beginwptr_sp1 wptr_sp2 endelse beginwptr_sp1 wptr_sp2 endendassign af_full = (wptr_gray == {~rptr_sp2[4],~rptr_sp2[3],rptr_sp2[2:0]}) ;assign af_empty = (rptr_gray == wptr_sp2) ;assign wptr_bin[4] = wptr_sp2[4] ;assign wptr_bin[3] = (^wptr_sp2[4:3]) ;assign wptr_bin[2] = (^wptr_sp2[4:2]) ;assign wptr_bin[1] = (^wptr_sp2[4:1]) ;assign wptr_bin[0] = (^wptr_sp2[4:0]) ;assign rptr_bin[4] = rptr_sp2[4] ;assign rptr_bin[3] = (^rptr_sp2[4:3]) ;assign rptr_bin[2] = (^rptr_sp2[4:2]) ;assign rptr_bin[1] = (^rptr_sp2[4:1]) ;assign rptr_bin[0] = (^rptr_sp2[4:0]) ;assign af_wlevel = wptr_wclk - rptr_bin ;assign af_rlevel = wptr_bin - rptr_rclk ;assign af_half_full = (af_rlevel >= 5'h7) ;endmodule
上面给出的是深度16,宽度32的示例,大家可以使用parameter参数化定义深度和宽度,方便不同需求下的调用。除了空满信号标志,也可以根据需要做出半空半满之类信号。上面需要注意的一点就是,格雷码必须在本时钟域下DFF输出,再往另一个时钟域同步。同步FIFO呢,就不用有格雷码转换,设计更加简单,就不专门开贴描述了。
Verilog基本电路设计之四:去抖滤波
debounce电路,就是常说的去抖滤波,主要用在芯片的PAD输入信号,或者模拟电路输出给数字电路的信号上。
parameter BIT_NUM = 4 ;reg [BIT_NUM-1 : 0] signal_deb ; //always @ (posedge clk or negedge rst_n)beginif (rst_n == 1'b0)signal_deb elsesignal_deb endalways @ (posedge clk or negedge rst_n)beginif (rst_n == 1'b0)signal_o else if (signal_deb[3:1]==3'b111)signal_o else if (signal_deb[3:1]==3'b000)signal_o else ;end
上面的电路,第一个always,还兼顾了去亚稳态作用。它可以滤掉的宽度是两个clk的cycle,对于大于两个cycle而小于三个cycle的信号,有些可以滤掉,有些不能滤掉,这与signal_i相对clk的相位有关。根据希望滤除的宽度相关,换算到clk下是多少个cycle数,从而决定使用多少级DFF。如果希望滤除的宽度相对cycle数而言较大,可以先在clk下做一个计数器,产生固定间隔的脉冲,再在脉冲信号有效时使用多级DFF去抓signal_i;或者直接将clk分频后再使用。
「博文精选」谈谈数字信号这个概念
数字信号看似一个非常常规而成熟的概念,其实含有很大的混淆。今天就来大概谈谈这个概念,和大家讨论。
按照我们通常的定义,数字信号是指幅度和时间都离散的信号叫“数字信号”。而很多书里面也说处理数字信号的电路就是数字电路。其实真的是这样吗?之前被我带过的女生质问过说她认为什么Digital Sensor、Digital LDO都是假的,因为这些电路处理的都是“模拟信号”。所以这些都是“模拟电路”。她觉得她当时做的课题不是“做数字”,因此对此很不满意。当时由于很多问题没想清楚,也不想和她深入争论这个问题。但现在得空了,就来好好分析一下这个问题。
这事首先要讨论一个问题。什么叫信号(Signal)。按照信号与系统的定义,信号是传递有关一些现象的行为或属性的信息的函数。而这个函数通常自变量是时间或者是位置。随着时间连续变化的信号,那么背定义为模拟信号。而不是随着时间连续变化,也就是间隔一段时间(通常为固定周期)变化的信号,其实就是离散时间信号。而如果离散时间信号只有有限个取值的,就是数字信号。所以我们谈数字信号,实际上谈的是信号本身的一种属性或者数学上的特征。如果抽象的来谈信号,其实就是一个数学上的函数的概念。一个数(自变量)与数(因变量)的关系。
但从另外一方面来讲,信号是必须有载体的。是要有物理的现成才能把信号表示出来。现实世界的物理现象(宏观上的)如果以时间为自变量,那么绝大部分都可以表示成某种物理量的变化过程。而这种变化过程中,时间是连续变化的而物理量也是连续变化的。这显然是一种模拟信号。例如温度的变化,飞机速度的变化等等。自然界有没有天生的数字信号?应该是没有的。但是应该是极其特定的条件下有天生的离散时间信号。此刻我的脑子里就浮现出来了一个匀速跳跃的青蛙。它的位移量应该是一个离散时间信号……(我是不是不知不觉又续了?)
如果我们要对这些信号加以记录和处理,我们应该是先把这些信号转变为电信号。这个转换的过程就叫做“传感”。执行这个过程的器件叫做传感器。传感器把某种物理量转变成了以电压或者电流表示的信号。这个信号是对现实世界物理量的“复刻”或者说“再现”,因此这个也符合模拟信号的特点。
我们也知道我们要把模拟信号用数字信号处理的办法来求解,是要把模拟信号用数字信号来表示。那么第一步就是要把模拟信号由时间上连续变为时间上离散的。大家都知道这个过程叫做采样。采样完了的信号时间上是离散的,间隔了若干周期才变化。但是因变量的取值仍然是随意的。那么在接下来的过程中,通过把这些因变量映射到固定的数值上去。这个过程上叫量化。但是这个量化,在实际的物理过程上就有问题了。按理说量化完了,这个信号就已经是自变量也离散,因变量也离散了。最后就应该是数字信号了啊。但是为什么我们的AD转换过程应该三步:采样、量化、编码啊(严格说来是四步:采样、保持、量化、编码,但是这个保持的过程是做ADC电路设计时候才考虑的)。这就涉及到一个问题:那就是数字信号的“表征”问题。
既然数字信号是自变量和应变量都是离散的。那我们其实最直观的想到的就是用一个有有限个幅度值的脉冲信号来表征它。比如1就是1V,2就是2V,3就是3V……事实上,在数模转换中,我们其实是把常规的数字信号转换成了这种类型的脉冲。但我们在真实的系统中并没有用这种方法来表征数字信号,而是采用了的一套二进制的数值系统来表征这个数字信号。这个二进制的数值系统是采用多个二值信号+权重的方式来表示数值的。所以我们知道了,编码的过程,本质上是将数字信号转换为以特定的二进制数值系统表征的过程。当然,也可以考虑将其转换为多进制(如苏联大力研制的三进制)或者其它体系的数值系统(如余数系统、随机数等)。而所谓的“数字信号处理”,实际上是对已经被某种数值系统表示出来的数字信号加以计算。本质上是在用“数值计算”的方法来处理。常规的“数值计算”自然是二进制的加减运算了。而如果表示为非常规的数值系统,其实也可以做数值计算。比如余数系统就是前几年大热的一种数值系统,很多做信号处理电路的人是在这个层面上做创新。发了(水了)不少论文。
回过头来说。构成这个二进制数值系统的根基,是二值化的特定信号。这种信号显然是一种数字信号(时间上离散,取值只有两种)。所以大家讲数字信号的时候往往是在讲这种信号。但这并不是数字信号的全部。但恰恰又是我们通常以这种二值信号为基础构建的二进制数值系统来表征了数字信号,从而产生了概念上的混淆。
最后回到当年那个女生问我的问题。现在我应该翻过来回答,凡是电路的工作过程中,信号的变化过程是以时间离散且应变量离散的方式进行的,都应该是Digital的。比如 Digital LDO,就是把LDO的变化从连续的可调,变为了通过在时间上开关一组LDO。从连续的控制变成了时间也离散,因变量也离散的控制。这种当然当得起“Digital”的名。
至于数值系统的事,回头再聊。
招聘信息相关问答
信号工高级技师论文如何写?
不用写。信号工没有高级技师职位。不用写。信号工没有高级技师职位。
铁路信号论文,怎么写啊?
1、论文题目:要求准确、简练、醒目、新颖。2、目录:目录是论文中主要段落的简表。(短篇论文不必列目录)3、提要:是文章主要内容的摘录,要求短、精、完...主...
铁路信号论文怎么写?
铁路信号论文与其它论文格式基本相同,如概论、现状、创新(含论点、论证和做法等),最后是结论。以下内容都是可以成为铁路信号论文:1、故障分析2、提高、...
浅谈MATLAB在信号与系统分析中的应用论文写..._投资分析考试...
第一章绪论§1-1课题研究的背景§1-2信号与系统分析国内外研究现状§1-3Matlab概述§1-4课题研究的目的及意义§1-5论文主要内容及结构...
求论文:举例说明细胞信号传递的多通路、多环节、多层次和网...
细胞信号转导的传递途径主要有哪些?1.G蛋白介导的信号转导途径G蛋白可与鸟嘌呤核苷酸可逆性结合。由x和γ亚基组成的异三聚体在膜受体与效应器之间起中介作用...
FFT得到的结果横坐标中每格为fs/N是怎么得到的?有谁对这个...
FFT本没有意义他只不过是DFT的快速算法知道DFT的意义就行了至于FFT知道他怎么算就行了算出各次协波的幅值FFT得到的结果横坐标中每格为fs/N电脑不可...
英语翻译在本论文写作过程中,我考虑了多种设计方案及技术.结...
[最佳回答]Inthisthesiswritingprocess,Iconsideravarietyofdesignandtechnology.Combinationofsubjects...
信号编码技术的发展?
1.模拟信号编码:早期的通信系统主要使用模拟信号编码技术,例如脉冲振幅调制(PAM)、频率调制(FM)和相位调制(PM)。这些技术能够将模拟信号直接映射到载波...
你对假汉芯的处理结果有何看法?
学术造假事件学术造假事件是指近年来,发生的一系列涉及学术造假的事件,涉及到多个高校、研究机构。近年来,全国多所高校、研究机构相继卷入学术造假事件。...
工程硕士学历经历怎么写啊-小红薯F0456D6D的回答-懂得
学习经历写作技巧:1、在许多情况下,学习经历部分最好是位于资历概述部分的下面也就是简历的开头部分。如果你的情况符合下列条件的一至两条,那么你...