FPGAボードDE10-StandardおよびDMA PL330の使用経験





私は自由にTerasic DE10-Standardボードを入手しました。 組み込みのJTAGプログラマ、LED、スイッチ、ボタン、オーディオ/ VGA / USB /イーサネットコネクタなど、多くの興味深いものがあります。 製造業者のウェブサイトで誰もがボードの仕様を読むことができるため、すべての機能をリストする必要は特にないと思います。



FPGAチップCyclone V SX-5CSXFC6D6F31C6Nがボード上にあることが重要です。 このチップには、2つのARM Cortex-A9プロセッサと110K FPGAロジックエレメントが含まれています。 これは実際のSoC HPS:システムオンチップ、ハードプロセッサシステムです。 このようなリソースを使用すると、かなり複雑なプロジェクトを実行できます。 次に、ボードを使用した私の経験についてお話します。



terasikaのWebサイトからLinuxイメージをダウンロードし、DE10標準ボード用の起動可能なSDカードを準備するのは非常に簡単です。 Linux OSはSDから起動し、ボードが起動し、その機能を実証します。







Linuxが起動すると、デスクトップにテストアプリケーションのアイコンが表示されます。 このテストGUIアプリケーションを使用すると、個々のボードのLEDをオン/オフしたり、スイッチやボタンの状態を監視したり、7セグメントインジケーターに値を設定したりすることができます。 興味深いことがたくさんあります。 私がこのプログラムをいじったとき、あなたは今、あなた自身のプロジェクトを迅速に作成し、それを素早く立ち上げることができると思います。



私は自分がFPGA初心者の開発者だとは思いません。 ソフトウェアプロセッサを使用してプロジェクトを行い 、Linuxカーネルとは何かを想像しました。 私自身、アルテラ/インテルFPGAを使用した開発ボードの開発に携わっています 。 しかし、正直なところ、これはHPS-FPGA SoCでの私の最初の経験です。 このボード、特にこのFPGA向けに独自のプロジェクトを作成し始めたとき、それは本当に簡単ではないことに気付きました。







もちろん、DE10-Standard自体に責任があるわけではありません。 開発のしやすさの錯覚があります。これはterasikのSDカードのイメージです。FPGAのサンプルプロジェクトのソースコードとテストプログラムのソースコードがあります。 あなたのニーズに合うようにそれを取り、すべてが動作するように思えます。 しかし、違います。



開発の容易さの第一印象はそれが欺de的であるということを理解する必要があります。 一目でわかるように、これは氷山の一角にすぎません。



私はたくさん読んで勉強しなければなりませんでした。例えば:



1. DE10-Standard_v.1.2.0_SystemCDディスクはボードに接続されており、さまざまなドキュメント、図、マニュアルのPDFファイルが38個含まれています。



2. Intelの「 Cyclone Vハードプロセッサシステムテクニカルリファレンスマニュアル 」は、3,536ページの技術的な説明です。



もちろん、一度に全部読む必要はありません。まったく読まないと思ったので、知識と経験を管理しますが、それでも読んで理解する必要がありました。



さらに多くのドキュメント、例のソースコード、さらにはフォーラムを含む優れたリソースがまだあります。 これにより、生活が楽になり、さらに困難になります。さらに多くの情報を読んで吸収する必要があるためです...残念ながら、ロケットボードフォーラムでも、質問への回答を見つけることが常に可能とは限りません。



したがって、SoC HPSの主題は複雑であるため、プロジェクトの開発は非常に複雑です。







多くのギアを備えた時計仕掛けを想像してください。 各ギアは次のギアにぴったり合うはずです-そうでなければ、何も回転しません。 HPS-FPGAシステムについても同じことが言えます。 システムは非常に多くのソフトウェアおよびハードウェアコンポーネントで構成されています:プリローダー、U-BOOT、Linuxカーネル、ドライバー、DTSファイルからDTBファイルが生成されますが、RootFSを作成する必要があり、もちろんFPGAでハードウェアシステム自体を開発する必要があります:FPGA SoCプロジェクトにはいくつかが含まれますIPブロック、メモリにマップされたハードウェアレジスタ、クロック周波数とドメイン、I / O信号など...



私はSoC用のFPGA用のプロジェクトを作成する方法を知っていると仮定し、プロジェクトに明らかなエラーが表示されないため、80%前後でうまく動作するはずだと思います。 また、自分のハードウェアプラットフォームを説明するDTSファイルの記述方法を大体知っていると思います。 DTSファイルを80%正しく作成したと確信しているとします。 DTBファイルは、DTSファイルから生成されます。 次に、FPGAハードウェアにカーネルドライバーを作成する必要があります。 簡単ではありませんが、ドライバーを作成できます。 そこで多くの間違いを犯さなかったと思いますか? 私のドライバーが少なくとも80%正しいことを願っています。 しかし、プリローダーはどうですか? プリローダーは、SDカードから読み取られて起動される最初のプログラムであり、システム上の必要なハードウェア構成レジスタをチップ上でプログラムする必要があります。 プリローダーは正しいですか? さて、80%の確信があるとしましょう。 考えてみると、私のシステムが機能する可能性はどのくらいですか? 0.8 * 0.8 * 0.8 * 0.8 = 0.4096 ...システム内のコンポーネントが多いほど、悪化します。 何かが機能しないか、まったく機能しない場合(カーネルパニックなど)、問題の場所を理解するのはかなり困難です。



私の仕事の目的は、DMAトランザクションを使用してシステムメモリからFPGAにデータを転送し、FPGAからシステムメモリにデータを戻すHPS-FPGAプロジェクトを作成することでした。 DMAを使用すると、プロセッサの負荷が軽減されます。 Cyclone V FPGAでのDMAの実装に関するハブに関する記事はすでにありましたDes333のように、独自のコントローラーを作成することはしたくありませんでした...既にシステムにあったPL330コントローラーを使用したかったのです。



しばらくDE10標準ボードを使用して、貴重な経験を得ました。 よろしければ、FPGAでSoC HPSの開発を開始することに決めた人にアドバイスをしたいと思います。



開発用のボードを準備する



これはおそらく、明らかなカテゴリからのアドバイスです。 システムを起動するために必要なファイルを含むSDカードイメージがあります:FPGAイメージ、DTBファイル、U-BOOT、およびLinuxカーネルzImage。 追加のセクションには、PreloaderとRootFSが含まれます。 FPGA用のSoC HPSプロジェクトを開発している場合、Quartus Prime CAD環境でコンパイルし、結果(RBF、Raw Binary File)をSDカードに書き込む必要があります。 次に、カーネルの一部としてLinuxカーネルとドライバーをコンパイルします。 また、結果のファイルをSDカードに書き込む必要があります。



ボードからSDカードを取り出し、コンピューターまたはラップトップのカードリーダーに挿入してファイルをカードに書き込むことは意味がありません。 これには時間がかかりすぎる場合があります。 さらに、頻繁にプラグ/アンプラグを行うと、ボードまたはラップトップのSDカードスロットが損傷する可能性があります。 必要なファイルがTFTPサーバーからネットワークからダウンロードされるように、U-BOOTを構成することをお勧めします。



このボードには、USBケーブルを介して開発者のコ​​ンピューターに接続するためのUART-USBコネクターがあります。 PUTTYなどの端末プログラムを開き、ボードをオンにします。 U-BOOTからのメッセージが端末でどのように実行されたかをすぐに確認できます。 ターミナルの任意のキーをすぐに押すと、ダウンロードを中断できます。



U-BOOT環境にいくつかの変数を追加しました。



ethaddr=fe:cd:12:34:56:67 ipaddr=10.8.0.97 serverip=10.8.0.36 xfpga=tftpboot 100 socfpga.rbf; fpga load 0 100 $filesize; run bridge_enable_handoff; tftpboot 100 socfpga.dtb xload=run xfpga; tftpboot 8000 zImage; bootz 8000 – 100
      
      





IP 10.8.0.36開発コンピューターに、TFTPサーバーをインストールしました。 / tftpbootフォルダーに、SoC FPGAプロジェクトをQuartus Primeでコンパイルした結果であるsocfpga.rbf (Raw Binary File)を保存します。 また、同じフォルダーにsocfpga.dtb (対応するデバイスツリーブロブとLinuxカーネルzImageファイル)を保存します。



さて、ボードの電源を入れると、ターミナルのいずれかのキーを押して次のコマンドを入力することで、通常のダウンロードをすぐに中断します。

>run xload







このコマンドを使用して、U-BOOTはTFTPサーバーから必要なファイルをダウンロードし、プロジェクトの最後にコンパイルされたイメージでFPGAを初期化し、最後のzImageをダウンロードします。 早くて簡単。 FPGAプロジェクトに変更を加えると、プロジェクトをクォートでコンパイルし、結果を/ tftpbootフォルダーにコピーします。 同様に、Linuxカーネルをコンパイルし、コンパイルの結果を/ ftfpbootフォルダーにコピーします。 ボードを再起動し、「xloadを実行」すると、新しいシステムのデバッグを試みることができます。



2.あなたがしようとしていることにできるだけ類似したオープンソースのサンプルSoC-HPSプロジェクトを見つけてみてください。



キャプテンの証拠。 もちろん、有能なエンジニアは自分ですべてをゼロから行うことができます。 ただし、プロジェクトのソースを見つければ、これからやろうとするような時間を少し節約できます。



最初、DE10-Standard_v.1.2.0_SystemCDにはHPS-FPGA用の2つのサンプルプロジェクトが含まれています。 最初のプロジェクトはDE10_Standard_GHRDで、これは最小限の機能、Linuxコンソール、LED、ボタン、スイッチの入力/出力ポートなどのシンプルな周辺機器マッピング周辺機器を表します。 2番目の例DE10_Standard_FBは、より複雑です。 ここでは、すでにFPGAにフレームバッファー、ビデオコントローラー、ビデオ信号をキャプチャおよびデコードするデバイス、およびその他の多くの機能が実装されています。 これにより、フルデスクトップLinuxを実行できます。 これらの例に満足している場合、すべてが問題なく使用できます。



個人的には、システムメモリーからFPGAにデータを転送し、FPGAからシステムメモリーにデータを転送する際にCPUをオフロードしたいため、DMAコントローラーを使用した例を探しました。 私はそのような例を探し、ロケットボードのウェブサイトで見つけました。



この例は実際にはあまり良くありませんが、少なくとも何か、あなたは何かを試みることができます。 Cyclone V HPSにはPL330 DMAコントローラーが組み込まれているので、使用してみたいと思います。 Loopback_FIFOサンプルプロジェクトからIPピールを取り出し、Quartus Prime QSYSを使用してDE10_Standard_GHRDプロジェクトのクローンに挿入しました。 残念ながら、プロジェクトに適切なDTSファイルを作成するのに多くの時間を費やしましたが、DTSファイルはサンプルアーカイブには含まれていませんでした。 また、Linuxカーネルのarch / arm / mach-socfpga / fpga-dma.cに DMAドライバーの例が既にあることもすぐにはわかりませんでした 。 私は自分のドライバーをほとんど書き始めたときに、これに気づきました。



これらの困難にもかかわらず、既存の例、プロジェクト、およびソリューションを検索して開発を開始することをお勧めします。 いくつかの例を見つけて、最適なものを選択してください-それで、開発を始めてください。



3.ドキュメントとしてLinuxカーネルソースを使用する



FPGA Cyclone V HPSを使用して、新しいハードウェアプラットフォームを開発しています。 高確率で、FPGAの新しいハードウェア用に独自のドライバーを作成する必要があります。 Linuxカーネルレベルドライバーの作成方法については、インターネット上に多くの記事があります。 しかし、これらの記事の多くは古くて時代遅れであり、誤った例を含んでおり、古いカーネルAPIを呼び出していることに注意してください。



プロジェクトに特定のバージョンのLinuxカーネルを選択した場合、ドライバーの作成方法に関するすべての情報は、このバージョンのカーネルのソースから具体的に取得でき、これが最も関連性の高い情報になります。 ./driversフォルダー内のドライバーの例、。 / Documentationフォルダー内の有効なドキュメント、。 / arch / arm / boot / dtsフォルダー内の* .DTSファイルの記述例



私の場合、DMAコントローラーを使用するプロジェクトの場合、DMAドライバーを作成するためのドキュメントは./Documentation/dmaengine/*ファイルから取得されました



カーネルソースは、DTSファイルの記述に役立ちます-私にとって、DTSファイルは非常に大きな問題でした。 テキスト形式のDTSファイルは、システムのハードウェアリソースを記述しています。 次に、DTSはDTBファイルにコンパイルされます。このファイルは、ドライバーがデバイスに属するリソースを認識できるように、カーネルによって使用されます。



私が理解しているように、理論的には、開発は次のようになります。



  1. Quartus Prime QSYS CAD環境でハードウェアシステムを開発し、HPSパラメーターを構成し、システムにコンポーネントとIPコアを追加し、コンポーネントを接続します。 QSYSを使用してシステムを生成し、結果のsoc_system.qsysおよびsoc_system.sopsinfoファイルを取得します。
  2. コマンドラインを使用して、* .sopsinfoファイルからDTSファイルを作成します。

    >sopc2dts --input soc_system.sopcinfo --output socfpga.dts --board soc_system_board_info.xml --board hps_clock_info.xml





  3. DTSファイルからDTBを作成します。

    >dtc -I dts -O dtb -o socfpga.dtb socfpga.dts







はロケットボードのページそのような指示を読みましたが、この方法はどういうわけかうまく機能しません(まったく機能しません)。 私にとっては、ハードウェアプロジェクトに合わせて既存のDTSファイル例を手動で修正することが唯一の作業方法であることに気付きました。



すでに書いたように、カーネルソースはDTSファイルの作成に役立ちます。 私は自分でこれをすぐには理解していませんでしたが、理解すると問題は速くなりました。 カーネルソースをドキュメントとして使用する必要があります!



./driver/dma/fpga-dma.cの DMAドライバーの例を見てみましょう



ドライバーはplatform_driver_probe()関数APIを呼び出し、構造体へのポインターを引数として渡します。



 #ifdef CONFIG_OF static const struct of_device_id fpga_dma_of_match[] = { {.compatible = "altr,fpga-dma",}, {}, }; MODULE_DEVICE_TABLE(of, fpga_dma_of_match); #endif static struct platform_driver fpga_dma_driver = { .probe = fpga_dma_probe, .remove = fpga_dma_remove, .driver = { .name = "fpga_dma", .owner = THIS_MODULE, .of_match_table = of_match_ptr(fpga_dma_of_match), }, }; static int __init fpga_dma_init(void) { return platform_driver_probe(&fpga_dma_driver, fpga_dma_probe); }
      
      





つまり、DTSファイルには、互換性のあるデバイス名を持つ対応するセクションが存在する必要があります。



fpga_dma: fpga_dma@0x10033000 {

compatible = " altr,fpga-dma ";








つまり、明らかにplatform_driver_probe関数はDTBファイルをスキャンし、メーカーaltrのfpga-dmaという名前のデバイスを探します。



ドライバーが関数を呼び出す場合



 csr_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr"); data_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "data");
      
      





つまり、DTSファイルには、「csr」と「data」というまったく同じ名前の名前付きレジスタが含まれている必要があります。 そうしないと、ドライバーは起動できません。



同様に、カーネルドライバーは名前でDMAチャネルを要求できます。



 static int fpga_dma_dma_init(struct fpga_dma_pdata *pdata) { struct platform_device *pdev = pdata->pdev; pdata->txchan = dma_request_slave_channel(&pdev->dev, "tx"); if (pdata->txchan) dev_dbg(&pdev->dev, "TX channel %s %d selected\n", dma_chan_name(pdata->txchan), pdata->txchan->chan_id); else dev_err(&pdev->dev, "could not get TX dma channel\n"); pdata->rxchan = dma_request_slave_channel(&pdev->dev, "rx"); if (pdata->rxchan)
      
      





次に、DTSファイルの対応するフラグメントを示します。これには、カーネルドライバーのソースとDTSファイルの相関関係が表示されます。



 fpga_dma: fpga_dma@0x10033000 { compatible = "altr,fpga-dma"; reg = <0x00000001 0x00033000 0x00000020>, <0x00000000 0x00034000 0x00000010>; reg-names = "<b>csr</b>", "<b>data</b>"; dmas = <&hps_0_dma 0 &hps_0_dma 1>; dma-names = "<b>rx</b>", "<b>tx</b>";
      
      





したがって、DTSファイルは、ドライバーがどのようにリソースを要求するかを考慮して記述する必要があります。 名前付きレジスタとDMAチャネルを使用する場合、名前はカーネルソースとDTSファイルの両方で一致する必要があります。 この方法でのみ、カーネルドライバーとDTS / DTBの2つのシステムギアが連携して動作します。



4.ソースが最新ではない可能性があることに注意してください。



ドライバーの開発とFPGAシステム用のカーネルのコンパイルを開始するには、Linuxカーネルコンパイラーとソースが必要でした。 そのため、最新の(当時の)Intel SoC FPGAエンベデッド開発スイートv17.0をダウンロードしてインストールしました。



完全インストール後、git_clone.shスクリプトが置かれた新しいフォルダー〜/ intelFPGA / 17.0 / embedded / embeddedsw / sourcesが見つかりました。 このスクリプトを実行し、カーネルソースを〜/ intelFPGA / 17.0 / embedded / embeddedsw / sources / linux-sourcesから取得しました。



Gitブランチは次のようになりました: sockfpga-4.1.22-ltsi-16.1-release 。 カーネルバージョン4.1.22-さて、それをさせてください。



バージョン4.1.22を当然のことと考え、これらのソースでこのブランチの作業を開始しました。 カーネルを構築したところ、fpga-dmaと呼ばれるDMAドライバーがあり、このドライバーは基本的にFPGAプロジェクトのLoopbackFIFO IPコアで動作します。 しかし、システムのメモリからFPGAにデータを転送するパフォーマンスは非常に低いことに気付きました。転送は、数サイクルに1ワードの単一転送で実行されます。 FPGAプロジェクトを100回再確認し、 fpga-dma.cドライバーを100回再確認しましたが、バスでバースト転送が発生しなかった理由を理解できませんでした。 PL330コントローラー自体のD3ドライバーのソースコードをすでに扱い始めました。 また、HPS PL330 DMAコントローラに関するCyclone Vハードプロセッサシステムテクニカルリファレンスマニュアルを読む必要がありました。 このDMAコントローラは非常に複雑で、それ自体に独自の命令セットがあります。独自のプログラムを作成する必要があります。 PL330 DMAコントローラのアセンブリ言語プログラムは次のようになります。



 DMAMOV CCR, SB4 SS64 DB4 DS64 DMAMOV SAR, 0x1000 DMAMOV DAR, 0x4000 DMALP 16 DMALD DMAST DMALPEND DMAEND
      
      





私のすべての研究の結果、ドライバー./drivers/dma/pl330.cはバースト送信のためにDMAコントローラーのCCRレジスタを初期化しないことに気付きました。 私は何をすべきか理解できませんでしたが、後で、カーネルの新しいバージョンがこの誤解に対する修正をすでに含んでいることがわかりました。



パッチをソースDMAドライバーに手動で追加し、バースト転送を受信しました! DMAメモリからデバイスへの転送をキャプチャするSignalTapのスクリーンショットを次に示します。







したがって、ある日、解決方法がわからない技術的な問題に遭遇した場合、再確認してください。Linuxカーネルの最近のソースで問題がすでに修正されている場合はどうでしょうか。 私が理解しているように、DMAコントローラーPL330のブロック転送の問題はカーネル4.6で解決しました。



5.システムの個々の部分に注意してください。



もちろん、FPGA SoCシステムの開発には特定の知識が必要です。 IPコアまたはVerilog / VHDL構文の機能と開発方法については触れたくありません。 もちろん、開発者は多くのことを知っている必要があります。 ただし、システムのすべての部分を一緒に動作させることは非常に単純なタスクではないという事実に注意を喚起したいと思います。 同期して回転する必要があるギアが多すぎます。



私の練習の例を挙げようとします。



PL330 DMAコントローラードライバーをIPコアで動作させようとしました。 このような問題に遭遇しました。デバイスへの書き込み操作は成功しますが、読み取り操作は常にタイムアウトで終了します。 インターネットで解決策を見つけようとしましたが、多くの開発者もこの問題について質問していることがわかりましたが、解決策はありません。 システムログに、fpga-dmaドライバーからのメッセージ「RX DMAを待っているタイムアウト!」が表示されます。 しかし、問題は何ですか? -明確ではありません。 TX送信ではすべてが正常なのに、RX送信では正常ではないのはなぜですか? FPGAプロジェクトでチャネルRXとTXを入れ替えると、反対の「TX DMAを待機しているタイムアウト!」 2番目のDMAチャネルの何が問題になっていますか?



Quartus Prime Qsysを使用してSoCを編集しています。 SoCシステムの最も重要なコンポーネントの1つは、hps_0、「Arria V / Cyclone Vハードプロセッサシステム」です。 このコンポーネントのプロパティを編集し、DMAチャネルとRXおよびTXの両方がオンになっていることを確認しました。







これで十分ですか? もちろん、そうではありません! QsysはQuartus Primeのsoc_systemコンポーネントを生成しますが、。 / hps_isw_handoff / soc_system_hps_0フォルダーにソフトウェアコンポーネントも作成します。



以下を示すhps.xmlファイルがあります。



 <hps> <system> <config name='DEVICE_FAMILY' value='Cyclone V' /> <config name='DMA_Enable' value='Yes Yes No No No No No No' /> <config name='dbctrl_stayosc1' value='true' /> <config name='main_pll_m' value='73' /> <config name='main_pll_n' value='0' /> <config name='main_pll_c0_internal' value='1' />
      
      





つまり、後でPreloaderコンポーネントを生成する必要があり、このXMLファイルを使用してコンパイルします。 コンパイルされたプリローダーは、SDカードの特別なセクションに記録する必要があります。 システムが起動すると、プリローダーが起動します。 特別なハードウェアレジスタに必要なエントリを作成することにより、システムに必要なすべてのコンポーネントが含まれます。



Cyclone V HPSリセットマネージャーレジスタは、物理アドレス0xFFD05000(Cyclone Vハードプロセッサシステムテクニカルリファレンスマニュアル)にあります。 個々のチャネルでDMAを有効にするには、Reset Managerレジスタの一部のビットをリセットする必要があります。



まあ。 Qsysのhps_0コンポーネントのプロパティを変更していますが、Preloaderを再コンパイルしてSDに書き込む必要があることを知っています。



しかし、これはすべてではありません!



2つのDMAチャネルを使用する場合、これら2つのチャネルに対して2つの割り込みが必要であり、DTSファイルで手動で宣言する必要があります。



hps_0_dma: dma@0xffe01000 {

compatible = "arm,pl330-16.1", "arm,pl330", "arm,primecell";

reg = <0xffe01000 0x00001000>;

interrupt-parent = <&hps_0_arm_gic_0>;

interrupts = <0 104 4>, <0 105 4>;

clocks = <&l4_main_clk>;








なぜそのような奇妙な数字104と105があるのですか?

Cyclone V HPSリファレンスマニュアルを読む必要がありました。 Generic Interrupt ControllerがDMA要求行IRQ 136および137を予約していることがわかります。







ただし、何らかの理由で、番号は「32」で始まります。 したがって、136-32 = 104および137-32 = 105が正しい数値であると判断します。 これらの魔法の計算は、割り込みセクションでDTSファイルの正しい値を提供します。 DTSファイルでPL330の2番目のIRQを宣言せずに、2番目のDMAチャンネルはカーネルドライバーで常にタイムアウトエラーを受信しました...覚える時間。



おわりに



ロケットボードWebサイトのページで見つけたDMAプロジェクトの例を含むオリジナルプロジェクトがありました。 ただし、DE10-StandardボードおよびLinux 4.1カーネルで動作させるようにしました。



ただし、これはおそらく大きな成果ではありません。



  1. 元のプロジェクトにはないDTSファイルを書きました。 かなり大変でした。
  2. ブロック転送(バースト転送)を取得するには、カーネルパッチを作成する必要があることに気付きました。
  3. SignalTapアナライザーをFPGAプロジェクトに接続すると、DMA転送時にバス上の信号を確認できるようになりました。
  4. DMAカーネルドライバーの作成方法を学習しました
  5. Cyclone V HPSの開発者のロードマップ全体を理解したことを願っています


SoCでDMAを試してみたい人は、fpga-dma alterドライバで実験を開始することをお勧めします。 DebugFSを使用します。これにより、ターミナルコンソールで単純な「cat」、「echo」コマンドを直接使用して、DMAチャネルでトランザクションを実行できます。







この記事がFPGA SoC HPS Cyclone Vを使い始めたばかりの人に役立つことを願っています。



ここでプロジェクトのソースを参照してください。



All Articles