I've posted an example of USB bulk transfer for the XMEGA to the projects section.
A few weeks ago I posted a USB bulk transfer example project for the AT32UC3B series. My aim was to develop a simple example that didn't use the ASF (or LUFA). At the time, the 32 bit Atmel parts were unfamiliar to me, and the datasheet was obscure in spots, but there was enough information there to figure out what was needed. The example I posted is pretty simple-minded and primitive, but it gets the job done.
For a related project, I wanted to do the same for the ATXmega16C4. This turned out to be a bit more difficult.
USB on the xmega series works differently than it does for the other Atmel parts I've seen (e.g. AT32, ATmega8u2, SAM3S). There is no dedicated memory either for endpoint registers or for endpoint data buffers. Additionally, the handshaking between firmware and hardware to acknowledge and transfer packets is different.
The datasheet pretty clearly explains how the registers and buffers should be set up, so that wasn't much of a problem. What the datasheet doesn't do is describe the details of the enumeration process and how setup packets are acknowledged and replied to, and how to go about setting the address once it's received from the host. This is done with fairly complete text and timing diagrams for the AT32UC3B; there's neither of these for the xmega.
So I spent about three weeks of banging my head against the wall, doing trial-and-error and making very slow and sporadic progress. The sticking point – how to set the address – was finally solved when I found this guy's USB stack:
Among all the USB stacks for the xmega I've seen online, this one was the least impenetrable, at least so far as finding the one piece of information I needed – how to set the address.
My point is that what with better documentation would have taken a few hours instead took me three weeks. I asked Atmel support for help on this, and the reply was that everything happened automatically, and all I had to do was to write the address to the proper register on receiving it, and everything would be fine. Not true, needless to say.
1. In the xmega LUFA stacks I've seen, a cobbled-together assembly routine, LACR16(), is used to clear bits in the endpoint registers. This is no longer necessary:
ep0_out_p->STATUS &= ~0x02;
for instance, works just fine.
2. On the other hand, clearing the transaction complete register cannot be accomplished by
USB_INTFLAGSBCLR = 0x02;
as you would think; instead, you have to do:
USB_FIFOWP = 0;
3. Unlike with the AT32UC3B, if the hardware receives an IN token it will immediately grab the data from the IN buffer without waiting for the firmware to write to it. To prevent this, the endpoint IN BUSNACK0 can be set preemptively, and then, after data is written to the IN buffer, cleared to send the data.