cancel
Showing results for 
Search instead for 
Did you mean: 

USB Superspeed Peripherals

cnlohr
New Contributor II

I'm working with the FX3 right now and I'm just trying to test continuous GPIF capture.  But, I'm running into issues that no matter how slowly I run it still seems to corrupt data when handing of threads on the GPIF bus.

Originally I started with watermarks on the threads and ping ponged based on the water marks, but, after reading through 124206 "Designing a GPIF II Master Interface" I switched to using DATA_COUNTs to handle ping-ponging between threads.

Currently I'm clocking it down at 50 MHz, and I'm capturing 16-bits at a time from the bus.   I can trigger the bus capture and all works well.  I can also see it ping-ponging between each thread at the exact correct time using an external scope with the correct numbers of samples read. 

The only issue is when I look at my USB data stream coming from the FX3, the data has missing(?) or maybe (extra?) frames between each handoff between threads.  It's not an insignificant amount, either.  If it was just a few microseconds all would be well, but it's way wrong.

Here is how I'm currently setting up my state machine:

cnlohr_0-1614042391543.png

cnlohr_2-1614042763085.png

The reason I think this is the issue, and not USB is because if I adjust the LD_DATA_COUNT, then the corruption happens at that interval.  Additionally, I have tried increasing clock rate to 100MHz on the GPIF bus, and I see the same issues. That said, here is my USB descriptor that I'm using:

cnlohr_1-1614042465037.png

My DMA Is set up as follows:

dmaCfg.size = 32768;//Seems to work here and 16384, but smaller values seem to drop data, a lot. Event at 16384 corruption happens.
dmaCfg.count = CY_FX_ISOSRC_DMA_BUF_COUNT; //3 - seems to crash if anything other than 3.
dmaCfg.prodSckId = CY_FX_PRODUCER_PPORT_SOCKET;
dmaCfg.consSckId = CY_FX_EP_CONSUMER_SOCKET;
dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
dmaCfg.notification = 0; //CY_U3P_DMA_CB_CONS_EVENT; (Currently disabled)
dmaCfg.cb = DMACallback ; //This never seems to be called. Could it need CY_U3P_DMA_TYPE_AUTO_SIGNAL?
dmaCfg.prodHeader = 0;
dmaCfg.prodFooter = 0;
dmaCfg.consHeader = 0;
dmaCfg.prodAvailCount = 0;

What tactic is best for continuous capture?

0 Likes
1 Solution
cnlohr
New Contributor II

Well, as it turns out my issue was on the PC end.  It turns out it was interpreting the first n subframes of the iso packet as containing the data, instead of going through the iso packet and finding which subframes were populated with data.  It was all on the PC side.

View solution in original post

0 Likes
8 Replies
cnlohr
New Contributor II

CORRECTION: This is my DMA configuration code, I copied that incorrectly.

 

CyU3PDmaMultiChannelConfig_t dmaCfg;
memset( (void*)&dmaCfg, 0, sizeof( dmaCfg ) );
dmaCfg.size = 32768;//Seems to work here and 16384, but smaller values seem to drop data, a lot.
dmaCfg.count = CY_FX_ISOSRC_DMA_BUF_COUNT;
dmaCfg.prodSckId[0] = CY_U3P_PIB_SOCKET_0;
dmaCfg.prodSckId[1] = CY_U3P_PIB_SOCKET_1;
dmaCfg.validSckCount = 2;
dmaCfg.consSckId[0] = 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 = CY_U3P_DMA_CB_PROD_EVENT; //CY_U3P_DMA_CB_CONS_EVENT;
dmaCfg.cb = DMACallback ; //This never seems to be called. Could it need CY_U3P_DMA_TYPE_AUTO_SIGNAL?
dmaCfg.prodHeader = 0;
dmaCfg.prodFooter = 0;
dmaCfg.consHeader = 0;
dmaCfg.prodAvailCount = 0;


apiRetStatus = CyU3PDmaMultiChannelCreate (&glChHandleIsoSrc, CY_U3P_DMA_TYPE_AUTO_MANY_TO_ONE, &dmaCfg);

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

0 Likes
Hemanth
Moderator
Moderator

Hi,

About endpoint and dma channel:

Please let me know the epCfg structure used for CyU3PSetEpConfig() for ISOC endpoint.

What are the values used for ISO_BURST, ISO_MAXPKT and ISO_PKTS?

Your DMA size (dmaCfg.size) should be ISO_BURST * ISO_MAXPKT * ISO_PKTS * optional_integer_multiplier?

You should also make sure that dmaCfg.size is multiple of 16 bytes.

About state machine:

1. You do not need state 6 and state 7; If you double click on the state, you will have a check box: 'repeat actions till next transition'. You can check this as you need to keep sampling data till counter is hit.

2. counter limit value of LD_DATA_COUNT should be (DMA_size_in_bytes/gpif_bus_width_in_bytes) - 1

If you make sure of above then there should not be any issue.

FYI: dmaCfg.cb can be NULL for AUTO channel.

Regards,

Hemanth
0 Likes
cnlohr
New Contributor II

Thank you for the quick reply. Using this setup, I am still getting corruption (transposed frames) every 32768 bytes.

Is MAXPKT equivalent to BURST?  This is my USB config

/* Super speed endpoint companion descriptor. */
0x06, /* Descriptor size */
CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */
(CY_FX_ISO_BURST - 1), /* Max no. of packets in a burst(0-15) - 0: burst 1 packet at a time */
0, /* Only one 16KB burst per micro-frame. */
0x00, (0x04 * CY_FX_ISO_BURST), /* Bytes per interval : 1024 * 1 * burst */


//epCfg Structure: CyU3PSetEpConfig

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);
}


#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. */

 

DMA, Now:

CyU3PDmaMultiChannelConfig_t dmaCfg;
memset( (void*)&dmaCfg, 0, sizeof( dmaCfg ) );
dmaCfg.size = 32768;//Seems to work here and 16384, but smaller values seem to drop data, a lot.
dmaCfg.count = CY_FX_ISOSRC_DMA_BUF_COUNT;
dmaCfg.prodSckId[0] = CY_U3P_PIB_SOCKET_0;
dmaCfg.prodSckId[1] = CY_U3P_PIB_SOCKET_1;
dmaCfg.validSckCount = 2;
dmaCfg.consSckId[0] = 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 = 0;//CY_U3P_DMA_CB_PROD_EVENT; //CY_U3P_DMA_CB_CONS_EVENT;
dmaCfg.cb = 0; //DMACallback; //This never seems to be called. Could it need CY_U3P_DMA_TYPE_AUTO_SIGNAL?
dmaCfg.prodHeader = 0;
dmaCfg.prodFooter = 0;
dmaCfg.consHeader = 0;
dmaCfg.prodAvailCount = 0;
apiRetStatus = CyU3PDmaMultiChannelCreate (&glChHandleIsoSrc, CY_U3P_DMA_TYPE_AUTO_MANY_TO_ONE, &dmaCfg);
CyU3PGpifSocketConfigure(0,CY_U3P_PIB_SOCKET_0,1,CyTrue,1);
CyU3PGpifSocketConfigure(1,CY_U3P_PIB_SOCKET_1,1,CyTrue,1);

 

0: Can I load thread 0 every clock cycle, ping over to thread 1 and back?

1: Is this more correct?

cnlohr_0-1614061173932.png

2: LD_DATA_COUNT = 32768 / 2 (16-bit) - 1 = 16383

0 Likes
cnlohr
New Contributor II

After doing more testing, by physically connecting the GPIO outputs to the inputs, I'm finding very little sense in which 32768-byte buffers show up where.  I.e. I would expect it to be ping-ponged, but I'm seeing random buffers A and B arbitrarily in time.  It looks like the boundary is good, but something about the buffer selection/packing is totally wrong.

0 Likes
cnlohr
New Contributor II

Even when simplifying everything, down to CY_FX_ISO_PKTS being 1, switching to 16384 bytes DMA / 16kB ISO Bursts when only going at 50 MHz.  It's still mangling the A/B buffers nonsensically. I've tried a variety of sizes in other ways and every situation seems to randomly interleave each DMA chunk.  What is the synchronization mechanism to make sure the DMAs are handled in order I.e. Thread0/Thread1/Thread0/Thread1/Thread0/Thread1 -> DMA A/DMA B/DMA C/DMA A/DMA B/DMA C -> USB Pipe Packet 0, 1, 2, 3, 4, 5, 6

0 Likes
cnlohr
New Contributor II

As this is looking more, and more like some sort of GPIF-II / DMA state machine error, I am going to post the rest of the code surrounding that.

This is my setup code:

    pibClock.clkDiv      = 8; //~400 MHz / 4.  or 400 / 8
    pibClock.clksrc=CY_U3P_SYS_CLK;
    pibClock.isHalfDiv   = CyFalse; //Adds 0.5 to divisor
    pibClock.isDllEnable = CyTrue;	//For async or master-mode
    apiRetStatus = CyU3PPibInit (CyTrue, &pibClock);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (CY_FX_DEBUG_PRIORITY, "P-port Initialization failed, Error Code=%d\r\n", apiRetStatus);
        CyFxAppErrorHandler (apiRetStatus);
    }

    /* Load the GPIF configuration for our project.. This loads the state machine for interfacing with SRAM */
    apiRetStatus = CyU3PGpifLoad (&CyFxGpifConfig);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (CY_FX_DEBUG_PRIORITY, "CyU3PGpifLoad failed, Error Code=%d\r\n", apiRetStatus);
        CyFxAppErrorHandler (apiRetStatus);
    }
    /* callback to see if there is any overflow of data on the GPIF II side*/
    //XXX Why is CYU3P_PIB_ERR_THR0_WR_OVERRUN getting called incessently?
    //CyU3PPibRegisterCallback (PibEventCallback, 0xfffb ); //Don't warn about CYU3P_PIB_ERR_THR0_WR_OVERRUN.  Seems to cause problems.
    CyU3PPibRegisterCallback (PibEventCallback, 0xffff ); //Well, this seems not to break it?
    //DataOverrunErrors


    /* Initialize the GPIO module. This is used to update the indicator LED. */
    gpioClock.fastClkDiv = 2;
    gpioClock.slowClkDiv = 0;
    gpioClock.simpleDiv  = CY_U3P_GPIO_SIMPLE_DIV_BY_2;
    gpioClock.clksrc=CY_U3P_SYS_CLK;
    gpioClock.halfDiv    = 0;

    apiRetStatus = CyU3PGpioInit (&gpioClock, NULL);
    if (apiRetStatus != 0)
    {
        /* Error Handling */
        CyU3PDebugPrint (CY_FX_DEBUG_PRIORITY, "CyU3PGpioInit failed, error code = %d\r\n", apiRetStatus);
        CyFxAppErrorHandler (apiRetStatus);
    }


    CyU3PDebugPrint( CY_FX_DEBUG_PRIORITY, "Past GPIO Init\r\n");

    //Continue normal start

    /* Start the USB functionality. */
    apiRetStatus = CyU3PUsbStart();
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "CyU3PUsbStart failed to Start, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* The fast enumeration is the easiest way to setup a USB connection,
     * where all enumeration phase is handled by the library. Only the
     * class / vendor requests need to be handled by the application. */
    CyU3PUsbRegisterSetupCallback(CyFxIsoSrcApplnUSBSetupCB, CyTrue);

    /* Setup the callback to handle the USB events. */
    CyU3PUsbRegisterEventCallback(CyFxIsoSrcApplnUSBEventCB);

    /* Register a callback to handle LPM requests from the USB 3.0 host. */
    CyU3PUsbRegisterLPMRequestCallback(CyFxIsoSrcApplnLPMRqtCB);
    
    /* Set the USB Enumeration descriptors */

    /* Super speed device descriptor. */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_DEVICE_DESCR, 0, (uint8_t *)CyFxUSB30DeviceDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB set device descriptor failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* High speed device descriptor. */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_DEVICE_DESCR, 0, (uint8_t *)CyFxUSB20DeviceDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB set device descriptor failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* BOS descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_BOS_DESCR, 0, (uint8_t *)CyFxUSBBOSDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB set configuration descriptor failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Device qualifier descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_DEVQUAL_DESCR, 0, (uint8_t *)CyFxUSBDeviceQualDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB set device qualifier descriptor failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Super speed configuration descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_CONFIG_DESCR, 0, (uint8_t *)CyFxUSBSSConfigDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB set configuration descriptor failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* High speed configuration descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_CONFIG_DESCR, 0, (uint8_t *)CyFxUSBHSConfigDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB Set Other Speed Descriptor failed, Error Code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Full speed configuration descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_FS_CONFIG_DESCR, 0, (uint8_t *)CyFxUSBFSConfigDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB Set Configuration Descriptor failed, Error Code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* String descriptor 0 */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 0, (uint8_t *)CyFxUSBStringLangIDDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB set string descriptor failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* String descriptor 1 */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 1, (uint8_t *)CyFxUSBManufactureDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB set string descriptor failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* String descriptor 2 */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 2, (uint8_t *)CyFxUSBProductDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB set string descriptor failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Connect the USB Pins with super speed operation enabled. */
    apiRetStatus = CyU3PConnectState(CyTrue, CyTrue);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyU3PDebugPrint (4, "USB Connect failed, Error code = %d\n", apiRetStatus);
        CyFxAppErrorHandler(apiRetStatus);
    }

This is my FX3 And endpoint configuration:

    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);

 

Rehash: My DMA Configuration:

    /* 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);

    CyU3PDmaMultiChannelConfig_t dmaCfg;
    memset( (void*)&dmaCfg, 0, sizeof( dmaCfg ) );
    dmaCfg.size            = MULTI_CHANNEL_XFER_SIZE;//Seems to work here and 16384, but smaller values seem to drop data, a lot.
     dmaCfg.count          = CY_FX_ISOSRC_DMA_BUF_COUNT;
     dmaCfg.prodSckId[0]   = CY_U3P_PIB_SOCKET_0;
     dmaCfg.prodSckId[1]   = CY_U3P_PIB_SOCKET_1;
     dmaCfg.validSckCount  = 2;
     dmaCfg.consSckId[0]   = 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   = 0;//CY_U3P_DMA_CB_PROD_EVENT; //CY_U3P_DMA_CB_CONS_EVENT;
     dmaCfg.cb             = 0; //DMACallback; //This never seems to be called.  Could it need CY_U3P_DMA_TYPE_AUTO_SIGNAL?
     dmaCfg.prodHeader     = 0;
     dmaCfg.prodFooter     = 0;
     dmaCfg.consHeader     = 0;
     dmaCfg.prodAvailCount = 0;
    apiRetStatus = CyU3PDmaMultiChannelCreate (&glChHandleIsoSrc, CY_U3P_DMA_TYPE_AUTO_MANY_TO_ONE, &dmaCfg);
    CyU3PGpifSocketConfigure(0,CY_U3P_PIB_SOCKET_0,1,CyTrue,1);
    CyU3PGpifSocketConfigure(1,CY_U3P_PIB_SOCKET_1,1,CyTrue,1);

My DMA Multi setup:

    apiRetStatus = CyU3PDmaMultiChannelSetXfer (&glChHandleIsoSrc, 0, 0 ); //0 = unlimited.

When the PC issues command 0xAA via a USB Control message, this code is executed:

            	CyU3PGpifSMStart (STARTRX2, ALPHA_STARTRX2);

If several hundred CYU3P_PIB_ERR_THR0_WR_OVERRUN events are received, this will be executed:

 CyU3PGpifDisable( 0 );

 Then when the USB pings again, it will reissue the SMStart.

 

Is it possible somehow the GPIF bus, and/or its threads/sockets are getting into a hosed state?  If so is there a clean way to reconfigure?

 

0 Likes
cnlohr
New Contributor II

Another observation - all of my tests had been done midway through a set of processes, but now I have more data at the beginning:

The first 5-8 ping-pongs work correctly, but then the next frame is uninitialized.  All zeroes.  Then a while later another packet is filled in.  Then over time, it seems randomly frames pilfer in.  The whole time the state machine continues to operate correctly, but something's log jamming internally.  Any suggestions on where/how I could find that out?

0 Likes
cnlohr
New Contributor II

Well, as it turns out my issue was on the PC end.  It turns out it was interpreting the first n subframes of the iso packet as containing the data, instead of going through the iso packet and finding which subframes were populated with data.  It was all on the PC side.

View solution in original post

0 Likes