↓JR踏切音の録音波形(16bit48KHz/450mSec)
当初の想いは、
・繰り返し再生だけできればよい
・簡単な回路にしたい
・実際の音に近づけたい
・踏切音以外にも使いたい
・8pinDIPのPICで小型化したい
というコンセプトで始めたその結果のエッセンスは、
・リアル音のサンプリングデータ:6bit8kHz(450mSec)
・データを焼くエリア:ProgramFlashMemory (1792Words)
・再生周波数:15.625KHz(Clock:16MHz)
・スピーカー直結可:10bitPWM出力によるD級ドライブ
という結論を得て、使用するPICは12F1572に落ち着きました。
↓回路図
<クロック>
次に再現できる振幅階調を考えてみます。PWMはパルス幅により振幅階調を表現しますので、クロック周波数とPWM周波数から生じる制約があります。
仮に16bit階調を得ようとしたとき、32MHzクロックにおいては1/32MHzでパルス幅が刻まれるため2^16*(1/32000000)=2.048mSec
のPWM周期つまり488Hzとなってしまい、踏切音の帯域を再生できません。
同様に10bitPWM機能を持つPICの32MHzクロックでは、1/(2^10*(1/32000000))=31.25KHzのPWM周波数で再生することができます。
32MHzクロック時に10bit32KHzですから、16MHzで10bit16KHzとなり、7bit16KHzは逆算して2^7*16000=2MHzのクロックで作れることになります。
しかし実は、PWM周期がクロックを階調bit分のカウントして作られるため、階調bitを減らすとPWM周期中のクロック数が減ることになり、
一周期中のクロック数では振幅値を更新するための処理が終わらないという状況が発生してしまいます。7bit16kHzの場合2^7=128の2周期分256クロックが使えますが、
実験的には最低でも256(8bit)*2のクロック数を確保する必要があることが判りました。従ってこの制約から、8bit16KHzのPWMを用意するために2^8*16000=4MHz以上のクロックが必要となります。
<実装のポイント>
さて実際のプログラミングを考えると、14bit/Word上位6bitと下位8bitには個別にアクセスできるため、7bit/byteで使うよりも下位byteの2bitを使わずに6bit/byteにした方が、
効率的にデータを作れて簡単に扱うことができます。そして(10bitPWMの場合)PWMパルス幅は、上位8bitと下位2bitを個別に設定するアーキテクチャであることから、下位2bitを使わずに6bitデータを上位byteにそのまま
代入できると煩わしさがなくなります(16bitPWMでは上位8bit/下位8bitなので、気にする必要なし)。従って上位6bit+下位2bit(00)=8bit以上の振幅階調でPWMを使えばコードが簡単になり、かつクロック数の条件も満たすことになります。
記憶領域の都合からくる6bit8kHzデータをシンプルに再生するために、4MHzクロックの8bit16KHzPWMを使えば十分なことは判りましたが、Synthesizerへの応用も考慮に入れてPWMは10bitフルに使い
クロック周波数は16MHzを採用しておくことにしました。こうすることで6bitの振幅データは、最大値の1/16(-4bit)となるため16倍の振幅変化を付けることが出来るようになります。
下位2bit(00)を付け加えた8bit振幅としても、4倍(2bit)の振幅変化を与えられます。この余裕はミュート機能の盛り込みに使用しました。
なおPWM周波数の16KHzを15.625KHzとしたのは分周(2進数)の扱い易さによるもので、プログラム中ではPWM3PRL=250とすれば正しい音程(16KHzPWM)での再生となりますが、振幅階調の余裕は1bit減ります。