Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ project(picomidi C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# Force enable MIDI host
add_definitions(
-DCFG_TUH_MIDI=1
-DCFG_TUH_DEVICE_MAX=2
)

pico_sdk_init()

include_directories(
Expand Down Expand Up @@ -42,3 +36,11 @@ target_link_libraries(picomidi
)

pico_add_extra_outputs(picomidi)

target_compile_definitions(picomidi PRIVATE
CFG_TUD_VID=0x1209
CFG_TUD_PID=0x4750
PICO_DEFAULT_UART=0
PICO_DEFAULT_UART_TX_PIN=0
PICO_DEFAULT_UART_RX_PIN=1
)
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ You'll need to add USB host functionality using one of these methods:
- Connect 5V power to VSYS (pin 39)
- Ensure proper grounding between all connected devices

## Status LED Behavior

- **Solid On**: Connected to computer as USB MIDI device
- **Blinking Fast**: MIDI data being transmitted/received
- **Slow Blink**: Not connected to computer
- **Off**: Critical error (should never occur)

## USB Device Recognition

The Pico will now properly identify as:
- Vendor ID: 0x1209 (PID Codes)
- Product ID: 0x4750
- Product Name: "PicoMIDI"

## Building the Firmware

1. Set up the Pico SDK development environment
Expand Down
6 changes: 4 additions & 2 deletions include/tusb_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
extern "C" {
#endif

// Common Configuration
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_DEVICE)
// #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HOST)
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
#define CFG_TUSB_OS OPT_OS_PICO
#define CFG_TUSB_MCU OPT_MCU_RP2040

Expand All @@ -15,6 +15,8 @@ extern "C" {
#define CFG_TUD_MIDI 1
#define CFG_TUD_MIDI_RX_BUFSIZE 64
#define CFG_TUD_MIDI_TX_BUFSIZE 64
#define CFG_TUD_VID 0x1209 // VID from pid.codes
#define CFG_TUD_PID 0x4750 // Test PID

// Host Configuration
#define CFG_TUH_ENABLED 1
Expand Down
20 changes: 12 additions & 8 deletions include/usb_descriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@

#include "tusb.h"

#ifdef __cplusplus
extern "C" {
#endif
// Interface numbers
enum {
ITF_NUM_MIDI = 0,
ITF_NUM_MIDI_STREAMING,
ITF_NUM_TOTAL
};

// Endpoint numbers
enum {
EPNUM_MIDI_OUT = 0x01,
EPNUM_MIDI_IN = 0x81
};

// Callbacks
uint8_t const * tud_descriptor_device_cb(void);
uint8_t const * tud_descriptor_configuration_cb(uint8_t index);
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid);

#ifdef __cplusplus
}
#endif

#endif
46 changes: 38 additions & 8 deletions src/main.c
Original file line number Diff line number Diff line change
@@ -1,35 +1,65 @@
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "hardware/gpio.h"
#include "tusb.h"
#include "usb_midi_host.h"
#include "din_midi.h"
#include "midi_router.h"

#define LED_PIN 25
static uint32_t last_activity_time = 0;

void core1_entry() {
uint32_t last_blink = 0;
bool led_state = false;

while (true) {
usb_midi_host_task();
din_midi_task();
midi_router_task();
sleep_us(100);
uint32_t now = to_ms_since_boot(get_absolute_time());

if (tud_mounted()) { // Check if USB is properly mounted
// Solid on when properly connected
gpio_put(LED_PIN, true);

// Blink briefly on activity
if ((now - last_activity_time) < 50) { // 50ms blink
gpio_put(LED_PIN, !gpio_get(LED_PIN));
}
} else {
// Slow blink (500ms) when not properly connected
if ((now - last_blink) > 500) {
gpio_put(LED_PIN, !gpio_get(LED_PIN));
last_blink = now;
}
}

sleep_ms(10);
}
}

int main() {
stdio_init_all();

// Initialize LED
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
gpio_put(LED_PIN, false);

// Initialize all components
tusb_init();
usb_midi_host_init();
din_midi_init();
midi_router_init();

// Start processing on core 1
multicore_launch_core1(core1_entry);

// Core 0 handles USB tasks
while (true) {
tud_task(); // Device task
tuh_task(); // Host task
tud_task(); // Handle device tasks
tuh_task(); // Handle host tasks

// Update activity time if MIDI is active
if (tud_midi_available() || usb_host_devices[0].connected || usb_host_devices[1].connected) {
last_activity_time = to_ms_since_boot(get_absolute_time());
}
}

return 0;
Expand Down
52 changes: 13 additions & 39 deletions src/usb_descriptors.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
#include "tusb.h"
#include "usb_descriptors.h"

//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+

tusb_desc_device_t const desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
Expand All @@ -13,28 +8,15 @@ tusb_desc_device_t const desc_device = {
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = 0x4001,
.idVendor = CFG_TUD_VID,
.idProduct = CFG_TUD_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};

//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+

enum {
ITF_NUM_MIDI = 0,
ITF_NUM_MIDI_STREAMING,
ITF_NUM_TOTAL
};

#define EPNUM_MIDI_OUT 0x01
#define EPNUM_MIDI_IN 0x81

uint8_t const desc_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUD_CONFIG_DESC_LEN + TUD_MIDI_DESC_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
Expand All @@ -43,21 +25,13 @@ uint8_t const desc_configuration[] = {
TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 0, EPNUM_MIDI_OUT, EPNUM_MIDI_IN, 64)
};

//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+

char const* string_desc_arr[] = {
(const char[]) {0x09, 0x04}, // 0: is supported language is English (0x0409)
"PicoMIDI", // 1: Manufacturer
"MIDI Router", // 2: Product
"123456", // 3: Serials
(const char[]) {0x09, 0x04}, // English
"PicoMIDI", // Manufacturer
"MIDI Router", // Product
"123456", // Serial
};

//--------------------------------------------------------------------+
// Callbacks
//--------------------------------------------------------------------+

uint8_t const * tud_descriptor_device_cb(void) {
return (uint8_t const *) &desc_device;
}
Expand All @@ -70,20 +44,20 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index) {
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void)langid;
static uint16_t desc_str[32];
uint8_t len;


if (index == 0) {
memcpy(&desc_str[1], string_desc_arr[0], 2);
len = 1;
desc_str[0] = (TUSB_DESC_STRING << 8) | 0x09;
} else {
const char* str = string_desc_arr[index];
len = strlen(str);

uint8_t len = strlen(str);
for (uint8_t i = 0; i < len; i++) {
desc_str[1 + i] = str[i];
}

desc_str[0] = (TUSB_DESC_STRING << 8) | (2*len + 2);
}

desc_str[0] = (TUSB_DESC_STRING << 8) | (2*len + 2);

return desc_str;
}