ラベル B063: BlackTank の投稿を表示しています。 すべての投稿を表示
ラベル B063: BlackTank の投稿を表示しています。 すべての投稿を表示

2012年8月17日金曜日

オーディオ・プラットフォームBlueTankの始まりとUZUMEオーディオ・フレームワーク

まえがき

先日からBlueTankだとか何とか書いていて、経緯を知らない人にとっては「何を言っているの?」という感じです。この記事では、オーディオ・プラットフォームBlueTankの始まりとUZUMEオーディオ・フレームワークについて触れたいと思います。

前々からオーディオ装置の開発をやりたいなぁと考えているわけですが、それっぽい入口を仕立てる度にシェルを作るのに忙しくなったり、デバッグ用ツールを作るのに忙しくなったりと何をやっているんだという状態です。

そうは言えども、徐々に何をどう進めようかという指針が明確になってきました。

まずは下回りを固めようという事でオーディオを簡単に扱うためのフレームワークを構築しようと考えるわけですが、実はDSP空挺団をホストされている酔漢さんが既に完成度の高いフレームワークを構築されています。

ということで、後はお手頃なハードウェア・プラットフォームを構築して、その上でフレームワークを使って楽しめば良いじゃないかとなるわけなのです。

ハードウェア・プラットフォーム

以前にBlackTankを設計した時に面倒な思いをして、「これを続けるのは大変だなぁ」と考えていました。
もっと手軽なプラットフォームで開発したいと考えたわけです。

そこに現れたのが金子システム社のDSP基板です。
お値段とサイズがコンパクトなのでほぼリスクなし。


こいつを載せるベース基板を作りさえすればスタートできるなぁと考えていました。
で、作ってみたのが以下の写真・・・。(え?)


基板マニアの私としては、この手作り感がどうしても許せません。
そして、複数個作れと言われても作る気になれません。
要するに、手作業でユニバーサル基板に配線する事に手軽さを感じませんでした。

結局のところ簡単なベース基板を設計する事にしました。
それがBlueTankとなったのです。
とはいえ、DSP基板上にほとんど必要な部品が搭載されているため、ベース基板の回路はスカスカです。


BlueTankで実現するかどうかわかりませんが、装置モノとして筺体設計も考えています。
BlueTankの基板はTAKACHIのLCS135-Hに収まるように設計してあります。


UZUMEオーディオ・フレームワーク

UZUMEオーディオ・フレームワークは、オーディオ処理に必要なリアルタイム制御部分を遮蔽し、オーディオの処理のみに注力できるように考えられているフレームワークです。


フレームワークでは、予め想定された用途の範囲でAPIが整備されています。

一部はBlueTankに適用できないので、対応はこれから考えますが、UZUMEオーディオ・フレームワークの比較的小さなプラットフォームの部類にBlueTankを該当させたい考えです。

「コンパクトなハードウェアで各種オーディオ処理の実験が可能!」というのがBlueTankの位置付けでしょうか。

プロジェクト・ページ


オーディオ・プラットフォームBlueTankにも、UZUMEオーディオ・フレームワークにも、プロジェクト・ページが存在します。興味のある人は訪れてみて下さい。


2011年12月11日日曜日

ディジタル・オーディオ実験用基板BlackTankの進捗状況

BlackTankは忘れた頃にやってくる・・・


MTM07で勢い余って展示しておいたBlackTankですが、急にやる気が出てきました。

私は、基板をスクエアーに作ってその中に機能を美しく詰め込むのが大好きです。
BlackTankも例に漏れずそんな感じで作ったオーディオ基板です。


と言っても、音質などは二の次で、とにかく色々楽しもうと色々欲張った感じになっています。
以下は、部品面、内層1、内層2、半田面の配線です。





この基板は、酔漢さんが進められておられるオーディオ・フレームワークUZUMEを利用できるように設計してあります。どうもMTM08には出展されるという事なので、BlackTankとしても出撃できるように準備をゆっくり開始する事にしました。

今日は久しぶりの通電と開発環境の確認です。

以前はOpenOCDを使ってデバッグしていたのですが、SWDを使った開発環境の方が手軽でした。
そこで、LPCXpressoのデバッガ側とターゲット側を切り離し、デバッガ側からそのままBlackTankに接続してデバッグする方針に変更です。


BlackTankでは、20ピンのJTAGを出しておいたので、そのままSWDによるデバッグも可能です。
このまま具合が良ければ、次回以降の設計でSWDの10ピンコネクタだけにするかもしれません。

2011年4月1日金曜日

ARM Cortex-M3 (NXP LPC1769)を用いたオーディオ処理の効率改善

概要

今回はプロセッサを用いた信号処理における効率改善に関するトピックです。


先日完成したARM Cortex-M3 (NXP LPC1769)を用いたオーディオ基板は @suikan_blackfin さんがお作りになったサンプルアプリケーションのおかげで素早く動作確認することができました。本当にありがとうございます。


氏はリアルタイムOSのポーティングから信号処理まで多岐に渡る分野で活躍されていて、言わば私の心の師匠ですが、恐れ多くもサンプルアプリケーションで気になったオーディオ処理の効率改善について記すことにしました。

巨人の肩に乗りまくりです。

オリジナルの設計

まず初めにオリジナルの設計がどのようなオーディオ処理ステップを踏むのかを整理してみます。
  • DMA転送されたオーディオバッファサイズ分のデータがrxbufに入っている。
  • 並び替えながらrxbufからaudio_data.inputBufferにコピーする。
  • オーディオ処理を実行する。
    • ここでは処理に応じてaudio_data.inputBufferからaudio_data.outputBufferへのコピーが発生する。
  • 並び替えながらaudio_data.outputBufferからtxbufにコピーする。
図を用いて整理すると以下のようになります。

要するに主記憶上におけるメモリコピーが少なくとも3回発生していることになります。
このメモリコピーはforループで実装されており、3回のforループによる性能への影響も気になるところです。

通常、性能という観点で見た場合、主記憶上でのメモリコピーや重複したforループは処理性能低下の主要な要因のひとつとなります。

そこで、今回は上記処理の効率改善を考えてみます。

最小限の処理から考えてみる

まず初めに、最小限の処理について考えます。

入力をそのまま出力に伝達する場合、単なるメモリコピーで済みます。
入力に何らかの処理を加え、出力に伝える場合でもこの入出力間のメモリコピーの間に何らかの処理を追加するだけで済みますので、本質的に上記と変わりません。

オリジナルの実装ではコーデックのデータ形式を踏まえて処理を行なっています。

まず初めに入力されたデータを内部で扱いやすい形式にメモリコピーします。

これはrxbufからinputBufferへのコピーです。


次にオーディオの処理を実行します。
これはinputBufferからoutputBufferへのコピーです。

オーディオの処理を実装する過程で、ここに様々な演算が入ることになります。

最後に結果を出力バッファに書き込みます。
これはoutputBufferからtxbufへのコピーです。

この作業はオーディオバッファの内容を、前段で都合の良い形式に並び替えた結果発生する作業と言えます。


まとめると以下のようになります。
  • コーデックから得られたデータ形式は扱いにくいので並び替える。
  • 並び替えは主記憶上でMCUが実行する。
  • 並び替えたデータは、コーデックがそのまま扱えないので再変換する。
コードブロックは以下のようになっていました。(一部はオリジナルと少し異なります。)

   index = 0;
   for (sample = 0; sample < AUDIOBUFSIZE / 2; sample++) {
       for (ch = 0; ch < 2; ch++) {
           audio_data.inputBuffer[ch][sample] = rxbuf[index++];
       }
   }
   audio_effect_through(
           &effect_param,
           audio_data.inputBuffer,
           audio_data.outputBuffer,
           AUDIOBUFSIZE / 2);
   index = 0;
   for (sample = 0; sample < AUDIOBUFSIZE / 2; sample++) {
       for (ch = 0; ch < 2; ch++) {
           txbuf[index++] = audio_data.outputBuffer[ch][sample];
       }
   }

オーディオエフェクト処理の前後でデータ形式変換を行なっていることがわかります。
前段と後段で各((AUDIOBUFSIZE / 2) x 2)回分のメモリコピーを行なっています。

実際にオーディオ処理関数内部の実装も見てみます。(一部はオリジナルと少し異なります。)

   void audio_effect_through(
           effect_param_t *param,
           AUDIOSAMPLE input[2][AUDIOBUFSIZE / 2],
           AUDIOSAMPLE output[2][AUDIOBUFSIZE / 2],
           int count)
   {
       int i;
 
       const int var0 = param->var0;
       const int var1 = param->var1;
       for (i = 0; i < count; i++)
       {
           output[LCH][i] = (input[LCH][i] >> 10) * var0;
           output[RCH][i] = (input[RCH][i] >> 10) * var1;
       }
   }

ここで上位から渡されるcountは(AUDIOBUFSIZE / 2)です。
よって、ここでも((AUDIOBUFSIZE / 2) x 2)回分のメモリコピーを行なっていることになります。

改善の提案

ここまではオリジナルの設計について整理しました。
それでは実際にオーディオ処理の効率改善をしてみます。

基本的な思想は以下の通りです。
  • 主記憶上におけるメモリコピーは性能に対して著しい劣化を伴う。
  • より多くの処理を実現するためにはメモリコピーを排除すれば良い。
  • メモリコピーを行なっている主な理由はデータ形式変換である。
  • データ形式変換が不要となるような枠組みを用意すれば、データ形式変換が不要となるはずである。
  • データ形式変換が不要となれば、必要となるバッファも削減することができ、RAM容量という観点から見ても有利である。
「データ形式変換」を実現しながらも、「メモリコピー」を発生させないという一見矛盾した課題を解決すれば良い事になります。この中でforループについても削減可能と判断しました。

オリジナルの実装ではオーディオ処理関数に渡るデータ形式が重要でした。
この点は改善案でも特に変わるものではありません。

オリジナルと異なるのはその実現手法です。
ここで実際のコードを示します。

   for (index = 0; index < AUDIOBUFSIZE; index+=2) {
       audio_effect_through(
               &effect_param,
               rxbuf + (index + 0), rxbuf + (index + 1),
               txbuf + (index + 0), txbuf + (index + 1));
   }

オーディオ処理関数へL-Rのステレオデータを揃えて渡す部分はコールバック関数とし、オーディオ処理関数内部で直接出力データを格納させる形式としました。

オリジナルに存在した前段と後段における形式変換用メモリコピーを排除することができます。
これにより内部作業用バッファinputBufferとoutputBufferも不要となりました。

audio_effect_throught関数はオーディオデータをスルーコピーする関数です。

   void audio_effect_through(
           const effect_param_t *param,
           const AUDIOSAMPLE *in_left,
           const AUDIOSAMPLE *in_right,
           AUDIOSAMPLE *out_left,
           AUDIOSAMPLE *out_right)
   {
       const int var0 = param->var0;
       const int var1 = param->var1;
       *out_left = ((*in_left) >> 10) * var0;
       *out_right = ((*in_right) >> 10) * var1;
   }

オーディオエフェクト関数には1サンプル毎に処理を依頼します。
処理結果は関数に渡されたバッファへのポインタを用いて直接格納します。


要するに冒頭にあった最小限の処理に近くなる仕組みです。



上記により中間バッファを排除しながらも、渡されるデータ形式はL-Rのステレオで揃っているという状況を作ることができます。
また、バッファサイズ分のforループも1回で済むようになり、効率改善が期待できます。

改善の効果

ここで実際の処理時間に与える効果を調査しました。
処理時間を測定するために、オーディオ処理ブロックに差し掛かったところでGPIOをハイレベルにし、オシロスコープにより観測します。

ここでの処理対象は1オーディオサンプルブロックでAUDIOBUFSIZEバイト分のデータです。
初めにオリジナル実装でオーディオスルーにかかっている処理時間を示します。
1オーディオサンプルブロックの処理に約70[us]の時間を要しています。


次に改良した実装でオーディオスルーを行なった場合の処理時間を調べます。
同じ1オーディオサンプルブロックの処理を約25[us]の時間で処理していることがわかります。


オリジナルの実装に対して約35%の時間で同等の処理が実現できる事が確認できました。
削減できた約45[us]は別の演算に割り当てることができます。
従来より高度な演算も可能な他、他のタスクにプロセッサを素早く譲ることができるようになります。

改善のまとめ

オーディオ処理関数の呼び出し方を変更し、主記憶上におけるメモリコピーを大幅に削減しました。
結果的に処理時間を削減でき、従来よりもシステムプロセッサを効率的に運用することが可能となりました。

今回の改善でオーディオエフェクト部分の設計者はデータ長を気にすることなく、1サンプルの処理に集中して記述できるようにもなりました。
オーディオエフェクト関数を同じパラメータで作成すれば、関数ポインタの切り替えのみでオーディオエフェクト処理を切り替えることが可能となります。


当然のことですが、オーディオ処理では特定サンプルに対して、時間軸方向前後のデータも用いてフィルタリング処理を行ないます。
提案手法ではオーディオ処理関数に渡ってくるデータは1サンプル分のみですが、オーディオエフェクト関数内部で静的メモリを保持し、バッファリングしながら処理をすることで、時間軸の前後方向のデータも用いて処理することが可能です。

RTOSを用いたシステムを構築する場合、局所的に見た性能改善とシステム全体を見た性能改善の双方の視点が欠かせません。
今回行なった性能改善は局所的なものですが、タスクの性質上高いプライオリティで動作します。
このタスクの処理時間を削減するだけで、他のタスクで行うことの出来るサービスが飛躍的に増えます。
例えば、ディスプレイに表示したい内容を別のタスクに伝達しようとか、そういった付加的なサービスにプロセッサ時間を使う事ができます。こういった要素が「他と違う何か(=付加価値)」に繋がっていきます。

なお、実験結果はコンパイラの最適化オプションを外した状態で行ないました。
最適化を施すことで、場合によってはより大きな改善が得られる可能性もあります。

2011年3月20日日曜日

LPC1769搭載オーディオ基板のハードウェアデバッグが完了

先月からダラダラと進めているARM Cortex-M3(LPC1769)搭載オーディオ基板のハードウェアデバッグが完了しました。
回避不能となるような致命的なバグはなく一安心というところです。


今回のプロジェクトでARM Cortex-M3の感じが大体つかめました。
@suikan_blackfinさんによるオーディオトークスルーもこのとおり動作しています。


会社で周りの人と話していると「マイコン=低機能」という思い込みを持っている人が意外に多いことに気づきます。
確かに業務で少し触れただけの過去の経験から現状を見ると「何が違うの?」ということになるのかもしれません。
これは非常に勿体無い話です。
10年、20年前とは状況が大きく変わっているのだということを実感するには、実際に触ってみるのが一番です。

例えば、今回の基板ではオーディオをコーデック経由でスルーさせながら、バックグラウンドでデバッグ用シェルが走っていたり、マイクロSDカードにアクセスしたり、有機ELディスプレイの表示をしたり、ユーザのスイッチ入力を監視したりしています。これらの仕事をワンチップのマイコンで実現できるわけです。

マイコンのシステムだからと言って、わざわざ周辺環境までチープにする必要はありません。
ストレージ(今回はマイクロSDカード)も欲しいし、デバッグにはシェルが欠かせません。

ARM Cortex-M3はこういった小規模開発の既存概念を変える道具として最適です。
データシート上で見る性能だけでなく、「実際にどこまでできるのか?」を自分で考えてみることで、誰も考えていなかった応用への発展が期待できそうです。

なお、このプロジェクトは引き続きファームウェア開発を行う予定です。

2011年3月7日月曜日

LPC1769搭載オーディオ基板のとんでもない実装ミス

昨日のこと、LPC1769搭載オーディオ基板のデバッグを開始して1時間後、とんでもない実装ミスを発見してがっくりしていました。

「なんだかSWDで繋がらないなぁ〜。」なんて思っていたんです。
前日までは「まぁ、デバッガの接続が間違っているんだろう。」なんて思っていました。

さてさて、データシートのパッケージ情報にはきちんと「1ピンはココ!」と当然示されていますね。


で、取り付けた状態の写真が以下です・・・。


ですが、冷静に基板を見て愕然・・・。
「1ピンはそこじゃない!」
なんと、1ピンは左上なのです!


もう全く意味がわかりません。

データシートを何のために見て実装したのでしょうか・・・。
シルクによる心理効果か、はたまた大きい穴に騙されたのでしょうか。

とにかくもう一台作り直しです。
今度はさすがに間違えません。


なんだかんだで2時間のハンダ付けを行ない2台目が完成。
あっさりSWDによる認識も完了しました。


なんと言いますか、一日働いた後で深夜のハンダ付けは避けようかと考えた出来事でした。

P.S. この方のようなユーモアを交えてお伝えするセンスを持ちあわせていないのが残念。

2011年3月3日木曜日

LPC1769搭載オーディオ基板のデバッグ用1号機が組み立て完了

先月の中旬に基板が上がってきてからダラダラと行なっていたLPC1769搭載オーディオ基板のデバッグ用1号機の組み立てがやっとこさ完了しました。
大した事ないハンダ付けのはずでしたが、その前に基板がおかしいだろうとか、FPCのハンダ付けでギャフンと言ったりしてなかなか進んでいませんでした。

ボリュームとスイッチは高さを合わせてあります。
最終的にアクリル板を上部に取り付けるようにする計画。


今回の基板は少しだけ奮発して値段のはるスイッチを使ってます。
左上の有機ELも表示させるのも楽しみ。


今日はショートチェックを済ませた後、通電を数十秒だけ行ないました。
デバッグ用シリアルインターフェースに接続したFT232RLを、パソコン側で認識できるのは確認しました。


基板のデバッグはまだまだこれから。
今週末にでもデバッグを進めようと思います。

2011年2月20日日曜日

痛い思いをしたFPC用コネクタのハンダ付け

B063: BlackTankには有機EL液晶が搭載される予定です。
接続部分はFPCになっていて、例によってFPC用コネクタなのですが、最初の実装は思いっきり失敗してしまいました。

半田を載せ過ぎてしまったのと、不要な半田を除去しようにも除去しきれなくてフラックスを付けながらグシグシとハンダゴテをあててどうにもならない状況になってしまいました。
ピンが曲がってしまったようにも見えていましたし、パターンにダメージがあると思うと、取り外さざるを得ない様相です。

仕方なく、最初に実装したコネクタは破壊することを前提に取り除くことにしました。

作業対象箇所にフラックスを塗って作業します。

フラックスを塗布することでハンダゴテ接触部位の急激な加熱を防いでくれます。
パターンは加熱させた状態で無理な力をかけるとすぐに剥がれてしまいます。


今回は幸いにもフラックスを塗りたくっているお陰・・・かどうかわかりませんが大丈夫でした。
フラックスリムーバーを使って綺麗にします。


当初付いていたコネクタには半田を盛りまくって取り外しました。


初めに付いていたコネクタと同じ型の物を付けようかとも思いましたが、ネガティブな感情になっていて挑戦することができませんでした。少し形状の異なるものを付けました。


フラックスを使うからといって、実装時に半田を山盛りにしても大丈夫というわけではありません。
今回はそんなことを痛感した体験でした。

ハンダ付けはこういった痛い思いをして上手になっていくものなのでしょう。

2011年2月18日金曜日

LPC1769搭載オーディオ基板のハンダ付けを始めました

LPC1769搭載オーディオ基板のハンダ付けを始めました。

方針は、プロセッサ周辺回路を搭載して基本動作を確認し、徐々にペリフェラルを実装するという方向で行こうと思っています。


一気に実装してしまいたい気持ちもあるのですが、今回は搭載する部品もそれぞれ結構な単価ですので、慎重モードです。


フラックスも当然ながら必須アイテム。

2011年2月14日月曜日

PCBCARTから4層基板が到着しました。

先日PCBCARTに発注した4層基板が到着しました。
気になる品質などについてレポートを。

FedExの包装の中にこんな感じでくるまれていました。


中身のパッキングは以下のような感じです。


オーダー情報などが記載されたレッテルが貼られています。


ちょっと見た限り良さそうな感じではあります・・・。


が・・・見つけてしまいました中国品質。
品質の均一さ加減をお伝えしようとスキャナで撮った映像を見た時に思わず笑ってしまいました。

皆さんも間違い探ししてみませんか?

こちらは部品面。


こちらは半田面。




わかりましたか?



答えは・・・。



デートコードを間違ったのでしょう。
手で削ってます。(笑)


そして、極めつけはこれ。
もう本当にこういうの好き。(笑)
現場の人の人間臭さが出ています。


あー、本当に4層なのかも気になってきました。
ちゃんとショートチェックと導通チェックもやらなくちゃ・・・。

一応サポートには軽いクレームを入れる予定。
でも、中国と言うバイタリティに溢れた国を俄然気に入ってしまいました。

2011年1月26日水曜日

PCBCARTに4層基板を発注

以前に何度か使用した事のあるPCBCARTですが、今回初めて4層基板を発注することにしました。


PCBCARTがデフォルトで設定しているパラメータのうち、シルクを両面にしたところ95x72[mm]の4層基板を4枚製作して送料込みで$208USドルです。

EAGLEのボードファイルでは事故が多数起きているようなので、ガーバーを出力。
CAM Processorでは、gerb274x-4layer.camとexcellon.camを使用しました。
ドリルラック情報はdrillcfg.ulpを使用しています。

出力されたファイルを1つのzipにまとめます。
README.txtには以下のような記述をしました。
Description of the files.

Drill rack: B063_BlackTank_LPC1768.drl
Drill data: B063_BlackTank_LPC1768.drd
Drill station info: B063_BlackTank_LPC1768.dri
Photoplotter info: B063_BlackTank_LPC1768.gpi

Component side: B063_BlackTank_LPC1768.cmp
Inner layer 2: B063_BlackTank_LPC1768.ly2
Inner layer 15: B063_BlackTank_LPC1768.l15
Solder side: B063_BlackTank_LPC1768.sol

Silk screen CMP: B063_BlackTank_LPC1768.plc
Silk screen SOL: B063_BlackTank_LPC1768.pls
Solder stop mask CMP: B063_BlackTank_LPC1768.stc
Solder stop mask SOL: B063_BlackTank_LPC1768.sts
Cream frame CMP: B063_BlackTank_LPC1768.crc
Cream frame SOL: B063_BlackTank_LPC1768.crs
ということで出来上がりが楽しみなこの基板。
今度は到着した時点でのレポートとなりそうです。

ちなみにこの基板は元旦から企画を始めて、10日で第1版の電気図面と基板設計が完了し、そこからお世話になっている方にレビューをお願いして、大幅に修正して第2版として完成したもの。

レビューして頂いたお陰で大幅に改良することができたと思っています。
お忙しい中レビューして頂いた方には本当に感謝です。