11 Replies Latest reply on Dec 29, 2017 1:26 PM by lohr85_1580361

    Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN

    lohr85_1580361

      I'm getting an unusual situation with my GPIF bus running as basically a raw dump of a 16-bit wide bus at 100 MHz going into my isochronous USB buffer.

       

      The flag CYU3P_PIB_ERR_THR0_WR_OVERRUN is called ALL the time.  It "looks" like all my data is getting through, though.  What would cause this to trigger continuously?

       

      Can I ignore the flag?

        • 1. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
          mddd

          What is your DMA buffer size? How much amount of data are you streaming?

           

          CYU3P_PIB_ERR_THR0_WR_OVERRUN error means you are trying to write more bytes than the DMA Buffer Size.

          • 2. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
            lohr85_1580361

            I was able to grasp that's what might be happening but the data rate seems ok, and it is hit exactly every single block that's transferred.

             

            I've set up my buffers in this way on the USB end

            #define CY_FX_ISOSRC_DMA_TX_SIZE        (0)             /* DMA transfer size is set to infinite */
            #define CY_FX_ISOSRC_THREAD_STACK       (0x1000)        /* Application thread stack size */
            #define CY_FX_ISOSRC_THREAD_PRIORITY    (8)             /* Application thread priority */
            #define CY_FX_EP_CONSUMER               0x83    /* EP 3 IN */
            #define CY_FX_EP_CONSUMER_SOCKET        CY_U3P_UIB_SOCKET_CONS_3    /* Socket 3 is consumer */

            #define CY_FX_ISOSRC_DMA_BUF_COUNT      (3)     /* Number of buffers in the DMA channel. (Now applied to GPIF) */
            #define CY_FX_ISO_PKTS                  (2)     /* Number of bursts per microframe. */
            #define CY_FX_ISO_BURST                 (16)    /* Number of packets per burst. This seems to "actually" be 15. */

            //Below here is from the fast_gpif2 stuff based on SRAMMASTER
            #define CY_FX_PRODUCER_PPORT_SOCKET             (CY_U3P_PIB_SOCKET_0)           /* GPIF Socket 0 is producer. */

             

            WRT the USB Section, here's what I have going...

             

                /* First identify the usb speed. Once that is identified,
                 * create a DMA channel and start the transfer on this. */

                /* Based on the Bus Speed configure the endpoint packet size */
                switch (usbSpeed)
                {
                    case CY_U3P_FULL_SPEED:
                        size    = 64;
                        isoPkts = 1;                /* One packet per frame. */
                        break;

                    case CY_U3P_HIGH_SPEED:
                        size    = 1024;
                        isoPkts = CY_FX_ISO_PKTS;   /* CY_FX_ISO_PKTS packets per microframe. */
                        break;

                    case  CY_U3P_SUPER_SPEED:
                        size = 1024;
                        if (glAltIntf == 1)
                            isoPkts = 1;                    /* One burst per microframe. */
                        else
                            isoPkts = CY_FX_ISO_PKTS;       /* CY_FX_ISO_PKTS bursts per microframe. */
                        break;

                    default:
                        CyU3PDebugPrint (4, "Error! Invalid USB speed.\n");
                        CyFxAppErrorHandler (CY_U3P_ERROR_FAILURE);
                        break;
                }

                CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg));
                epCfg.enable   = CyTrue;
                epCfg.epType   = CY_U3P_USB_EP_ISO;
                epCfg.burstLen = (usbSpeed == CY_U3P_SUPER_SPEED) ? (CY_FX_ISO_BURST) : 1;
                epCfg.streams  = 0;
                epCfg.pcktSize = size;
                epCfg.isoPkts  = isoPkts;

                /* Consumer endpoint configuration */
                apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_CONSUMER, &epCfg);
                if (apiRetStatus != CY_U3P_SUCCESS)
                {
                    CyU3PDebugPrint (4, "CyU3PSetEpConfig failed, Error code = %d\r\n", apiRetStatus);
                    CyFxAppErrorHandler (apiRetStatus);
                }

                /* Flush the endpoint memory */
                CyU3PUsbFlushEp(CY_FX_EP_CONSUMER);

             

             

            I've set up my DMA in this way on the other end in the following way. Changing most of these values never causes the problem to go away.

             

                dmaCfg.size           = 32768-2048;//Seems to work here and 32768, but smaller values seem to drop data, a lot.
                dmaCfg.count          = CY_FX_ISOSRC_DMA_BUF_COUNT;
                dmaCfg.prodSckId      = CY_FX_PRODUCER_PPORT_SOCKET;
                dmaCfg.consSckId      = CY_FX_EP_CONSUMER_SOCKET;
                dmaCfg.dmaMode        = CY_U3P_DMA_MODE_BYTE; //Is this right?  Changing it doesn't seem to effect anything.
                dmaCfg.notification   = 0xffffff; //CY_U3P_DMA_CB_CONS_EVENT;
                dmaCfg.cb             = DMACallback ; //This never seems to be called.
                dmaCfg.prodHeader     = 0;
                dmaCfg.prodFooter     = 0;
                dmaCfg.consHeader     = 0;
                dmaCfg.prodAvailCount = 0;

                CyU3PDebugPrint (4, "DMA Config Size = %d\r\n", dmaCfg.size);

                //apiRetStatus = CyU3PDmaChannelCreate (&glChHandleIsoSrc, CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaCfg); XXX CNL
                apiRetStatus = CyU3PDmaChannelCreate (&glChHandleIsoSrc, CY_U3P_DMA_TYPE_AUTO, &dmaCfg);

                if (apiRetStatus != CY_U3P_SUCCESS)
                {
                    CyU3PDebugPrint (4, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
                    CyFxAppErrorHandler(apiRetStatus);
                }

                apiRetStatus = CyU3PDmaChannelSetXfer (&glChHandleIsoSrc, CY_FX_ISOSRC_DMA_TX_SIZE);
                if (apiRetStatus != CY_U3P_SUCCESS)
                {
                    CyU3PDebugPrint (4, "CyU3PDmaChannelSetXfer Failed, Error code = %d\n", apiRetStatus);
                    CyFxAppErrorHandler(apiRetStatus);
                }

            • 3. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
              mddd

              The configuration looks fine. Once the DMA buffer is filled completely (32k - 2k bytes), it takes few microseconds before the next buffer is available. You need to wait till the next buffer is available and then start sampling. Then this problem of missing data will go away.

              1 of 1 people found this helpful
              • 4. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
                lohr85_1580361

                How would that be possible? Data would still be streaming from the GPIF bus.  Would I have to hook it in such a way to copy the data to the CPU memory then back out to the USB?  Surely there is some configuration to tell the GPIF bus not to push the next packet?

                • 5. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
                  mddd

                  You can look for the DMA_TH_RDY_0 signal in your state machine. If low,, it means the buffer is not available. What is the data source? Is there any external peripheral connected to the GPIF bus?

                  • 6. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
                    lohr85_1580361

                    It's an ADC.  I can't really wait since it doesn't have a buffer, itself and I'm sampling at bus-speed...  How is this normally handled if you need to read out a large stream with a DMA seam somewhere in the middle of it? You can't just /wait/ on some peripherals.  (For example, if you are reading a large frame out of a video sensor where the frame is larger than a single DMA buffer)

                     

                    *EDIT* Perhaps multiple pipes?

                    • 7. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
                      mddd

                      Yes thats correct. You can use multiple pipes in such cases where the external peripheral does not support flow control.

                       

                      You can create a MultiChannel Dma Channel where you will have 2 P-port sockets as Producers and only one consumer.

                      In the GPIF state machine you can ping-pong between the 2 sockets.

                       

                      Once the socket-0 is filled with (32k-2k) bytes, start sampling the data into socket-1 and so on.

                      • 8. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
                        lohr85_1580361

                        It's 6 AM locally and I've been at this all night.  Must sleep.  But, so I can sleep well, just confirming.  Using the ping-pong mechanism (not sure still if it would rapidly ping pong or only when it needs to... Or does it just ping pong for a pre-canned number of bytes) it should be possible to sustain feeding the USB endpoint consumer continuously at 100 MHz?

                         

                        Also EDIT: Do I need to do 32k-2k, or should it be 32k only?

                        • 9. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
                          mddd

                          You can perform ping-pong based on your needs. The buffer size can be 32K too. The USB bandwidth will not be problem at all.

                           

                          The ping-pong method just eliminates the buffer switching delay that is encountered when using a single socket.

                          • 10. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
                            lohr85_1580361

                            I'm sure I'm doing something foolish here, seems to be getting more data with what I think is a ping pong, but, I'm not really sure about some of the nomenclature as I just started messing with this a few days ago.

                             

                            I've got two states..

                            State 1: IN_DATA (Sink=Socket, Thread Number=Thread0); --> !DMA_RDY_TH0 (transition to two)

                            State 2: IN_DATA (Sink=Socket, Thread Number=Thread1); --> !DMA_RDY_TH1 (transition to one)

                             

                            And it looks like I have my multi-dma thing set up right as it is getting data from both sources.

                             

                            Still getting a bunch of CYU3P_PIB_ERR_THR1_WR_OVERRUN/THR0 overruns, though.

                             

                            Also, thank you very much for your help!

                            • 11. Re: Constant CYU3P_PIB_ERR_THR0_WR_OVERRUN
                              lohr85_1580361

                              I've spent a very long time with this one, now.  The sources are ping-ponging but the overflow (both of them) flags are still being set.  I have a workable solution but it feels VERY wrong.

                               

                              I've tried setting up watermarks for the DMA to try to catch it before the end, in case there is some sort of latency between adding the byte and the flag DMA_RDY_TH0/DMA_RDY_TH1 being set... But it seems that the watermark stuff just adds more to to the lost bytes in most cases unless I configure the DMA as such, then it seems about the same?

                                  CyU3PGpifSocketConfigure(0,CY_U3P_PIB_SOCKET_0,2,CyTrue,1);
                                  CyU3PGpifSocketConfigure(1,CY_U3P_PIB_SOCKET_1,2,CyTrue,1);

                              Though, I have seen references to needing to expose the watermark.  Not sure if that's needed to use it for flags like DMA_WM_TH0, DMA_WM_TH1.

                               

                               

                              My solution is as such:

                                  CyU3PGpifSocketConfigure(0,CY_U3P_PIB_SOCKET_0,1,CyTrue,1);     CyU3PGpifSocketConfigure(1,CY_U3P_PIB_SOCKET_1,1,CyTrue,1);

                              Then, in the GPIF designer, I have one state that fills data into thread 0 until DMA_WM_TH0 is flagged, then I have a new state that reads exactly one more word. Then, I start filling thread 1's socket, until DMA_WM_TH1 is flagged, read one more word and ping back to the first.  I am worried this will have other problematic side-effects.  Is this the correct way to do it?