2014年1月26日日曜日
ビデオやオーディオのDMAバッファ管理手法(の続編の続編)
2012年の投稿「ビデオやオーディオのDMAバッファの管理手法 (動かして遊べるソースコード付き!)」や、2013年の投稿「DMAバッファ管理手法の続編」で触れたDMAバッファの管理手法は、以下の図に示すような簡単な概念を使って、実入出力処理を抽象化する手法について説明したものでした。
DMAを使用した転送を行なう場合、当たり前ですがDMAエンジンに対して転送指令を行なう必要があります。先の実装は抽象化した処理モデルに対する実装のみを提示したもので、実際にどこでDMAの設定を施して良いのかについては特に明示していませんでした。また、処理対象バッファの実装のヒントも示しておらず、実際の実装との距離を感じた方もいるかもしれません。
そこで、今回はframe.hにバッファの追加場所を、main.cにはDMAの設定箇所を@todoで記載したものを今回御紹介します。
DMAの設定後、完了するまでそのバッファの内容に触れてはいけませんが、これは抽象化した処理モデルによって保証されています。実デバイスの処理に依存する箇所は、主にバッファとDMAに対する設定のみですので、実際には抽象化されたコードから実装までの距離は殆どありません。実際に私もこのモデルを使用してDSP上にオーディオ処理アプリケーションを書いていますが、まさに今回の実装をそのまま使用して遊んでいます。
今回の設計は特定のチャネルのみを想定していますが、この一連のモデルを拡張するだけで複数のチャネルを対象に処理する事ができるようになります。以下のように入出力チャネル数に応じて入力遅延器、出力キューを増やせばよい事になります。
DMAを使用した転送を行なう場合、当たり前ですがDMAエンジンに対して転送指令を行なう必要があります。先の実装は抽象化した処理モデルに対する実装のみを提示したもので、実際にどこでDMAの設定を施して良いのかについては特に明示していませんでした。また、処理対象バッファの実装のヒントも示しておらず、実際の実装との距離を感じた方もいるかもしれません。
そこで、今回はframe.hにバッファの追加場所を、main.cにはDMAの設定箇所を@todoで記載したものを今回御紹介します。
無保証です。使用した結果の責任は一切負いません。
DMAの設定後、完了するまでそのバッファの内容に触れてはいけませんが、これは抽象化した処理モデルによって保証されています。実デバイスの処理に依存する箇所は、主にバッファとDMAに対する設定のみですので、実際には抽象化されたコードから実装までの距離は殆どありません。実際に私もこのモデルを使用してDSP上にオーディオ処理アプリケーションを書いていますが、まさに今回の実装をそのまま使用して遊んでいます。
今回の設計は特定のチャネルのみを想定していますが、この一連のモデルを拡張するだけで複数のチャネルを対象に処理する事ができるようになります。以下のように入出力チャネル数に応じて入力遅延器、出力キューを増やせばよい事になります。
冒頭の概念図に示したように、システム側で準備すべきバッファは、チャネル数に依存しない一連のバッファが一つあれば済むのもポイント。上位層のコードは、抽象化によって処理内容が一目でわかるようになるほか、将来の変更に対する柔軟性が高まりますので、遅延器やキューに対する処理によるオーバーヘッドを許容できるシステムにおいては、十分に検討のある方法です。
こんな感じで、2014年のCuBeatSystemsのブログは、ビデオやオーディオのDMAバッファ管理手法は続編の続編の続編から始まる事になりました。
今年もよろしくお願い申し上げます。
ラベル:
Break time,
DMA,
viomodel
2013年3月31日日曜日
DMAバッファ管理手法の続編
シンプルな制御モデル
昨年10月の投稿「ビデオやオーディオのDMAバッファの管理手法 (動かして遊べるソースコード付き!)」では、ビデオやオーディオなどを扱うファームウェアで、DMAバッファをどのように扱うと良いのかについて述べました。先の投稿で上げた制御モデルは以下のようなシンプルなものでした。
この制御モデルは、巷でよく見かける配列のインデックスを使って制御する方法よりも抽象化が可能で、チャネル数の変更や遅延量の制御などを簡単に実現する事が可能です。
このシンプルな制御モデルの応用可能範囲は、ビデオやオーディオに限りません。
例えば、データロガー等の場合、出力側にSDカードのような書き込み処理に時間がかかる物を配置する事があります。
この場合、viproc側でデータ収集設定(DMA設定)、voproc側でSDカードへの書き込みという事になります。
何がポイントですか?
先の制御モデルのポイントの一つは「queueによって入出力の関係が切れている」事です。
実は先日のシンプルな制御モデルは非常にシンプルにした一例で、実際に使用する場合にはもう少し思考を進める必要があります。
話を先に進める前に簡単にポイントを振り返っておきましょう。
- 遅延器(DELAY)は、DMAリクエスト発行からDMA完了までの時間を保証する。
- キュー(QUEUE)は、処理時間が一定でない後段に前段が影響を受けないようにする。
- 遅延器(DELAY)とキュー(QUEUE)によって、入力と出力の時間依存関係を緩いものにする。
入力側と出力側の両方でDMAを使用する場合も考慮して、先のシンプルな制御モデルに対して少し思考を進めてみましょう。
今回は対象領域も明確にしておきました。
入力処理では、入力キューからバッファを取得し、DMAリクエストを発行した後、入力遅延器にバッファを格納します。加えて、入力遅延器から出力キューに過去のバッファを移動させます。
出力処理では、出力キューからバッファを取得し、DMAリクエストを発行した後、出力遅延器にバッファを格納します。加えて、出力遅延器から入力キューに過去のバッファを移動させます。
上記文面を見ておわかり頂けると思いますが、入出力で完全に対称系になっています。
上記モデルを使用する事で、先に挙げたようなチャネル数の変更や遅延量の制御だけでなく、入出力の位相が曖昧な場合でも制御が破綻するような事がありません。
上記の制御モデルを使用する場合、以下のような事も考慮すると良いでしょう。
- 入力と出力は別々のハードウェアが担当しているのが普通。
- 入力割り込み、出力割り込みは非同期系として設計する。
- RTOSを使用する場合、入力と出力の処理スレッドは別々に設計する。
- キューから取り出せない場合、どのように振舞うべきか?
- 制御系が何を期待するのかによって挙動を決めます。
- 全体をリセットする場合、どのようにリセットすべきか?
- これは意外に難しい問題です。
- ハードウェアがどのように振舞うのかによっても大きく変わります。
- その他。(色々あります)
動かして遊べるソースコード
今回も動かして遊べるソースコードを用意しました。
先の投稿のソースコードと見比べてみるのも楽しいと思います。
ラベル:
Break time,
DMA,
viomodel
2012年10月31日水曜日
ビデオやオーディオのDMAバッファの管理手法 (動かして遊べるソースコード付き!)
DMAバッファを管理する
ビデオやオーディオのように絶え間なくやってくるデータの入出力を処理する場合、一般にDMAを使います。システムの中において、バッファの状態は主に「DMA中」、「DMA完了」、「未使用」の3種類に分類する事ができます。
DMAは、リクエストを出してからバッファにデータが完全にやってくるまでに時間がかかります。
DMAのリクエストを出してから即座にそのバッファに対して処理を開始する事は通常しません。
ビデオやオーディオのDMAバッファの管理は、DMAを出してからDMA完了イベントを待ち、到着したデータに対して処理を始める事になります。
配列による手法
DMAバッファを管理する機構を実現する際によく見かけるのは以下のような配列を用いた手法です。バッファや管理構造体を配列として保持し、何番目が「DMA中」、何番目が「DMA完了」といった具合にインデックスで管理する方法です。非常にシンプルですし、何の問題もないのですが、実装してみると意外とごちゃごちゃした感じになる傾向があります。これは、「システムの全体挙動を見る」という視点を持って見た場合、「配列にアクセスする」という実装詳細が目に入ってきてしまうためなのかもしれません。
モデルベースによる手法
少し考え直して、以下のような簡単なモデルを作ってみました。このモデルには登場人物が4人います。
queueは、任意の長さを構成可能なFIFOで、「未使用」状態のバッファを格納しておく場所です。
delayは、任意の遅延数を構成可能なFIFOで、設定した遅延数でデータが出てくるディレイ・ラインです。
viprocは、ビデオやオーディオを入力するモジュールで、データを入力すべきタイミングでのみ実行されるものです。viprocは、自身が呼ばれたらqueueからバッファを取りだし、バッファにデータを入力するためにDMAをリクエストします。加えて、バッファをdelayに押し込んで終了します。
voprocは、ビデオやオーディオを出力するモジュールで、データを出力すべきタイミングでのみ実行されるものです。voprocは、自身が呼ばれたらdelayからバッファを取りだし、バッファからデータを出力するためにDMAをリクエストします。加えてqueueにバッファを押しこんで終了します。
上記設計の場合、queueの深さは出力DMAが完了するために必要な深さが必要です。
その点さえ注意すれば、上記のモデルは以下のようなメリットがあります。
- 実装の抽象度が高く、メインテナンスが容易。
- データ入力が確定するまでの遅延数をdelay(ディレイ・ライン)の長さで任意に調整可能。
- 入出力が完全同期系でなくても、delayとqueueの範囲で吸収可能。
- 使用可能なバッファ数はqueueの長さで決められ、先読みなどの処理も容易。
- その他。
モデルベースによる手法を用いる事で実装の抽象度が上がってシンプルな実装を実現できます。
上記に示したメリットは配列による手法でも当然のように実現可能です。
が、実際に実現した実装を比較してみるとモデルベース設計の効果がわかると思います。
動かして遊べるソースコード
実際に上記のモデルを動かして遊べるソースコードを用意しました。viomodel.tar.gzからダウンロードして下さい。
2013年03月31日追記
「DMAバッファ管理手法の続編」に続編を書きました。
ラベル:
Break time,
DMA,
viomodel
登録:
コメント (Atom)