Raspberry Pi Pico I2C MIDI Interface – Part 2

Following on from Raspberry Pi Pico I2C MIDI Interface this post looks at how to use the I2C MIDI layer with the Adafruit MIDI library for CircuitPython.

IMG_5710

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

These are the key tutorials for the main concepts used in this project:

If you are new to microcontrollers, see the Getting Started pages.

Parts list

  • Arduino Uno, Nano, or similar
  • Raspberry Pi Pico
  • 3.3V to 5V level shifter
  • 2x 10kΩ resistors
  • Optional: old 8Ω loudspeaker
  • Optional: 220Ω resistor (for the loudspeaker)
  • Optional: One of the Ready-Made MIDI Modules for the Arduino

The Circuit

RaspberryPiPicoI2CMIDITest2_bb

This takes the circuit from the previous part and uses that “as is” for the sending part of the test.  Then one of the Ready-Made MIDI Modules is added for the receiving part of the test.

As before, all boards need power, e.g. over their USB connections.

For my tests, I actually used two different Arduinos, but I could have just reloaded the second sketch onto the same one.

The Code

I now have some code that allows me to use the Adafruit MIDI library for CircuitPython.  Looking at the library, it appears to interface to a device that implements a read() and write() method (along with a constructor) and I think it only acts on single bytes at a time.

Consequently, I seem to be able to get away with the following implementation for my I2CMIDI module, which gives a class that can be passed into the Adafruit MIDI Library as in the examples that follow.

This is using the Adafruit_CircuitPython_BusDevice which takes care of things like locking the I2C bus when required and remembering the I2C address to use.

Note: This will only work as an I2C controller at present.  I haven’t looked at what is required (or even if it is possible) to work as a peripheral.

# Saved as i2cmidi.py
from adafruit_bus_device import i2c_device
I2CMIDI_CTRL = 1
I2CMIDI_PRPH = 2

DEVICE_DEFAULT_I2C_ADDR = 0x40
I2CBUFSIZE = 1

class I2CMIDI:
    def __init__(self, i2c, address=DEVICE_DEFAULT_I2C_ADDR, ctrl=I2CMIDI_CTRL):
        self.i2c_device = i2c_device.I2CDevice(i2c, address)
        self.buf = bytearray(I2CBUFSIZE)

    def read(self, len):
        with self.i2c_device as i2c:
            i2c.readinto(self.buf, end=len)
        return self.buf

    def write(self, buf, len):
        with self.i2c_device as i2c:
            i2c.write(buf, end=len)

To test the sending, there is a slight variant of the code used last time (note it imports the above code as i2cmidi):

import time
import board
import busio
import adafruit_midi
from adafruit_midi.note_off import NoteOff
from adafruit_midi.note_on import NoteOn
import i2cmidi

addr = 0x40
i2c = busio.I2C(board.GP13, board.GP12)
i2cmidi = i2cmidi.I2CMIDI(i2c, addr, i2cmidi.I2CMIDI_CTRL)

midi = adafruit_midi.MIDI(midi_out=i2cmidi, midi_in=i2cmidi, out_channel=0)

while True:
    midi.send(NoteOn(60,64))
    time.sleep(0.2)
    midi.send(NoteOff(60,0))
    time.sleep(0.8)

This was connected up to the Arduino running the I2CMIDIReceive example once again on I2C address 0x40.

To test the basic receive functionality, I used the I2CMIDItoSerialRelay example, in SERIAL2I2C mode, but with the device as an I2CMIDIPERIPHERAL (still on address 0x40) – the default code assumes an I2CMIDICONTROLLER for the MIDI sending part…

import board
import digitalio
import busio
import adafruit_midi
from adafruit_midi.note_off import NoteOff
from adafruit_midi.note_on import NoteOn
import i2cmidi

addr = 0x40
i2c = busio.I2C(board.GP13, board.GP12)
i2cmidi = i2cmidi.I2CMIDI(i2c, addr, i2cmidi.I2CMIDI_CTRL)

midi = adafruit_midi.MIDI(midi_in=i2cmidi)

while True:
    msg = midi.receive()
    if (isinstance(msg, NoteOn)):
        print ("Note On: \t",msg.note,"\t",msg.velocity)
    if (isinstance(msg, NoteOff)):
        print ("Note Off:\t",msg.note,"\t",msg._velocity)

So this is as far as I’ve got.  It seems to work.  I’ve received the occasional error:

OSError: [Errno 19] Unsupported operation

But I’ve not been able to track that down yet.  I wonder if it is something to do with the Arduino end locking up.

Closing Thoughts

The general shape of the idea is starting to come together now, but I’m not convinced I’ve really caught the nuances of creating a device for use with the Adafruit MIDI library.  And so far I’ve only implemented an I2C controller, although it can now act as a MIDI OUT and MIDI IN.

So far, I’ve looked through the following online information about this:

… but not really being a python person, I’m sure there is plenty still missing.  If you have any advice, do drop it in the comments!

Kevin

Leave a comment