I am quite enthusiastic about the new Raspberry Pico. However I find the C SDK not very friendly and I prefer to have something as simple as the Arduino API. I did not want to wait for the official Arduino support – so I started my own project.

The last couple of days I tried to wrap my head around the TinyUSB Midi support in order to provide some simple C++ class to use the Pico as USB Midi Device. There is one big caveat in using TinyUSB – as soon as you add the relevant libraries, you loose your serial output to USB. This is a little bit annoying!

Here is my example test sketch that generates some random tones:

#include "Arduino.h"
#include "USB.h"

USBMidi midi = USBMidi::instance();
int note;

void setup() {
    Serial1.begin();
    midi.begin();
    Serial1.println("setup ended");
}

void loop() {
    midi.noteOff(note);
    note = 58 + rand() % 14;
    Serial1.print("playing note ");
    Serial1.println(note);
    midi.noteOn(note);
    delay(1000);
}

And here is the corresponding CMakeList.txt:

# PICO initialization
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
include("${PICO_SDK_PATH}/external/pico_sdk_import.cmake")

# define project settins
set(ARDUINO_SKETCH_NAME "usb_midi" )
set(PICO_SDK_ARDUINO_PATH $ENV{PICO_SDK_ARDUINO_PATH})
set(ARDUINO_USB_MIDI_PATH ${PICO_SDK_ARDUINO_PATH}/Arduino/USB/midi)

# Standard Sketch logic
project("${ARDUINO_SKETCH_NAME}" C CXX ASM)
file(GLOB USB_SRC ${ARDUINO_USB_MIDI_PATH}/*.cpp )
file(GLOB CURRENT_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp )
set(ARDUINO_SKETCH_SOURCE  ${CURRENT_SRC} ${USB_SRC})
set(ARDUINO_SKETCH_INCLUDES ${ARDUINO_USB_MIDI_PATH})
set(ARDUINO_SKETCH_LIB "tinyusb_device" "tinyusb_board" "pico_fix_rp2040_usb_device_enumeration"  )

#set(CMAKE_C_FLAGS_DEBUG "-Og") 
#add_compile_options(-DCFG_TUSB_DEBUG=3 )

include("${PICO_SDK_ARDUINO_PATH}/ArduinoSketch.cmake")

You need to add the tinyusb libraries “tinyusb_device” and “tinyusb_board”. For me it was only working when I also added the “pico_fix_rp2040_usb_device_enumeration” library. I found this in the examples provided by TinyUSB.

If you have a FTDI device and want to see debug log messages as serial output you can activate the logging by adding the following line.

add_compile_options(-DCFG_TUSB_DEBUG=3 )

The default Tx pin is on GPIO0.

The basic processing logic of the example provided by TinyUSB looks as follows:

/*------------- MAIN -------------*/
int main(void)
{
  board_init();
  tusb_init();

  while (1)
  {
    tud_task(); // tinyusb device task
    led_blinking_task();
    midi_task();
  }
  return 0;
}

On top of that, you need to provide implementations for all relevant callbacks and settings.
I tried to wrap as much as possible into the USBMidi C++ class. The begin() method is calling the board_init() and tusb_init() . It is critical that the tud_task() method is called in short intervalls – so I moved it to a repeating Timer.
My implementation of the MIDI functionality can be found on github.

After installing the sketch on the Pico it shows up as Midi Divice: On OS/X e.g. it appears automatically in the Midi Manager as active device:


1 Comment

Pomax · 19. October 2024 at 21:06

Looks like your github link has become a 404.

(Always good not to link to “a tree” but a specific commit for a file, so it’ll never become a 404 when you rename or even delete a branch)

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *