「リアルタイムOS不要」 ソフトウェア・パイプライン、チャネル、各タスクのCPU割り付け、ハードウエア・スケジューラ 

xCORE-200 で動作するソフトウエアは、「C言語」で設計します。
一方、デバイスの物理ポート(ピン)や、CPU間の通信、タスクのCPUへの割り付け等の、デバイスに依存する箇所だけは、拡張言語「xC」にて記述します。

拡張言語といっても、デバイス依存部分を記述するためのライブラリと理解して頂ければ結構です。
このライブラリも、数は少ないので、習得に時間はかかりません。

xC の基本的な部分を列挙すると下記になります。その他は、C言語による組込みソフトウエアの各タスクの設計同様に、C言語で設計していきます。

ポート設定・動作
チャネル(CPU間通信)
タイマー
イベント設定
タスクのCPU割り当て


詳細は、XMOS Programming Guide に譲るとして、まず初めに、ソフトウェア・パイプラインがなぜ容易に設計できるのか、USB Audio のソフトウェアを例に見ていきます。



コア・ダイアグラムとソフトウェア・パイプライン


USB Audio Design Guide には、次のような図が出てきます。
これを、Core Diagram と呼んでいます。丸一つ一つが、CPU に相当します。丸の中に記載されているのが、そのCPUで実行されるソフトウェア・タスクになります。

/files/images/14442/39/threads-crop.png

各タスクは、他のタスク(CPU)と、チャネル(chan)と呼ばれる通信経路を使用して、データの受け渡しを行います。その通信経路は、上図では、矢印で記載されています。

グレーの部分が、各ポートを示しています。


上図では、各ソフトウェア・タスク(CPU)がデータをやり取りする形でシステムが構成されています。これが、ソフトウェア・パイプラインです。


データの流れについて一例を上げると、左上の"USBポート(ULPI)"からのオーディオ・データが、各タスク(Decoupler, Mixer, Audio Driver 等)を経由して、下部中央の"I2S" ポートに出力されています。実は、これが USB-DAC を実現しているソフトウェアになります。




タスク間通信経路:チャネル(chan)


各タスクは、While(1) {} を持ち、それが実行されるCPUが割り当てられます。このため、各タスク(while(1){})は、対応するCPUを占有し続けることになります。

前述のようなソフトウェア・パイプラインを実現するためには、その各タスク同士が、データの送受信を行う必要があります。このデータの送受信を行う方法として、チャネル(chan)が用意されています。

このチャネルの仕組みを使用することで、各タスク間の同期をとることができます。


このチャネル(chan)は、2種類容易されています。
 chan
  streaming chan

chan を使用した通信では、データを送信後、内部的にACK に相当する受信処理を実施してから、通信処理が完了します。この仕組みを使用して、タスク間での同期処理を実現することができます。

以下の図は、タスク"Task0()" と タスク"Task1()" が、それぞれ別々のCPUに割り当てられている例になります。タスクのCPU割り当ては、main関数内の "par{}" という xC 記述で行っています。

この動作を簡単に、説明します。



[1] Task0 は、Task1 に対して、ローカル変数"x"の内容を送信しています(0-1)。Task1 側で受信が終了すると、Task0 も次の処理(0-2)に移ることができます。

[2] Task1 では、Task0 にてデータが送信されるまで、(1-1) の箇所で処理が止まっています。データ受信後、次の処理(1-2)に移ることができます。

[3] 同様に、Task0 側では、Task1 からのデータを待っています(0-2)。データを受信後、(0-3)の処理を実行することができます。

この例では、Task0 と Task1 がチャネルの仕組みを使用することで、タスク間の同期をとっています。



streaming chan の場合には、ACKに相当する受信処理がないため、通信経路上の Buffer に空きがある限り、送信後次の処理に移ることができます。






リアルタイムOS不要

上記の簡単なソフトウェア例を見て頂くとお分かりのように、OS の処理が出てきません。

上記の記述(par{})から、xC compiler が Task0 と Task1を各CPUに割り当て、しかも、ハードウエア実装されているスケジューラーが、Task0 と Task1 を並列に実行します。

このため、タスク切り替えのオーバーヘッドを気にすることなく、また、共有メモリ無しでソフトウェア・パイプラインを設計・実装していくことができます。



つまり、前述のコア・ダイアグラムで設計した
「ハイレベルのソフトウェア・アーキテクチャ」と、

チャネル(chan)の仕組みを使用して
「C言語で実装されたソフトウェア・コード」の構造が、
一致しているのです。



ハイレベルのソフトウェア・アーキテクチャと、実際の実装が一致しているため、仕様変更等にも柔軟に対応することが可能になります。

例えば、タスクを足して、矢印の接続先を変更するだけで、ソフトウェア・パイプラインの変更ができます。このため、機能の追加や削除が、容易となります。



このことは、組込みソフトウェアの生産効率を上げるだけでなく、シンプルなソフトウェア構造による、設計品質の向上が実現できることを意味します。






パイプライン・ステージの追加と削除が容易!

チャネルの仕組みを使用することで、ソフトウエア・パイプラインを容易に構築できることを紹介いたしましたが、xCORE-200 ならば、パイプライン・ステージの追加や削除も容易に実施できます。また、そのステージの追加と削除を、他のタスクに影響を与えることなく実現できます。

このことは、一旦、xCORE-200 を利用したソフトウェア・プラットフォームを構築すれば、その拡張、エンハンスメント、メンテナンス「コスト」が低いことを意味します。

以下の図は、ソフトウェア・パイプライン A -> C に、タスクB を新たなパイプライン・ステージとして追加した例です。

左側の"task_A"と"task_C" で構成された2段のソフトウェア・パイプラインがあります。これに、タスク "task_B" を追加して、右側の3段のソフトウェア・パイプラインに拡張する例です。

各タスクは、専用のCPUが割り当てられます。コンテキスト・スイッチは発生しません。




この追加では、"task_A" と "task_C" の機能はそのままで、"task_A" の出力を "task_C" から "task_B" に変更しています。そして、"task_C" の入力を "task_A" から "task_B" に変更しています。

上図は、パイプラインの各ステージの処理時間の制限が 20us の場合になります。"task_B" のパイプライン・ステージの追加は、"task_A", "task_C" の各ステージの処理時間に影響を与えません。

これは、パイプライン・処理であること、そして、各タスクが専用のCPUに割り当てられていることから実現できます。


このように、xCORE-200 を使用した組み込みソフトウェア開発では、完全に並列に動作する各CPUと、ソフトウェア・パイプラインを容易に構築できるアーキテクチャを使用して、柔軟で拡張性の高いシステムを設計し実装することが可能です。








次回は、その他の「xC」(拡張C言語)を見ていきます。


(その他の投稿については、右上の「ページ」をご確認ください)

0 件のコメント:

コメントを投稿