Raspberry PI でYMF825を鳴らす（Node編）

一つ前の記事「[Raspberry PI でYMF825を鳴らす](https://qiita.com/YumeYakata/items/b709c304313f65888f10)」はサンプルプログラムを使ったトライでした。こちらはNodeに置き換えて鳴らしてみます。物理的な接続は前の記事を参照してください。

## SPI送信
SPIの通信モジュールとして、[pi-spi](https://github.com/natevw/pi-spi) を使いました。
> npm install pi-spi

でインストールします。データの転送用として、以下のサブルーチンを作っておきます。

```spisub.js
var SPI = require('pi-spi');
var spi = SPI.initialize("/dev/spidev0.0");
const HIGH=1;
const LOW=0;

function writeSingle( adrs, data )
{
	buf = Buffer([adrs, data]);
	ss(LOW);	//信号ssをLOWにする

	spi.transfer(buf,buf.length,function(e,d){
		if (e) {	//エラー処理
			console.error(e);
			process.exit(-1);
		}
	});

	delayMs(1);	//1msec waitします
	ss(HIGH);	//信号ssをHIGHにする
}
```

## GPIO制御

GPIO の制御（SSをLOW/HIGHに設定）します。[File System](https://nodejs.org/api/fs.html) をダイレクトに使いました。

> npm install fs

```
fsgpio = require('fs');
fsgpio.writeFileSync('/sys/class/gpio/export', 25);					//SS
fsgpio.writeFileSync('/sys/class/gpio/gpio25/direction', 'out'); 	//SS
function ss(en)
{
	fsgpio.writeFileSync('/sys/class/gpio/gpio25/value', en);
}

fsgpio.writeFileSync('/sys/class/gpio/export', 16);					//RESET
fsgpio.writeFileSync('/sys/class/gpio/gpio16/direction', 'out'); 	//RESET
function reset(en)
{
	fsgpio.writeFileSync('/sys/class/gpio/gpio16/value', en);
}
```

## レジスタ・イニシャライズ

[レジスター仕様書](https://github.com/yamaha-webmusic/ymf825board/blob/master/manual/fbd_spec2.md)を参照しました。

```initialize.js

function initialize()
{
	ss(HIGH);

	//	1.	powerOnReset( void );
	reset(LOW);              //Reset を一旦Lowに設定
	delayMs(1000);           //wait 1sec

	//	2.	RST_N : high
	reset(HIGH);             //Reset をHighに戻す

	//	3.	DRV_SEL	: low
	// ←仕様書に説明がありません。多分LSB=0 が5.0V ではないかと**想像**されます。
	writeSingle(29, 1);	 //  3.3v　
        
	//	4.	AP0 : 0
	// Analog Block Power-down control
	writeSingle(2, 0x0e);    //  AP0 だけパワーダウンしない？

	//	5.	CLKE : "1"
	// ←クロックをアクティブ
	// ←この状態ではALRST=High になっているはず。
	writeSingle(0, 0x01);

	//	6.	ALRST : low
	// ←リセット状態を解除
	writeSingle(1, 0x00);

	//	7.	SFTRST	:	0xa3
	// ←仕様書に説明がありません。SFTRST=0xa3 以外、たとえば0xff とか設定してみましたが、動作しませんでした。（意味わかりません。）
	writeSingle(26, 0xa3);
	delayMs(100);           //待った方がよさそうなので

	//	8.	SFTRST	:	0x00
	// ←仕様書に説明がありません。おまじない。
	writeSingle(26, 0x00);
	delayMs(100);           //待った方がよさそうなので

	//	9.	AP1 AP3: "0"
	writeSingle(2, 0x04);          //なぜ分けてパワーダウンするのだろう？

	//	10.	AP2: "0"
	writeSingle(2, 0x00);           //なぜ分けてパワーダウンするのだろう？

	//	11.
	writeSingle(25, 0x81);	//	-18[dB]
	writeSingle(27, 0x3f);	//	set itp max
	writeSingle(20, 0x00);	//	set itp on
	writeSingle(3, 0x01);	//	amp gain(6.5[dB])
	writeSingle(9, 0xcc);	//	0[dB] Sequencer Volume

	//	12.	シーケンサー設定
	// ←上位3bitは説明あり。AllKeyOff/AllMute/AllEGRstをリセット
	// ←残りのビットは説明がありません。おまじない
	writeSingle(8, 0xf6);
	writeSingle(8, 0x00);	//	リセットから復帰
}
```

## 音のパラメータの初期化
Tone Parameterを以下のようにまとめて設定します。

```
function Tone_init()
{
	mTone=Buffer([
		0x07,0x90,0x00,0x43,0x00,0x67,0xff,0x9d,0x00,0x10,0x40,0x20,0x33,0xe2,0xa3,0x00,
		0x50,0x00,0x10,0x41,0xd3,0x88,0x01,0x10,0x00,0x20,0x62,0xd4,0x02,0x01,0x10,0x00,
		0x00,0x45,0x50,0xc4,0xfb,0x8c,0x44,0x70,0x95,0x10,0x82,0xff,0x12,0x45,0x10,0x00,
		0x10,0xb0,0xf1,0x49,0x44,0x10,0x02,0x10,0x72,0xff,0x10,0x41,0x10,0x00,0x00,0x45,
		0x00,0x03,0x70,0x16,0x44,0x10,0x0b,0x00,0x92,0x70,0x3c,0x43,0x10,0x40,0x00,0x03,
		0x70,0x22,0x44,0x10,0x4b,0x00,0x92,0x70,0x36,0x43,0x10,0x00,0x00,0x43,0x20,0x37,
		0xf1,0x4e,0x44,0x10,0x05,0x40,0x6b,0xc7,0x54,0x44,0x70,0x00,0x20,0x69,0xf2,0x5e,
		0x44,0x20,0x00,0x60,0x82,0xb6,0x00,0x44,0x10,0x00,0x00,0x45,0x30,0x46,0xf5,0x41,
		0x44,0xe0,0x03,0x70,0x66,0xce,0x2e,0x44,0x20,0x00,0x20,0x26,0xc5,0x78,0x44,0x77,
		0x08,0x40,0x55,0xfd,0x04,0x54,0x60,0x00,0x00,0x45,0x30,0x3f,0xf0,0x98,0x44,0x70,
		0x0d,0x40,0x47,0xf0,0x2e,0x44,0x50,0x00,0x00,0x11,0x60,0x62,0x03,0x17,0x0e,0x00,
		0x51,0x81,0x02,0x03,0x10,0x00,0x00,0x45,0x58,0x50,0xf0,0x14,0x44,0xc0,0x17,0x78,
		0x77,0xf7,0x00,0x44,0xb0,0x00,0x68,0x6a,0xf8,0x00,0x44,0xc0,0x00,0x78,0x77,0xf7,
		0x00,0x44,0x70,0x10,0x00,0x45,0x58,0x97,0xff,0x08,0x44,0x70,0x0e,0x58,0xf8,0xaf,
		0x00,0x44,0x50,0x30,0x68,0x55,0xf0,0x9c,0x44,0x20,0x28,0x98,0x9a,0xca,0x50,0x44,
		0x50,0x00,0x00,0x43,0x00,0x67,0xff,0x9d,0x00,0x10,0x40,0x20,0x33,0xe2,0xa3,0x00,
		0x50,0x00,0x10,0x41,0xd3,0x88,0x01,0x10,0x00,0x20,0x62,0xd4,0x02,0x01,0x10,0x00,
		0x00,0x45,0x50,0xc4,0xfb,0x8c,0x44,0x70,0x95,0x10,0x82,0xff,0x12,0x45,0x10,0x00,
		0x10,0xb0,0xf1,0x49,0x44,0x10,0x02,0x10,0x72,0xff,0x10,0x41,0x10,0x00,0x00,0x45,
		0x00,0x03,0x70,0x16,0x44,0x10,0x0b,0x00,0x92,0x70,0x3c,0x43,0x10,0x40,0x00,0x03,
		0x70,0x22,0x44,0x10,0x4b,0x00,0x92,0x70,0x36,0x43,0x10,0x00,0x00,0x43,0x20,0x37,
		0xf1,0x4e,0x44,0x10,0x05,0x40,0x6b,0xc7,0x54,0x44,0x70,0x00,0x20,0x69,0xf2,0x5e,
		0x44,0x20,0x00,0x60,0x82,0xb6,0x00,0x44,0x10,0x00,0x00,0x45,0x30,0x46,0xf5,0x41,
		0x44,0xe0,0x03,0x70,0x66,0xce,0x2e,0x44,0x20,0x00,0x20,0x26,0xc5,0x78,0x44,0x77,
		0x08,0x40,0x55,0xfd,0x04,0x54,0x60,0x00,0x00,0x45,0x30,0x3f,0xf0,0x98,0x44,0x70,
		0x0d,0x40,0x47,0xf0,0x2e,0x44,0x50,0x00,0x00,0x11,0x60,0x62,0x03,0x17,0x0e,0x00,
		0x51,0x81,0x02,0x03,0x10,0x00,0x00,0x45,0x58,0x50,0xf0,0x14,0x44,0xc0,0x17,0x78,
		0x77,0xf7,0x00,0x44,0xb0,0x00,0x68,0x6a,0xf8,0x00,0x44,0xc0,0x00,0x78,0x77,0xf7,
		0x00,0x44,0x70,0x10,0x00,0x45,0x58,0x97,0xff,0x08,0x44,0x70,0x0e,0x58,0xf8,0xaf,
		0x00,0x44,0x50,0x30,0x68,0x55,0xf0,0x9c,0x44,0x20,0x28,0x98,0x9a,0xca,0x50,0x44,
		0x50,0x00,0x80,0x03,0x81,0x80]);

	ss(LOW);
	spi.transfer(mTone,mTone.length,function(e,d){
		if (e) {
			console.error(e);
			process.exit(-1);
    	}
	});
	delayMs(100);
	ss(HIGH);
}
```

## 音を鳴らす
取りあえず、１音鳴らすには以下を実行します。音を鳴らしっぱなし（ずーっと鳴っている）にしたかったので、Tone Number=2 を鳴らしています。

```main.js
	initialize();
	Tone_init();

	writeSingle(11,0);		// channel number
	writeSingle(12,0x7C);	// volume setting registers
	writeSingle(16,0x71);	// each voice volume 
	writeSingle(15,0x30);	// KeyOn & Tone Numbber
	writeSingle(13,0x14);	// frequency information & octave
	writeSingle(14,0x5B);	// frequency information
	writeSingle(15,0x42);	// KeyOn & Tone Numbber
```