/* ## Cypress USB 3.0 Platform source file (cyfxisolpauto.c) ## =========================== ## ## Copyright Cypress Semiconductor Corporation, 2010-2018, ## All Rights Reserved ## UNPUBLISHED, LICENSED SOFTWARE. ## ## CONFIDENTIAL AND PROPRIETARY INFORMATION ## WHICH IS THE PROPERTY OF CYPRESS. ## ## Use of this file is governed ## by the license agreement included in the file ## ## /license/license.txt ## ## where is the Cypress software ## installation root directory path. ## ## =========================== */ /* This file illustrates the ISO loop Application example using the DMA AUTO mode */ /* This example illustrates a loopback mechanism between two USB isochronous endpoints. The example comprises of vendor class USB enumeration descriptors with two isochronous endpoints. A ISO OUT endpoint acts as the producer of data from the host. A ISO IN endpint acts as the consumer of data to the host. The loopback is achieved with the help of a DMA AUTO channel. DMA Auto channel is created between the producer USB ISO endpoint and the consumer USB ISO endpoint. Data is transferred from the host into the producer endpoint which is then directly transferred to the consumer endpoint by the DMA engine. CPU is not involved in the data transfer. The DMA buffer size is defined based on the USB speed. 64 for full speed, 1024 for high speed and 1024 for super speed. CY_FX_ISOLP_DMA_BUF_COUNT in the header file defines the number of DMA buffers. */ #include "cyu3system.h" #include "cyu3os.h" #include "cyu3dma.h" #include "cyu3error.h" #include "cyfxisolpauto.h" #include "cyu3usb.h" #include "cyu3uart.h" uint8_t glEp0Buffer[32] __attribute__ ((aligned (32))); /* Local buffer used for vendor command handling. */ uint8_t glBenchmarkMode = 3; CyU3PThread isoLpAppThread; /* ISO loop application thread structure */ CyU3PDmaChannel glChHandleIsoLp; /* DMA Channel handle */ CyBool_t glIsApplnActive = CyFalse; /* Whether the application is active or not. */ /* Application Error Handler */ void CyFxAppErrorHandler ( CyU3PReturnStatus_t apiRetStatus /* API return status */ ) { /* Application failed with the error code apiRetStatus */ /* Add custom debug or recovery actions here */ /* Loop Indefinitely */ for (;;) { /* Thread sleep : 100 ms */ CyU3PThreadSleep (100); } } /* This function initializes the debug module. The debug prints * are routed to the UART and can be seen using a UART console * running at 115200 baud rate. */ void CyFxIsoLpApplnDebugInit (void) { CyU3PUartConfig_t uartConfig; CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; /* Initialize the UART for printing debug messages */ apiRetStatus = CyU3PUartInit(); if (apiRetStatus != CY_U3P_SUCCESS) { /* Error handling */ CyFxAppErrorHandler(apiRetStatus); } /* Set UART configuration */ CyU3PMemSet ((uint8_t *)&uartConfig, 0, sizeof (uartConfig)); uartConfig.baudRate = CY_U3P_UART_BAUDRATE_115200; uartConfig.stopBit = CY_U3P_UART_ONE_STOP_BIT; uartConfig.parity = CY_U3P_UART_NO_PARITY; uartConfig.txEnable = CyTrue; uartConfig.rxEnable = CyFalse; uartConfig.flowCtrl = CyFalse; uartConfig.isDma = CyTrue; apiRetStatus = CyU3PUartSetConfig (&uartConfig, NULL); if (apiRetStatus != CY_U3P_SUCCESS) { CyFxAppErrorHandler(apiRetStatus); } /* Set the UART transfer to a really large value. */ apiRetStatus = CyU3PUartTxSetBlockXfer (0xFFFFFFFF); if (apiRetStatus != CY_U3P_SUCCESS) { CyFxAppErrorHandler(apiRetStatus); } /* Initialize the debug module. */ apiRetStatus = CyU3PDebugInit (CY_U3P_LPP_SOCKET_UART_CONS, 8); if (apiRetStatus != CY_U3P_SUCCESS) { CyFxAppErrorHandler(apiRetStatus); } CyU3PDebugPreamble (CyFalse); } /* This function starts the ISO loop application. This is called * when a SET_CONF event is received from the USB host. The endpoints * are configured and the DMA pipe is setup in this function. */ void CyFxIsoLpApplnStart ( void) { uint16_t size = 0; CyU3PEpConfig_t epCfg; CyU3PDmaChannelConfig_t dmaCfg; CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; CyU3PUSBSpeed_t usbSpeed = CyU3PUsbGetSpeed(); /* 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; break; case CY_U3P_HIGH_SPEED: size = 1024; break; case CY_U3P_SUPER_SPEED: size = 1024; 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 = (usbSpeed == CY_U3P_FULL_SPEED) ? 1 : CY_FX_ISO_PKTS; /* Producer endpoint configuration */ apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_PRODUCER, &epCfg); if (apiRetStatus != CY_U3P_SUCCESS) { CyU3PDebugPrint (4, "CyU3PSetEpConfig failed, Error code = %d\n", apiRetStatus); CyFxAppErrorHandler (apiRetStatus); } /* Consumer endpoint configuration */ apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_CONSUMER, &epCfg); if (apiRetStatus != CY_U3P_SUCCESS) { CyU3PDebugPrint (4, "CyU3PSetEpConfig failed, Error code = %d\n", apiRetStatus); CyFxAppErrorHandler (apiRetStatus); } /* The DMA buffer size field has to be a multiple of 16. This is a * requirement of the DMA engine. So the size has to be made adjusted * to match this. (size + 0x0F) & ~0x0F will give this value. In this * case it is always going to be 1024. */ dmaCfg.size = ((size + 0x0F) & ~0x0F); /* Adjust for the mult and burst sizes. */ if (usbSpeed == CY_U3P_SUPER_SPEED) { dmaCfg.size *= (CY_FX_ISO_PKTS * CY_FX_ISO_BURST); } if (usbSpeed == CY_U3P_HIGH_SPEED) { dmaCfg.size *= CY_FX_ISO_PKTS; } dmaCfg.count = CY_FX_ISOLP_DMA_BUF_COUNT; dmaCfg.prodSckId = CY_FX_EP_PRODUCER_SOCKET; dmaCfg.consSckId = CY_FX_EP_CONSUMER_SOCKET; dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE; dmaCfg.notification = 0; dmaCfg.cb = NULL; dmaCfg.prodHeader = 0; dmaCfg.prodFooter = 0; dmaCfg.consHeader = 0; dmaCfg.prodAvailCount = 0; apiRetStatus = CyU3PDmaChannelCreate (&glChHandleIsoLp, CY_U3P_DMA_TYPE_AUTO, &dmaCfg); if (apiRetStatus != CY_U3P_SUCCESS) { CyU3PDebugPrint (4, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus); CyFxAppErrorHandler(apiRetStatus); } /* Flush the Endpoint memory */ CyU3PUsbFlushEp(CY_FX_EP_PRODUCER); CyU3PUsbFlushEp(CY_FX_EP_CONSUMER); /* Set DMA Channel transfer size */ apiRetStatus = CyU3PDmaChannelSetXfer (&glChHandleIsoLp, CY_FX_ISOLP_DMA_TX_SIZE); if (apiRetStatus != CY_U3P_SUCCESS) { CyU3PDebugPrint (4, "CyU3PDmaChannelSetXfer Failed, Error code = %d\n", apiRetStatus); CyFxAppErrorHandler(apiRetStatus); } /* Update the status flag. */ glIsApplnActive = CyTrue; CyU3PDebugPrint(8,"App Started\r\n"); } /* This function stops the ISO loop application. This shall be called whenever * a RESET or DISCONNECT event is received from the USB host. The endpoints are * disabled and the DMA pipe is destroyed by this function. */ void CyFxIsoLpApplnStop ( void) { CyU3PEpConfig_t epCfg; CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; /* Update the flag. */ glIsApplnActive = CyFalse; /* Flush the endpoint memory */ CyU3PUsbFlushEp(CY_FX_EP_PRODUCER); CyU3PUsbFlushEp(CY_FX_EP_CONSUMER); /* Destroy the channel */ CyU3PDmaChannelDestroy (&glChHandleIsoLp); /* Disable endpoints. */ CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg)); epCfg.enable = CyFalse; /* Producer endpoint configuration. */ apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_PRODUCER, &epCfg); if (apiRetStatus != CY_U3P_SUCCESS) { CyU3PDebugPrint (4, "CyU3PSetEpConfig failed, Error code = %d\n", apiRetStatus); CyFxAppErrorHandler (apiRetStatus); } /* Consumer endpoint configuration. */ apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_CONSUMER, &epCfg); if (apiRetStatus != CY_U3P_SUCCESS) { CyU3PDebugPrint (4, "CyU3PSetEpConfig failed, Error code = %d\n", apiRetStatus); CyFxAppErrorHandler (apiRetStatus); } CyU3PDebugPrint(8,"App Stopped\r\n"); } /* Callback to handle the USB setup requests. */ CyBool_t CyFxIsoLpApplnUSBSetupCB ( uint32_t setupdat0, /* SETUP Data 0 */ uint32_t setupdat1 /* SETUP Data 1 */ ) { /* Fast enumeration is used. Only requests addressed to the interface, class, * vendor and interface/endpoint control requests are received by this function. * This application does not support any class or vendor requests. */ uint8_t bRequest, bReqType; uint8_t bType, bTarget; uint16_t wValue; CyBool_t isHandled = CyFalse; /* Decode the fields from the setup request. */ bReqType = (setupdat0 & CY_U3P_USB_REQUEST_TYPE_MASK); bType = (bReqType & CY_U3P_USB_TYPE_MASK); bTarget = (bReqType & CY_U3P_USB_TARGET_MASK); bRequest = ((setupdat0 & CY_U3P_USB_REQUEST_MASK) >> CY_U3P_USB_REQUEST_POS); wValue = ((setupdat0 & CY_U3P_USB_VALUE_MASK) >> CY_U3P_USB_VALUE_POS); if (bType == CY_U3P_USB_STANDARD_RQT) { /* Handle SET_FEATURE(FUNCTION_SUSPEND) and CLEAR_FEATURE(FUNCTION_SUSPEND) * requests here. It should be allowed to pass if the device is in configured * state and failed otherwise. */ if ((bTarget == CY_U3P_USB_TARGET_INTF) && ((bRequest == CY_U3P_USB_SC_SET_FEATURE) || (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE)) && (wValue == 0)) { if (glIsApplnActive) CyU3PUsbAckSetup (); else CyU3PUsbStall (0, CyTrue, CyFalse); isHandled = CyTrue; } } if (bType == CY_U3P_USB_VENDOR_RQT) { // Benchmark set/get test if (bRequest == 0x0E || bRequest == 0x0F) { // only support the loop mode if (bRequest == 0x0E && ((wValue & 0xFF)!=3)) { CyU3PUsbStall (0, CyTrue, CyFalse); isHandled = CyTrue; } else { glEp0Buffer[0] = 3; CyU3PUsbSendEP0Data(1, glEp0Buffer); isHandled = CyTrue; } } } return isHandled; } /* This is the callback function to handle the USB events. */ void CyFxIsoLpApplnUSBEventCB ( CyU3PUsbEventType_t evtype, /* Event type */ uint16_t evdata /* Event data */ ) { switch (evtype) { case CY_U3P_USB_EVENT_SETINTF: /* Stop the application before re-enabling. */ if (glIsApplnActive) { CyFxIsoLpApplnStop (); } /* If alt. setting 1 is selected, start the loop back function. */ if (evdata == 0x0001) { /* Disable the low power entry to optimize USB throughput */ CyU3PUsbLPMDisable(); CyFxIsoLpApplnStart (); } break; case CY_U3P_USB_EVENT_RESET: case CY_U3P_USB_EVENT_DISCONNECT: /* Stop the loop back function. */ if (glIsApplnActive) { CyFxIsoLpApplnStop (); } break; default: break; } } /* Callback function to handle LPM requests from the USB 3.0 host. This function is invoked by the API whenever a state change from U0 -> U1 or U0 -> U2 happens. If we return CyTrue from this function, the FX3 device is retained in the low power state. If we return CyFalse, the FX3 device immediately tries to trigger an exit back to U0. This application does not have any state in which we should not allow U1/U2 transitions; and therefore the function always return CyTrue. */ CyBool_t CyFxIsoLpApplnLPMRqtCB ( CyU3PUsbLinkPowerMode link_mode) { return CyTrue; } /* This function initializes the USB Module, sets the enumeration descriptors. * This function does not start the ISO streaming and this is done only when * SET_CONF event is received. */ void CyFxIsoLpApplnInit (void) { CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; /* 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(CyFxIsoLpApplnUSBSetupCB, CyTrue); /* Setup the callback to handle the USB events. */ CyU3PUsbRegisterEventCallback(CyFxIsoLpApplnUSBEventCB); /* Register a callback to handle LPM requests from the USB 3.0 host. */ CyU3PUsbRegisterLPMRequestCallback(CyFxIsoLpApplnLPMRqtCB); /* 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); } CyU3PDebugPrint(8,"App Initialized\r\n"); } /* Entry function for the IsoLpAppThread. */ void IsoLpAppThread_Entry ( uint32_t input) { /* Initialize the debug module */ CyFxIsoLpApplnDebugInit(); /* Initialize the ISO loop application */ CyFxIsoLpApplnInit(); for (;;) { CyU3PThreadSleep (1000); } } /* Application define function which creates the threads. */ void CyFxApplicationDefine ( void) { void *ptr = NULL; uint32_t retThrdCreate = CY_U3P_SUCCESS; /* Allocate the memory for the threads */ ptr = CyU3PMemAlloc (CY_FX_ISOLP_THREAD_STACK); /* Create the thread for the application */ retThrdCreate = CyU3PThreadCreate (&isoLpAppThread, /* ISO loop App Thread structure */ "21:ISO_loop_AUTO", /* Thread ID and Thread name */ IsoLpAppThread_Entry, /* ISO loop App Thread Entry function */ 0, /* No input parameter to thread */ ptr, /* Pointer to the allocated thread stack */ CY_FX_ISOLP_THREAD_STACK, /* ISO loop App Thread stack size */ CY_FX_ISOLP_THREAD_PRIORITY, /* ISO loop App Thread priority */ CY_FX_ISOLP_THREAD_PRIORITY, /* ISO loop App Thread priority */ CYU3P_NO_TIME_SLICE, /* No time slice for the application thread */ CYU3P_AUTO_START /* Start the Thread immediately */ ); /* Check the return code */ if (retThrdCreate != 0) { /* Thread Creation failed with the error code retThrdCreate */ /* Add custom recovery or debug actions here */ /* Application cannot continue */ /* Loop indefinitely */ while(1); } } /* * Main function */ int main (void) { CyU3PIoMatrixConfig_t io_cfg; CyU3PReturnStatus_t status = CY_U3P_SUCCESS; /* Initialize the device */ status = CyU3PDeviceInit (NULL); if (status != CY_U3P_SUCCESS) { goto handle_fatal_error; } /* Initialize the caches. Enable both Instruction and Data Caches. */ status = CyU3PDeviceCacheControl (CyTrue, CyTrue, CyTrue); if (status != CY_U3P_SUCCESS) { goto handle_fatal_error; } /* Configure the IO matrix for the device. On the FX3 DVK board, the COM port * is connected to the IO(53:56). This means that either DQ32 mode should be * selected or lppMode should be set to UART_ONLY. Here we are choosing * UART_ONLY configuration. */ io_cfg.isDQ32Bit = CyFalse; io_cfg.s0Mode = CY_U3P_SPORT_INACTIVE; io_cfg.s1Mode = CY_U3P_SPORT_INACTIVE; io_cfg.useUart = CyTrue; io_cfg.useI2C = CyFalse; io_cfg.useI2S = CyFalse; io_cfg.useSpi = CyFalse; io_cfg.lppMode = CY_U3P_IO_MATRIX_LPP_UART_ONLY; /* No GPIOs are enabled. */ io_cfg.gpioSimpleEn[0] = 0; io_cfg.gpioSimpleEn[1] = 0; io_cfg.gpioComplexEn[0] = 0; io_cfg.gpioComplexEn[1] = 0; status = CyU3PDeviceConfigureIOMatrix (&io_cfg); if (status != CY_U3P_SUCCESS) { goto handle_fatal_error; } /* This is a non returnable call for initializing the RTOS kernel */ CyU3PKernelEntry (); /* Dummy return to make the compiler happy */ return 0; handle_fatal_error: /* Cannot recover from this error. */ while (1); } /* [ ] */