Instantly share code, notes, and snippets.
Last active
January 16, 2026 19:22
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save tecteun/033bcec557ecf9675a37530e95acb75f to your computer and use it in GitHub Desktop.
usb midi bridge usb-a to usb-c and uart0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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