提到异步时钟域的信号处理,想必是一个FPGA规划中很要害的技能,也是令许多工程师对FPGA望而生畏的原因。可是异步信号的处理真的有那么奥秘吗?那么就让特权同学和你一同渐渐解开这些所谓的难点问题,不过请留意,往后的这些关于异步信号处理的文章里将会要点从工程实践的视点动身,以一些特权同学遇到过的典型事例的规划为依托,从代码的视点来剖析一些特权同学以为经典的跨时钟域信号处理的办法。这些文章都是即兴而写,或许不会做太多的分类或许概括,也有一些特例,期望网友自己掌握。
别的,关于异步时钟域的论题,引荐咱们无妨去看看这些不错的文章,如《跨过距离:同步国际中的异步信号》等。
首要说MCU与FPGA之间的异步通讯,参与CPLD助学活动的朋友应该都留意到了那块BJ-EPM板子上预留了16PIN的单片机接口,可是那个试验里其实也没有给出什么试验代码。究其原因,大概是特权同学有点自私了吧(呵呵~~~),由于最初刚触摸MCU与FPGA通讯处理的时分,是为了做一个液晶控制板,用的是很老的EPM7128,资源很小,探索了个把月才搞定,不过其时的处理办法上并不保险,后来跟着不断学习不断堆集经历才寻找到现在的处理办法。不想揭露源码自有所谓的“比较要害的技能”一说,现在想来蛮有些可笑的。网络这么大一个渠道,凭什么你只讨取不同享呢?所以,特权同学往后会尽力把自己的点点滴滴规划经历和咱们共享。当然了,在提出自己的观念和观点的一起,也一定会得到更多高人不同的或许更好的见地,协助别人的一起自己也在前进,何乐而不为呢。
罗嗦了一大堆,步入正题吧……
首要,这个项目是根据单片机的运用,假如你对单片机的读写时序不是很娴熟,无妨看看特权同学的一篇具体评论51单片机扩展RAM读写时序的文章《单片机的扩展RAM读写时序》。下面简略看下11.0592MHz的51单片机的读写时序图吧。
大体和上面的波形相差无几,地址总线没有画出来,不过地址总线一般是会早于片选CS到来,而且晚于片选信号CS吊销(这个说法不是肯定的,可是至少关于下面的运用是这样)。
咱们现在的作业是作为MCU的从机,即模仿MCU的扩展RAM。MCU若宣布写时序,FPGA就得在数据安稳于数据总线时将其锁存起来;MCU宣布读时序,FPGA就要在MCU锁存数据的树立时刻之前把数据放到数据总线上,而且到MCU锁存数据的坚持时刻完毕后才能将数据吊销。根本上,咱们要干的便是这些活,下面评论verilog在规划上怎么完成,可是限于篇幅,不对时序剖析做评论,假定这是一个很抱负的总线时序。
其实这个MCU的读写时序的时刻相对仍是很富余的,由于咱们的FPGA用的是50MHz的晶振。所以一个很根本的主意是要求咱们把MCU端的信号同步到FPGA的时钟域上,到达异步信号的同步处理。
verilog代码:
//———————————————————————-
//———————————————————————-
input clk; //50MHz
input rst_n; //复位信号,低有用
input mcu_cs_n; //MCU片选信号,低有用
input mcu_wr_n; //MCU写信号,低有用
input[3:0] mcu_addr; //MCU地址总线
input[7:0] mcu_db; //MCU数据总线
reg[3:0] mcu_addr_r; //mcu_addr锁存寄存器
reg[7:0] mcu_db_r; // mcu_db锁存寄存器
//////mcu_cs_n和mcu_wr_n一起拉低时wr_state拉低,表明片选并写选通
wire wr_state = mcu_cs_n || mcu_wr_n; //写状况标志位,写选通时拉底
always @ (posedge clk or negedge rst_n)
if(!rst_n) begin
mcu_addr_r <= 4’h0;
mcu_db_r <= 8’h00;
end
else if(!wr_state) begin
mcu_addr_r <= mcu_addr;// mcu_addr锁存寄存器
mcu_db_r <= mcu_db;// mcu_db锁存寄存器
end
wire pos_wr; // MCU写状况上升沿标志位
reg wr1,wr2; // MCU写状况寄存器
always @ (posedge clk or negedge rst_n)
if(!rst_n) begin
wr1 <= 1’b1;
wr2 <= 1’b1;
end
else begin
wr1 <= wr_state;
wr2 <= wr1;
end
assign pos_wr = ~wr2 && wr1; //写选通讯号上升沿pos_wr拉高一个时钟周期
上面的代码便是根据MCU宣布的异步时序的一种同步处理。当然了,这种处理是根据特定的运用。MCU写选通吊销时,pos_wr信号(运用了脉冲边缘检测办法处理)会拉高一个时钟周期,就可以运用此信号作为后续处理的状况机中的一个指示信号。然后对现已锁存在FPGA内部相应寄存器里的地址总线和数据总线进行处理。
别的,关于mcu_addr_r和mcu_db_r的锁存为什么要在wr_state为低时进行,这个问题特权同学是这么考虑的:wr_state拉低期间即MCU片选和写选通一起有用期间数据总线/地址总线一定是安稳的,而为了有更足够的数据树立时刻,比较常见的做法是用mcu_wr_n的上升沿锁存数据,而假如用比如posedge mcu_wr_n来做触发锁存数据/地址,那就很简单呈现异步抵触的问题(这个问题的损害今后的文章具体评论),达不到同步的作用,所以这儿就用一个电平信号作为使能信号来得愈加保险。换个视点看,无非是wr_state上升沿的前0-20ns都有或许是最终锁存下来的数据,这关于咱们足够的MCU写时序来说是捉襟见肘了。理论上来说,wr_stata是一个总线使能信号,应该要做至少一级同步再运用更保险一些,可是出于咱们富余的时序,即便是wr_stata没有进行同步处理,退一步说,呈现了wr_state的一个亚稳态时在锁存数据,那么此刻的数据总线/地址总线的数据也不会受到影响,该什么值仍是什么值。不同的运用中往往有答应非常规处理的时分,就像时序剖析中的时序破例相同。期望咱们能了解这个部分,不了解也没有联系,今后的文章会更深入探讨异步时钟域中亚稳态这个大问题,届时再回头看看或许你就理解了。