Skip to content

Add ATmega32U4 USB MIDI 2.0 device example (stock Arduino core)#1

Merged
sauloverissimo merged 1 commit into
mainfrom
feat/atmega32u4-device-arduino
Jul 14, 2026
Merged

Add ATmega32U4 USB MIDI 2.0 device example (stock Arduino core)#1
sauloverissimo merged 1 commit into
mainfrom
feat/atmega32u4-device-arduino

Conversation

@sauloverissimo

Copy link
Copy Markdown
Owner

This adds examples/atmega32u4-device-arduino, a complete USB MIDI 2.0 device that runs on a plain 8-bit ATmega32U4 (Arduino Leonardo, Pro Micro, Micro). It enumerates as a native MIDI 2.0 endpoint, answers UMP Stream and MIDI-CI Discovery, and loops a small showcase of the message surface. It flashes with a normal Arduino upload and fits in about 17 KB of flash and 1.3 KB of SRAM.

The interesting part is the transport: it rides the stock Arduino core through PluggableUSB, so there is no LUFA, no TinyUSB and no extra USB stack. The midi2 core in this repo builds and parses the UMP, reassembles SysEx7 and answers MIDI-CI, while the midi2duino library carries the packets over USB. A thin Midi2Usb veneer wires the responders and the message processor onto the transport and exposes readable send* helpers, with no std::function and no heap.

The showcase covers, on group 0:

  • Channel Voice 2.0: notes with 16-bit velocity, 32-bit CC and pitch bend, program change, channel and poly pressure, per-note pitch bend
  • Flex Data: tempo and time signature
  • Data messages: SysEx7, SysEx8, Mixed Data Set
  • UMP Stream: endpoint info and name, device identity, function block info and name, stream configuration

MIDI-CI Discovery is answered with a per-boot randomized MUID. Anything the device does not support is NAKed, and its capabilities are advertised as 0x00, so nothing is over-promised.

It passes the MIDI 2.0 Workbench self-certification and is validated on hardware. On Linux the kernel reads the Group Terminal Block and exposes one bidirectional Function Block named Main; on Windows MIDI Services it shows up as ATmega32U4 MIDI 2.0 with UMP as the native format. A board photo and the Windows captures are in the example folder.

One caveat: the stock Arduino core does not forward SET_INTERFACE to PluggableUSB, so the device always speaks UMP and targets MIDI 2.0 hosts. The README explains it.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2c1ff13233

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

void Midi2Usb::begin() {
midi2_dispatch_init(&g_dp);
stream_responder_attach(&g_dp);
midi2_proc_init(&g_proc, g_sysex7_buf, sizeof g_sysex7_buf, NULL, 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep Data128 messages on the echo path

When a host sends MT 0x5 Data128 traffic (SysEx8 or MDS), this processor consumes those messages before on_ump is called; because the SysEx8 buffer/callback is disabled here, they are then silently dropped. That contradicts the example's advertised/validated Data128 surface and its echo behavior, so SysEx8/MDS sent by a host will not come back unless Data128 is explicitly forwarded or handled.

Useful? React with 👍 / 👎.

Comment on lines +46 to +48
for (uint32_t i = 0; i < count; i++)
if (!midi2duino_write_word(words[i]))
return i; /* ring full: partial write reported */

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Write MIDI-CI SysEx7 packets atomically

MIDI-CI replies are emitted as two-word SysEx7 UMP packets, but this callback queues each word separately; if the TX ring has only one free slot while a Discovery reply is being generated, the first word is accepted and the second fails, leaving an incomplete UMP at the head of the ring that can block or corrupt later USB output. Use the complete-message write path so either the whole packet is queued or none of it is.

Useful? React with 👍 / 👎.

@sauloverissimo sauloverissimo merged commit 37beb2e into main Jul 14, 2026
18 checks passed
@sauloverissimo sauloverissimo deleted the feat/atmega32u4-device-arduino branch July 14, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant