Raspberry Pi のUARTとMIDIシールドのUARTを接続して、5pin DINのMIDIを送受信します。リンク先はスイッチサイエンスさのカタログページです。私の持っているMIDIシールドは一世代前のものです。
Raspberry Piでシリアル通信を扱えるように設定します。Raspberry PiのConfigurationを開きます。5. Interface Optionsを選択します。
> pi@raspberrypi:~ $ sudo /usr/bin/raspi-config
I6 Serial Poartを選択します。
Would you like a login shell to be accessible over serial?と聞かれますので、 いいえとします。
次にWould you like the serial port hardware to be enabled? と聞かれます。シリアルポートのハードウェアを使いますので、はいを選びます。
「了解」「Finish」でウィンドウを閉じます。rebootします。
> pi@raspberrypi:~ $ sudo reboot
Raspberry PiとMIDIシールドを接続します。ここで考慮しないといけないのは、Raspnerry Piのシリアル入出力(TXD, TRD)が3.3Vであるのに対して、MIDIの入出力は5Vなので変換をしないとなりません。以下手持ちの部品で作成しました。Raspberry PiのTXDを、MIDIシールドのTXDに接続するためにNPNトランジスタで電圧を上げています。また、MIDIシールドの出力をRaspberry Piで受けるには電圧を下げれば良いので、ここではツェナーダイオードで変換しています。
USB-MIDIインターフェースとしてRoland UM-ONEを使っています。UM-ONEのコネクタの刻印でINを、シールドのMIDI INに接続、コネクタのOUTをシールドのMIDI OUTに接続します。インターフェースに寄っては逆の場合もあります。
python3を使った、MIDI送信と受信のプログラムを書いておきます。
送信 - Note Onを1回出力します。
import serial ser = serial.Serial('/dev/ttyAMA0', '31250', timeout=0.1) ser.write(chr(0x90).encode()) ser.write(chr(0x60).encode()) ser.write(chr(0x7F).encode()) ser.close()
受信 - MIDIのイベントを受信します。
import serial ser = serial.Serial('/dev/ttyAMA0', '31250', timeout=0.1) mcnt=0 message=[0,0,0] while True: a=ser.read() if(a!=b''): for x in a: if(x&0x80): message[0]=x message[1]=0 message[2]=0 mcnt=1 else: if(mcnt==1 or mcnt==2): message[mcnt]=x mcnt=mcnt+1 if(mcnt==3): for i in range(3): print(hex(message[i])," ",end="") print("") mcnt=0 ser.close()
上ではPythonのサンプルプログラムを提示しましたが、ここからはC言語を使います。C言語からシリアルポートを扱うには、ファイルにアクセスするのと同等で、ファイルをオープンする、ファイルに対して書き込む、ファイルから読み込むようなプログラムを書きます
(1) gpioを扱うためにWiringPiをインストールします。他にもライブラリがあるようなのですが、情報が多かったのでこちらを使うこととしました。 「Wiring Piのインストール&設定」を参照いたしました。
> git clone https://github.com/WiringPi/WiringPi.git > cd WiringPi > ./build
(2) /boot/config.txt を編集して以下の3行を書き加えます。その後、rebootします。 いくつかのサイトを参考にさせていただきました。
> sudo vim /boot/config.txt # uart baud rate for MIDI enable_uart=1 dtoverlay=pi3-miniuart-bt dtoverlay=midi-uart0 > sudo reboot
いろいろ読んでみて、私の理解は次のようなものです。Raspberry Piにはシリアル通信できるポートがいくつかあります。 その中で、UART0(/dev/ttyAMA0)が、GPIOピン(8ピンと10ピン)につながっています。 ところが、通常はこのポートがBluetoothでつかわれてしまっています。 ですので、他のポートMini UART(/dev/ttyS0)を起こして、Bluetoothを移動し、 /dev/ttyAMA0を空けて使えるようにする、ということをやらないとなりません。
enable_uart=1はMini UARTを起こして、GPIO14,15に設定すします。
dtoverlay=pi3-miniuart-btは、BluetoothをMini UARTに設定します。これで、UART0が空く)
dtoverlay=midi-uart0はシリアル通信の設定で通信速度を38kbpsとすると、MIDIの通信速度31.25kbpsに設定してくれます。
この設定をすると、上のPythonでの入手力もBaudrateの設定を38400に変更しないとなりません。
// serialmidisend.c #include <stdio.h> #include <wiringPi.h> #include <wiringSerial.h> int main() { /* シリアルポートオープン */ int fd = serialOpen("/dev/ttyAMA0",38400); if(fd<0){ printf("can not open serialport"); } serialPutchar(fd,0x90); serialPutchar(fd,0x40); serialPutchar(fd,0x7F); delay(1000); //1sec待つ serialPutchar(fd,0x80); serialPutchar(fd,0x40); serialPutchar(fd,0x00); return 1; }
>gcc serialmidisend.c -lwiringPi
//serialmidireceive.c #include <stdio.h> #include <wiringPi.h> #include <wiringSerial.h> int main() { /* シリアルポートオープン */ int fd = serialOpen("/dev/ttyAMA0",38400); int n, i; unsigned char cc; if(fd<0){ printf("can not open serialport"); } while(1){ /* 受信処理 */ n=serialDataAvail(fd); if(n!=0){ for(i=0; i<n; i++){ cc=serialGetchar(fd); printf("%02x:",cc); } printf("\n"); serialFlush(fd); } } return 1; }
>gcc serialmidireceive.c -lwiringPi