ヤマハ音源IC YMZ294
2023.06.16 / 2025.10.25更新
YouTube でも紹介しています。画像をクリックすると再生できます。
ヤマハ音源IC YMZ294は、PSG音源LSIです。3系列の矩形波発生器と1系列のノイズ発生器、エンベロープ発生器を内蔵しており、メロディ音効果音の発音が可能です。
この音源ICは、2002年2月には秋月電子でも取扱いが開始されており、23年6月時点で1個300円で販売されています。
使い方はネット上にすでに多くの情報があり、データシートも2ページで完結しています。
この音源ICは一般的に5V単一電源が使用され、Arduinoから制御することが多いようです。
しかし、Arduinoでは、プログラムサイズの制約が大きいので、今回はESP32S2を使って動かしてみました。
●ヤマハ音源IC (YMZ294)

・YAMAHAのPSG(Programmable Sound Generator, SSG)音源。
・YM2149相当の音源LSI。
・3系列の矩形波発生器と1系列のノイズ発生器、エンベロープ発生器を内臓。
・8オクターブの発音域。
・5V単一電源。
※ピアノの最低音部、ノート番号21,22は発音できません。
| /CS /WR A0 |
8bitデータバスからのアドレスとデータ書込みコントロール
(0,0,0)→SSGLPにアドレス書込み
(0,0,1)→SSGLPにデータ書込み |
| 5V | |
| SO | 音声信号のアナログ出力 |
| GND | |
| CLK | マスタークロック入力 |
| 4/8MHz | 周波数(4MHz:HIGH/8MHz:LOW)選択 |
| /IC | (LOW)システムリセット、レジスタアレーのゼロクリア |
| D0~D7 | 8bitのデータバス |
| /TEST | テスト用端子。無接続 |

YAMAHAの音源IC(YMZ294)の使い方の基礎
●まずは基本のArduinoで動作確認

Arduino Nano Pinout

| Nano | - | YMZ294 | - | Quartz/Speaker |
| D10 | - | /CS | | |
| D10 | - | /WR | | |
| D11 | - | A0 | | |
| +5V | - | 5V | - | Quartz:Vcc |
| | | SO | - | Speaker(+) |
| GND | - | GND | - | Quartz:GND |
| | | CLK | - | Quartz:Output |
| +5V | - | 4/8MHz | | |
| D12 | - | /IC | | |
| D0-D7 | - | D0-D7 | | |
| | | /TEST | | |
AVRでファミコン風音源YMZ294を使う
YMZ294 Arduino Library
●YMZ294制御概要
YMZ294は,レジスタに値を書きこむことで音の周波数や音量,エンベロープなどを設定できるようになっています。
レジスタに値を書き込むには,WR(書き込み許可),CS(チップセレクト),A0(アドレス指定)の3つの設定ピンのHIGH/LOWを切り替え,D0〜7に値をセットします。
void setup() {
DDRD = 0b11111111;
DDRD:ATmega328PのポートD(デジタルピン0から7)の方向レジスタ
(0=IN, 1=OUT)をすべて出力に指定します。
Arduino 日本語リファレンス - ポート操作
ArduinoのUARTピン0(RX)、1(TX)を占有していまうため、
シリアル通信にはソフトウェアシリアルを使用します。
ポートDを使用したくない場合は、独自にデータピンを設定してください。
const int DATA_PIN[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = 0; i < 8; i++) pinMode(DATA_PIN[i], OUTPUT);
pinMode(WRCS_PIN, OUTPUT);
pinMode(A0_PIN, OUTPUT);
pinMode(RESET_PIN, OUTPUT);
WR(書き込み許可),CS(チップセレクト),A0(アドレス指定)の3つの
設定ピンを出力モードにします。
void ymz294_set_register(byte addr, byte value)
{
digitalWrite(WRCS_PIN, LOW);
digitalWrite(A0_PIN, LOW);
PORTD = addr;
digitalWrite(WRCS_PIN, HIGH);
digitalWrite(WRCS_PIN, LOW);
digitalWrite(A0_PIN, HIGH);
PORTD = value;
digitalWrite(WRCS_PIN, HIGH);
}
レジスタ・アドレスを指定する際には、
WR,CS,A0をすべてLOWにし、D0~7にアドレス値をセット。
WRとCSをHIGHにして,アドレスのセットを完了します。
データを送信する際には、
WR,CS,をLOWに、A0をHIGHにして、D0~7にデータをセット。
WR,CS,A0をすべてHIGHにして,データのセットを完了します。
ymz294_SetMixer(0b111, 0b000);
ヤマハ音源IC YMZ294では、1つのチャンネルで1つの音を出力させることが可能です。
ミキサーレジスタの該当するビットを0にすると音を出力します。
上記の設定では、最大3つのトーンを同時出力(0b000)、ノイズは停止(0b111)させています。
■開発環境
ソースコードのビルドには、PlatformIOを使用しています。
Arduino開発環境構築 PlatformIO
ymz294_nano328.ino
#define REG_A_L 0x00 // channel-A 周波数上位4ビットを格納するアドレス
#define REG_A_H 0x01 // channel-A 周波数下位8ビットを格納するアドレス
#define REG_B_L 0x02 // channel-B 周波数上位4ビットを格納するアドレス
#define REG_B_H 0x03 // channel-B 周波数下位8ビットを格納するアドレス
#define REG_C_L 0x04 // channel-C 周波数上位4ビットを格納するアドレス
#define REG_C_H 0x05 // channel-C 周波数下位8ビットを格納するアドレス
#define REG_NOISE 0x06 // ノイズ音の周波数情報(5bit)
#define REG_MIXER 0x07 // ミキサーの設定情報(6bit)
#define REG_VOLUME_A 0x08 // channel-Aの音量コントロール情報(5bit)
#define REG_VOLUME_B 0x09 // channel-Bの音量コントロール情報(5bit)
#define REG_VOLUME_C 0x0A // channel-Cの音量コントロール情報(5bit)
#define REG_ENV_L 0x0B // エンベロープの周波数情報下位8bit
#define REG_ENV_H 0x0C // エンベロープの周波数情報上位8bit
#define REG_ENV_SHAPE 0x0D // エンベロープ形状(4bit)
#define BASE_FREQ 125000
#define CHANNEL_A 0
#define CHANNEL_B 1
#define CHANNEL_C 2
const byte WRCS_PIN = 10;
const byte A0_PIN = 11;
const byte RESET_PIN = 12;
#define VELOCITY_STD 64
static const float NoteFrequency[] = {
8.2, 8.7, 9.2, 9.7, 10.3, 10.9, 11.6, 12.2, 13.0, 13.8,
14.6, 15.4, 16.4, 17.3, 18.4, 19.4, 20.6, 21.8, 23.1, 24.5,
26.0, 27.5, 29.1, 30.9, 32.7, 34.6, 36.7, 38.9, 41.2, 43.7,
46.2, 49.0, 51.9, 55.0, 58.3, 61.7, 65.4, 69.3, 73.4, 77.8,
82.4, 87.3, 92.5, 98.0, 103.8, 110.0, 116.5, 123.5, 130.8, 138.6,
146.8, 155.6, 164.8, 174.6, 185.0, 196.0, 207.7, 220.0, 233.1, 246.9,
261.6, 277.2, 293.7, 311.1, 329.6, 349.2, 370.0, 392.0, 415.3, 440.0,
466.2, 493.9, 523.3, 554.4, 587.3, 622.3, 659.3, 698.5, 740.0, 784.0,
830.6, 880.0, 932.3, 987.8, 1046.5, 1108.7, 1174.7, 1244.5, 1318.5, 1396.9,
1480.0, 1568.0, 1661.2, 1760.0, 1864.7, 1975.5, 2093.0, 2217.5, 2349.3, 2489.0,
2637.0, 2793.8, 2960.0, 3136.0, 3322.4, 3520.0, 3729.3, 3951.1, 4186.0, 4434.9,
4698.6, 4978.0, 5274.0, 5587.7, 5919.9, 6271.9, 6644.9, 7040.0, 7458.6, 7902.1,
8372.0, 8869.8, 9397.3, 9956.1, 10548.1, 11175.3, 11839.8, 12543.9,
};
uint8_t busy[3] = {0,0,0};
// 指定したチャンネルの基本となる音量を指定する
void setChannelVolume(uint8_t channel, uint8_t vol)
{
// Volume:0~127 -> 0~15(4bit)
uint8_t bit4;
if (vol < 10) { bit4 = 0; }
else if (vol < 22) { bit4 = 1; }
else if (vol < 34) { bit4 = 3; }
else if (vol < 46) { bit4 = 5; }
else if (vol < 58) { bit4 = 7; }
else if (vol < 70) { bit4 = 8; }
else if (vol < 82) { bit4 = 9; }
else if (vol < 94) { bit4 = 11; }
else if (vol < 106) { bit4 = 13; }
else { bit4 = 15; };
ymz294_set_register(REG_VOLUME_A + channel, bit4);
}
// 音を鳴らす
void noteOn(uint8_t channel, uint8_t note, uint8_t velocity)
{
int8_t chno = -1;
for(uint8_t i=0; i<3; i++) {
if (busy[i] == note) {
chno = i;
break;
}
}
if (chno == -1) {
for(uint8_t i=0; i<3; i++) {
if (busy[i] == 0) {
chno = i;
busy[i] = note;
break;
}
}
}
if (chno == -1) return;
uint16_t freqbit = 0;
// 125000/周波数(HZ)の整数値を12ビットで各チャンネルのレジスタにセットする。
// レジスタは8ビット構成なので、上位4ビットと下位8ビットに分けて格納する。
// 12ビットなので周波数はB0(No.23/30.9Hz)以上を指定する。
float freq = NoteFrequency[note];
if (freq > 0) freqbit = BASE_FREQ / freq;
freqbit &= 0b0000111111111111; // 12bit
ymz294_set_register(REG_A_L + (chno * 2), freqbit & 0xff);
ymz294_set_register(REG_A_H + (chno * 2), (freqbit >> 8) & 0xff);
setChannelVolume(chno, velocity);
}
// 音を止める
void noteOff(uint8_t channel, uint8_t note, uint8_t velocity)
{
int8_t chno = -1;
for(uint8_t i=0; i<3; i++) {
if (busy[i] == note) {
chno = i;
busy[i] = 0;
break;
}
}
if (chno == -1) return;
setChannelVolume(chno, 0);
}
void ymz294_reset(void)
{
// 全てのレジスタに0をセットし、ハードウエアをリセットする
ymz294_reset_param();
ymz294_reset_hardware();
}
void ymz294_SetMixer(byte noise, byte square)
{
uint8_t mixer; // Mixer Status (6bit)
mixer = ((noise & 0b111) << 3) | (square & 0b111);
ymz294_set_register(REG_MIXER, mixer);
}
void ymz294_reset_param(void)
{
ymz294_set_register(REG_A_L, 0);
ymz294_set_register(REG_A_H, 0);
ymz294_set_register(REG_B_L, 0);
ymz294_set_register(REG_B_H, 0);
ymz294_set_register(REG_C_L, 0);
ymz294_set_register(REG_C_H, 0);
ymz294_set_register(REG_NOISE, 0);
ymz294_set_register(REG_MIXER, 0);
ymz294_set_register(REG_VOLUME_A, 0);
ymz294_set_register(REG_VOLUME_B, 0);
ymz294_set_register(REG_VOLUME_C, 0);
ymz294_set_register(REG_ENV_L, 0);
ymz294_set_register(REG_ENV_H, 0);
ymz294_set_register(REG_ENV_SHAPE, 0);
}
void ymz294_reset_hardware(void)
{
// ハードウエアリセットはWRCS_PINがHIGH、A0_PINがLOWの状態でRESET_PINをLOWにし、
// 少し間をおいてからRESET_PINをHIGHにする。
digitalWrite(WRCS_PIN, HIGH);
digitalWrite(A0_PIN, LOW);
digitalWrite(RESET_PIN, LOW);
delay(10);
digitalWrite(RESET_PIN, HIGH);
}
void ymz294_set_register(byte addr, byte value)
{
// addr
digitalWrite(WRCS_PIN, LOW);
digitalWrite(A0_PIN, LOW);
PORTD = addr; // PORTD:出力状態設定レジスタ
// for (int i = 0; i < 8; i++) digitalWrite(DATA_PIN[i], bitRead(addr, i));
digitalWrite(WRCS_PIN, HIGH); // データ送信
// value
digitalWrite(WRCS_PIN, LOW);
digitalWrite(A0_PIN, HIGH);
PORTD = value; // PORTD:出力状態設定レジスタ
// for (int i = 0; i < 8; i++) digitalWrite(DATA_PIN[i], bitRead(value, i));
digitalWrite(WRCS_PIN, HIGH); // データ送信
}
void setup()
{
DDRD = 0b11111111; // DDRD:ポートDの方向レジスタ 0=IN, 1=OUT
// for (int i = 0; i < 8; i++) pinMode(DATA_PIN[i], OUTPUT);
pinMode(WRCS_PIN, OUTPUT);
pinMode(A0_PIN, OUTPUT);
pinMode(RESET_PIN, OUTPUT);
ymz294_reset();
ymz294_SetMixer(0b111, 0b000);
for (int note = 23; note <= 108; note++) {
noteOn(CHANNEL_A, note, VELOCITY_STD);
delay(200);
noteOff(CHANNEL_A, note, 0);
}
noteOn(CHANNEL_A, 60, VELOCITY_STD);
delay(200);
noteOff(CHANNEL_A, 60, 0);
noteOn(CHANNEL_B, 64, VELOCITY_STD);
delay(200);
noteOff(CHANNEL_B, 64, 0);
noteOn(CHANNEL_C, 67, VELOCITY_STD);
delay(200);
noteOff(CHANNEL_C, 67, 0);
noteOn(CHANNEL_A, 60, VELOCITY_STD);
noteOn(CHANNEL_B, 64, VELOCITY_STD);
noteOn(CHANNEL_C, 67, VELOCITY_STD);
delay(1000);
noteOff(CHANNEL_A, 60, 0);
noteOff(CHANNEL_B, 64, 0);
noteOff(CHANNEL_C, 67, 0);
}
void loop() {}
●Arduino Nano → QT Py ESP32S2 への移植
Adafriot QT Py ESP32S2 は独立した2つのI2Cポートを持っています。
1つをI2Cパラレル変換(PCF8574)に使い、もう1方をMIDIデータ受信に使用します。
●Adafruit QT Py ESP32-S2 WiFi Dev Board with STEMMA QT
・ESP32-S2 240MHz
・4 MB Flash & 2 MB PSRAM
・2.4 GHz Wi-Fi (SoC)
・Two I2C ports
・Hardware UART
・Hardware SPI
・Hardware I2S on any pins
・3.3V regulator with 600mA peak output
Adafruit QT Py ESP32-S2
YMZ294を制御するには、8本のデータピンと3本の制御ピンが必要です。
QT Py ESP32-S2 はピン数が少ないので、I2C→パラレル8ビット変換モジュールを使うことで、2本のI2Cピンでデータ送信を行います。
●Adafruit PCF8574 I2C GPIO Expander
I2Cバスと8ビットパラレルを変換するモジュールです。Adafruit のモジュールは、SCL、SDAがプルアップされていて便利です。

SCL - I2C clock pin, This pin is level shifted so you can use 3-5V logic, and there's a 10K pullup on this pin.
SDA - I2C data pin, This pin is level shifted so you can use 3-5V logic, and there's a 10K pullup on this pin.
P7-P0 - I/O pins, left-to-right as P7 through P0.
A0 - address pin. The default I2C address is 0x20.
INT - The INT pin is the IRQ output, which will automatically alert you when input pins change value.

Adafruit PCF8574 I2C GPIO Expander > Pinouts
I/Oエキスパンダー PCF8574N でも構いません。


IC単体で使用する場合には,SDA,SCLのところに10KΩ抵抗を挟んでpull-upします。
QT Py ESP32S2 | | YMZ294 | | |
| A1(TX) | ──── | /CS | | |
| A1(TX) | ──── | /WR | | |
| A2(A0) | ──── | A0 | | |
| 3V3 | ──── | 5V | ──── | Quartz:Vcc |
| | | SO | ──── | Speaker(+) |
| GND | ──── | GND | ──── | Quartz:GND |
| | | CLK | ──── | Quartz:Output |
| 3V3 | ─10KΩ─ | 4/8MHz | | |
| A3(RX) | ──── | /IC | | |
| | | /TEST | | |
| | | | |
SCL SDA GND 3V | PCF8574 ──── | D7~D0 | | |
QWIIC-I2C ↑ MIDI入力 | | | | |

組み立てるとこんな感じになります

左側のモジュールでは、microSDカードからMIDIファイルを読み込んで、I2C接続により、YMZ294側モジュールに送信しています
●AGPTEK R08 ポータブル FMラジオ MP3プレーヤー

外部入力端子付きラジオをスピーカーとして使いました。
YMZ294とスピーカーの外部入力端子の間にローパスフィルタとハイパスフィルタを組み合わせてバンドパスフィルタ回路を挟んでいます。

8086ベースのPC エミュレータ(FabGL)用モジュールとして公開されている回路の一部です。
ESP32 Display Controller and Graphics Library
秋月電子で販売している両面TH丸型ユニバーサル基板(ペットボトル基板)27mm に配線しました。
これを1つ作っておくとなにかと便利です。
これらを繋ぎ合わせると下記のようになります。

●3.3Vロジック
・4/8MHz, /IC, /TEST以外は最小2.2Vでラッチ
・4/8MHz, /IC, /TESTは最小3.5Vでラッチ
/TESTは無接続、4/6はロジックで弄らないので、/IC(リセット)が使えない程度です。
Raspberry piでYMZ294を鳴らす
●コードの要点
ポート・レジスタ経由から、I2Cパラレル変換への変更です。
void pcf8574_write(uint16_t register_value)
{
Wire.beginTransmission(PCF8574_I2C);
Wire.write(register_value & 0x00FF);
Wire.endTransmission();
}
void ymz294_set_register(byte addr, byte value)
{
// addr
digitalWrite(WRCS_PIN, LOW);
digitalWrite(A0_PIN, LOW);
pcf8574_write(addr);
digitalWrite(WRCS_PIN, HIGH); // データ送信
// value
digitalWrite(WRCS_PIN, LOW);
digitalWrite(A0_PIN, HIGH);
pcf8574_write(value);
digitalWrite(WRCS_PIN, HIGH); // データ送信
}
YouTube動画では、MIDIファイルを配列にして読み込ませ演奏させています。
MIDIファイルの詳細は下記の過去記事をご覧ください。

MIDIフォーマット解析

MIDIフォーマット解析で使用したAdafruit Music Makerとはさすがに比べ物になりませんが、ゲーム音楽やちょっとしたメロディーラインを考える際には便利かもしれません。
YMZ294では同時に発音できるのは3音までなので、MIDIファイルから音を省いています。
■参考文献
・【音楽×電子工作】YMZ294 ヤマハの音源ICで遊んでみたよ~~~
・解説記事:ヤマハ製の音源 IC YMZ294 を使ってみた
・ノイズを使った効果音
・音楽の素材屋さん
・ピアノMidiファイル集
|
Raspberry Pi(ラズベリー パイ)は、ARMプロセッサを搭載したシングルボードコンピュータ。イギリスのラズベリーパイ財団によって開発されている。
たいていのことは100日あれば、うまくいく。長田英知著
「時間がなくて、なかなか自分のやりたいことができない」
「一念発起して何かを始めても、いつも三日坊主で終わってしまう」
「色んなことを先延ばしにしたまま、時間だけが過ぎていく」
そこで本書では、そんな著者が独自に開発した、
まったく新しい目標達成メソッド「100日デザイン」について、
その知識と技術を、余すところなくご紹介します。
まんがで納得ナポレオン・ヒル 思考は現実化する
OLとして雑務をこなす日々に飽き足らず、科学者だった父が残した薬品を商品化すべく、起業を決意した内山麻由(27)。彼女はセミナーで知り合った謎の女性からサポートを得ながら、彼女と二人三脚でナポレオン・ヒルの成功哲学を実践し、さまざまな問題を乗り越えていく。
ヒル博士の<ゴールデンルール>に従い、仕事に、恋に全力疾走する彼女の、成功への物語。
今日は人生最悪で最高の日 1秒で世界を変えるたったひとつの方法 ひすいこたろう著
偉人の伝記を読むと、最悪な日は、不幸な日ではなく、新しい自分が始まる日であることがわかります。最悪な出来事は、自分の人生が、想像を超えて面白くなる兆しなのです。偉人伝を読むことで、このときの不幸があったおかげで、未来にこういう幸せがくるのかと、人生を俯瞰する視線が立ち上がるのです。
ご飯は私を裏切らない heisoku著
辛い現実から目を背けて食べるご飯は、いつも美味しく幸せを届けてくれる。
29歳、中卒、恋人いない歴イコール年齢。バイト以外の職歴もなく、短期バイトを転々とする日々。ぐるぐると思索に耽るけど、ご飯を食べると幸せになれる。奇才の新鋭・heisokuが贈るリアル労働グルメ物語!
【最新版Gemini 3に対応!】できるGemini (できるシリーズ)
Geminiを「最強の知的生産パートナー」として使いこなすための、実践的なノウハウを凝縮した一冊です。
基本的な操作方法から、具体的なビジネスシーンでの活用、日々の業務を自動化するGoogle Workspaceとの連携、さらには自分だけのオリジナルAIを作成する方法まで余すところなく解説します。
Rustプログラミング完全ガイド 他言語との比較で違いが分かる!
Rustの各手法や考え方を幅広く解説!
500以上のサンプルを掲載。実行結果も確認。
全24章の包括的なチュートリアル。
ポチらせる文章術
販売サイト・ネット広告・メルマガ・ブログ・ホームページ・SNS…
全WEB媒体で効果バツグン!
カリスマコピーライターが教える「見てもらう」「買ってもらう」「共感してもらう」すべてに効くネット文章術
小型で便利な Type-C アダプター USB C オス - USB3.1 オスアダプター
Type-C端子のマイコンボードをこのアダプタを介して直接Raspberry Piに挿すことができます。ケーブルなしで便利なツールです。
Divoom Ditoo Pro ワイヤレススピーカー
15W高音質重低音/青軸キーボード/Bluetooth5.3/ピクセルアート 専用アプリ/USB接続/microSDカード
電源供給USBケーブル スリム 【5本セット】
USB電源ケーブル 5V DC電源供給ケーブル スリム 【5本セット】 電源供給 バッテリー 修理 自作 DIY 電子工作 (100cm)
|