FX3 DMA Engine hangs(?) with small manual transfers

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
mcn
Level 2
Level 2
10 replies posted 5 questions asked 10 sign-ins

I have a manual single DMA channel which is dealing with multiple small packets, one at a time. After committing the buffer, the data arrives at the host just fine.

However, I cannot start a new DMA transfer because the previous one is ACTIVE indefinitely.

The setup is:

dmaCfg.size = 96;  // Multiple of 32 required
dmaCfg.count = 192;  // 256 seems to crash? Not sure why, should be plenty of memory?
dmaCfg.prodSckId = CY_U3P_PIB_SOCKET_0;
dmaCfg.consSckId = CY_U3P_UIB_SOCKET_CONS_1
dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
dmaCfg.prodHeader = 16; // Multiple of 16 required
dmaCfg.notification = 0xffff; // I'll take anything
dmaCfg.cb = funcCallback;
...
CyU3PDmaChannelCreate(&handle, CY_U3P_DMA_TYPE_MANUAL, &dmaCfg);
CyU3PDmaChannelSetXfer(&handle, 80);

In my callback, I get a CY_U3P_DMA_CB_PROD_EVENT:

CyU3PDmaChannelGetBuffer(&handle, &bufp, CYU3P_NO_WAIT);
CyU3PMemCopy(bufp.buffer - 16, &header, 16);
CyU3PDmaChannelCommitBuffer(&handle, bufp.count + 16, 0);
CyU3PEventSet(&glEvents, PROD_COMPLETE_EVENT, CYU3P_EVENT_OR);

Then, in my event handler, I try to queue up my next packet by waiting for the transfer to complete. 

CyU3PDmaChannelWaitForCompletion(&handle, 1000);

But it never completes. The state is ACTIVE forever. 

Is there a better way to handle multiple manual transfers? I'm sure I could completely reset & abort, but that seems like overkill.

Thanks!

0 Likes
1 Solution
mcn
Level 2
Level 2
10 replies posted 5 questions asked 10 sign-ins

For #3: Try not calling setXfer in the XFER_CPLT callback and pend it using an event. You will get a PROD, XFER_CPLT, PROD. If you blindly commit the second PROD, you get the NOT_STARTED error. I think this is expected given what we've found out about the DMA engine. setXfer() does not limit the producer, but rather the consumer. As a result, the XFER_CPLT is saying the consumer has received everything it should, but the producer is still filling buffers. Therefore, it's possible to get a PROD after the XFER_CPLT.

You've helped immensely figure this out. Key takeaways:

  1. SetXfer() sets the number of bytes/buffers that can be consumed, not the number of buffers which will be produced. The DMA engine will produce buffers until it runs out, no matter what size the SetXfer is.
  2. dmaCfg.count = 1 ensures only a single buffer is produced for each Commit().
  3. The DMA engine can deliver a PROD after a XFER_COMPLETE.
  4. In byte mode, setXfer() sets the total bytes to be consumed. The producer will grab this many bytes minus prodHeader.

I'm going to mark this as the solution for quick reference to future generations. If this keeps you from getting support credit or something, let me know and I'll change it. Thanks for your help!

 

View solution in original post

0 Likes
8 Replies