Skip to content

Instantly share code, notes, and snippets.

@tecteun
Last active January 16, 2026 19:22
Show Gist options
  • Select an option

  • Save tecteun/033bcec557ecf9675a37530e95acb75f to your computer and use it in GitHub Desktop.

Select an option

Save tecteun/033bcec557ecf9675a37530e95acb75f to your computer and use it in GitHub Desktop.
usb midi bridge usb-a to usb-c and uart0
// be sure to run at / enable 240mhz
// enable operating system "FreeRTOS"
// otherwise it crashes somewhere, after few minutes
/*********************************************************************
MIT license, check LICENSE for more information
Copyright (c) 2023 rppicomidi
Modified from device_info.ino from
https://github.com/sekigon-gonnoc/Pico-PIO-USB/blob/main/examples/arduino/device_info/device_info.ino
2nd Copyright notice below included per license terms.
*********************************************************************/
/*********************************************************************
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
MIT license, check LICENSE for more information
Copyright (c) 2019 Ha Thach for Adafruit Industries
All text above, and the splash screen below must be included in
any redistribution
*********************************************************************/
#ifdef __OPTIMIZE_SIZE__
#error "Please use the Tools->Optimize: Menu to choose any Optimize setting other than -Os"
#endif
//#ifndef ARDUINO_ARCH_RP2040
//#error "This program only works with RP2040-based boards"
//#endif
#if defined(USE_TINYUSB_HOST) || !defined(USE_TINYUSB)
#error "Please use the Menu to select Tools->USB Stack: Adafruit TinyUSB"
#endif
#include "pio_usb.h"
// The following definitions apply to the custom hardware decribed in the
// README.md file for the usb_midi_host library and for the commercial
// Adafruit RP2040 Feather with USB A Host board. If you have your own
// hardware, please change the definitions below
//#include <SoftwareSerial.h>
//SoftwareSerial SSerial(D7, D6); // RX, TX
//#define COM_SERIAL SSerial
// Pin D+ for host, D- = D+ + 1
#ifndef PIN_USB_HOST_DP
#define PIN_USB_HOST_DP D12
#endif
#include <Adafruit_TinyUSB.h>
// USB MIDI object
Adafruit_USBD_MIDI usb_midi;
// USB Host object
Adafruit_USBH_Host USBHost;
// holding the device address of the MIDI device
uint8_t dev_idx = TUSB_INDEX_INVALID_8;
// constants won't change. Used here to set a pin number:
const int ledPin = PIN_LED; // the number of the LED pin
// Variables will change:
int ledState = LOW; // ledState used to set the LED
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0; // will store last time LED was updated
// constants won't change:
const long interval = 500; // interval at which to blink (milliseconds)
int PIN = 16;
#define NUMPIXELS 1
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// the setup function runs once when you press reset or power the board
void setup()
{
// Manual begin() is required on core without built-in support e.g. mbed rp2040
if (!TinyUSBDevice.isInitialized()) {
TinyUSBDevice.begin(0);
}
usb_midi.setStringDescriptor("MidiBridgeThing");
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
usb_midi.begin();
pinMode(ledPin, OUTPUT);
//Serial.begin(115200);
//Serial1.setTX(D0);
//Serial1.setRX(D1);
//Serial1.begin(31250);
Serial1.begin(31250);
}
void loop()
{
#ifdef TINYUSB_NEED_POLLING_TASK
// Manual call tud_task since it isn't called by Core's background
TinyUSBDevice.task();
#endif
// not enumerated()/mounted() yet: nothing to do
if (!TinyUSBDevice.mounted()) {
return;
}
while (usb_midi.available() > 0) {
uint8_t b = usb_midi.read();
Serial1.write(b);
// Split the byte into 3 parts
uint8_t r = (b >> 5) & 0x07; // top 3 bits
uint8_t g = (b >> 2) & 0x07; // middle 3 bits
uint8_t bl = b & 0x03; // bottom 2 bits
// Scale up to full 0–255 brightness
r = r * 36; // 0–7 → 0–252
g = g * 36; // 0–7 → 0–252
bl = bl * 85; // 0–3 → 0–255
pixels.setPixelColor(0, pixels.Color(r, g, bl));
}
/*
uint8_t packet[4];
if (usb_midi.available() > 0) {
usb_midi.readPacket(packet);
Serial1.write(packet, 4);
pixels.setPixelColor(0, pixels.Color(2 * packet[4], 2 * packet[3], 2 * packet[2]));
}
*/
while (Serial1.available() > 0){
uint8_t data = Serial1.read();
pixels.setPixelColor(0, pixels.Color(2 * data, 2 * data, 2 * data));
bool connected = dev_idx != TUSB_INDEX_INVALID_8 && tuh_midi_mounted(dev_idx);
// device must be attached and have at least one endpoint ready to receive a message
if (connected && tuh_midi_get_tx_cable_count(dev_idx) >= 1) {
uint8_t message[1] = { data };
// Transmit the note message on the highest cable number
uint8_t cable = tuh_midi_get_tx_cable_count(dev_idx) - 1;
tuh_midi_stream_write(dev_idx, cable, message, sizeof(message));
// transmit any previously queued bytes (do this once per loop)
tuh_midi_write_flush(dev_idx);
}
usb_midi.write(data);
}
//Serial1.flush();
}
// core1's setup
void setup1() {
pixels.begin();
//pinMode(Power,OUTPUT);
//digitalWrite(Power, HIGH);
pixels.setBrightness(50);
pixels.setPixelColor(0, pixels.Color(0, 255, 0)); // Red color
pixels.show();
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
pio_cfg.pin_dp = PIN_USB_HOST_DP;
USBHost.configure_pio_usb(1, &pio_cfg);
USBHost.begin(1);
}
// core1's loop
void loop1()
{
irq_set_enabled(USBCTRL_IRQ, false);
USBHost.task(); //10us timeout
pixels.clear();
pixels.show();
/*
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
pixels.setPixelColor(0, pixels.Color(random(0, 255), random(0, 255), random(0, 255)));
pixels.show();
} else {
ledState = LOW;
pixels.setPixelColor(0, pixels.Color(0, 0, 0));
pixels.show();
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
*/
irq_set_enabled(USBCTRL_IRQ, true);
}
//--------------------------------------------------------------------+
// TinyUSB Callbacks
//--------------------------------------------------------------------+
// Invoked when device with hid interface is mounted
// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
// can be used to parse common/simple enough descriptor.
// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
// therefore report_desc = NULL, desc_len = 0
void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t* mount_cb_data)
{
if (dev_idx == TUSB_INDEX_INVALID_8) {
// then no MIDI device is currently connected
dev_idx = idx;
}
}
// Invoked when device with hid interface is un-mounted
void tuh_midi_umount_cb(uint8_t idx)
{
if (idx == dev_idx) {
dev_idx = TUSB_INDEX_INVALID_8;
}
}
void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets)
{
if (dev_idx == idx) {
if (num_packets != 0) {
/*
uint8_t buf[4];
while (tuh_midi_packet_read(dev_addr, buf)) {
Serial1.write(buf, 4);
}
pixels.setPixelColor(0, pixels.Color(2*buf[0], 2*buf[1], 2*buf[2]));
pixels.show();
*/
uint8_t cable_num;
uint8_t buffer[48];
while (1) {
uint32_t bytes_read = tuh_midi_stream_read(dev_idx, &cable_num, buffer, sizeof(buffer));
if (bytes_read == 0)
return;
for (uint32_t jdx = 0; jdx < bytes_read; jdx++) {
Serial1.write(buffer[jdx]);
usb_midi.write(buffer[jdx]);
}
usb_midi.flush();
if (bytes_read > 2) {
pixels.setPixelColor(0, pixels.Color(2 * buffer[bytes_read], 2 * buffer[bytes_read - 1], 2 * buffer[bytes_read - 2]));
pixels.show();
}
}
}
}
}
void tuh_midi_tx_cb(uint8_t idx, uint32_t num_bytes)
{
(void)idx;
(void)num_bytes;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment