それほど手間取らなかったですけれども、忘れないうちにメモ
手間取らなかったのは、Electric Druid の非常に詳しい解説記事のおかげです。感謝
オリジナルのノイズジェネレータは、以下のようなハードウェアによる実装です。LSFR (Linear Feedback Shift Register) と呼ばれているアルゴリズムで、簡単な構成のわりに非常に高品質なノイズが得られます。回路図中の XOR ゲート二つ 31-a と 31-b でクロックを発生し、4006 シフトレジスタ二個で (IC32, 33) LFSR を構成しています。左側のゲート IC31-d が何をしているか最初わからなかったのですが、上記 Electric Druid の記事により、電源投入時にレジスタの値を全部1 にするためだということがわかりました。いやほんと感謝
クローンではファームウェアによる実装なので組まなくてはいけない部分です。ここでもまたクロックが必要、Electric Druid の記事から、クロック周波数は約 300 kHz 、でも部品の構成によって大幅に変わるけど、耳で聴きとれるほどの変化は出ないよ。ということでしたので、れいによって割り込みは使わず、Timer0 のカウンタ値が 8 進んだらノイズジェネレータのシフトレジスタを更新、という方針にしました。 16 MHz CPU クロック / 8 プリスケーラ / 8 カウントで約 250 kHz のクロックが得られます。実際にオシロスコープで確認したところ、おおまかに 250 kHz が出ますが、64 CPU クロックという短い周期で更新ということでポロポロ更新周期を逃すらしく、波形はだいぶん崩れていました。でもノイズだし気にしないことにします。
以下がノイズ部分の実装、もう少し要領よく短く書きたいところですが余力のある時にまた今度。実装の詳しくは github で見られます https://github.com/naokiiwakami/tr909-clone-firmware
/*
* Noise generator
*
* Noise generator is updated every 8 Timer0 increments - about 250 kHz
*/
current_timer_value >>= 3;
if (current_timer_value != noise_clock) {
uint8_t temp = (noise_register >> 12) & 1;
temp ^= (noise_register >> 30) & 1;
if (temp) {
SetBit(PORT_NOISE, BIT_NOISE);
} else {
ClearBit(PORT_NOISE, BIT_NOISE);
}
noise_register <<= 1;
noise_register += temp;
}
noise_clock = current_timer_value;
ノイズ波形は以下のような感じです。あまりノイズには見えませんが、聴いてみると確かにホワイトノイズです