IOの設定
まず、Arduinoに接続されたピンに対して便宜上名前を付けます。
const byte IC_PIN = A0;
const byte CS_PIN = A1;
const byte WE_PIN = A2;
const byte A0_PIN = A3;
const int DATA_PIN[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
setup()内ですべて出力に設定します。
for (int i = 0; i < 8; i++) {
pinMode(DATA_PIN[i], OUTPUT);
}
pinMode(CS_PIN, OUTPUT);
pinMode(A0_PIN, OUTPUT);
pinMode(IC_PIN, OUTPUT);
pinMode(WE_PIN, OUTPUT);
レジスタ書き込みファンクション
音源ICの機能は全てレジスタにアクセスすることで制御できます。
これは同じYAMAHA製のFM音源ICも含めて基本的なことなので、この概念を理解すると他の音源ICもレジスタの仕様をチェックするだけで使えるようになります。
CS_PINがLOWの状態でDATA_PINにバイトデータをセットし、CS_PINをHIGHにするとバイトデータがYM2413に送られます。このときA0_PINがLOWの場合はレジスタのアドレス、A0_PINがHIGHの場合はレジスタに入れる値となります。
すぐにCS_PINピンの状態を変えても反応しないことがあるため、アドレス書き込み時には12us程度、データ書き込み時には84us程度ウェイトを入れます。
この方法でレジスタに値をセットするファンクションを定義します。
void set_register(byte addr, byte value)
{
// addr
digitalWrite(A0_PIN, LOW);
digitalWrite(CS_PIN, LOW);
for (int i = 0; i < 8; i++) {
digitalWrite(DATA_PIN[i], bitRead(addr, i));
}
delayMicroseconds(12);
digitalWrite(CS_PIN, HIGH);
// value
digitalWrite(A0_PIN, HIGH);
digitalWrite(CS_PIN, LOW);
for (int i = 0; i < 8; i++) {
digitalWrite(DATA_PIN[i], bitRead(value, i));
}
delayMicroseconds(84);
digitalWrite(CS_PIN, LOW);
}
F-Numberを指定して出力
音の出力はF-Numberという値を使用します。
音程とF-Numberの対応表はアプリケーションマニュアルに書いてあります。
レジスタ0x10(+チャンネル番号)にF-Numberの下位8ビットを指定します。
レジスタ0x20(+チャンネル番号)に音階(オクターブ)とF-Numberの上位1ビットを指定します。
チャンネルとF-Numberを設定するファンクションを定義
レジスタ0x20(+チャンネル番号)に音のオン/オフ(key)も指定するするのですが、今回はkey=1(オン)を固定で設定します
void SetFNumber(int ch, int oct, int f_number) {
// F-Numberの下位8ビット
set_register(0x10 + ch, f_number & 0xff);
// key=1, oct, F-Numberの上位1ビット
set_register(0x20 + ch, (1 << 4) | (oct << 1) | (f_number >> 8));
}
演奏
チャンネル0の音色を3(ピアノ)、音量を15にします。
チャンネル0に440HzのA(ラ)の音程のF-Number(288)とオクターブ4をセットします。
1秒後にチャンネル0の演奏を止めます。
この時0x20(+チャンネル番号)に0を入れます。こうすることによりkeyのビットも0になるので、演奏も止まります。
この処理は1回だけ実行するつもりだったので、setup()内の最後に追加しました。
SetInstVol(0, 3, 16);
SetFNumber(0, 4, 288);
delay(1000);
set_register(0x20, 0);
これで起動後、1秒間だけ音が出力されるはずです。
今回はおまけでloop()無いでドレミファソラシドを演奏するサンプルも書きました。
void loop() {
delay(1000);
SetFNumber(0, 4, 172);
delay(500);
SetFNumber(0, 4, 192);
delay(500);
SetFNumber(0, 4, 216);
delay(500);
SetFNumber(0, 4, 229);
delay(500);
SetFNumber(0, 4, 257);
delay(500);
SetFNumber(0, 4, 288);
delay(500);
SetFNumber(0, 4, 323);
delay(500);
SetFNumber(0, 4, 343);
delay(1000);
set_register(0x20, 0);
}
最後にソース全文を掲載するので、参考にどうぞ。
// Output Pins
const byte IC_PIN = A0;
const byte CS_PIN = A1;
const byte WE_PIN = A2;
const byte A0_PIN = A3;
const int DATA_PIN[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
void setup() {
for (int i = 0; i < 8; i++) {
pinMode(DATA_PIN[i], OUTPUT);
}
pinMode(CS_PIN, OUTPUT);
pinMode(A0_PIN, OUTPUT);
pinMode(IC_PIN, OUTPUT);
pinMode(WE_PIN, OUTPUT);
reset();
SetInstVol(0, 3, 16);
SetFNumber(0, 4, 288);
delay(1000);
set_register(0x20, 0);
}
void loop() {
delay(1000);
SetFNumber(0, 4, 172);
delay(500);
SetFNumber(0, 4, 192);
delay(500);
SetFNumber(0, 4, 216);
delay(500);
SetFNumber(0, 4, 229);
delay(500);
SetFNumber(0, 4, 257);
delay(500);
SetFNumber(0, 4, 288);
delay(500);
SetFNumber(0, 4, 323);
delay(500);
SetFNumber(0, 4, 343);
delay(1000);
set_register(0x20, 0);
}
// 初期化
void reset() {
digitalWrite(WE_PIN, LOW);
digitalWrite(IC_PIN, LOW);
delayMicroseconds(100);
digitalWrite(IC_PIN, HIGH);
delay(1000);
}
// F-Number指定
void SetFNumber(int ch, int oct, int f_number) {
set_register(0x10 + ch, f_number & 0xff);
set_register(0x20 + ch, 16 | (oct << 1) | (f_number >> 8));
}
// 音色と音量指定
void SetInstVol(int ch, int inst, int vol) {
set_register(0x30 + ch, (inst << 4) | vol);
}
// レジスタセット
void set_register(byte addr, byte value)
{
// addr
digitalWrite(A0_PIN, LOW);
digitalWrite(CS_PIN, LOW);
for (int i = 0; i < 8; i++) {
digitalWrite(DATA_PIN[i], bitRead(addr, i));
}
delayMicroseconds(12);
digitalWrite(CS_PIN, HIGH);
// value
digitalWrite(A0_PIN, HIGH);
digitalWrite(CS_PIN, LOW);
for (int i = 0; i < 8; i++) {
digitalWrite(DATA_PIN[i], bitRead(value, i));
}
delayMicroseconds(84);
digitalWrite(CS_PIN, LOW);
}
[asin:B0044X2E5S:detail]