cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

RF データ コンバーター ソフトウェア ドライバー - 簡単でストレスフリー

Xilinx Employee
Xilinx Employee
4 0 363

本ブログは英語版のRF Data Converter Software Drivers - Really Foolproof, not Really Frustratingを翻訳したものです。

 

こんにちは、ザイリンクスのアプリケーションズ エンジニアの Keith Lumsden (キース ラムスデン) と申します。

ザイリンクス コミュニティに最近追加された「Design and Debug Techniques Blog (設計やデバッグテクニックのブログ)」への寄稿を依頼され、大変光栄に思います。

私の主なフォーカスは、Zynq® UltraScale RFSoC 製品に統合された RF データ コンバーターを使用するお客様にサポートを提供することです。

私は、アナログおよびミックスド シグナル システム、FPGA アーキテクチャ、I/O およびシグナル インテグリティにキャリアの多くを費やしてきました。  ハードウェア系のエンジニアであるため、エンベデッド ソフトウェアは他人事だと思っていました (罪があるかもしれません)

私の考え方は、RF データ コンバーターの誕生で変わりました。世界クラスの RF-ADC および RF-DAC Zynq UltraScale+ アーキテクチャに統合されたのです。従来の RF およびアナログ エンジニアは、これまでになかった形でエンベデッド システムに必然的に接するようになっています。

RF データ コンバーター ソリューション:

詳しい方はご存知のように、RF データ コンバーターは Vivado Design Suite IP コアとしてパッケージされています。これにより、ザイリンクス提供のソフトウェア ドライバーを通じて RF Analog-to-Digital Converter (RF-ADC) および RF Digital-to-Analog Converter (RF-DAC) タイルのステータスおよび制御を管理できます。

Zynq UltraScale+ RFSoC RF Data Converter IP 製品ガイド』 (PG269) (v2.2 英語版v2.0日本語版) に、IP のすべての詳細およびドライバーの詳しい付録が含まれています。

K_1.jpg

RF アナライザー (英語版日本語版) を使用すると、すばやく開始できます。

RF アナライザーは MicroBlaze™ ベースのデザインで、任意のボードの任意のデバイスに展開できる通信層があります。また、RF-ADC で受信している内容を視覚的に表示することを可能にしたり、スティミュラス生成および RF-DAC を介した送信を有効にしたりする GUI もあります。重要なことに、アプリケーションはソフトウェア ドライバーを使用してビルドされます。

RF アナライザーは、RF システムの問題を突き止めようとしている場合に非常に効果的で、スタンドアロンで機能し、デザインまたはボードに依存しないため、システムの RF 部分を検証するために使用すると大きな効果を得ることができます。

一般的なユース ケースは、システムの RF-ADC および RF-DAC をデバッグする場合と、ランタイムにテストするために小型のアプリケーションを書き込む必要がある場合です。RF アナライザーおよびカスタム デザインの両方でソフトウェア ドライバーを使用する必要があると想定し、ドライバーに慣れ親しんでデバッグ用に使い始める方法を示すブログ記事を書くことにしました。次回のブログ記事では、RF アナライザーのアンボックスおよび順を追った説明をする予定です。

RF データ コンバーター システムについては既にある程度理解されている方も多いかと思いますので、未知のものへと話を発展させるのではなく、知識の層を重ねるため、ドライバーについて学習することにしましょう。

このブログ記事では、次について説明します。

  • どのようにドライバーがビルドされるか
  • データ構造体
  • アプリケーション プログラミング インターフェイス (API) を使用した単純なアプリケーションの作成

ここでは、ベアメタル アプリケーションの作成に専念し、これを基にした Linux アプリケーションの作成方法は、今後のブログ記事で説明する予定です。

ドライバーの構築:

RFdc ドライバーの良い点の 1 つは、Libmetal を使用してビルドされることです。Libmetal はザイリンクスが開発したオープン ソース ソフトウェア スタックで、LinuxRTOS (Realtime OS)、およびベアメタル環境におけるデバイスへのアクセス、デバイス割り込みの処理、およびメモリ アクセス要求を実行する一般的なユーザー API を提供します。

これが意味することは何でしょうか。まず、関心のあるドライバー部分がユーザー空間に実装されるため、ハードウェアとの通信機構を気にする必要がないことを意味します。また、API Linux およびベアメタル アプリケーションで共通しているため、2 つの API 呼び出しセットを学ぶ必要がなく、ベアメタルから Linux へのコードの移植を心配する必要がないことも意味します。

K_2.jpg

次の画像に、XRFdc ドライバー ソース コードの詳細を示します。ドライバーのソースは、ザイリンクス SDK インストール ディレクトリまたは Github こちらにあります。

K_3.jpg

この図では、下部に xrfdc_hw.h ファイルがあります。このヘッダー ファイルには、RF-ADC および RF-DAC タイルのレジスタ アドレス マップとして理解されている可能性のあるものが含まれています。このファイルはユーザー用ではなく、ドライバーの内部機構に使用されます。識別子はアプリケーションの記述時に役立つわけではないため、このファイルで使用する必要はなく、勉強する必要もありません。

ほかのヘッダー ファイルの xrfdc.h および xrfdc_mts.h は次を含んでいるため、より重要になります。

  • API 呼び出しで必要なデータ構造体のすべて。
  • API 呼び出しをインプリメントするコードで使用されるインライン (ヘルパー) 関数。
  • アプリケーションで使用するマクロ (ADC タイルには値 0DAC タイルには値 1 API 呼び出しに渡す代わりに、XRFDC_ADC_TILE/XRFDC_DAC_TILE マクロを必要に応じて使用できるため便利です。これにより、コードが読みやすく理解しやすくなります)
  • 最も重要なのは、アプリケーションで使用される API 呼び出しのプロトタイプがこれらのファイルに表示されることです。

次に、API 呼び出しのソース コードを見てみます。ここで、ユーザー API 呼び出しの機能をインプリメントします。通常は、個々の API 呼び出しのインプリメンテーションについて詳しく勉強する必要はありません。

  • xrfdc.c: これは、アプリケーションで使用する API の本体です。
  • xrfdc_intr.c: これにより、RF データ コンバーターからの割り込みを管理するために必要な API 呼び出しがインプリメントされます。
  • xrfdc_mixer.c: XRFdc ドライバーのミキサー設定のインターフェイス関数が含まれています。
  • xrfdc_mts.c: XRFdc ドライバーの複数タイル同期関数が含まれています。

XRFdc ソフトウェア ドライバーの使用

ドライバー ソースに含まれているものを確認したので、実際にそれを使用して実行する必要がある内容についてお話しましょう。

上記で説明したとおり、xrfdc.h ヘッダー ファイルを最も参照することになります。これには、データ構造体および API 関数プロトタイプが含まれています。データ構造体および API 呼び出しについては、『Zynq UltraScale+ RFSoC RF Data Converter IP 製品ガイド』(PG269) (v2.2 英語版v2.0日本語版) の付録 D にも完全に文書化されています。

まず、データ構造体からお話しましょう。

データ構造体とは、RF データ コンバーターに関する情報を意味あるグループに分類する方法です。私は、データ構造体のことを「コンテナー」と考えることにしています。プロのソフトウェア開発者の方からは、「コンテナーは C++ 用語だから、そのように使用するべきではない」と言われそうですが、私はこれが良いたとえだと思っています。

例として、RF-ADC または RF-DAC タイルの位相ロック ループ (PLL) に対するデータ構造体を見てみましょう。PLL に関して把握が必要な可能性のある内容 (: イネーブルされているか、入力クロック、出力するサンプル クロック) がすべて記述されているのがわかります。

K7.png

このような構造体が存在すると、API 間で容易に渡すことができ、場合によっては 1 つで読み出してもう 1 つで変更することも可能です。

また、ある構造体内に別の構造体を含めることもできます。

たとえば、XRFdc_PLL_Settings XRFdc_DAC_Tile のメンバーです。

K8.png

さらに、構造体は透過的であるため、1 つのメンバーだけをコードで変更できます。例として、コンプレックス ミキサーでの NCO (Numerically Controlled Oscillator=数値制御型オシレーター)周波数の変更を挙げることにします。

MixerSettings 構造体には、周波数に対して Freq というメンバーがあるため、コードで次のように変更できます。

MixerSettings.Freq = 2000;//MHz

データ構造体の基礎を習得したら、使用できる API 呼び出しの理解に取り組む必要があります。これらは、アプリケーションの構築ブロックです。

個々の API 呼び出しの機構は、ユーザーに対して抽象化され、XRFdc.c ファイルに実装されています。

呼び出しを使用する場合、知っている必要があるのは 3 点のみです。

  • ターゲットとする ADC または DAC タイルの機能。
  • 入力として渡す必要があるもの。
    これは通常、RF タイル タイプ、タイル ID、およびタイルに必要な個別ブロックを指定することを意味します。
    場合によっては、使用する構造体が API に渡される必要があります。
  • 出力として返すもの。
    たとえば、構造体の内容が返されるようにすることができます。

 

このドライバーで使用される API のタイプは、数個しかありません。

  • タイルを制御するために使用できる管理呼び出しがあります。たとえば、XRFdc_StartUp/XRFdc_Shutdown は、個々の RF-ADC または RF-DAC タイルを起動またはシャットダウンするために使用されます。
  • 概要ステータス レポートを有効にするための API 呼び出しがあります。例は、XRFdc_GetIPStatus/XRFdc_GetBlockStatus です。
  • 個々のサブブロックに対する Get および Set API 呼び出しもあります。たとえば、XRFdc_GetMixerSettings および XRFdc_SetMixerSettings をそれぞれ使用して、コンプレックス ミキサー設定に対して get および set の両方を使用できます。

場合によっては、Get および Set 呼び出しが IP でも設定されます (: コンプレックス ミキサー設定)。一部はランタイム実行専用です。このような例には、RF-ADC しきい値フラグおよび直交変調補正 (QMC) があります。

最後に、これらの変更によっては、タイルの再起動が必要になります。PLL セットアップの変更は、その一例です。

Hello RFdc

ドライバーの感触を得たので、非常に単純な最初のアプリケーションを Zynq UltraScale+ RFSoC ZCU111 評価ボード用に作成できます。

今回は、ADC データをキャプチャするだけにします。デザインについては、今後のブログでいつでも詳しく説明することが可能です。  

IQ データ パターンをいくつか送信し、ミキサーを使用してベースバンドにミキシングした後、デザインの System ILA (Integrated Logic Analyzer) ブロックに出力します。

K_4.jpg

ここでは、先ほどお話した概要ステータスおよび管理 API の一部と、get および set API の一部を示します。

この場合、IP のステータスをチェックし、タイルが正しく開始されていることを確認します。

次に、データパスのステータスをリードバックします。

最後に、ミキサー設定を確認します。

このデザインをインプリメントしてビットストリームを取得したら、ハードウェア ハンドオフ ファイル (HDF) をエクスポートし、SDK を起動します。エンベデッド デザインおよび SDK について詳しく知りたい場合は、チュートリアル (英語版日本語版) を参照すると有益です。

HDF ファイルによってハードウェア プラットフォームが SDK に作成されるため、HDF ファイルでは、デザインで使用されるすべてのペリフェラルおよびそれらのアドレスを認識しています。次は、ボード サポート パッケージの作成です。これにより、ハードウェア定義を取得して、必要な関連ドライバーおよびライブラリをすべて読み込みます。

[File] → [New] [Board Support Package] をクリックします。

作成したハードウェア プラットフォームを選択し、[Next] をクリックします。

K_5.jpg

特定のライブラリを含めるよう指示するメッセージが表示されます。[libmetal] がオンになっていることを確認し、[OK] をクリックします。この段階で、アプリケーションの作成に必要なものがすべて揃ったことになります。

K_6.jpg

[File] → [New] [Application Project] をクリックして、サンプルを作成します。

作成したハードウェア プラットフォームおよび BSP をポイントするようにします。

K_7.jpg

[Next] をクリックし、空のプロジェクトを選択します。

私のアプリケーションのソース コードをこのブログ記事に添付しました。これをインポートすると、テンプレートとして使用できます。

主な機能をいくつか説明しましょう。

まず、xparameters.h ファイル (必要なハードウェア パラメーターがすべて含まれている) および前述の xrfdc.h ファイル (API 呼び出しのドライバー構造体および関数プロトタイプが含まれている) を含める必要があります。

私の場合、ZCU111 ボードを持っており、起動時にクロックをプログラムする必要があります。これを有効にするため、ドライバー ソースの「examples」フォルダーにあるファイルの一部を追加します。

XRFdc 最上位構造体のスタティック インスタンスを作成するところをお見せします。つまり、構造体のインスタンスが 1 つあり、必要になる可能性がある任意の API または関数からそれをポイントできるということをここで示します。

static XRFdc RFdcInst;  /* RFdc driver instance */

main 関数内で、必要な構造体をすべて宣言します。

       int Status;

       XRFdc_Config *ConfigPtr;

       XRFdc *RFdcInstPtr = &RFdcInst;

       XRFdc_BlockStatus BlockStatus;

       XRFdc_IPStatus myIPStatus;

       XRFdc_Mixer_Settings MixerSettings = {0};

ここでは、作成したドライバーのスタティック インスタンスへのポインターを作成しているだけです。

次に、ドライバーを初期化します。これは毎回実行する必要があります。基本的には、xrfdc_g ファイルにある config 表を取得し、XRFdc_LookupConfig 関数を使用して xparameters からの値および設定をこの表に挿入します。次に、これを config ポインターの ConfigPtr に格納します。その後、XRFdc_CfgInitialize API を呼び出すと、RFdcInstPtr に設定が挿入されます。   

これで、アプリケーションでドライバーを使用できるようになりました。

ADC タイルへの入力クロックをプログラムするところをお見せします。

ここでは、XRFdc_GetIPStatus を使用して、有効にした ADC タイルのステータスを確認します。

Status = XRFdc_GetIPStatus(RFdcInstPtr, &myIPStatus);

                    if (Status != XRFDC_SUCCESS) {

                       return XRFDC_FAILURE;

                       }

int powerup_status;

int tile_state;

powerup_status = myIPStatus.ADCTileStatus[0].PowerUpState;

tile_state = myIPStatus.ADCTileStatus[0].TileState;

printf("ADC PowerUp Status: %u\n", powerup_status);

printf("ADC Tile State: %u\n", tile_state);

 

この場合、タイル ステートが 15 になるようにする必要があります。これは、ブロックがスタートアップ ステート マシンの最後に達しており、電源投入ステートが 1 (有効でアクティブであること意味している) であることを示します。

次に使用する API 呼び出しは、XRFdc_GetBlockStatus です。これにより、サンプリング周波数が何に設定されており、デジタル データパスがどのように設定されているかが表示されます。ここでは、この API 呼び出しのタイル タイプを抽象化するために XRFDC_ADC_TILE を使用しています。

 

Status = XRFdc_GetBlockStatus(RFdcInstPtr, XRFDC_ADC_TILE, 0, 0, &BlockStatus);

       if (Status != XRFDC_SUCCESS) {

       return XRFDC_FAILURE;

       }

最後に、XRFdc_GetMixerSettings を使用して、ミキサーの詳細をいくつか表示します。

変更を加えた後、XRFdc_SetMixerSettings を使用して新しい設定を書き込みます。

その後、タイル イベントを生成し、変更をハードウェアに適用します。

すると、ミキサー スケールを 0 から 2 (ハードウェアで AUTO から 1.0 ) 変更したことと、ミキサー設定も変更されたことが、XRFdc_GetMixerSettings によって示されます。

それでは、SDK のデバッガーでアプリケーションを実行してみましょう。

アプリケーションを右クリックし、[Run As...] [Run Configurations] をクリックします。ここでは、システム デバッガーを使用し、[Program FPGA] もオンにします。

([Debug As] を選択することもでき、これを選択すると、[Debug] パースペクティブが有効になり、コードのステップ スルーなどを実行できるようになります。)

K_8.jpg

UART シリアル コンソールに表示されるものを見てみましょう。

(ここでは、ビルトイン SDK ターミナルを使用して接続していますが、任意のターミナル エミュレーターを使用できます。)

K_9.jpg

次が実行されていることがわかります。

  • Hello! が出力される。
  • ZCU111 ボードでクロックがプログラムされる。
  • タイル ステートが 15 (完全に開始されており、AXI ストリームからの有効なデータがあることを意味する) になる。
  • デジタル データパスのブロック ステータスがレポートされる。
  • ミキサー設定の読み出しが表示され、変更が確認される。

最後のチェックでは、RF-ADC からのデータが System ILA に渡されていることが示されます。

K_9a.jpg

最終の考察:

これで、アプリケーションを記述する開始点ができました。私の ZCU111 プロジェクト用にハードウェアブロック デザインをビルドする Tcl スクリプトおよび XDC ファイルを添付しました。アプリケーションの C コードも添付されています。

これらの添付ファイルは、RF データ コンバーターと通信するために記述するアプリケーションの出発点として使用できるはずです。ぜひご自分のベアメタル アプリケーションで練習することをお勧めします。

このブログ記事を基に、今後 RFSoC のほかのデザインおよびデバッグ機能を紹介していく予定です。次回は、任意のプラットフォームで任意の RFSoC デバイスをデバッグできるように、RF アナライザーのアンボックスおよび順を追った説明をします。 

それでは、またお会いしましょう。