USB DMA to / from circular buffers

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi. I'm working on a HS USB audio class 2 app based on the AT32UC3A364.

I'm getting USB data to and from a host PC but now I want use the USB DMA to handle micro frames. No problems to set it up and get data to / from the host. My question has to do with how to handle DMA'ing to and from a circular buffer.

The code that actually moves samples to/from i2s uses a circular buffer. The DMA transfers are only able to write to a linear address range - no wrap. Furthermore, the number of samples received from the host and hence transferred via DMA can change every packet. i.e. 80 bytes, 96 bytes, 80 bytes etc.

I've considered setting up a linked-list transfer scenario when the current DMA transfer would wrap past the end of the circular buffer. Before undertaking this I just thought I'd see if anyone had any insight / observations?

Thanks very much for any insight!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would do that by creating two or mor transfer descriptors for the DMA and then point them at each other. Not sure how to make the check that a certain transfer descriptors data has been fully sent, but I guess it should be simlpe to look at what transfer descriptor is working right now.

But then if you are sending as little as 96 bytes, what would the DMA do? The 96 bytes would all be sent in one USB frame anyway. Just set the endpoint size to 512 and 512 bytes will take as long time to send as 1.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks very much for your response!

The issue I see with setting up a linked transfer is handling the destination (OUT) and source (IN) circular buffer wrapping. I considered having an array of buffers each with a length count that is filled or emptied by the DMA then consumed or produced by the i2s interrupt code.

As for what the DMA is doing, the hardware design for this product (not mine) relies on bit-banging 2 I2S streams on the NMI. Consequently the number of available machine cycles is very low, so using DMA to move microframes seems like a "cycle-free" way to accomplish it.

I am considering using an array / list of buffers, each with sufficient size to hold the largest microframe (192 bytes) , and a count of used bytes. Similar to what you stated, I could implement the list of buffers as circular linked list in the same format as the DMA descriptors. Then DMA and i2s could traverse (different elments of) the list. The only issue here has to do with OUT packets (from the host). Based on my interpretation of the USB DMA spec, it is necessary to set CHBYTELENGTH=0 for the transfer to complete on a short packet (which all transfers will be). So later, when i2s needs to consume the correct amount from the buffer, it needs a count. I guess one way to determine the length of the packet would be to examine the HSBADDR field and given that every buffer will be aligned on a 256 byte boundary, the lower 8 bits of HSBADDR will give the length of the transfer. Furthermore, the i2s routine can zero the low 8bits so the next DMA transfer is to the start of the buffer again. Maybe?!??

thanks for your time!