CPLD/FPGA中双向总线的实现方法

作者:duoduo

    对于CPLD/FPGA初学者而言,如何实现双向信号往往是个难题。duoduo当年初接触CPLD/FPGA的时候也为这个问题头疼过。让我们透过下面这个简单的例子看看CPLD/FPGA设计中如何实现双向信号。

    假设HOST通过CPLD/FPGA读写外设(比如MCU通过CPLD/FPGA读写一块memory的情况),为了简化问题的说明,假设HOST端只有写信号hwr_,读信号hrd_和双向8位数据总线hd;外设端相应有写信号swr_,读信号srd_和双向8位数据总线sdCPLD/FPGA对所有信号只作一个通路的作用,即对HOST和外设来讲,它们都认为自己是直接连接到了对方,而不知道CPLD/FPGA的存在(显然实际电路中这样做可能并没有什么用处,但是这个例子只是用来说明双向信号的用法)。

    下图中表示了信号流向,虚线部分表示在CPLD/FPGA中通过的信号流。可以看到,hwr_swr_hrd_srd_都只是单向信号,HdSd则是双向的总线。

    单向信号很简单就不多说了,看看双向信号如何实现。首先从CPLD/FPGAIO结构上分析如何实现双向。尽管ICIO Pad结构上可能很复杂,但是从实现双向功能这个目的来看,我们可以把IO Pad结构简化成下面的图示:

    图中A_OUT_OEA_OUTA_IN均为CPLD/FPGA内部信号,A则是CPLD/FPGA的引脚信号名。显然,A_IN始终反映了A的实际状态,即引脚输入,A_OUTA_OUT_OE控制,当A_OUT_OE为高的时候A_OUT可以通过三态缓冲器输出到引脚上,即引脚输出。因此,在CPLD/FPGA内部定义A_IN(实际上A_IN就是A)A_OUTA_OUT_OE三个信号用于内部逻辑,并合适地产生A_OUT_OE信号,就可以实现双向引脚。

    根据这个实现双向IO的原理,对上面的HOST读写外设的例子,我们可以这样来描述:

module bidir(

       hwr_,

       hrd_,

       hd,

       swr_,

       srd_,

       sd,

       //dumy

);

 

input  hwr_;

input  hrd_;

inout  [7:0]    hd;

output swr_;

output srd_;

inout  [7:0]    sd;

//input  dumy;

 

wire hd_out_oe;

reg [7:0]  hd_out;

wire sd_out_oe;

reg [7:0]  sd_out;

 

always @(hwr_)

begin

       if (!hwr_)       sd_out = hd;

end

 

always @(hrd_)

begin

       if (!hrd_) hd_out = sd;

end

 

assign swr_ = hwr_;

assign srd_ = hrd_;

//assign sd_out_oe = !hwr_ & dumy;

assign sd_out_oe = !hwr_;

assign hd_out_oe = !hrd_;

 

assign hd = hd_out_oe ? hd_out : 8'hzz;

assign sd = sd_out_oe ? sd_out : 8'hzz;

endmodule

    这段描述使用的是VerilogHDL,其中有个被注释掉的信号dumy,暂时先不解释。这个描述是可综合的,我们使用AlteraMaxPlusII来仿真一下:

    嗯,看起来不错,hwr_有效的时候hd正确传送到了sd,实现了hd输入,sd输出;hrd有效的时候sd正确传送到了hd,实现了sd输入,hd输出,这样hdsd两个双向8位总线都正确实现了。

    且慢,有没有不太好的地方?上面描述中hwr_直接作为了sd输出的使能控制信号sd_out_oe,由于swr_直接来自hwr_,因此swr_上沿到来后sd输出被立即关闭,许多外设器件要求有一定的数据写保持时间,而现在sd的写保持时间却为0。怎样克服这个缺点呢?把前面关于dumy信号的代码去掉注释符号”//”,把assign sd_out_oe = !hwr_;这句注释掉,再编译仿真一下看看:

    哈哈,这下sd的输出保持时间够长了吧?dumy是用户定义的一个CPLD/FPGA外部引脚,按照上面的描述,在实际电路中将其固定接高,由于需要dumy信号和hwr取反然后通过与逻辑再形成sd_out_oe,带有门延迟,因此与最初的描述方法相比,sd输出关闭被延迟了。使用dumy信号这种方法需要额外占用CPLD/FPGA的一个引脚,也可以采取其他方式实现这个延迟功能。而Hd不需要这样特殊处理,为什么?呵呵,读者自己想想看?

    还有一个看起来不太好的地方:HOSThrd_有效而外设尚未将数据准备好的时候,hd总线上有一段时间的不定态,不过这不影响HOST的读功能,一般情况下不需要特殊处理,如果不希望出现这个现象,可以通过sd上拉、时钟同步处理等手段将其消除。

    方才上面说过,这个例子只是用来说明双向信号的实现方法,例子本身可能没有什么实际用处,嘿嘿,如果把

        assign hd = hd_out_oe ? hd_out : 8'hzz;  

        assign sd = sd_out_oe ? sd_out : 8'hzz;  

        改写为:

        assign hd = hd_out_oe ? {hd_out[3:0],hd_out[7:4]} : 8'hzz;
        assign sd = sd_out_oe ? {sd_out[3:0],sd_out[7:4]} : 8'hzz;

        发生什么现象了?对,输入输出总线上高低半字节互换了!这就是曾经用过的最简单的一种硬件加密方法,有用了吧?

    写文章好累呀,简直比用VerilogHDL写代码还难:)

 

 

 
 
Copyright @2004-2005      http://www.ifelec.com      All Rights Reserved
版权所有:接口工作室      站长:duoduo