Ryuz's tech blog

FPGAなどの技術ブログ

Ultra96V2(ZynqMP)のDebian動作中にPLからDisplayPort出力

概要

前回の続きで、ある程度私なりの使い方が落ち着いてきて、github コードをにも上げましたので簡単に説明を書いておきます。

事前に断っておきますと、正しいやり方でも何でもなく、さしあたって「安直にPLから画像出力表示したい」という欲求から「力技で何とかしました」というメモとなります。

私の環境

DP-HDMI変換はどんなものでもいいわけではなさそうです。私は@basaro_k氏のこちらの記事を参考に探しました。

このDebian環境は非常によくできており、起動した段階で DisplayPort には 1920x1080 サイズで映像出力がなされており、ログインプロンプトが出ております。 おそらくちゃんよプラグアンドプレイでモニタのEDIDが読み込まれたうえで適切な出力設定がなされていると思われます。

DisplayPort の仕組み

ZynqMP の DisplayPort 出力は

といった特徴があるようで、大まかな構成はUG1085から引用すると

UG1085 Figure33-2

の部分がわかりやすいです。

今回の方針

本来であればLinuxの表示ドライバにお願いしてPLからの出力を出してもらうのがスジです。しかし今回はスジを通さずに、Linux が気づかないうちにこっそり出力を借りて、使い終わったらばれないようにこっそり元に戻すという方針で行きます。

AV_BUF_AUD_VID_CLK_SOURCE を弄るとPL側のタイミングで映像を作れるのですが、どうやら切り替えには再同期が必要なようで、いきなり書き換えるという暴挙に出るとそのあと元に戻してももうコマンドプロンプトは表示されなくなります。

ですので、AV_BUF_AUD_VID_CLK_SOURCE はそのままに、既に出力されている映像フォーマットに合わせてPL側で映像を作るという方針を取っております。

実際の処理

作成したプロジェクト

github に置いております。

DP関連のレジスタにアクセスする

まず、Linux の起動時に DisplayPort がどのように設定されているのか調べます。まずは DisplayPort 周りのレジスタにアクセスするために Device Tree overlay にて UIO をマップしています(乱暴)。 ソースはこちら

    uio_dp {
        compatible = "generic-uio";
        reg = <0xfd4a0000 0x00010000>;
    };

の部分となります。/dev/mem 経由でも良いのですが、アプロケーションを root で動かさないといけなくなるので、今回は一時的に overlay した UIO にユーザーアクセス権を付ける方法でごまかしました(あまりセキュアではないです)。

現在出ている出力フォーマットを知る

まず Linux起動時に DisplayPort に設定されているレジスタにアクセスします。 UIOへのメモリアクセス方法は私の旧ブログこのあたりなどを参考にしてください。

下記のレジスタをざっと読みだせば、フォーマット情報をうかがい知ることができるようです。

DP_MAIN_STREAM_HTOTAL   0x00000180
DP_MAIN_STREAM_VTOTAL   0x00000184
DP_MAIN_STREAM_POLARITY 0x00000188
DP_MAIN_STREAM_HSWIDTH  0x0000018C
DP_MAIN_STREAM_VSWIDTH  0x00000190
DP_MAIN_STREAM_HRES     0x00000194
DP_MAIN_STREAM_VRES     0x00000198
DP_MAIN_STREAM_HSTART   0x0000019C
DP_MAIN_STREAM_VSTART   0x000001A0

現在の設定に合わせてde信号を作る

Zynq のコア設定で Live Video を有効にすると関連のポートが現れます。

Live Video 設定
DisplayPort 出力

ここで、現在モニタに出力中の内容をPLで取得できるのですが今回必要なのは

  • dp_video_ref_clk
  • dp_video_out_vsync
  • dp_video_out_hsync

の3つです。

これは先に取得した内容で動作する出力タイミング時の波形です。 画像を合成するには、内部の合成処理のサイクル分少し早いタイミングで入力側の映像を合わせてやらないといけません。

ですので、ここで出力されるタイミングに同期する形で、少しだけ早いサイクルで de 信号を生成する回路を用意します。 それがこちらです

特に難しいことはやっておらず。WISHBONEバスからレジスタ設定した値でカウントしてdeを生成しております。

ですので、

  • DPレジスタを読んでフォーマットを知る
  • フォーマットに合わせて少し早いサイクルで de を出す設定をする 15~16サイクルぐらい?(ザ・目分量)

というプログラムをPS側ですれば、いい感じに表示に合う位置に映像を持ってくることができます。

映像表示

生成した映像は、PSに接続するわけですが、この時

  • dp_video_in_clk
  • dp_live_video_in_pixel1

の2つだけ繋げばいいようです。dp_video_in_clk には dp_video_ref_clk のクロックをそのまま入れています。

DisplayPort 入力

そしてこのままだと、ビデオ側の映像はまだブレンドされていませんので

の2つを書き換えます。

そして使い終わったらこの2つのレジスタを元の値に戻しておけば、Linux に気づかれることなく状態復帰できる模様です。

このあたりの一連のPS側のプログラムはこちらになります。

動作風景

少し発展させて、静止画表示にさらにカメラ画像も追加したプロジェクトの動作風景です。

表示風景

コマンドプロンプトとアルファブレンドされているのがお分かりいただけるかと思います。静止画を転送した後にカメラを中央に取り込んでいます。

なお、カメラは拙作の変換基板を使って RaspberryPI 用のカメラを繋いでいます(周りに余計なものがいろいろ写ってますが無視してください(笑))

カメラ接続