【ZYBO】オーディオ・コーデックSSM2603を使ってみる(I2Cアクセス)

ZYBOにはアナログ・デバイセズ社製オーディオ・コーデックSSM2603が搭載されています。これを使って色々遊んでみたいと思っています。

SSM2603のレジスタはI2Cバスでアクセスできます。ZynqのPSにはI2Cコントローラーが搭載されているので、これを使用すれば簡単にレジスタ設定が出来るはず、ということで試してみました。

使用OS Windows 10
Vivado 2016.3

尚、VivadoのBlock Design基本的な手順や使用方法については以下を参照して下さい。
【Zynq】ZYBOでPSのMIOを使用してLチカしてみた

I2Cについて

こちらのページが非常に分かりやすかったです。
Bluefish Webpage – I2Cの低速通信について

Zynq PSでI2Cコントローラの使用設定

今回のプロジェクト設定です。

項目 設定
Project Name
  Project name i2c_test
  Project location C:/fpga/zybo/i2c_test/2016.3
Project Type RTL Project
Add Sources デフォルト
Add Existing IP(optional) デフォルト
Add Constraints(optional) デフォルト
Default Part
  Select Boards
  Display Name Zybo

プロジェクト作成後、以下内容の制約ファイルを追加します。(ZYBO_Master.xdcを編集するのが一番簡単です。)

#Audio Codec/external EEPROM IIC bus
#IO_L13P_T2_MRCC_34
set_property PACKAGE_PIN N18 [get_ports iic_0_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports iic_0_scl_io]

#IO_L23P_T3_34
set_property PACKAGE_PIN N17 [get_ports iic_0_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports iic_0_sda_io]

Block Designを作成後、Processing Systemを追加。設定ダイアログを開いて、以下を設定。

  • “Peripheral I/O Pins”で”I2C 0″の”EMIO”をダブルクリック。これにより、PLから制御可能なピンとI2Cコントローラを接続できます。ZYBOのSSM2603はI2Cピンが汎用I/Oに接続されているので、EMIOを使用する必要があります。
  • “DDR Configuration”の”Enable DDR”をOFF。今回は関係ありませんが不要設定はOFFにしておきます。
  • PS設定 I2C EMIO
    PS設定 Enable DDR OFF
    設定変更を適用してダイアログを閉じた後、”processing_system7_0″に”IIC_0″ポートが追加されます。”IIC_0″ポートを右クリックして”Make External”を選択。以上でBlock Designの設定は完了です。
    Block Design I2C

    “Sources”ビュー→”Sources”タブ→”Hierarchy”タブに表示されるBoard_Designを右クリックして”Generate Output Products”と”Create HDL Wrapper”を実行。これでH/Wの実装は終了ですので、”Generate Bitstream”をクリックして一通りの処理を実行します。最後にハードウェア情報をエクスポートするのも忘れないようにして下さい。(File→Export→Export HardwareでInclue Bitstreamにチェック)

    I2Cコントローラの制御(S/W)

    VivadoメニューからXilinx SDKを起動します(File→Launch SDK)。起動後、”File”→”New”→”Application Project”を選択して、以下設定で新規作成します。
    New Application Project
    New Application Project template
    プロジェクトが追加されたら、左側”Project Explorer”の”i2c_test”を右クリックして”New”→”Source File”からCソースファイルを追加。今回のソースは次のような感じです。

    #include "xparameters.h"
    #include "xiicps.h"
    #include "xil_printf.h"
    
    #define IIC_SCLK_RATE 100000
    #define SSM2603_REG_NUM 14
    XIicPs iic;
    
    int main ()
    {
        XIicPs_Config *config;
        int status;
        // SSM2603レジスタアドレス
        u8 sendBuf[SSM2603_REG_NUM]     = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
                                            0x07, 0x08, 0x09, 0x0F, 0x10, 0x11, 0x12};
        // SSM2603レジスタリード値格納用バッファ
        u8 recvBuf[2*SSM2603_REG_NUM]   = {0};
    
        // ドライバ初期化
        config = XIicPs_LookupConfig(XPAR_XIICPS_0_DEVICE_ID);
        if (config == NULL) {
            xil_printf("XIicPs_LookupConfig error");
            return XST_FAILURE;
        }
        status = XIicPs_CfgInitialize(&iic, config, config->BaseAddress);
        if (status != XST_SUCCESS) {
            xil_printf("XIicPs_CfgInitialize error");
            return XST_FAILURE;
        }
        // ハードウェア実行に問題がないかを確認するためのセルフテスト
        status = XIicPs_SelfTest(&iic);
        if (status != XST_SUCCESS) {
            xil_printf("XIicPs_SelfTest error");
            return XST_FAILURE;
        }
        // I2Cクロックスピード設定
        XIicPs_SetSClk(&iic, IIC_SCLK_RATE);
        
        // SSM2603全レジスタリード
        for (u8 i = 0; i < SSM2603_REG_NUM; i++) {
            u8 sendBufTemp;
            sendBufTemp = sendBuf[i] << 1;  // アドレスは7bitで上詰め
            // リピートスタートコンディションを有効設定
            XIicPs_SetOptions(&iic, XIICPS_REP_START_OPTION | XIICPS_7_BIT_ADDR_OPTION);
            // I2C送信アクセス
            status = XIicPs_MasterSendPolled(&iic, &sendBufTemp, 1, 0x1a);
            if (status != XST_SUCCESS) {
                xil_printf("XIicPs_MasterSendPolled error");
                return XST_FAILURE;
            }
            // リピートスタートコンディションをクリア
            XIicPs_ClearOptions(&iic, XIICPS_REP_START_OPTION);
            // I2C受信アクセス
            status = XIicPs_MasterRecvPolled(&iic, recvBuf, 2, 0x1a);
            if (status != XST_SUCCESS) {
                xil_printf("XIicPs_MasterRecvPolled error");
                return XST_FAILURE;
            }
            // 受信データ表示
            xil_printf("address:%x data:%x%x\r\n", sendBuf[i], recvBuf[1], recvBuf[0]);
        }
    
        return 0;
    }

    ハマったところは以下2点です。

  • スレーブアドレスは上位ビットから出力されるので1bit左シフト。
  • レジスタリード時はライト→リードとデータ転送方向が変化するのでリピートスタートコンディションを発行。リピートスタートコンディションについては参考ページを参照。
  • ここまでで実装は終了です。System Debuggerを実行(i2c_testプロジェクトを右クリック→”Run As”→”1 Launch on Hardware (System Debugger)”)すると、画面下部の”TCF Debug Virtual Terminal – ARM Cortex-A1 MPCore #0″にレジスタリード値が表示されます。”TCF Debug Virtual Terminal”はTerminalの右上にあるディスプレイアイコン(Display Selected Console)から選択可能です。
    Xilinx SDK TCF Debug Virtual Terminal

    シェアする

    • このエントリーをはてなブックマークに追加

    フォローする