マイコン(Master)とZynq(Slave)をI2C通信する方法 (3)Zynqのソフトウェア構成

Vitis
スポンサーリンク

本記事の概要

概要

I2C(Inter-Integrated Circuit)規格でマイコンとZynqをデータを通信する方法を解説。実験に用いるマイコンには、Wio TerminalのATSAMD51P19を選ぶ。まず、マイコンの方をマスター(Manager, Master)として、スレーブ(Subordinary, Slave)であるZynqからデータを要求する。
本記事では、ZynqのPS部で動作させるサンプルプログラムxiicps_intr_slave_example.cについて解説する。

前回の記事から、センシングデバイスをI2C通信で制御する知見を得るため、I2C通信規格について学ぶとともに、ZynqとWio TerminalのマイコンATSAMD51P19とのI2C通信に挑戦しています。

前回の記事へのリンク

本記事の概要

前回までの記事で

  • Wio TerminalとZyboの接続
  • Zynqで動かすソフトウェアの土台となるハードウェア構成

まで構想・構築ができたので、次にZynqで動かすソフトウェアを作ります。

ソフトウェアはすでにVitisで提供されているサンプルプログラムxiicps_intr_slave_example.cを用いました。
本記事では、サンプルプログラムの動作原理について調べた内容を解説していきます。

本記事の対象読者:以下の状況に直面している方
  • I2C通信の動作原理、構成について知りたい場合
  • ZynqのプロセッサからI2C通信を行うAPIドライバの使用方法を知りたい場合
  • Wio Terminalを使った、外部機器とのI2C通信の方法を知りたい場合

前回の記事と今後の記事では、以下の順に解説をしています。

  1. I2C通信の概略とデバイス間の接続方法
  2. Zynqにおけるブロックデザイン
  3. サンプルプログラムxiicps_intr_slave_example.cにおけるドライバAPIの動作原理(←本記事)
  4. Wio Terminalの制御コード(Arduino)

Vitis IDEでのアプリケーションの構築

workspaceの立ち上げ

前回の記事でXSAファイルの作成までできたので、XSAファイルからVitisのworkspaceを作成します。

workspaceの作成方法は、Hello worldとLED点滅回路と同様なので省略します。
以下の記事を参考にしていただければと思います。

Vitis IDEが立ち上がったら、アプリケーションプロジェクトを作成します。
今回は、ゼロから作るのではなく、Vitis IDE上にすでに用意されているサンプルプログラムを活用しようと思います。

サンプルプログラムxiicps_intr_slave_example.cを利用する

別の記事にまとめたのですが、 Vitis IDE上には各APIの機能説明してあるドキュメンテーションへのリンクや用例へのリンクがすでに用意されています。
こちらの記事で、I2C通信のペリフェラルに関連するドライバのドキュメンテーションと用例の参照方法を解説しているので、ご覧いただければと思います。

I2Cペリフェラルを制御するドライバに関してのドキュメンテーションを参照したところ、ZynqをI2Cのスレーブ機器として扱うサンプルコードには、以下の2つがあるようです。

slave側として扱うときのI2CのドライバAPIのサンプルコード
  • xiicps_intr_slave_example.c: 外部のマスター端末からの割り込みが発生した時に作動
  • xiicps_polled_slave_example.c: ポーリングモード(一定の時間ごとに順に要求がないか尋ねるモード)で作動

今回は、Wio Terminalのマイコンに主導権を握らせて、I2C通信をさせたかったので、割り込みを使う xiicps_intr_slave_example.c を利用します。

xiicps_intr_slave_example のアプリケーションプロジェクトをインポートし、このプロジェクトをそのままビルドして使用しました。

githubにも同様のドキュメンテーションと用例のアプリケーションがあるので、Vitisを立ち上げずにすぐに確認したい方はこちらを参照するのもよいでしょう。

embeddedsw/XilinxProcessorIPLib/drivers/iicps at master · Xilinx/embeddedsw
Xilinx Embedded Software (embeddedsw) Development. Contribute to Xilinx/embeddedsw development by creating an account on GitHub.

サンプルプログラムにおける処理の解説

単にサンプルプログラムを読み込んだだけでは、あまり理解した気にならないので、用例のソースコードを読み解いていくことにしました。
ソースコードには英語で丁寧な注釈が記載されているので、それを補足するような図解が主になると思います。

動作概要

まず、サンプルプログラムでどういう処理を行っているのか確認しておきます。

xiicps_intr_slave_exampleでは、外部のマスターデバイスからの要求を受けると、

  • まず、数列0, 1, …, TEST_BUFFER_SIZE-1を順にマスターデバイスへ送信
  • 次に、全く同じデータをマスターデバイスの方から受信することを期待
  • 一致したら成功

という一連の処理を行います。

Aardvark社のテスト装置で動作確認できるとのことですが、持っていないので同じことをWio Terminalにやらせる予定です。

Aardvark I2C/SPI Host Adapter - Total Phase
Aardvark I2C/SPI Host Adapter is a fast and powerful I2C bus and SPI bus host adapter via USB. Learn more now!

次回の記事で掲載予定のWio Terminalのプログラムでは、このシーケンスに従った処理をArduinoスケッチに記述していきます。

処理内容

ソースコードのフローチャート

xiicps_intr_slave_exampleにおけるメインの関数は、IicPsSlaveIntrExampleという関数です。

関数 IicPsSlaveIntrExample の一連のシーケンスは以下のフローチャートの通りです。

初期設定

まず、初期設定として、

  • I2Cペリフェラルのインスタンスの初期化
  • 割り込みの設定
  • I2Cペリフェラルの設定
  • 送信バッファと受信バッファの初期化

を順に行っています。

以前、LED点滅回路のタイマー割り込みの記事でインスタンスの概念と割り込みの方法について解説したので、割り込みについて詳しく知りたい方はぜひこの記事もご覧いただければと思います。

I2Cペリフェラルのインスタンスの初期化

まず、I2Cペリフェラルのインスタンスの初期化を行い、アプリケーション上で定義したIicインスタンスと、実際のデバイス上で用意されているI2Cペリフェラルとを紐づけ、IicインスタンスのAPI関数だけでペリフェラルを制御できるようにしています。

割り込みの設定

次に、割り込みの設定を行っています。
関数SetupInterruputSystemが別に定義されており、この関数で必要な設定をすべて行っています。

上で示した図のように、 関数SetupInterruputSystemの処理を実行すると、

  1. 割り込み命令を受けると…
  2. GICインスタンスの割り込みハンドラに処理を渡して、
  3. XiicPS_SlaveInterruptHandlerというAPI関数を呼び出す

という割り込みの設定がなされます。

GIC(Generic Interrupt Controller;汎用割り込みコントローラ)とは

ZynqのProcessing System (PS)では、GICと呼ばれる割り込みコントローラが使用されています。GICは、CPUに送信される割り込み信号を集中的に管理・送信するデバイスです。

https://japan.xilinx.com/support/documentation/user_guides/j_ug585-Zynq-7000-TRM.pdfより抜粋

ポイントは、XiicPS_SlaveInterruptHandlerというAPI関数はどういった処理を行っているのかです。

この関数はスレーブモードで使われる関数で、I2Cペリフェラルにおいてどういったイベントがトリガーとなって割り込みが発生したのかを分類してくれます。

関数の最後で別のハンドラ(関数)を呼び出し、イベントごとに異なった処理を行わせることが可能です。
xiicps_intr_slave_exampleでは、受信完了(RecvComplete)と送信完了(SendComplete)とその他の3イベントに分類して、その後の処理を変えています。

XiicPS_SlaveInterruptHandler ()

機能:
  割り込み発生時、I2CペリフェラルのInterrupt Status Registerを参照し、イベントを分類。I2Cインスタンス上で定義されたStatus Handlerに、イベントの値とともに処理を渡す。
パラメータ:
 ・InstancePtr:I2Cインスタンスのポインタ
返り値:なし

I2Cペリフェラルの設定

割り込みの設定が完了したら、次はIiCインスタンスの各種設定を行い、I2Cペリフェラルを制御します。
I2Cペリフェラルに、以下の3つを設定しています。

  • Status Handlerの割り付け(Handlerという別に定義した関数を割り付け)
  • スレーブモードとスレーブアドレスの登録
  • クロック周波数400kHz
   /*
	 * Setup the handlers for the IIC that will be called from the
	 * interrupt context when data has been sent and received, specify a
	 * pointer to the IIC driver instance as the callback reference so
	 * the handlers are able to access the instance data.
	 */
	XIicPs_SetStatusHandler(&Iic, (void *) &Iic, Handler);
	XIicPs_SetupSlave(&Iic, IIC_SLAVE_ADDR);

	/*
	 * Set the IIC serial clock rate.
	 */
	XIicPs_SetSClk(&Iic, IIC_SCLK_RATE);

IIC_SLAVE_ADDR(今回は0x45)はZynqのスレーブアドレスで、次回紹介するWio Terminalのプログラムでは、マスター側はこのスレーブアドレスと通信します。

送信バッファと受信バッファの初期化

最後に、データを送受信するための送信バッファと受信バッファの値を初期化していました。
送信バッファに「数列0, 1, …, TEST_BUFFER_SIZE-1」を格納し、受信バッファにゼロを格納します。

以上で初期設定が完了です。


データ転送

次は、データ伝送です。
まず、送信設定を行い、マスター機器への送信が完了したら、次に受信設定を行います。

割り込みを利用したデータ送信

XIicPs_SlaveSendというAPI関数によって、I2Cで送信したい配列を指定しています。

ドライバに用意されているいくつかのAPI関数では、必要なI2Cペリフェラルのレジスタ設定をすべて行ってくれるのでとても有用です。 XIicPs_SlaveSend は、割り込みをトリガーとしてスレーブからデータ送信を行いたい場合のレジスタ設定を行います。

XIicPs_SlaveSend()

機能:
 割り込みをトリガーとして送信を開始するモードにレジスタを設定
パラメータ:
 ・InstancePtr:I2Cインスタンスのポインタ
 ・MsgPtr:送信バッファのポインタ
 ・ByteCount:送信するバイト数
返り値:なし

送信完了のイベントが割り込みによって発生したら、whileループを抜けてデータの受信を待ちます。

割り込みを利用したデータ受信

次に、データ受信モードの設定に入ります。
XIicPs_SlaveRecvというAPI関数によって、受信モードへのレジスタ設定と受信したデータを格納するためのバッファを指定しています。

XIicPs_SlaveRecv()

機能:
 割り込みをトリガーとして受信を開始するモードにレジスタを設定
パラメータ:
 ・InstancePtr:I2Cインスタンスのポインタ
 ・MsgPtr:受信バッファのポインタ
 ・ByteCount:受信するバイト数
返り値:なし

ここでも、受信完了のイベントが割り込みで発生するのをwhileループで待ちます。

受信を完了したら、送信バッファと受信バッファを比較して、一致するか否かを判定して終了です。

まとめ

本記事では、ZynqのI2Cペリフェラルをスレーブモードで制御するアプリケーションを読み込み、アプリケーションでの処理について調べた内容をまとめました。

Vitisでは、非常に多くのAPIが用意されていて、使いこなす・理解するにはある程度の慣れが必要です。
一方、ドキュメンテーションと用例を見つけることができれば、注釈や解説は比較的丁寧に書かれているので、それを活用すれば楽にアプリケーションを構築できます。

ひがし

お疲れさまです。
次回の記事では、Wio Terminalに作ったマスター側のプログラムの解説をしたのち、実際の動作を確認した結果を掲載します。

最後までご覧いただきありがとうございました!

スポンサーリンク


次回の記事のリンク

参考:コードの動作を確認したシステムの構成

開発環境

環境
  • 開発用PC: Windows 10, 64bit
    • Vivado Design Suite – HLx Edition – 2020.2
    • Vitis コア開発キット – 2020.2
  • 開発用基板: Zybo Zynq-7010評価ボード(Board Rev.4)
    • Zynq XC7Z010-1CLG400C
  • 開発用マイコン: Wio Terminal
    • ATSAMD51P19

開発ボード Zybo Zynq-7010評価ボード

コメント