4 Replies Latest reply on Aug 31, 2018 1:21 AM by wu.zhijian_1557526

    End point DMA channel stuck on volume data transfer


      Hi, there


      I have a file stored in SPI flash ROM, and need to transfer to the host after boot up.

      I'm using two DMA channels working with end points. One is for receiving host command, the other is for data out transfer.

      After command come in, the DMA callback will explain the command, read data from SPI flash and do the steps below:

           CyU3PDmaChannelGetBuffer(&DCITxChHandle, &txBuffer, 0);

           CyU3PMemCopy(txBuffer.buffer, (uint8_t*)TxBuffer, tx_length);

           CyU3PDmaChannelCommitBuffer (&DCITxChHandle, tx_length, 0);


      Now my situation is if I don't manipulate the SPI module in the callback, just transfer any data in the ram, the firmware works fine. if I want to write the flash in the callback function, no matter how many data should write to the flash, it still works fine.


      But when I read data from flash and send to the host, it will stuck after certain packages. It looks like that when stuck begin, first command had been received, but the commit buffer stay in somewhere din't been sent out, and then the second command. When the third command came in, the first stuck buffer begin to really sent out, and then the 4th command came in, the second commit buffer go out, and so on.


      I tried different DMA size and different DMA count, the symptoms are the same. except that large DMA size and the large count looks could transfer more correct echo data.


      In callback function, I manipulate the SPI like this


      if (!(aStatus & SPI_ENABLE)) // SPI Module disabled


           aStatus &= ~DQ32_ENABLE;

           aStatus |= SPI_ENABLE;




      status = hwspi_flash_read (FlashAddress, data, data_length);


      CyU3PReturnStatus_t hwspi_flash_read (uint32_t addr, uint8_t* buf, uint16_t len)


          uint8_t  Command[4];

          CyU3PReturnStatus_t status = CY_U3P_SUCCESS;


          if (len == 0) return CY_U3P_SUCCESS;



          Command[0] = 0x03; // read command

          Command[1] = (addr >> 16) & 0xFF;

          Command[2] = (addr >>  8) & 0xFF;

          Command[3] =  addr        & 0xFF;


          CyU3PSpiSetSsnLine (CyFalse);

          status = CyU3PSpiTransmitWords (Command, 4);

          if (status == CY_U3P_SUCCESS)

              status = CyU3PSpiReceiveWords (buf, len); // read data

          CyU3PSpiSetSsnLine (CyTrue);


          return status;



      I trid using Events in callback and  Thread to handle command explanation, so that all the procedure calling will out of the call. Don't fix the problem.


      Any suggesting will welcome.

        • 1. Re: End point DMA channel stuck on volume data transfer



          1. Who is the producer and consumer for channel handle DCITxChHandle?

          2. In which endpoint does the Host send commands to read the data? Are you using vendor commands or Other endpoints?

          3. Where is TxBuffer getting filled?


          My assumptions of your implementation:

          - Producer for DCITxChHandle channel is CPU and consumer is USB.

          - Producer for other channel (whose channel handle is not mentioned in your description) is USB and the consumer is CPU. Let me name this handle as DCIRxChHandle

          - When you get a callback for DCIRxChHandle, you parse the command and call hwspi_flash_read() API which fills TxBuffer.


          If above assumption is true, then you should be doing getBuffer, memcopy and commit buffer on the channel handle DCITxChHandle.


          So, to be clear, please post the two DMA channel descriptions(producer, consumer, callback function registered) and also separately post in which callback you are doing what.




          • 2. Re: End point DMA channel stuck on volume data transfer

            Hi, Hemanth

            Your assumptions are just what I have done. Here I post what you want.


            uint16_t U3V_InitControl(void)


            uint32_t Status;

                uint16_t size = 512;

                CyU3PEpConfig_t epCfg;

                CyU3PDmaChannelConfig_t dmaCfg;


                uint8_t Message[USBUART_DMA_BUF_SIZE];


                /* Based on the Bus speed configure the EP packet size */

                switch (CyU3PUsbGetSpeed())


                case CY_U3P_FULL_SPEED:

                    size = 64;



                case  CY_U3P_SUPER_SPEED:

                    /* Turning low power mode off to avoid USB transfer delays. */

                    CyU3PUsbLPMDisable ();

                    size = 1024;




                    size = 512;




                CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg));


                epCfg.enable = CyTrue;

                epCfg.epType = CY_U3P_USB_EP_BULK;

                epCfg.burstLen = 1;

                epCfg.streams = 0;

                epCfg.pcktSize = size;


                Status = CyU3PSetEpConfig(U3V_CONTROL_EP_OUT, &epCfg); // Consumer EP configuration

                CyU3PDebugStringPrint (Message, USBUART_DMA_BUF_SIZE, "CyU3PSetEpConfig U3V_CONTROL_EP_OUT:%x\n", Status);



                Status = CyU3PSetEpConfig(U3V_CONTROL_EP_IN, &epCfg);  // Producer EP configuration

                CyU3PDebugStringPrint (Message, USBUART_DMA_BUF_SIZE, "CyU3PSetEpConfig U3V_CONTROL_EP_IN:%x\n", Status);



                /* Create a Tx DMA_MANUAL_OUT channel between CPU producer socket and USB consumer socket      */


                CyU3PMemSet ((uint8_t *)&dmaCfg, 0, sizeof (dmaCfg));


                dmaCfg.size           = size;

                dmaCfg.count         = DCI_DMA_BUF_COUNT;

                dmaCfg.prodSckId  = CY_U3P_CPU_SOCKET_PROD;

                dmaCfg.consSckId  = CY_U3P_UIB_SOCKET_CONS_0 | U3V_CONTROL_EP_OUT;

                dmaCfg.dmaMode  = CY_U3P_DMA_MODE_BYTE;

                dmaCfg.notification = 0;

                dmaCfg.cb           = NULL;


                Status = CyU3PDmaChannelCreate  (&DCITxChHandle, CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaCfg);

                CyU3PDebugStringPrint (Message, USBUART_DMA_BUF_SIZE, "CyU3PDmaChannelCreate DCITxChHandle:%x\n", Status);



                CyU3PMemSet ((uint8_t *)&dmaCfg, 0, sizeof (dmaCfg));


                /* Create a Rx DMA_MANUAL_IN channel between USB producer socket and CPU consumer socket */

                dmaCfg.size         = size;

                dmaCfg.count        = DCI_DMA_BUF_COUNT;

                dmaCfg.prodSckId    = CY_U3P_UIB_SOCKET_PROD_0 | U3V_CONTROL_EP_OUT;

                dmaCfg.consSckId    = CY_U3P_CPU_SOCKET_CONS;

                dmaCfg.dmaMode      = CY_U3P_DMA_MODE_BYTE;

                dmaCfg.notification = CY_U3P_DMA_CB_PROD_EVENT;

                dmaCfg.cb           = U3V_DCIRxCallback;


                Status = CyU3PDmaChannelCreate (&DCIRxChHandle, CY_U3P_DMA_TYPE_MANUAL_IN, &dmaCfg);

                CyU3PDebugStringPrint (Message, USBUART_DMA_BUF_SIZE, "CyU3PDmaChannelCreate DCIRxChHandle:%x\n", Status);



                /* Flush the Endpoint memory */




                Status = CyU3PDmaChannelSetXfer (&DCITxChHandle, DCI_DMA_BUF_SIZE);

                CyU3PDebugStringPrint (Message, USBUART_DMA_BUF_SIZE, "CyU3PDmaChannelSetXfer DCITxChHandle:%x\n", Status);



                Status = CyU3PDmaChannelSetXfer (&DCIRxChHandle, DCI_DMA_BUF_SIZE);

                CyU3PDebugStringPrint (Message, USBUART_DMA_BUF_SIZE, "CyU3PDmaChannelSetXfer DCIRxChHandle:%x\n", Status);



                return CyFalse;



            void U3V_DCIRxCallback(

                    CyU3PDmaChannel   *chHandle, /* Handle to the DMA channel. */

                    CyU3PDmaCbType_t   type,     /* Callback type.             */

                    CyU3PDmaCBInput_t *input)    /* Callback status.           */


                U3V_CCD   *ptCCD;

                U3V_ACK   ACK_data;



                if (type == CY_U3P_DMA_CB_PROD_EVENT)


                ptCCD = (U3V_CCD *) input->buffer_p.buffer;



                if (ptCCD->command_id == READMEM_CMD || ptCCD->command_id == WRITEMEM_CMD)


                DCI_PROCESS_CMD = CyTrue;

               //CyU3PEventSet (&glU3VEvent, U3V_DCI_NEW_COMMAND, CYU3P_EVENT_OR);











            void Command_Entry (void)


                CyU3PDmaBuffer_t rxBuffer;

                CyU3PDmaBuffer_t txBuffer;

                READMEM_CMD_t    *ptRD_CMD;

                READMEM_ACK_t    *ptRD_ACK;

                WRITEMEM_CMD_t   *ptWR_CMD;

                WRITEMEM_ACK_t   *ptWR_ACK;

                U3V_ACK          *ptEV_ACK;

                uint16_t         tx_length;



            //while (1)


            if (CyU3PDmaChannelGetBuffer(&DCIRxChHandle, &rxBuffer, 0)!=CY_U3P_SUCCESS)




            ptRD_CMD = (READMEM_CMD_t *)  rxBuffer.buffer;

            ptWR_CMD = (WRITEMEM_CMD_t *) rxBuffer.buffer;

            ptEV_ACK = (U3V_ACK *) rxBuffer.buffer;



            if (ptRD_CMD->CCD.command_id == READMEM_CMD)


            ptRD_ACK = (READMEM_ACK_t *)TxBuffer;

            ptRD_ACK->ACK.Prefix = U3VC;

            ptRD_ACK->ACK.command_id = READMEM_ACK;

            ptRD_ACK->ACK.request_id = ptRD_CMD->CCD.request_id;

            ptRD_ACK->ACK.length = ptRD_CMD->read_length;

            ptRD_ACK->ACK.status_code.Word = U3V_ReadMemory(ptRD_CMD->register_address.DWord, &ptRD_ACK->data, ptRD_ACK->ACK.length);



            DCI_PROCESS_CMD = CyFalse;

            tx_length = sizeof(U3V_ACK) + ptRD_CMD->read_length;




            if (ptWR_CMD->CCD.command_id == WRITEMEM_CMD)


            ptWR_ACK = (WRITEMEM_ACK_t *)TxBuffer;

            ptWR_ACK->ACK.Prefix = U3VC;

            ptWR_ACK->ACK.command_id = WRITEMEM_ACK;

            ptWR_ACK->ACK.request_id = ptWR_CMD->CCD.request_id;

            ptWR_ACK->ACK.length = 4;

            ptWR_ACK->ACK.status_code.Word = U3V_WriteMemory(ptWR_CMD->register_address, &ptWR_CMD->data, ptWR_CMD->CCD.length - 8, &ptWR_ACK->length_written);

            ptWR_ACK->reserved = CyU3PGetTime();



            DCI_PROCESS_CMD = CyFalse;

            tx_length = sizeof(U3V_ACK) + 4;




            if (ptEV_ACK->command_id == EVENT_ACK)


            // TODO: clean event status




            if (tx_length != 0)


            txBuffer.size  = DCI_DMA_BUF_SIZE;

            txBuffer.count = tx_length;

            CyU3PDmaChannelGetBuffer(&DCITxChHandle, &txBuffer, 0);

            CyU3PMemCopy(txBuffer.buffer, (uint8_t*)TxBuffer, tx_length);



            //txBuffer.status = CY_U3P_DMA_BUFFER_OCCUPIED|CY_U3P_DMA_BUFFER_EOP;

            CyU3PDmaChannelCommitBuffer (&DCITxChHandle, tx_length, CY_U3P_DMA_BUFFER_OCCUPIED|CY_U3P_DMA_BUFFER_EOP);


            CyU3PDmaChannelDiscardBuffer(&DCIRxChHandle); // drops the content of the active buffer




            I manipulate SPI module in U3V_WriteMemory/U3V_ReadMemory.

            • 3. Re: End point DMA channel stuck on volume data transfer



              Please share the FW source files to srinath.s@cypress.com so that we could try it out on the development boards.


              Best regards,

              Srinath S

              • 4. Re: End point DMA channel stuck on volume data transfer

                HI, there


                Looks the problem is caused of that the dma stop sending out data. the SPI interface always works fine.

                I added the codes into U3V_DCI_Callback(), which the callback of the DMA channel, like the red parts.

                Just before sending our the data. It works fine.


                void U3V_DCI_Callback(

                CyU3PDmaChannel  *chHandle, /* Handle to the DMA channel. */

                CyU3PDmaCbType_t  type,    /* Callback type. */

                CyU3PDmaCBInput_t *input)    /* Callback status.          */


                … …


                    if (dmaInfo.count > 0) {

                dmaInfo.buffer = DCITxBuffer;

                dmaInfo.size  = sbrmBlock->Maximum_Acknowledge_Transfer_Length;

                dmaInfo.status = 0;


                CyU3PUsbLPMDisable(); // Looks important, << WU: The only line I added


                while (CyU3PDmaChannelGetBuffer(&DCITxChHandle, &txBuffer, 0) != CY_U3P_SUCCESS);

                CyU3PMemCopy(txBuffer.buffer, dmaInfo.buffer, dmaInfo.count);

                CyU3PDmaChannelCommitBuffer(&DCITxChHandle, dmaInfo.count, 0);