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