外部 I/O の使用

SDSoC™ 環境で生成されるハードウェア アクセラレータは、ハードウェア接続から直接またはメモリ バッファー (フレーム バッファーなど) を使用してシステム入力および出力と通信できます。システム I/O の例には、アナログ/デジタル コンバーターおよびデジタル/アナログ コンバーター、画像、レーダー、LiDAR、超音波センサー、HDMI™ マルチメディア ストリームなどがあります。

メモリ バッファー使用した外部 I/O へのアクセスおよびダイレクト ハードウェア接続を使用した外部 I/O へのアクセスに示すように、プラットフォームは、プラットフォーム ライブラリ関数を呼び出すことにより、ソフトウェアでアクセスされるハードウェアにストリーム接続をエクスポートします。ダイレクト ハードウェア接続は AXI4-Stream チャネルを使用してインプリメントされ、メモリ バッファーへの接続は SDSoC 環境でサポートされる標準データ ムーバーでインプリメントされる関数呼び出しで認識されます。

SDSoC プラットフォームの作成方法の詳細と例は、SDSoC 環境プラットフォーム開発ガイド を参照してください。

メモリ バッファー使用した外部 I/O へのアクセス

このセクションでは、SDSoC 設計環境の「ボード、キット、およびモジュール」から入手可能なモーション検出の ZC702 + HDMI IO FMC または ZC706 + HDMI IO FMC プラットフォームを使用します。外部メモリへの HDMI データ転送は、コンフィギュレーション済みの SDSoC プラットフォームで実行されます。アプリケーションはプラットフォーム インターフェイスを呼び出して、DDR メモリのフレーム バッファーからデータを処理する必要があります。次の図に、デザインの設定例を示します。

図: モーション検出デザインのコンフィギュレーション



SDSoC 環境は、プラットフォームへのアクセラレータ インターフェイスを介して外部フレーム バッファーにアクセスします。zc702_hdmi プラットフォームには、Video4Linux2 (V4L2) API を介してフレーム バッファーにアクセスするソフトウェア インターフェイスが含まれます。V4L2 フレームワークには、Linux でのリアルタイム ビデオ キャプチャをサポートするデバイス ドライバーのコレクションにアクセスする API が含まれます。この API がアプリケーション開発プラットフォーム I/O のエントリ ポイントとなります。

m2m_sw_pipeline.c から抜粋したコードの motion_demo_processing 関数は、関数呼び出しインターフェイスを示しています。

extern void motion_demo_processing(unsigned short int *prev_buffer,
            unsigned short int *in_buffer,
            unsigned short int *out_buffer,
            int fps_enable,
            int height, int width, int stride);
.
.
.
unsigned short *out_ptr = v_pipe->drm.d_buff[buf_next->index].drm_buff;
unsigned short *in_ptr1 = buf_prev->v412_buff;
unsigned short *in_ptr2 = buf_next->v412_buff;
v_pipe->events[PROCESS_IN].counter_val++;

motion_demo_processing(in_ptr1, in_ptr2, out_ptr,
                       v_pipe->fps_enable,
                       (int)m2m_sw_stream_handle.video_in.format.height,
                       (int)m2m_sw_stream_handle.video_in.format.width,
                       (int)m2m_sw_stream_handle.video_in.format.bytesperline/2);

アプリケーションは motion_detect.c 内のこの API にアクセスします。motion_demo_procesing は、img_process 関数により定義されて呼び出されます。

void motion_demo_processing(unsigned short int *prev_buffer,
                             unsigned short int *in_buffer,
                             unsigned short int *out_buffer,
                             int fps_enable,
                             int height, int width, int stride)
{
      int param0=0, param1=1, param2=2;

      img_process(prev_buffer, in_buffer, out_buffer, height, width, stride);
}

最後に、img_process でさまざまなフィルターが呼び出されて、データが変換されて処理されます。

void img_process(unsigned short int *frame_prev,
                  unsigned short int *frame_curr,
                  unsigned short int *frame_out,
                  int param0, int param1, int param2)
{
...
}

フレーム バッファーにアクセスするためにプラットフォーム API を使用すると、アプリケーション開発者がビデオ フレームを処理するためにドライバー レベルでプログラムする必要はありません。

このコード例に使用されたプラットフォームは、SDSoC ダウンロード ページの「ZC702 + HDMI IO FMC」または「ZC706 + HDMI IO FMC」から入手できます。

SDSoC 環境へのアクセス

SDSoC 環境のプロジェクトには、次のようにアクセスします。
  1. プラットフォームをシステムにダウンロードして抽出します。
  2. SDx™ を開いて、新規アプリケーション プロジェクトを作成します。
  3. [Platform] ダイアログ ボックスで [Add Custom Platform] を選択します。
  4. [Specify Custom Platform Location] ダイアログ ボックスからダウンロードしたプラットフォームのディレクトリを指定し、[OK] をクリックします。
  5. [Platform] ダイアログ ボックスから [zc702_trd] または [zc706_trd] というカスタム プラットフォーム フォルダーを選択して [Next] をクリックします。
  6. [System Configuration] ダイアログ ボックスはデフォルトの設定のままにして [Next] をクリックします。
  7. [Templates] ダイアログ ボックスで Dense Optical Flow (1PPC) テンプレートを選択して [Finish] をクリックします。

ダイレクト ハードウェア接続を使用した外部 I/O へのアクセス

メモリ バッファー使用した外部 I/O へのアクセスの例では、アプリケーションがメモリ バッファーを介してどのようにシステム I/O にアクセスするかを示しましたが、プラットフォームには、SDSoC 環境で生成されたアプリケーション内でのハードウェア アクセラレータへのダイレクト ハードウェア接続もあります。次の図は関数 s2mm_data_copyAXI4-Stream チャネルを使用してプラットフォームと通信しzero_copy、データ ムーバー (AXI4 マスター インターフェイスとしてインプリメント) を使用して DDR メモリへ書き込むところを示しています。このデザイン テンプレートは samples/platforms/zc702_axis_io プラットフォームの aximm サンプル デザインです。

図: AXI4 データ ムーバー デザイン



この例では、zc702_axis_io が 50 MHz で実行され、AXI4-Stream Data FIFO IP ブロックにフリーランニング バイナリ カウンター (図では Platform IP) を接続することで、実際の I/O の代わりに使用されています。AXI4-Stream Data FIFO IP ブロックでは、AXI4-Stream マスター インターフェイスがデータ モーション クロックからのクロックを使用するプラットフォームにエクスポートされます (このデータ モーション クロックの周波数は 50 MHz 入力クロックと異なることがあります)。

ストリーム ポートに対しては、ダイレクト I/O インターフェイスは sys_port プラグマを使用して指定します。次のコードの抜粋では、stream_fifo_M_AXIS に直接接続が指定されています。

#pragma SDS data sys_port (fifo:stream_fifo_M_AXIS)
#pragma SDS data zero_copy(buf)
int s2mm_data_copy(unsigned *fifo, unsigned buf[BUF_SIZE]) 
{
#pragma HLS interface axis port=fifo
     for(int i=0; i<BUF_SIZE; i++) {
#pragma HLS pipeline
          buf[i] = *fifo;
     }
     return 0;
}

次の main アプリケーション コードの場合、rbuf0 変数により FIFO 入力ストリームが s2mm_data_copy 関数にマップされるので、sds++ コンパイラで AXI4-Stream チャネルを使用してダイレクト ハードウェア接続が作成されます。s2mm_data_copy 関数は zero_copy データ ムーバーを使用して buf を転送するので、バッファーは sds_alloc を使用して物理的に隣接するメモリに割り当て、sds_free を使用して解放する必要があります。

int main() 
{
     unsigned *bufs[NUM_BUFFERS];
     bool error = false;
     unsigned* rbuf0;
     
     for(int i=0; i<NUM_BUFFERS; i++) {
          bufs[i] = (unsigned*) sds_alloc(BUF_SIZE * sizeof(unsigned));
     }
     
     // Flush the platform FIFO of start-up garbage
     s2mm_data_copy(rbuf0, bufs[0]);
     s2mm_data_copy(rbuf0, bufs[0]);
     s2mm_data_copy(rbuf0, bufs[0]);

     
     for(int i=0; i<NUM_BUFFERS; i++) {
       s2mm_data_copy(rbuf0, bufs[i]);
     }
     
     error = check(bufs);

     printf("TEST %s\n\r", (error ? "FAILED" : "PASSED"));
     
     for(int i=0; i<NUM_BUFFERS; i++) {
          sds_free(bufs[i]);
     }
     return 0;
}

AXI4-Stream を使用してプラットフォームを作成してメモリに直接書き込む方法については、SDSoC 環境プラットフォーム開発ガイド の付録「SDSoC プラットフォームの例」を参照してください。