Wildcard
Files: audio_interface_2.sch audio_interface_2.brd lufa (see Demos/Devices/ClassDriver/MIDI and Demos/Devices/ClassDriver/AudioInput)
This week there’s a lot on the menu: soft robotics, bioprinting, coil plotting, wire EDM, and many more. I’d like to learn them all, but for now I’ll continue my exploration of LUFA. So far I have a virtual serial port example working, but let’s see what else I can do. Throughout I’ll be using the board that I designed and fabricated last week.
MIDI
In outputs week I taught an ATtiny44 to speak MIDI, albeit not perfectly. Now I can try on an XMEGA. I should also be able to ditch the FTDI cable and special software, since everything should work over USB using standard device drivers.
Luckily LUFA has a MIDI device example. To make it work with my board I followed the same steps I previously used for the virtual serial port example.
When I plug it in, it shows up as “LUFA MIDI Demo” in Apple’s system MIDI configuration utility.
It’s also recognized by Logic Pro and Ableton Live. So I can use it to control software instruments in all my usual environments. I definitely won’t be using the FTDI cable for MIDI anymore.
Audio
This is what I’m ultimately after for my final project, but it’s going to be a lot trickier. LUFA’s AudioInput example isn’t configured to support XMEGAs, so I either have to redo my board with a different microcontroller, or dive deep into LUFA and add the missing functionality for XMEGAs. The former is a bounded problem, but the latter is a lot more educational. So down the rabbit hole I go…
To begin I cleared out the LUFA LED, Button, and ADC code since they’re either not defined for XMEGAs or not something I want to use. When building I still immediately get an error that XMEGA is not a supported architecture. I fixed this by editing Config/LUFAConfig.h
. I took the following values from the MIDI example’s config file.
#if (ARCH == ARCH_AVR8)
// ... existing AVR config code here ...
#elif (ARCH == ARCH_XMEGA)
#define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)
#define USE_FLASH_DESCRIPTORS
#define FIXED_CONTROL_ENDPOINT_SIZE 8
#define FIXED_NUM_CONFIGURATIONS 1
#define MAX_ENDPOINT_INDEX 2
#else
Now the compiler complains about invalid registers. Progress! To fix this I need to figure out what LUFA is doing with these AVR8 registers, then implement the same thing for XMEGA. This ended up being pretty easy since I was already familiar with the XMEGA’s ADC.
At this point the code compiles, and the board is recognized as an audio device, but can’t transmit any audio. More precisely, the board tries to transmit audio, in that it does generate samples and pass them to a LUFA method that should transmit them… but nothing gets through to my computer. Still, I’m excited that it can present itself as a CDC audio input at all.
It turns out there was one final set of modifications that had to be made, and I still don’t understand why. I accidentally stumbled across this thread on AVRFreaks, in which someone mentions getting audio to function by changing certain USB endpoint and buffer sizes. Sure enough, after modifying the relevant numbers I could pass audio data to my computer. I posted a message on the LUFA support list asking why these changes do what they do, but no one has responded yet. Endpoint and buffer sizes of 64 and 128 bytes work, but 256 does not.
And it’s still not working properly. When I record audio on my computer, the result ends up shorter and higher pitched than intended. So something is probably going wrong with the sample rate. (It’s also obviously bit-crushed, but that’s expected since the XMEGA is only sampling with 12-bit resolution.) My current theory is that the data transfer is not happening over isochronous USB, and this is confusing the host driver. The results sure sound like a throughput issue (i.e. the audio board sends less samples than the computer expects, so the computer squashes them together and pads the ends with zeros), but even without isochronous USB I think I should have enough bandwidth for one channel of audio. Perhaps it also has to do with jitter (non-isochronous USB doesn’t make the same guarantees about packet delivery times).