xilinx vivado eeprom 書き込み

vivado xilinx ILA setting FPGA

自分用なのでコメントされても返信できません

環境

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の理解がないから いろいろと
ゆっくり調べていこうと思う

コメント

タイトルとURLをコピーしました