2009/01/16(金)[SOPC][NEEK] WM8731を使う

[NEEK] オーディオ出力(本日のデバッグ)

avalon-I2C module

opencores.comで公開されているI2C moduleを拾ってきて,バスインタフェース部分をAvalon仕様に変更して使おうとしています.


NEEKの場合は,SCKのPAD部に注意が必要です.Pull Upされていないので,FPGAがドライブする必要があります.実装例を以下に記します.

assign HC_I2C_SDAT = (sda_padoen_o==1'b0 ? sda_pad_o : 1'bz) ;

assign scl_pad_i = HC_I2C_SCLK ;
assign HC_I2C_SCLK = scl_padoen_o ;	// if module request SCL=1, then padoen=high.

シミュレーションしてみると挙動が変でした.信号を見ていくと,cr[7:4]のクリア動作が効いていないように見えます.夜を挟んで半日かけて気づくという失態をしてしまいましたが,問題箇所は自分で実装したこのあたり.
コーダーとしては最悪ですなw

	if (avs_s0_write==1'b1 && CmdReg_sel==1'b1 && core_en==1'b1)
		if (avs_s0_byteenable[0]==1'b1)
			cr <= avs_s0_writedata[7:0] ;
	else begin
		if (done | i2c_al)
		  cr[7:4] <= #1 4'h0;			// clear command bits  when done or	 when aribitration lost
		cr[2:1] <= #1 2'b0;				// reserved bits
		cr[0]	<= #1 1'b0;				// clear IRQ_ACK bit
	end

if-elseの対応が,気持ちと実装とで齟齬があったというオチです.普段はif/elseともにブロック化しておくクセをつけていましたが,流用してきたコードは不要なbegin-endを削られており,そこに追加したものだから,こんなミスが生まれたというわけですね.

流用とはいえ,自分で手を入れるのであれば,自分のコーディングルールにあわせて直してしまうほうが安心かもしれません.
直すときにバグを作りこむ危険性も十分にあるので,なんともいえませんが….

	if (avs_s0_write==1'b1 && CmdReg_sel==1'b1 && core_en==1'b1) begin	// ここから
		if (avs_s0_byteenable[0]==1'b1)
			cr <= avs_s0_writedata[7:0] ;
	end															// ここまでのblock化を忘れている
	else begin
		if (done | i2c_al)
		  cr[7:4] <= #1 4'h0;			// clear command bits  when done or	 when aribitration lost
		cr[2:1] <= #1 2'b0;				// reserved bits
		cr[0]	<= #1 1'b0;				// clear IRQ_ACK bit
	end


avalon-I2C module~修正後

I2C slave addressを変更するとACK検出できず.
→E_I2C_NACKでreturnできた.



memo

NEEK - LINEOUT回路図を参照する.(lcd_multimedia_daughtercard.pdf,Rev.1.1)
PhoneOUTがCを通して接続されている.本当のLINEOUT端子はN.C.となっている.



DAI

FIFO readのタイミングがうそくさかった.
Tx startしても,ステータスが変化しなかったので,読み出し側が動いていないと判断.
→ read-reqとstate machineとクロック(分周しているものを流用)の影響が大.
~system clock一本で作ることになったので,見直しすべきと思われる.

外部クロックを使用することを想定すれば,非同期で作っておくべきだが..
2種類用意しておくべきか.最適化で不要レジスタを破棄してくれることを期待して,ちょいと切り替えてしまうか...??



オーディオ周りのアクセス→OK

正弦波テーブルを作成して,入力してみた.
無駄に32bitデータを突っ込んで再生.48個のデータ配列なので,48kHzサンプリングくらい→1kHzの音となる.

ついでに,ノイズキャンセリングイヤフォンの真似ができないかやってみた.
左右位相をひっくり返してみたけれども,キャンセルして聞こえなくなることは無かった.
# 180度ひっくり返すのではなく,スピーカ配置場所と再生周波数からずらしてやる必要があると思われる..?



総合動作確認

動作フロー

  • NEEKのLCD daughter boardに載っている,WM8731をI2C経由で初期化する.
  • FatFsを使って,SDカードをマウント,FATを認識させる.
  • SDのルートにおいたファイルを開く.
  • ファイルはあらかじめ48kspsのリニアPCMデータを格納しておく
  • ファイルからデータを読み出し,DAIに渡す.16bit dataだったので16bit左シフトして渡す.
  • ファイルの終端に着いたら先頭へseekして無限に繰り返す

結果

再生することに成功...(ただし,wavファイルはPCM 48kHz 16bit stereo決めうち)

ヘッダ部解析も行っておらず,ゴミデータ再生あり.

サンプリングレート変換には,ssrc*1を使用させていただいた.再生するデータが手持ちに無かったので,windows標準の起動音で確認した.

NiosII IDEのデバッグビルドでも安定して走っている模様.



ToDo

  • 実装したIPの公開資料作成
  • 同,ここでの公開と配布
  • 割込みハンドラを用いてバックグランドでの再生\ただし,ファイルシステムをマルチタスク環境下で用いるための安全性確認が必要.\また,そろそろRTOSを乗せるべきだと思う.

NiosII環境からの離脱も視野に入れるべきか...なぁ? opencoresのRISC/MIPS/SH互換IPもあることだし,WishBone準拠IPにすれば利用価値が上がると思う.