Raspberry PiにMIDIシールドを接続

Raspberry Pi のUARTとMIDIシールドのUARTを接続して、5pin DINのMIDIを送受信します。リンク先はスイッチサイエンスさのカタログページです。私の持っているMIDIシールドは一世代前のものです。

https://www.switch-science.com/

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()


C言語でMIDI送受信

上では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に変更しないとなりません。

MIDI送信

// 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

MIDI受信

//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