FPGA 雙向口的使用及Verilog實現


FPGA的雙向口在FPGA的設計應用中使用及其廣泛,如I2C接口中的SDA,3線制的SPI接口中的數據線,傳統控制總線中的數據總線,以及內存的訪問DDR3/DDR4的數據總線等都是雙向訪問的。雙向訪問涉及到的概念比較多,如三態的概念,高阻的概念,輸入、輸出引腳合並,輸入輸出分時復用等概念,因此初學者往往比較迷惑,覺得無所適從,本文從底層基本原理入手,揭示雙向口的機理,並用Verilog程序開發為例一步步引導大家如何使用雙向口(inout)的使用與開發。

  1. 雙向口涉及的基本模型
    • 三態門

為了描述方便,這里給兩個命名tri0和tri1(tri是三態門(tri-state的縮略寫法,其實在Verilog語法中有兩個模型與之對應,分別為bufif0,bufif1。圖1,2中的oe在傳統的三總線結構中,通常對應OE(讀)或WE(寫)。

      • tri0

bufif0是三態門模型,其例化格式如下:

bufif0 tri0 (out, in, oe); //tri0是bufif0的例化名。

其電路形態形態如圖1:

 

%title插圖%num

圖1 bufif0

 

在這兩個模型中,oe端決定輸出的形態,在tri0的模型中,如果oe為’0’, out就得到out0(out0是FPGA內部邏輯產生的值)的值,最終輸出到端口PAD上。如果 oe為’1’,此時三態門的輸出為高阻狀態,在Verilog 描述中用’Z’表示,即三態門與外界是斷開狀態,如圖2所示。

%title插圖%num

圖2

圖1,2中的oe在傳統的三總線結構中,通常對應OE(讀)或WE(寫)。

      • tri1

bufif1是另一種三態門模型,其例化格式如下:

bufif1 tri1 (out, in, oe); //tri1是bufif1的例化名。

其電路形態形態如圖3:

%title插圖%num

圖3 buffif1

在這兩個模型中,oe端決定輸出的形態,在tri1的模型中,如果oe為’1’, out就得到out0(out0是FPGA內部邏輯產生的值)的值,最終輸出到端口PAD上。如果 oe為’0’,此時三態門的輸出為高阻狀態,在Verilog 描述中用’Z’表示,即三態門與外界是斷開狀態,如圖4所示。

%title插圖%num

圖4

圖3,4中的oe在傳統的三總線結構中,通常對應OE#(讀)或WE#(寫)。

  • 輸入、輸出在雙向口合並

FPGA的I/O基本上都支持雙向數據操作,但是由於對外輸出端口只有一個,因此需要在端口處合並。

    • 利用tri0合並,如圖5,

%title插圖%num

圖5

在圖5中,輸出流向從FPGA內部邏輯out0–>out–>PAD;輸入流向PAD–>in–>FPGA 內部邏輯。

    • 利用tri1合並,如圖6

%title插圖%num

圖6

在圖6中,輸出流向從FPGA內部邏輯–>out0–>out–>PAD;輸入流向PAD–>in–>FPGA 內部邏輯。

    • 輸入、輸出分時復用。

從圖5,6可以看出,由於PAD 共享輸入、輸出。一般在推拉驅動模型中,三態門的輸出能力相對較強,考慮到如果接到FPGA外部器件有同樣的接口,應該嚴格控制他們的時序關系,以免發生短路。如圖7,

%title插圖%num

圖7

在圖7中如果a,b兩個器件同時輸出(兩個器件的oe都為’1’),如果恰好一個器件輸出為高,一個為低,則會引起短路現象。因此要嚴格控制時序,保證a,b兩個器件避開由內部邏輯同時驅動輸出的情況。只有在兩個器件oe一個為高,另一個為低,或者兩個器件的oe都為低的時候,兩個器件的端口才能連在一起。

  • 分時復用的實現
    • 推拉結構

在傳統的工業控制總線中,分為主從模式。一般MCU或FPGA為MASTER,SRAM 、EPROM等器件為從模式。在這種模式下,FPGA生成控制信號oe, 同時取反后接到對方的OE端上。如圖8:

 

%title插圖%num

圖8

圖8中,由於oe是由一個主器件控制,因此實現推拉模式,即主器件輸入,從器件輸出;主器件輸出,從器件輸入。從輸出角度看,在輸出的時段內,高低電平直接輸出,這一點不同后面要介紹的漏極開路(OD)帶上拉電阻的結構。

推拉MOS管模型如圖9:

%title插圖%num

圖9

例1:Master 模式單線控制雙向接口(Verilog)。

門級描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
module bidir_gate
(
     input            clk,
     input            rst,
     inout      [3:0] a,
     output           noe,
     output reg [3:0] in_val 
);
 
reg [3:0] counta, countb;
 
assign noe = ~counta[3];
bufif1 tri1_0(a[0], countb[0], ~noe);
bufif1 tri1_1(a[1], countb[1], ~noe);
bufif1 tri1_2(a[2], countb[2], ~noe);
bufif1 tri1_3(a[3], countb[3], ~noe);
 
always@(posedge clk or posedge rst)
if(rst)
begin
     counta <= 0;
     countb <= 0;
end
else
begin
     counta <= counta + 1;
 
     if(counta == 15)
         countb <= countb + 1;
 
     if(noe)
         in_val <= a;
end
endmodule

RTL描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
module bidir_RTL
(
     input            clk,
     input            rst,
     inout      [3:0] a,
     output           noe,
     output reg [3:0] in_val 
);
 
 
reg [3:0] counta, countb;
 
assign noe = ~counta[3];
assign  a  = (!noe) ? countb : 4'bZZZZ;   //雙向口輸出
 
 
always@(posedge clk or posedge rst)
if(rst) begin
     counta <= 0;
     in_val <= 0;
end
else begin
     counta <= counta + 1;
 
     if(counta==15)
         countb <= countb + 1;
 
     if(noe)
         in_val <= a; //獲得輸入,可以給FPGA內部其它模塊使用
end
 
endmodule

在RTL的描述中可以看出,在Verilog中直接使用高阻4’bZZZZ就起到了三態門的效果,因此應習慣這種使用方法。

例2:Master 模式雙向結構(Verilog RTL), 結構模式參看例1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
module bidir_gate
(
     input            clk,
     input            rst,
     inout      [3:0] a,
     output           noe,
     output           nwe,
     output reg [3:0] in_val 
);
 
 
reg [3:0] counta, countb;
 
assign noe = ~counta[3];
assign nwe = counta[3];   //采用tri0模型
assign a   = ~nwe ? countb : 4'bZZZZ;
 
always@(posedge clk or posedge rst)
if(rst) begin
     counta <= 0;
end
else begin
     counta <= counta + 1;
 
     if(counta==15)
         countb <= countb + 1;
 
    if(~noe) in_val <= a;
 
end
 
 
 
endmodule
      • 上拉電阻結構(OD結構)

上拉電阻結構適合總線模型,如I2C總線,485總線等多master多slave的結構。在上拉電阻的結構中,雙向口一般不需要讀(noe)、寫(nwe)控制接口配合。但需要協議配合實現。以I2C 為例,在主、從的結構中都采用OD的方式如圖10,因此多個器件的輸出端可以直接通過連線接在一起。但在由於輸出沒有推拉結構,在期望高電平輸出時,由於MOS管關閉,實際輸出為也為高阻,因此需要在總線上結上拉電阻,以保證在輸出階段且輸出為高電平時,可以得到確保的高電平狀態,如圖11,

%title插圖%num

圖10 OD結構

%title插圖%num

圖11

在OD(或OC)的設計中,Verilog描述在輸入、低電平輸出時與推拉結構一致,只有在輸出高電平時不同。在輸出高電平時要確保真正輸出的是高阻。I2C總線接口就是標准的OD結構,在SDA,SDL都要加上拉電阻,如圖12

%title插圖%num

圖12

由於inout信號一般只在端口使用,因此在FPGA的內部邏輯(內部模塊)將會把inout(雙向口)變換成input, output類型進行傳遞, 具體的使用見例3.

例3:I2C接口Verilog描述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
module I2C_intereface
(
     inout        SCL,
     inout        SDA,
     input  [7:0] datain,
     output [7:0] dataout
);
 
 
wire    SCL_in;
wire    SDA_in;
 
wire    SCL_out;
wire    SDA_out;
 
assign  SCL     = SCL_out ? 1’bZ : 1’b0;   //這里處理方式與推拉結構不同。
assign  SCL_in  = SCL;
assign  SDA     = SDA_out ? 1’bZ : 1’b0;
assign  SDA_in  = SDA;
 
I2C  I2C_inst
(
     .SCL_in  (SCL_in),
     .SDA_in  (SDA_in),
 
     .SCL_out (SCL_out),
     .SDA_out (SDA_out),
 
     .datain  (datain),
     .dataout (dataout)
)
 
 
endmodule

上面程序中,輸入直接賦值給SDA_in,是全階段賦值,即把輸出階段也給輸入端賦值,因此在I2C 的程序中,何時使用輸入的值,應有嚴格定時。關於I2C的時序描述請參照I2C部分內容。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM