秋月電商で販売しているヤマハ音源IC(YMZ294)を Arduinoで制御して音出してみます。このLSIの発売日は2002年と10年以上前のモノになります。YMZ294で検索すると、何件かの ホームページを見つけることができます。いくつか参考とさせていただきました。
ArduinoはLeonardoを想定しています。 YMZ294の8ビットのデータバスに、LeonardoのD2,D3,...D9を接続します。 また、制御ピンWrite(/WR)、Chip Select(/CS)、AOにそれぞれ、D10、D13,D1を接続します。 リセット(/IC)にD12を接続します。 なを、Arduino Unoでも同じ接続で良いです。

秋月で購入したYMZ294には、4MHzの水晶発信子が付属していました。いつも接続に戸惑ってしまうので、下に実物の写真と共に掲載しておきます。 上から見て黒丸がNCで、左周りにGround, Output, +VDDです。
ピン番号とGPIOの対応づけをログラムに定義しておきます。
// データバス #define PIN_D0 2 #define PIN_D1 3 #define PIN_D2 4 #define PIN_D3 5 #define PIN_D4 6 #define PIN_D5 7 #define PIN_D6 8 #define PIN_D7 9 // 制御ピン #define PIN_WR 10 #define PIN_A0 11 #define PIN_IC 12 #define PIN_CS 13
各ピンを初期設定します。
void setup() {
pinMode(PIN_WR, OUTPUT);
pinMode(PIN_A0, OUTPUT);
pinMode(PIN_IC, OUTPUT);
pinMode(PIN_CS, OUTPUT);
pinMode(PIN_D0, OUTPUT);
pinMode(PIN_D1, OUTPUT);
pinMode(PIN_D2, OUTPUT);
pinMode(PIN_D3, OUTPUT);
pinMode(PIN_D4, OUTPUT);
pinMode(PIN_D5, OUTPUT);
pinMode(PIN_D6, OUTPUT);
pinMode(PIN_D7, OUTPUT);
8ビットのデータをYMZ294に書き込むには、データを1ビットづつGPIOに設定します。
// Set 8bit data to 8 Pins
void send(uint8_t d)
{
uint8_t c=d&0x01;
digitalWrite(PIN_D0,c);
d>>=1; c=d&0x01;
digitalWrite(PIN_D1,c);
d>>=1; c=d&0x01;
digitalWrite(PIN_D2,c);
d>>=1; c=d&0x01;
digitalWrite(PIN_D3,c);
d>>=1; c=d&0x01;
digitalWrite(PIN_D4,c);
d>>=1; c=d&0x01;
digitalWrite(PIN_D5,c);
d>>=1; c=d&0x01;
digitalWrite(PIN_D6,c);
d>>=1; c=d&0x01;
digitalWrite(PIN_D7,c);
init294(); //YMZ294の初期化(後述)
}
YMZ294のレジスタにデータを書き込むには2つの値(アドレスとデータ)、をそれぞれ書き込みます。書き込みはA0, /CS, /WRの3つのピンを使います。 ちなみに、"/"は通常は正、使いたい時にゼロに設定するピンであることを示しています。A0が0の時レジスタのアドレスを設定、 A0が1の時、レジスタにデータを書き込みます。 書き込みの手順(シーケンス)は次の図を見て下さい。
// Set Address and Data
// a : address
// d : data
void set_address_data(uint8_t cs, uint8_t a, uint8_t d){
digitalWrite(PIN_A0,0);
digitalWrite(PIN_WR,0);
digitalWrite(PIN_CS,0);
send(a); delay(1);
digitalWrite(PIN_CS,1);
digitalWrite(PIN_WR,1);
delay(1);
digitalWrite(PIN_A0,1);
digitalWrite(PIN_WR,0);
digitalWrite(PIN_CS,0);
send(d); delay(1);
digitalWrite(PIN_CS,1);
digitalWrite(PIN_WR,1);
delay(1);
}
YMZ294をリセットし、各レジスタのレジスタに初期値を設定します。
void init294() {
// Reset
digitalWrite(PIN_IC,0);
delay(100);
digitalWrite(PIN_IC,1);
// YMZ294 Register Initialize
// 楽音周波数
send_data(0x00,0x00); //Channel A Low
send_data(0x01,0x00); //Channel A High
send_data(0x02,0x00); //Channel B Low
send_data(0x03,0x00); //Channel B High
send_data(0x04,0x00); //Channel C Low
send_data(0x05,0x00); //Channel C High
delay(10);
send_data(0x06,0x00); //ノイズ周波数の設定
// ミキサーの設定
send_data(0x07,0x38); //楽音ChannelA,B,C ON
delay(10);
// 音量コントロールどDAC
send_data(0x08,0x00); //Channel A
send_data(0x09,0x00); //Channel B
send_data(0x0A,0x00); //Channel C
delay(10);
// エンベロープ周波数
send_data(0x0B,0x00); //Low
send_data(0x0C,0x00); //High
// エンベロープの形状
send_data(0x0D,0x0D);
}
音を出すには周波数を設定し、音量を上げます。ここでは、MIDIのキーコードを与えると音が出る void NoteOn(uint8_t keycode)関数を示します。Channel Aの周波数を設定し、音量を上げています。
// Convert MIDI Note Number to Frequency Register Value
uint16_t mCoef[128]= {
4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095,
4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095,
4095, 4095, 4095, 4095, 4095, 4095, 4095, 4050,
3822, 3608, 3405, 3214, 3034, 2863, 2703, 2551,
2408, 2273, 2145, 2025, 1911, 1804, 1703, 1607,
1517, 1432, 1351, 1276, 1204, 1136, 1073, 1012,
956, 902, 851, 804, 758, 716, 676, 638,
602, 568, 536, 506, 478, 451, 426, 402,
379, 358, 338, 319, 301, 284, 268, 253,
239, 225, 213, 201, 190, 179, 169, 159,
150, 142, 134, 127, 119, 113, 106, 100,
95, 89, 84, 80, 75, 71, 67, 63,
60, 56, 53, 50, 47, 45, 42, 40,
38, 36, 34, 32, 30, 28, 27, 25,
24, 22, 21, 20, 19, 18, 17, 16,
15, 14, 13, 13, 12, 11, 11, 10 };
void NoteOn(uint8_t keycode)
{
uint16_t x = mCoef[keycode];
uint8_t hb=(x>>8)&0x0F;
uint8_t lb=(x&0xFF);
send_data(0x00,lb);
send_data(0x01,hb);
send_data(0x08,0x08); //音量を上げる
}
音を止める時は、音量をゼロにします。
void NoteOn()
{
send_data(0x08,0x00); //音量を下げる
}