I2C BUS SDA Multiplex

概要)

今回は、I2C busのデータラインSDAのマルチプレックスを考えてみます。

IC2 busのSDAラインは、普段はmaster側の出力ポートですが、device側からのACK, リード時のデータ読み込み時等、master側は入力ポートになる双方向ポートに設定する必要があります。これをマルチプレックスするとなると、そう単純ではありません。FPGAで単純に考えると、双方向ポートを2つ用意して、それを接続すれば良いように見えますが、コンパイルは通りません。

I2C SDA => FPGA => SDA_A, SDA_BのようにFPGAに入力されたSDAの出力先を変更したいケースがありますが、上記の理由で、そう単純にはいきません。

コンパイルが通らない例)

Error : BIDIR pin "SDA_1" feeds BIDIR pin "SDA_0"

当初は何も考えずに上記の回路で、間に切り替えSWを入れれば良いかと考えましたが、コンパイルはエラーのようになりました。

対策回路)

ここから、トライステートIOでお互いを制御するものを考えましたが、これも正しく動かず(デッドロックしてしまう)、順序回路で次のようなものを考えました。

これによって、双方向のIOが作成できました。注意点は、clkinのサンプリングレートで伝達が遅延するということです。

Verilogコード

module i2c_sda_bidir_io(clkin, sda0_in, sda0_out, sda1_in, sda1_out);

input clkin;

input sda0_in;

output reg sda0_out;

input sda1_in;

output reg sda1_out;

reg [3:0]indx;

initial begin

indx = 0;

sda0_out = 1;

sda1_out = 1;

end

always@(posedge clkin) begin

case (indx)

0: begin

if (sda0_in==0) begin

sda1_out=0;

indx=2;

end

else begin

indx=1;

end

end

1: begin

if (sda1_in==0) begin

sda0_out=0;

indx=3;

end

else begin

indx=0;

end

end

2: begin

if (sda0_in==1) begin

sda1_out=1;

indx=0;

end

end

3: begin

if (sda1_in==1) begin

sda0_out=1;

indx=0;

end

end

default: begin

sda0_out=1;

sda1_out=1;

indx=0;

end

endcase

end

endmodule