I2Cで制御できる80円のPSG互換チップで遊ぼう

# 概要
LPC810をPSG互換チップとして動作させるファームウェアを作ってみました。オリジナルのPSGとは異なりI2Cで制御できるようにしたので気軽に電子工作に組み込むことができます。ArduinoやRaspberry Piのお供に、またLチカからのステップアップにぜひご利用ください。


# SoundCortex
## LPC810について
[秋月電子にて80円](http://akizukidenshi.com/catalog/g/gI-07191/)で入手できます。[YMZ294](http://akizukidenshi.com/catalog/g/gI-00181/)はちょっと高くてなー、とか足が多くて制御できないなー、なんて人。[YMZ285](http://akizukidenshi.com/catalog/g/gI-02618/)を買って騙された！って人にお勧め。ぜひこのチップを爆買いしてSoundCortexを焼いてPSGとして使いましょう。

ちなみにファームウェアの書き込みはシリアルで出来ます。電子工作やってたらUSB-USART変換器の1つくらいは持ってると思うので、特に追加設備なしで書き込みできるかと思います。あるいは本棚漁れば古いトラ技と付属のライターが出てくるのではないでしょうか。

## ファームウェア
LPC向けにSoundCortexというファームウェアを作って[GitHub](https://github.com/toyoshim/SoundCortex)にて公開しています。このファームを搭載したチップの事はSoundCortexChip、通称SCCと呼ぶのが良いのではないでしょうか。

回路図はこんな感じになります。簡単ですね。

![schem.png](https://qiita-image-store.s3.amazonaws.com/0/12843/9cc3c701-4fcd-709b-4c49-b99c138bf79f.png)

この図では680Ωの抵抗と0.01uFのコンデンサでLPFを挟んでますが、面倒ならPIO0_4とGNDを直接圧電ブザーなんかに繋いでも大丈夫。出力的には8-bit/46.875kHzのPWMで再生されますので、ノイズの大半はよほど耳が良い人じゃないと聴こえないかと思います。図のLPFは23.4kHzがカットオフ周波数になってます。

（2016/4/14追記：ヘッドフォン出力のインピーダンスは〜100Ω程度に抑えた方が良いようなので、RとCは一桁ずつずらした方が良いかもしれません。2回目の制作では手持ちの部品の関係で75Ωと0.1uFの組み合わせでカットオフ21.2kHzのLPFを構成する方法をとりました。）

I2CバスはSDA/SCLともにpull upが必要ですのでmaster側でやってなければ経路で適宜pull upして下さい。Raspberry Pi Model B+で試したところ、外側でのpull upは不要でした。

## PSG互換モード
SoundCortex自体は色々なチップのエミュレーションを追加しようと思っているのですが、現状ではPSG互換のファームウェアのみ提供しています。

I2Cはslave address 0x50でアクセスできます。書き込みは2 bytes単位で行って下さい。最初の1 byteがPSGの内部レジスタ番号、続く1 byteが書き込む値です。例えば[0x00, 0xFF]を書き込めばPSGレジスタ0に0xFFが書き込まれます。速度はあまり検証していないのですが、一般的な100kHzはもちろん通りますし、運が良ければ3MHzで書けると思います。

拡張機能としてレジスタ0xFFに0を書き込むと3.579545MHz（デフォルト）、0以外を書き込むと4MHzのオシレータを繋げたPSGとして動作します。また0xFFを読みだすとメジャーバージョン1、0xFEを読みだすとマイナーバージョン0が読み出されるはずです。

あと、いつもの事ですがエンベロープはエミュレートしてません。あんまり使われることがないのでモチベーションがわかなかったり、テストする（データ探す）のが面倒だったりとか。

# 使ってみよう
## Raspberry Pi編
![IMG_20160404_234019.jpg](https://qiita-image-store.s3.amazonaws.com/0/12843/e44baed7-39f0-0f44-4334-44ccfd1a5445.jpeg)
Raspberry Piとの接続は電源合わせてもたった4本の線で繋ぐだけ。
オーディオは別途2本配線しつつ、間にお遊びでLED刺してます。

Raspberry Piについては[この辺](http://pinout.xyz/)でピンアウトを調べて下さい。1: 3v3、3: SDA、5: SCL、9: GNDとなっています。

I2Cはraspi-configやGUIから簡単に有効化できます。有効化したらi2c-toolsをインストールしておくと簡単なテストができて便利です。

```shell-session
pi@raspberrypi:~ $ sudo apt-get install i2c-tools
```

```shell-session
pi@raspberrypi:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
pi@raspberrypi:~ $ 
```

こんな感じで0x50の場所に何か繋がっていることが確認できます。

```shell-session
pi@raspberrypi:~ $ sudo i2cget -y 1 0x50 0xff
0x01
pi@raspberrypi:~ $ sudo i2cget -y 1 0x50 0xfe
0x00
```

バージョン番号もちゃんと読み出せてますね。

実際にC言語などからアクセスしようとするとこんな感じになります。

```c
#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>

static int fd = -1;

void SoundCortexOpen() {
  fd = open("/dev/i2c-1", O_RDWR);
  if (fd < 0) {
    perror("file open error");
    exit(EXIT_FAILURE);
  }
  if (ioctl(fd, I2C_SLAVE, 0x50)) {
    perror("can not set address");
    exit(EXIT_FAILURE);
  }
}

void SoundCortexWrite
(unsigned char reg, unsigned char data) {
  if (fd < 0)
    SoundCortexOpen();
  unsigned char cmd[2];
  cmd[0] = reg;
  cmd[1] = data;
  write(fd, cmd, 2);
}
```

で、例えばfMSXなんかに手を加えてみましょう。AY8910.cのWrite8910からSoundCortexWrite(R, V)みたいな感じで呼んであげれば、あら不思議。MSXエミュレータの出力がLPC810から出てきます。

という[デモ](https://www.youtube.com/watch?v=buaCriXYXNY)をYouTubeに上げてみましたよ。ちなみにこのデモはLPF通さずにミキサー直で録音してます。

## Arduino編
![IMG_20160406_042957.jpg](https://qiita-image-store.s3.amazonaws.com/0/12843/645dc121-6051-19c5-9a2d-469352059eb0.jpeg)

Arduino UNOに繋げて試してみました。写真ではpullup入れてますが、標準のWire.hを使う限りではpullup不要みたいですね。入れといて実害はないので、そのままにしてます。電源は3.3Vを使うようにしてください。LPC810の定格の問題です。digispark使って面倒だから5Vで繋げてみたけど、やっぱり動きませんでした。

```c
#include <Wire.h>

void SoundCortexWrite(uint8_t reg, uint8_t value) {
  Wire.beginTransmission(0x50);
  Wire.write(reg);
  Wire.write(value);
  Wire.endTransmission();
}

void setup() {
  Wire.begin();
  SoundCortexWrite(0x00, 0xfd);
  SoundCortexWrite(0x01, 0x01);
  SoundCortexWrite(0x07, 0xfe);
  SoundCortexWrite(0x08, 0x0f);
}

void loop() {
}
```

これでラの音が鳴ります。最初の2回の書き込みでCh.1のTPを0x01fdに設定して出力周波数をラの高さに合わせています。で、続くレジスタ7への0xfeの書き込みでCh.1の出力を有効化、レジスタ8で音量を最大に設定しています。

## PC編
[I2CBridge](https://github.com/toyoshim/I2CBridge)ってのをやはりLPC810で作りました。こいつをUSBシリアル変換器とSoundCortexの間に刺してあげれば、PCからシリアルを叩く事でI2Cバスにコマンドを送り出すことができます。ファームウェアの開発中はこっちの方がテストが楽なので、基本こちらでテストしてたんですが、やはりシリアルの速度がI2Cと比べると遅いですね。230400bpsで安定して通信出来ていたんですが、それでもPSGだけの演奏でも[ちょっともたり](https://www.youtube.com/watch?v=6Br4kE7lqt4)ます。ましてやSCCと一緒に演奏させた日にはボロボロ……。

# こんな事に使うと良いと思う
## MIDI楽器
USBやBLE、あるいはオリジナルのDINのMIDI。インタフェースまでは簡単にできるんだけど、シンセのエミュレーションは素人にはなかなか手がでないもの。そこでMIDIを受けてPSG音源を使って演奏する……となれば敷居はだいぶ下がるはず。

## 改造目覚まし時計
ちょっと凝ったブザーや演奏がマイコンから簡単にできますよ。

## ChipTuneプレイヤー
世の中に存在するChipTune向けのサウンドフォーマットをマイコンから再生するとかどうですか。わりと多くのフォーマットがCPUエミュレーションが必要だったりして大変ですけど。

## その他もろもろの電子工作
もっと音出しましょう。