2012年9月29日土曜日

AC'97 Codecを制御してみる 2

だいぶ間が空いてしまった。

DIGILENT社のSpatan6 評価ボードであるAtlysに実装されているAC'97 odec (LM4550)を制御してみている。 LM4550とFPGA間のI/FはAC LinkというシリアルI/Fであり、256bitからなるフレームは、16bitまたは20bit長の全部で13固のスロットで構成される。これは、前回のブログに書いた。  FPGA側は素直に256bit長のparallel to serial変換回路を実装するのが安直であるが、13個のスロットには仕様上予約となっている項目や今回の実装では使用しない項目等があり、これらは全て0が設定するので、256bitのparallel to serial回路では無駄が多い気がして、以下のような回路にした。

送信部

受信部


この送受信部はCodecから出力されるクロック(12.288MHz)で動作するが、その上位の回路(送信データの供給元や受信データを格納先)は100MHzと50MHzとかの別のクロックで動作させたい。したがって、これら領域は異種クロックで動作することになるため、やりとりするデータのクロックの乗替えが必要になる。これは非同期FIFOを使うことにした。

送信用

受信用


回路としては大体こんな感じだが、例えば音を出すためには音源データが必要であり、以前作成したFunction Generator用のRTLを若干変更して組み込んだ。また、LM4550は初期状態では全てのボリュームがMute状態になっているため、必要なボリュームレジスタのMuteを解除する必要がある。Codec内部レジスタは本AC97コントローラのレジスタ経由でソフトウェアからアクセスできるようにしているので、Function Generator用のソフトウェアにその処理を追加した。

wavファイルデータをDRAMに展開しFunction GeneratorのLBUFの機能を使って再生させてみた。

(注意:曲が流れます。)


また、DDSで単一周波数信号(例えば1KHz)を出力させても音はでるが、オシロスコープで波形をみると輝線が太く波形的には汚い。どうも水晶発振器出力の24.576MHzが重畳しているようだ。
これは実装(基板設計)の問題と思われるのでRTLではどうしようもない。



2012年8月31日金曜日

AC'97 Codecを制御してみる

AtlysボードにはNational SemiconductorのLM4550というAC'97 Codecが搭載されている。
Wikipediaによると、AC'97はIntelが提唱したサウンドインタフェースの標準規格で機能的には論理コントローラとアナログコーデックがありこれらがAC-Linkという5線式の双方向シリアルインターフェースバスで接続される。 LM4550は機能的にはアナログコーデックであり、今回これを制御する論理コントローラを作ってみようという訳だ。
LM4550のブロック図をデータシートから以下に引用する。




出力はLINE_OUT~MONO_OUTの3系統、入力はMIC~PHONEの7系統があるが、Atlysボードで使用できるのは出力はLINE_OUTとHP_OUT、入力はLINE_INとMIC1のみとなっている。


AC_LinkはBIT_CLK、SYNC、SDATA_OUT、SDATA_IN、RESET#からなるシリアルインターフェースで、SDATA_xxxがデータ信号であり、IN/OUTは論理コントローラ側からみた方向付けになっている。つまり、SDATA_OUTは論理コントローラ→コーデック、SDATA_INはコーデック→論理コントローラ。BIT_CLKは文字通りのビットクロックでSDATA_xxxはこのクロックに同期して転送される。このクロック信号はコーデックが駆動する。 SDATA_xxxで送受されるデータは以下のようなフレーム構造で全体のビット長は256ビットである。通常はフレーム周期は出力側のサンプリングレートに一致するので、BIT_CLKはサンプリングレートの256倍の周波数になる。

SDATA_OUTラインのデータフレーム構造は以下のようになっている。
1フレームは13個のSLOTで構成され、SLOT0は16ビット長のTAG情報、SLOT1~12は20ビット長で図に示す情報となっている。オーディオ情報とコーデック制御情報が多重化されていて、フレームサイズは固定長であるが、TAG SLOTのビットで有効・無効を表示できるようになっている。



SDATA_INラインのデータフレームは以下のようになっている。


今回は、以前作成したDDS IPからコーデックに出力したりDRAM上に何か音楽データを置いてコーデックに出力(再生)させたり、LINE_INにアナログ信号を入れてキャプチャしてみたりしてみたいと考えている。
AC'97の論理コントローラIPについて確固としたイメージを持っている訳でも無く、どちらかというとDAC/ADCとして使う感じなので、このプロジェクトのタイトルは「AC'97 IPの作成」とはしていない。

まずは、AC-Link I/Fのシリパラ変換部を作る必要がある。


2012年8月26日日曜日

近況

毎日、暑い日が続きますなー
そのせいか、ここのところ体調がvery bad conditionで異常な疲労感に襲われている。
この土日も殆ど寝て過ごしてしまった。

8月も終わるのでさすがの暑さも和らぐだろうと期待している。
なんとか体調回復させて活動再開したい。


2012年8月7日火曜日

next theme

さーて、年に一度の夏休みも終わったので活動を再開しよう。
次のテーマは、IPという形にはならないかも知れないがAtlysボードに載っているAC97 Codec (LM4550)の制御をやってみようと思う。


2012年7月31日火曜日

cross gcc for zumi32 9

画面に胡麻塩のようなノイズが描画されたり時間が経過するとハングアップしてしまうのは、zumi32のバグだった。
構造上、割込みによる分岐でも遅延スロットが発生してしまうがこの場合の遅延スロットは無効にしているつもりだったのだがその処理が不完全だった。いやーややこしい。
zumi32_exec.vの該当個所を以下のような感じに修正した。


修正の結果正常動作するようになった。
以下はAtlysとDE0で同じFreeRTOSプログラムを動作させている様子だ。OSのTickTimerの時定数はAtlys用(100MHzクロックで1msec)になっていて、まったく同じバイナリをDE0でも動作させている(DE0側は80MHzクロック)ため、DE0側のLEDの動きが遅くなっているが、どちらも正常に動作している。(ディスプレイのアナログ側で表示されているのがDE0のVGA出力、デジタル側がAtlysのDVI出力) また、DE0のLCDに表示されている文字列はEPCSに入っているプログラムによるものだ。 DE0起動後、fpgaデータのsofを直接Cyclon IIIにダウンロードし、プログラムでもLCDは触っていないため、起動時に表示された文字列がそのまま残ってしまっている。

今回のバグはホントにややこしくて、何故か条件分岐命令のbnzを使った場合ハングアップし、それ以外の分岐命令、例えばbzとbrの組み合わせで代用したりした場合はハングアップし無かったりという現象の見せ方をしたりしていて手間取ってしまった。でも、何とか修正できたのでよかった。

先日公開したsnapshot版は修正版に更新した。
今回はFreeRTOS部も含めたのでファイルサイズが18MBになってしまった。

FreeRTOSも動くようになったので今後の展開としては、あんなことやこんなことそんなことまで色々考えられるがソフトばかりだとつまらないので、ここらでgccの移植は一休みにして今度は別のテーマをやろうかなと考えている。一晩寝たらまた気が変わるかも知れないが・・・


2012年7月23日月曜日

cross gcc for zumi32 8

割込みも問題なく動いたのに気をよくして、リアルタイムモニタの移植に挑戦してみている。
移植するリアルタイムモニタはFreeRTOSというものだ。
FreeRTOSはWikipediaによれば組み込みシステム用のリアルタイムオペレーティングシステムだそうで、多数のマイクロコントローラに移植されている。
ライセンスはGPLで、ソースはhttp://www.freertos.org/から入手できる。
ただし、ドキュメントは購入しなければならないようだ。上記freertos.orgかまたはアメリカのamazonで購入可能のようだが、私のカードは非対応のため購入できなかった。日本のamazonでも買えるようにしてくれたらいいのに。。
しかたがないので、ソースツリーの各種マイクロコントローラ用の実装例を参考にして移植を進めることにした。また、FreeRTOSの使い方(PIC32MX版)というページが見つかったので、そちらのページを参考にさせていただいた。
で、何とか動き出すところまできた。
現状、マンデルブロー描画タスクとナイトライダータスク(LEDをナイトライダー風に点灯させるタスク)の2タスクを作って動かしてみている。tickタイマーの周期は10msecとしている。

以下はマンデルブロー描画タスク部、時間待等はせずにひたすら描画処理を行う。

以下はナイトライダータスク部、vTaskDelayを利用して100msec周期に起床して動作する。

以下はmain関数
ハードウェア初期化後上記2タスクの生成後、スケジューリングを開始している。
2タスクとも同じ優先度にしている。


このプログラムをビルドしたところ、コードサイズが命令メモリの容量を越えてしまったため、メモリサイズを倍の16KBに拡張した。

以下は動作の様子
LEDの点滅と平行して描画処理も動作している。

一見うまく動いているように見えるのだが、描画の方をよく見ると胡麻塩ノイズのような点々があり何か変だ。また、この状態でしばらく放置しておくと停止(ハングアップ?)してしまった。
時間経過でハングすることからスタックまわりの移植がバグっているのかも知れない???
さーて、あたしゃどうやってこれをデバッグすればいいんでしょう。。(-_-);
でも、、、、楽しい。ムフフフフ・・・


2012年7月17日火曜日

cross gcc for zumi32 7

DE0にも実装してみた。

システムアーキテクチャは以下のようにした。


プログラムは以下のとおり


プログラムはAtlysで動かした物と基本的には同じだが、DE0はLCDがあるのでそこへの文字列出力もするようにした。また、DE0ではコアクロックが80MHzになるため、タイマーへの設定値も変えている。(pwm_init内部で換算している。)

以下動作している様子

コンパイラの方はまだ改善の余地があると思っているが、この辺でスナップショット版を公開することにした。
例によって以下に置いた。(表の最上段)

http://www.hi-ho.ne.jp/bravo-fpga/

コンパイラはパッチのみで、GCC自体のソースは含んでいない。
ビルド手順はREADMEに書いてある。

詳細ドキュメントは・・・そのうち書きたい。


2012年7月15日日曜日

cross gcc for zumi32 6

zumi32には4種の例外がある。reset例外、address error例外、interrupt例外、syscall例外だ。
reset例外はzumi32が動作を開始するときに発生する例外で0x0番地から命令を実行する。address error例外はワード境界以外で命令フェッチが発生したときに発生する例外で0x40番地から命令を実行する。interrupt例外は割込み例外で0x20番地から命令を実行する。syscall例外はsyscall命令により発生する例外で0x80番地から命令を実行する。reset例外以外の例外発生時は戻り番地がEPCレジスタに退避される。EPCレジスタの値はld_epc命令で汎用レジスタにロードすることが出来る。また、除算命令を実装していないので、0除算例外は組み込んでいない。今回はハードウェア割込みを使ったプログラムがちゃんと動くかを見てみた。割込み機能はCAN IPの実機検証時にも使ったので動作するだろうと思っていたのだが、zumi32のw_interrupt信号の生成論理にバグが見つかり、条件によってはEPCに正しい戻り番地が退避されない場合があることがわかった。いやーハマったハマった。
以下は修正後の論理。


上記修正後、正常動作するようになった。
Cのプログラムは以下のようにした。


フォアグランドではマンデルブロートの描画を行わせる。バックグランドは10msec毎にタイマー割込みが発生し、その割込みルーチンで計時しsprintfで時計表示形式の文字列に変換しdraw_strで画面表示する。 sprintfはコードサイズを小さくしたかったので自作版を使った。これは浮動小数関係をサポートしていないが、その代わりコンパクトだ。 また、interrupt例外からhw_interruptへ至る部分はアセンブラで書いている。例外時のアドレス間隔をもっと広くすればinterrupt_entry部のコードをそこに置けるようになるのだが、それだと例外を使わない簡単なプログラムの場合もその領域を空ける必要がある。アクセス速度の関係で命令用メモリはFPGAの内蔵RAMを使いたいので、なるべく無駄な領域は取りたくない。ということでこの様な実装になっている。


以下は動いている様子




割込みが動くようになったので、簡単なリアルタイムモニタなら動かせるかも知れないな。


2012年7月10日火曜日

cross gcc for zumi32 5

ASCII文字のFONT ROMを追加して、文字列の描画をやってみた。

以下はプログラム

以下はその結果

Cでの開発環境ができればプログラムの作成効率が格段に上がると予想してはいたのだが想定以上だ。 普通にコードを書いてコンパイルしてFPGA側にダウンロードすれば普通に動く。この過程で躓く箇所は全くない。PC上でプログラムを作って動かす感覚と何ら変わらない。
なんか不思議な気分だ。


2012年7月7日土曜日

cross gcc for zumi32 4

幾つかプログラムを作成して実機で走らせてみた。
実機はSpartan6用DDR2 SDRAMコントローラの時に作成したDigilent Atlys用RTLを使用した。


まずは簡単な物からということで、LEDをナイトライダーのように点滅させるプログラムを試してみた。


コンパイルされたtest.elfから .text セクションと .rodata セクションをobjcopyで抽出し、これを、
odコマンドで32bit hex形式のテキストデータ列に変換している。


命令用メモリとデータ用メモリは上記のシステム図からも判るとおりバックドアからも読み書きできるようになっており、ローダプログラムでこのデータ列をダウンロードしzumi32を起動する。
で、無事動作した。


次に、LEDの動きに合わせてDVIの画面に垂直線を描画するようにしてみた。




これだけだと、何だか物足りない (^^);

そこで、マンデルブロー集合を描画させてみることにした。
プログラムは「C言語によるアルゴリズム事典」という本を参考にした。
演算は固定小数方式にした。


ここで、bootstrapルーチンでbss領域のゼロクリアを忘れていたり、gccの__mulsi3という整数乗算用関数をバグっていたりという初歩的なミスが発覚したりして手間取ったが最終的に以下のように描画させることが出来た。



表示画像(4:3)とディスプレイ(16:9)のアスペクト比が合っていないため横方向に膨らんで見えているが、アスペクト比が合って入れば以下のように見えるはずだ。
 → ディスプレイの設定を変更してアスペクト比を自動で変えるようにした。色味が上(撮影画像)と下(期待値・・・プログラムでppm形式のファイルを生成し、それをjpegに変換した)とで違うのは撮影に使用したデジカメの設定の問題だ。目視では下の期待値と同じ色味で見えている。



このプログラムでは乗算があるが、zumi32は乗算器を持っておらずソフトウェアでエミュレートしている。そのせいもあると思うが一画面描画するのに結構時間がかかる。画素数 1024 x 768 で演算のmax iteration数は64で1分30秒位だ。 gccのmachine descriptorもまだ全然洗練されてなくて、-O2オプションでコンパイルして生成されるコードも今一な出来なのでそのせいもあるのかも知れない。もっと効率の良いコードが出力されるmdファイルを書けるようになりたいもんだ。

でも、ここまで出きるようにはなった。  やったー \(^_^)/


2012年7月3日火曜日

cross gcc for zumi32 3

なんとか、zumi32用gccのビルドが通るようになった。
gccのソースは全部込みの場合、fortranやjavaやobjc, ada等も含まれるが、今回はgcc-coreとgcc-g++のみを対象にしている。また、newlib-1.19.0もビルドした。



試しに以下のプログラムのコンパイルをしてみた。



生成されたa.outを逆アセンブルして確認。



良さげな雰囲気だ。 (^_^)

でも、多分まだ実装漏れや間違いがあると思うが、そこそこのプログラムはコンパイル出来そうな気がする。後は使いながらバグ出し&修正するしかないかな?

ERROR: Failed to spawn fakeroot worker to run ...

なにかと忙しくてなかなか趣味の時間を確保できない。 ...orz  家の開発機のOSはLinux Mintなのだが、最近バージョンを22に更新したところ、myCNC用のpetalinuxをビルドできなくなってしまった。ビルドの途中で ERROR: Failed to spawn ...