Spartan-3A スタータキット

〜サウンド〜


2007/04/25

あなたは 人目のお客様です.

シリアル受信ができるようになった. 実はもう夜12時に近いのだが,あとちょっとした時間でできそうなので, ついでにサウンドを鳴らしてみよう.

で,ユーザーガイドを読んでみたのだが, どうもサウンドの端子はAUD_LとAUD_Rがジャックに直結らしく, D/A変換などは無いようだ. つまりスピーカに対して,0と1のデジタル信号しか出力できない. これってどうやってアナログ出力を実現するんだ!?

いろいろ調べてみたところ,PWMという方法があるらしく, まあ簡単にいうと0と1を交互にパルスとして出力し,パルスの幅を調整することで, 「平均的に」アナログ出力を実現するようだ. たとえば0と1が半々で出力されるなら平均して0.5になり, 1対3の割合で出力されるなら平均して0.75になる,という具合だ. これはモーターの制御などにも利用されるらしい. 実際にはパルスが高速に出力されるため,別の周波数成分が入ってしまうが, きっとそういう周波数成分は人間の可聴範囲やスピーカーの有効周波数範囲よりも ずっと高くなってしまうのでフィルタされてしまい,とくに問題無いのだろう.

※ (2007/05/09追記)Interfaceの2005/05号にPWM変調について書いてある.

人間の可聴範囲はたしか4kHzくらい〜40kHzくらいだったような気がする. まず音を出すためには, このへんの適当な周波数で正弦波を作ってやらなければならない. で,さらにPWM出力するために,もっと高い周波数でサンプリングし, 正弦波の振幅に合わせてパルス出力してやらなければならない.

で,書いたのがこんな感じ.

sound.v
sound.ucf

音声として正弦波を作成する. これはスライドスイッチの状態を見て周波数が変化する. 一番低い音の場合はスライドスイッチをすべてONにした場合で, sin_period の値は 16'b0000011110000000 == 1920 となり, 50MHz / 1920 / 8 = 約3.3kHz となる. 一番高い音の場合はスライドスイッチの左端のみONにした場合で, sin_period の値は 16'b0000000010000000 == 128 となり, 50MHz / 128 / 8 = 約49kHz となる. 可聴範囲からちょっと外れている感じだろうか. ちなみに正弦波は8箇所でサンプリングしている. サンプリング定理によれば,最低でも2倍の周波数でサンプリング しなければならないが,8倍(8箇所)でサンプリングしているのでこれで十分.

PWM出力のパルスは,そのときの音声の振幅に合わせて5MHzで出力される. これは振幅の値からパルス列のパターンに変換し, 5MHzでシフトしながら出力することで実現している. 実際には下ボタンを押している間だけ,出力される. 出力はステレオ(右も左も同じものを出力するだけ)になっている. ユーザーガイドによると,モノラルの場合にはAUD_Rはハイインピーダンスにすべき らしい(AUD_Lの出力が流れ込んでしまうからだろう)ので注意.


スピーカーのジャックを接続

アンプつきステレオスピーカーを接続する. で,下ボタンを押すことで音が出た.

まず,スライドスイッチを0001の状態で下ボタン押下でサウンド出力. スピーカーからはろくに音が出ない.計算上は49kHzの音声なので,可聴範囲外か?

スライドスイッチを0111の状態で下ボタン押下でサウンド出力. スピーカーからは音が出た.計算上は約7kHzだが,けっこう高い音が出ている.

スライドスイッチを1111の状態で下ボタン押下でサウンド出力. スピーカーからは音が出た.計算上は3.3kHz.けっこう高い音が出ている.

う〜ん,いちおう音は出ているのだけど, なんかやたら高い音が出ている気がする. なんか実装がおかしい?


メールは kozos(アットマーク)kozos.jp まで