自分用なのでコメントされても返信できません
環境
FPGA ALINX_AX7103
vivado 2024.1
コード
サンプルコード https://github.com/alinxalinx/AX7103 はコメントが化けてたりするからこっちで書き直し
eeprom_test.v
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// モジュール名: eeprom_test
// 機能: I2Cバスを使用してEEPROMに書き込みと読み出しを行う
//////////////////////////////////////////////////////////////////////////////////
module eeprom_test
(
input sys_clk_p, // システムクロック(差動入力、正)
input sys_clk_n, // システムクロック(差動入力、負)
input RSTn, // リセット信号(負論理)
output SCL, // EEPROM I2Cクロック
inout SDA // EEPROM I2Cデータ
);
wire [7:0] RdData; // EEPROMから読み出したデータ
wire Done_Sig; // I2C通信完了信号
reg [3:0] i; // ステートマシンの状態
reg [3:0] rLED; // LED表示用(読み出したデータの表示)
reg [7:0] rAddr; // EEPROMのアドレス
reg [7:0] rData; // EEPROMに書き込むデータ
reg [1:0] isStart; // I2C開始信号(01: 書き込み, 10: 読み出し)
/////////////////// 差動クロックを単一クロックに変換 ////////////////////////
wire sys_clk_ibufg;
IBUFGDS #
(
.DIFF_TERM ("FALSE"),
.IBUF_LOW_PWR ("FALSE")
)
u_ibufg_sys_clk
(
.I (sys_clk_p),
.IB (sys_clk_n),
.O (sys_clk_ibufg)
);
/***************************/
/* EEPROMの書き込みと読み出し */
/***************************/
always @ ( posedge sys_clk_ibufg or negedge RSTn )
if( !RSTn ) begin
i <= 4'd0;
rAddr <= 8'd0;
rData <= 8'd0;
isStart <= 2'b00;
rLED <= 4'b0000;
end
else
case( i )
0:
if( Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end // I2C書き込み完了を待つ
else begin isStart <= 2'b01; rData <= 8'h12; rAddr <= 8'd0; end // EEPROMに0x12をアドレス0に書き込む
1:
if( Done_Sig ) begin isStart <= 2'b00; i <= i + 1'b1; end // I2C読み出し完了を待つ
else begin isStart <= 2'b10; rAddr <= 8'd0; end // EEPROMのアドレス0から読み出す
2:
begin rLED <= RdData[3:0]; end // 読み出したデータの下位4ビットをLEDに表示
endcase
/***************************/
// I2C通信モジュール
/***************************/
iic_com U1
(
.CLK( sys_clk_ibufg ),
.RSTn( RSTn ),
.Start_Sig( isStart ), // I2Cの読み書きコマンド: 2'b01=書き込み, 2'b10=読み出し
.Addr_Sig( rAddr ), // EEPROMのアドレス
.WrData( rData ), // EEPROMに書き込むデータ
.RdData( RdData ), // EEPROMから読み出したデータ
.Done_Sig( Done_Sig ), // I2C通信完了信号
.SCL( SCL ),
.SDA( SDA )
);
/***************************/
// ChipScope ILA(信号の観察用)
/***************************/
wire [7:0] probe0;
ila_0 u_ila_0(
.clk(sys_clk_ibufg),
.probe0(probe0)
);
assign probe0[7:0] = RdData[7:0];
endmodule
iic_com.v
module iic_com
(
input CLK, // システムクロック
input RSTn, // リセット信号(負論理)
input [1:0] Start_Sig, // 読み書きコマンド(01: 書き込み, 10: 読み出し)
input [7:0] Addr_Sig, // EEPROMのワードアドレス
input [7:0] WrData, // EEPROMに書き込むデータ
output [7:0] RdData, // EEPROMから読み出したデータ
output Done_Sig, // EEPROMの読み書き完了信号
output SCL, // I2Cクロック
inout SDA // I2Cデータ
);
parameter F250K = 10'd800; // 250KHz I2Cクロックの分周係数(例: 200MHz / 800 = 250KHz)
reg [4:0] i; // ステートマシンの状態
reg [4:0] Go; // 次の状態への遷移用
reg [10:0] C1; // クロックカウンタ
reg [7:0] rData; // 送信/受信データ
reg rSCL; // SCL信号
reg rSDA; // SDA信号
reg isAck; // ACK信号
reg isDone; // 完了信号
reg isOut; // SDAの出力制御
assign Done_Sig = isDone;
assign RdData = rData;
assign SCL = rSCL;
assign SDA = isOut ? rSDA : 1'bz; // SDAの出力制御
//****************************************//
//* I2Cの書き込みシーケンス *//
//****************************************//
always @ ( posedge CLK or negedge RSTn )
if( !RSTn ) begin
i <= 5'd0;
Go <= 5'd0;
C1 <= 11'd0;
rData <= 8'd0;
rSCL <= 1'b1;
rSDA <= 1'b1;
isAck <= 1'b1;
isDone <= 1'b0;
isOut <= 1'b1;
end
else if( Start_Sig[0] ) // I2C書き込みコマンド
case( i )
0: // スタート信号の生成
begin
isOut <= 1; // SDAを出力モードに
if( C1 == 0 ) rSCL <= 1'b1;
else if( C1 == 800 ) rSCL <= 1'b0; // SCLをHIGHからLOWに
if( C1 == 0 ) rSDA <= 1'b1;
else if( C1 == 400 ) rSDA <= 1'b0; // SDAをHIGHからLOWに(スタート条件)
if( C1 == 1000 -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
1: // デバイスアドレスの送信(書き込み)
begin rData <= {4'b1010, 3'b000, 1'b0}; i <= 5'd7; Go <= i + 1'b1; end // 0x50 (書き込み)
2: // ワードアドレスの送信
begin rData <= Addr_Sig; i <= 5'd7; Go <= i + 1'b1; end
3: // データの送信
begin rData <= WrData; i <= 5'd7; Go <= i + 1'b1; end
4: // ストップ信号の生成
begin
isOut <= 1'b1;
if( C1 == 0 ) rSCL <= 1'b0;
else if( C1 == 200 ) rSCL <= 1'b1; // SCLをLOWからHIGHに
if( C1 == 0 ) rSDA <= 1'b0;
else if( C1 == 600 ) rSDA <= 1'b1; // SDAをLOWからHIGHに(ストップ条件)
if( C1 == 1000 -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
5: // 完了信号の設定
begin isDone <= 1'b1; i <= i + 1'b1; end
6:
begin isDone <= 1'b0; i <= 5'd0; end
7,8,9,10,11,12,13,14: // データ送信(デバイスアドレス/ワードアドレス/データ)
begin
isOut <= 1'b1;
rSDA <= rData[14-i]; // MSBから送信
if( C1 == 0 ) rSCL <= 1'b0;
else if( C1 == 200 ) rSCL <= 1'b1; // SCLのHIGH期間
else if( C1 == 600 ) rSCL <= 1'b0;
if( C1 == F250K -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
15: // ACKの受信
begin
isOut <= 1'b0; // SDAを入力モードに
if( C1 == 400 ) isAck <= SDA; // ACKを読み取る
if( C1 == 0 ) rSCL <= 1'b0;
else if( C1 == 200 ) rSCL <= 1'b1;
else if( C1 == 600 ) rSCL <= 1'b0;
if( C1 == F250K -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
16:
if( isAck != 0 ) i <= 5'd0; // ACKがなければリセット
else i <= Go;
endcase
else if( Start_Sig[1] ) // I2C読み出しコマンド
case( i )
0: // スタート信号の生成
begin
isOut <= 1;
if( C1 == 0 ) rSCL <= 1'b1;
else if( C1 == 800 ) rSCL <= 1'b0;
if( C1 == 0 ) rSDA <= 1'b1;
else if( C1 == 400 ) rSDA <= 1'b0;
if( C1 == 1000 -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
1: // デバイスアドレスの送信(書き込み)
begin rData <= {4'b1010, 3'b000, 1'b0}; i <= 5'd9; Go <= i + 1'b1; end // 0x50 (書き込み)
2: // ワードアドレスの送信
begin rData <= Addr_Sig; i <= 5'd9; Go <= i + 1'b1; end
3: // 再スタート信号の生成
begin
isOut <= 1'b1;
if( C1 == 0 ) rSCL <= 1'b0;
else if( C1 == 200 ) rSCL <= 1'b1;
else if( C1 == 1000 ) rSCL <= 1'b0;
if( C1 == 0 ) rSDA <= 1'b0;
else if( C1 == 200 ) rSDA <= 1'b1;
else if( C1 == 600 ) rSDA <= 1'b0;
if( C1 == 1200 -1 ) begin C1 <=11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
4: // デバイスアドレスの送信(読み出し)
begin rData <= {4'b1010, 3'b000, 1'b1}; i <= 5'd9; Go <= i + 1'b1; end // 0x51 (読み出し)
5: // データの受信
begin rData <= 8'd0; i <= 5'd19; Go <= i + 1'b1; end
6: // ストップ信号の生成
begin
isOut <= 1'b1;
if( C1 == 0 ) rSCL <= 1'b0;
else if( C1 == 200 ) rSCL <= 1'b1;
if( C1 == 0 ) rSDA <= 1'b0;
else if( C1 == 600 ) rSDA <= 1'b1;
if( C1 == 1000 -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
7: // 完了信号の設定
begin isDone <= 1'b1; i <= i + 1'b1; end
8:
begin isDone <= 1'b0; i <= 5'd0; end
9,10,11,12,13,14,15,16: // データ送信(デバイスアドレス/ワードアドレス)
begin
isOut <= 1'b1;
rSDA <= rData[16-i]; // MSBから送信
if( C1 == 0 ) rSCL <= 1'b0;
else if( C1 == 200 ) rSCL <= 1'b1;
else if( C1 == 600 ) rSCL <= 1'b0;
if( C1 == F250K -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
17: // ACKの受信
begin
isOut <= 1'b0;
if( C1 == 400 ) isAck <= SDA;
if( C1 == 0 ) rSCL <= 1'b0;
else if( C1 == 200 ) rSCL <= 1'b1;
else if( C1 == 600 ) rSCL <= 1'b0;
if( C1 == F250K -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
18:
if( isAck != 0 ) i <= 5'd0;
else i <= Go;
19,20,21,22,23,24,25,26: // データ受信
begin
isOut <= 1'b0;
if( C1 == 100 ) rData[26-i] <= SDA; // MSBから受信
if( C1 == 0 ) rSCL <= 1'b0;
else if( C1 == 200 ) rSCL <= 1'b1;
else if( C1 == 600 ) rSCL <= 1'b0;
if( C1 == F250K -1 ) begin C1 <= 11'd0; i <= i + 1'b1; end
else C1 <= C1 + 1'b1;
end
27: // NACKの送信
begin
isOut <= 1'b1;
if( C1 == 0 ) rSCL <= 1'b0;
else if( C1 == 200 ) rSCL <= 1'b1;
else if( C1 == 600 ) rSCL <= 1'b0;
if( C1 == F250K -1 ) begin C1 <= 11'd0; i <= Go; end
else C1 <= C1 + 1'b1;
end
endcase
endmodule
IP
左のサイドバーより、 IP Catalog > Search: ILA (Integrated Logic Analyzer)



設定箇所
- Number of Probes:X 1 (probe0のみ使用)
- Probe Width: 8 (probe0[7:0])
動作確認

RdDataに 0x12が格納されてるから動いてるっぽい
コードコピペしてるだけで全く中身を理解してないのとまずI2Cの理解がないから いろいろと
ゆっくり調べていこうと思う
コメント