スティルハウスの書庫の書庫

はてなダイアリーで書いてた「スティルハウスの書庫」を移転してきました。

DE0で音を出してみた。

前からFPGAでHDLを書いてみたかったので、2か月ほど前にDE0っていう入門用ボードを買って遊んでる。デジタル回路といえば中学のころにフリップフロップでLEDをピカピカさせた程度の経験しかないため、入門書を読みながら勉強し直し。デジタル時計くらいは作れるようになった。

つづいては4bit CPUを作ってみたいのだけど、その前にDE0で音を出してみたいなぁと思ってた。画像処理とか敷居高いけど音声処理ならFPGAでわりと簡単にいじれるかな?と思ったのと、G+でとよしまさんに教えてもらったWeb Music Developers JP Advent Calendar 2012にも何かエントリしてみたかったし。。

標準のDE0にはUSBやボタンやSDスロットは付いてるけど音関連のインターフェースはまったくなくて、FPGAで音を出したいときどうすればいいんだろ。。このあたりの電子工作的発想とか経験がまるでないので、DAコンバーターやアンプが必要?とか考えて、DE0拡張キットってやつにDAコンバーターとスピーカーが付いてるらしいのでポチってみた。なんか俺、ソリトンの思うつぼ。。

今日その拡張キットが届いたので、さっそく音の出し方のところを読んでみた。するとなんと、FPGAの出力端子にそのままスピーカーつなぐだけで、あとは適当な周波数で0と1を出力してやれば音が出るらしい(330Ωの抵抗をかます)。そんなもんなのか。DAコンバーターなくてもよかったなw

というわけで、まずは440Hzで0と1を出力するところからトライ。DE0では50MHzのクロックが供給されてるので、50MHz ÷ 440Hz = 113636回に1回の割合で0と1を繰り返すカウンタを作ればよいはず。適当に32ビットくらいのカウンタを用意すればいいか。こんなVerilog HDLのコードを書いた:

module Osc(
	input CLK,
	input nBTN,
	output SPKR
);

reg [31:0] cnt;
always @(posedge CLK) begin
	if (cnt == 32'd113636)
		cnt <= 32'd0;
	else
		cnt <= cnt + 1;
end
assign SPKR = !nBTN && (cnt < 56818);

endmodule

まずはreg文で32ビットのカウンタcntを用意しとく。CLKの値が50MHzで0と1を繰り返すので、always @(posedge CLK)っていうループ文みたいなやつで、そのクロックごとにcntに1を足すコードを書いておく。そして113636回数えたら0に戻す。あとは、cntの値が0〜56818(113636÷2)までの間なら1、そうでなければ0をSPKR(スピーカーにつながる端子)に出力する。そのとき、nBTN(ボタン)と&&しとくとボタンが押されたときだけ音がなるはず。

このコードをDE0のツール(Quartus II)でコンパイルしてUSB経由でDE0に読み込ませる。HDLってこんなふうにあたかもプログラミング言語みたいにロジックを書けるけど、もちろんCPUが手続き的に処理するんじゃなくて、すべて論理演算とフリップフロップのデジタル回路に変換されて、FPGA上でそれが再現される仕組み。だから俺の書いたコードが光の速さでしかも全演算が超並列に動くわけだ。HDL惚れてまうで。

ロードすると、それっぽい音がでた!やった!

次の野望:正弦波を出してみたい。サインカーブの波形データをHDLでベタに並べてサインテーブルを作って、それをD/Aコンバーターを通せばよいはず。D/Aコンバーター使わずとも、PWMとか、とよしまさんが教えてくれたDelta-Sigma modulationって回路を組んでもよいらしい(シャープの1bitオーディオみたいなやつですな)。まぁ、せっかく買ったのでラクしてD/Aコンバーター使う方向で行こうかな。