Need buffer full to DMA to USB EP IN?

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

cross mob
Anonymous
Not applicable

 Hi,

   

I am trying hard to understand the difference in the behavior between the bulk auto demo and one app where I set an auto dma between the uart rx and USB EP IN.

   

In the bulk auto demo, the bytes will be looped back onto the EP IN, no mather how few of them. No need to fill the DMA buffer before hitting the transfer data-IN button. There will be as many as sent, no padding (looked with some analyzer).

   

In the example I build, there is no way to get any bytes out of the EP before the DMA buffer is full. This seems to be the normal behavior when reading the doc, but I can not explain why the bulk loopback demo "seems" to be different.

   

My application is a simple DMA AUTO channel between UART (producer) and EP1 (consumer), 16-byte twin buffers (the smallest), infinite transfer, etc.

   

Any rational explanation for this behavior?

   

Thx for any help,

   

Martin

0 Likes
4 Replies
Anonymous
Not applicable

Hi mgaron,

   

may be I can try to help you with more detailed code snippet informations about initializing the dma and the endpoints. The uart initialization would be also interesting.

   

regards,

   

lumpi

0 Likes
Anonymous
Not applicable

 Hi Lumpi and thanks for offering your help.

   

 

   

Please see the code below: In short, 1 bulk EP out, 1 bulk EP in. (It's really the bulk loopback auto demo rigged to a physical loopback on UART)

   

AUTO DMA is set between EP 1 out and UART tx. This one works fine.

   

AUTO DMA is set between UART Rx and EP1 in. No transfer unless the DMA buffer is full.

   

[testing of return code removed for clarity]

   

 

   
              CyU3PMemSet((uint8_t *)&lUARTCfg, 0, sizeof(lUARTCfg));   
   
       lUARTCfg.baudRate = CY_U3P_UART_BAUDRATE_115200;   
   
       lUARTCfg.stopBit  = CY_U3P_UART_ONE_STOP_BIT;   
   
       lUARTCfg.parity   = CY_U3P_UART_NO_PARITY;   
   
       lUARTCfg.txEnable = CyTrue;   
   
       lUARTCfg.rxEnable = CyTrue;   
   
       lUARTCfg.flowCtrl = CyFalse;   
   
       lUARTCfg.isDma    = CyTrue;   
   
       lRetStatus = CyU3PUartInit();   
   
        
   
       lRetStatus = CyU3PUartSetConfig(&lUARTCfg, (CyU3PUartIntrCb_t)0);   
   
    
        lRetStatus = CyU3PUartTxSetBlockXfer(0xFFFFFFFFU);    
   
   
    
        lRetStatus = CyU3PUartRxSetBlockXfer(0xFFFFFFFFU);    
    
     ...    
    
     
         lSize = 512;     
     
         CyU3PMemSet((uint8_t *)&lEPCfg, 0, sizeof(lEPCfg));     
     
         lEPCfg.enable = CyTrue;     
     
         lEPCfg.epType = CY_U3P_USB_EP_BULK;     
     
         lEPCfg.burstLen = 1;     
     
         lEPCfg.streams = 0;     
     
         lEPCfg.pcktSize = lSize;     
     
      
     
     
         /* Endpoints configuration. */     
     
         lRetStatus = CyU3PSetEpConfig(CY_FX_EP_PRODUCER, &lEPCfg);     
     
         lRetStatus = CyU3PSetEpConfig(CY_FX_EP_CONSUMER, &lEPCfg);     
     
            
     
         /* Create a DMA Auto Channel between two sockets of the U port.     
     
          * DMA size is set based on the USB speed.     
     
          */     
     
         lDMACfg.size = lSize;     
     
         lDMACfg.count = PT_FX3_U3V_DMA_BUF_CNT;     
     
         lDMACfg.prodSckId = CY_FX_EP_PRODUCER_SOCKET;     
     
         lDMACfg.consSckId = CY_U3P_LPP_SOCKET_UART_CONS;     
     
         lDMACfg.dmaMode = CY_U3P_DMA_MODE_BYTE;     
     
         lDMACfg.notification = 0;     
     
         lDMACfg.cb = (CyU3PDmaCallback_t)0;     
     
         lDMACfg.prodHeader = 0;     
     
         lDMACfg.prodFooter = 0;     
     
         lDMACfg.consHeader = 0;     
     
         lDMACfg.prodAvailCount = 0;     
     
      
     
     
         lRetStatus = CyU3PDmaChannelCreate(&sDMAChHandle[0],     
     
           CY_U3P_DMA_TYPE_AUTO,     
     
           &lDMACfg);     
     
         /* Create a DMA Auto Channel between two sockets of the U port.     
     
          * DMA size is set based on the USB speed.     
     
          */     
     
         lDMACfg.size = 16; //lSize;     
     
         lDMACfg.count = PT_FX3_U3V_DMA_BUF_CNT;     
     
         lDMACfg.prodSckId = CY_U3P_LPP_SOCKET_UART_PROD;     
     
         lDMACfg.consSckId = CY_FX_EP_CONSUMER_SOCKET;     
     
         lRetStatus = CyU3PDmaChannelCreate(&sDMAChHandle[1],     
     
           CY_U3P_DMA_TYPE_AUTO,     
     
           &lDMACfg);     
     
         /* Flush the Endpoint memory. */     
     
         CyU3PUsbFlushEp(CY_FX_EP_PRODUCER);     
     
         CyU3PUsbFlushEp(CY_FX_EP_CONSUMER);     
     
      
     
     
         /* Set DMA Channel transfer size. */     
     
         lRetStatus = CyU3PDmaChannelSetXfer(&sDMAChHandle[0], 0);     
     
         lRetStatus = CyU3PDmaChannelSetXfer(&sDMAChHandle[1], 0);     
    
   
   
        
   
        
   
    So everything looks fine when sending small packets on the endpoint. I see as few chars on the terminal as was sent from the control center.   
   
        
   
    On the opposite direction, I need to send      lDMACfg.size bytes for them to be able to get anything on the IN endpoint (Otherwise I get error: BULK IN transfer failed with Error Code:997)   
   
        
   
    Please let me know if you require further details.   
   
        
   
    Martin   
   
        
   

 

   
        
0 Likes
Anonymous
Not applicable

Hi,

   

I am not sure but I think I have heard about DMA receive data has to be a multiple of 4 bytes till DMA events occur. May be you try using a manual DMA buffer and then check these events. The dma buffer size of an USB endpoint should be 64 bytes for full speed, 512 bytes for high speed and 1024 bytes for super speed. You are using 16 bytes in the receive case. Have you changed this?

   

An other solution would be using UART in byte by byte mode instead of DMA mode. And then setup your USB endpoints as manual channels with....

   

    CY_U3P_CPU_SOCKET_CONS = 0x3F00,            /* Socket through which the FX3 CPU receives data. */
    CY_U3P_CPU_SOCKET_PROD                      /* Socket through which the FX3 CPU produces data. */
 

   

that can work, but first try the UartReveice function if it returns after receiving expected byte count. If that also not works, it is possible that there is a restriction in the FX3 that UartReceive won't work if it reveices lesser than e. g. 4 or 16 bytes. That can be may be post a question with respect to the UartReceive and restrictions.

   

regards

   

lumpi

0 Likes
Anonymous
Not applicable

Hi,

   

in the FX3 SDK release notes is a chapter with known issues and solutions with a descritpion to your issue...

   

 

   

7. Any UART/I2C/SPI read transfers in DMA mode that do not fill up the entire DMA buffer will
not trigger a DMA callback or a transfer complete event. The application needs to check for
transfer completion based on the UART/I2C/SPI events and then invoke the
CyU3PDmaChannelSetWrapUp() API on the DMA channel.

   

regards

   

lumpi

0 Likes