Project 21: TinyUSB Composite MIDI + HID Controller (Custom Descriptor Lab)

Build a single NeoTrellis firmware image that enumerates as MIDI + HID + vendor diagnostics, with endpoint telemetry and cross-OS validation.

Quick Reference

Attribute Value
Difficulty Level 5: Master
Time Estimate 2-3 weeks
Main Programming Language C/C++ with TinyUSB
Alternative Programming Languages Bare-metal USB C (advanced extension)
Coolness Level Level 5: The “WTF, That’s Possible?”
Business Potential 3. The “Open Core”
Prerequisites USB basics, class descriptors, endpoint concepts
Key Topics Composite descriptors, endpoint management, TinyUSB concurrency, host compatibility

1. Learning Objectives

By completing this project, you will:

  1. Design and validate coherent composite USB descriptors.
  2. Implement concurrent MIDI and HID functionality on one device.
  3. Manage endpoint throughput and latency under burst traffic.
  4. Apply TinyUSB callback/task context rules safely.
  5. Produce repeatable host-compatibility evidence across major OSes.

2. All Theory Needed (Project-Scoped)

2.1 Enumeration Pipeline

Control endpoint (EP0) descriptor exchange defines whether host class drivers can bind correctly.

2.2 Composite Layout

Interface numbering, endpoint assignment, and descriptor lengths must remain internally consistent.

2.3 TinyUSB Concurrency Boundaries

Keep callbacks short; route heavy work to event queues and task context.

2.4 Endpoint Service Policy

Latency emerges from queueing and service cadence. Monitor NAK/stall patterns under load.

2.5 Validation Scope

Use descriptor dumps plus functional tests in DAW/media-key contexts on multiple OSes.


3. Project Specification

3.1 What You Will Build

A composite USB device exposing:

  • MIDI streaming interface
  • HID consumer-control interface
  • vendor diagnostics endpoint pair

3.2 Functional Requirements

  1. Descriptor set passes host parsing and class binding.
  2. MIDI note/CC messages transmit and receive correctly.
  3. HID transport controls trigger host media actions.
  4. Vendor endpoint supports simple command/telemetry exchange.

3.3 Non-Functional Requirements

  • Performance: Endpoint p99 latency under target threshold.
  • Reliability: No stall loops in 30-minute mixed traffic test.
  • Portability: Works on macOS, Windows, Linux.

3.4 Real World Outcome

$ usb_composite_probe --device NeoTrellisPro
Device: VID=0x239A PID=0x80A1 Speed=Full (12 Mbps)
Interfaces:
  IF0: MIDI Streaming
  IF1: HID Consumer Control
  IF2: Vendor Diagnostics
Descriptor validation: PASS
Endpoint latency p99:
  MIDI IN=0.82ms HID IN=1.10ms Vendor OUT=1.45ms
Cross-OS matrix: macOS PASS, Windows PASS, Linux PASS

4. Solution Architecture

4.1 High-Level Design

Host <--EP0 control--> descriptor engine
Host <--MIDI EPs-----> MIDI event bridge
Host <--HID EP-------> transport key mapper
Host <--Vendor EPs---> diagnostics/config channel

4.2 Key Components

Component Responsibility Key Decision
Descriptor builder produce coherent descriptor tree strict interface/endpoint map review
MIDI bridge map grid events to USB MIDI packets priority for note-on/off integrity
HID mapper transport/media controls report format compatibility
Vendor diagnostics telemetry and config query low-bandwidth and bounded handlers

4.3 Descriptor Audit Checklist (Pseudocode)

assert(config_total_length == sum(interface_blocks))
assert(unique_endpoint_numbers_per_direction)
assert(class_subclass_protocol fields match function intent)
assert(max_packet_size valid for full-speed endpoint type)

5. Implementation Guide

5.1 Phases

  1. Bring up MIDI-only descriptor set.
  2. Add HID interface and validate host behavior.
  3. Add vendor channel and endpoint telemetry.
  4. Stress-test mixed traffic with logs.

5.2 The Core Question You’re Answering

“Can one USB device expose multiple stable personalities without hidden latency or compatibility failures?”

5.3 Questions to Guide Design

  1. Which endpoints are interrupt vs bulk and why?
  2. Where are context boundaries between callbacks and main loop?
  3. What telemetry will reveal endpoint starvation early?

5.4 Thinking Exercise

Draw your full descriptor tree on paper and compute all total-length fields manually before implementing.

5.5 Interview Questions They Will Ask

  1. Walk through USB enumeration for your composite device.
  2. Why might a device appear but class binding fail?
  3. How do you debug intermittent endpoint latency spikes?
  4. What TinyUSB APIs are unsafe in ISR/callback context?
  5. How would you evolve this design toward MIDI 2.0?

5.6 Hints in Layers

  • Hint 1: Validate descriptors first, logic second.
  • Hint 2: Add one interface at a time.
  • Hint 3: Keep callbacks enqueue-only.
  • Hint 4: Maintain per-endpoint counters and latency summaries.

5.7 Common Pitfalls and Debugging

Problem Why Fix Quick Test
MIDI missing in DAW malformed MIDI interface descriptors repair class-specific descriptor block compare host descriptor dump
HID keys lag callback path too heavy defer processing to main loop high-rate HID spam test
Random stalls endpoint type/size mismatch align descriptors and transfer policy sustained mixed transfer test

5.8 Definition of Done

  • Composite descriptors validated and versioned.
  • MIDI and HID operate simultaneously for 30 minutes.
  • Vendor diagnostics endpoint returns deterministic responses.
  • Cross-OS compatibility matrix recorded.

6. References