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

USB superspeed peripherals Forum Discussions

Level 4
Level 4
25 sign-ins 25 replies posted 10 replies posted


I'm trying to set up an endpoint, but when I write to the endpoint, I can't read the data from my app or the control center. I'm hoping if I post the code in question, some kind soul can help me figure out what I'm doing wrong.

I've included the function that configures the endpoints and the function that writes log messages to the host machine.

The endpoint in question is 10, and it's an IN endpoint, meaning it goes from the FX3 to the host. It's the last one listed in the descriptor, which means in my list of endpoints it's also the last one. When it isn't clear what value something is, I'll look it up in the debugger and put its value in a comment so you can follow along.

int8_t configureEndpoints()
	// Wait until descriptor is parsed in another thread
	CyU3PMutexGet (&descriptorMutex, CYU3P_WAIT_FOREVER);
	CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
	CyU3PEpConfig_t epCfg;
	CyU3PDmaChannelConfig_t dmaCfg;
	CyU3PDmaType_t dmaType;
	struct ConfigurationDescriptor *config = _getCurrentConfig();
	for (uint8_t interfaceIndex = config->firstInterface;
			interfaceIndex < config->firstInterface + config->numInterfaces;
		struct InterfaceDescriptor *interface = gInterfaceDesc + interfaceIndex;
		// for each interface in a configuration
		for (uint8_t endpointIndex = interface->firstEndpoint;
				endpointIndex < interface->firstEndpoint + interface->numEndpoints; ++endpointIndex){
			struct EndpointDescriptor *endpoint = gEndpointDesc + endpointIndex;
			// for each endpoint in an interface

			// Configure the corresponding endpoint
			CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg));
			epCfg.enable   = CyTrue;
			epCfg.epType   = endpoint->type;// CY_U3P_USB_EP_INTR
			epCfg.burstLen = 1;
			epCfg.streams  = 0;
			epCfg.pcktSize = endpoint->packetSize; // 528

			apiRetStatus = CyU3PSetEpConfig(endpoint->address, &epCfg); // 0x8a
				// Should never happen
				// We got a bad endpoint number from the descriptor
				// bursts of more than 1 are only supported on certain endpoints
				// We're hardcoding this to false for now anyway, so this should never happen

			// Set up the DMA buffer for the endpoint
			uint8_t epLeadsToHost = endpoint->address & IN_Endpoint; // 0x80, but used as a boolean
			uint8_t addressNum = endpoint->address & ~IN_Endpoint; // 10
			dmaCfg.size           = endpoint->packetSize; // 528
			dmaCfg.count          = DMA_CHANNEL_SIZE / endpoint->packetSize; // 16
			if (epLeadsToHost && addressNum == 10){
				// Debug endpoint
				dmaCfg.notification = 0;
				dmaCfg.prodSckId = CY_U3P_CPU_SOCKET_PROD;
				dmaCfg.consSckId = CY_U3P_UIB_SOCKET_CONS_0 + addressNum;
			else if (epLeadsToHost) {
				// Data goes from the device to the host
				// This block isn't used for the endpoint we're talking about
			else {
				//Data goes from the host to the device
				// This block isn't used for the endpoint we're talking about either
			dmaCfg.dmaMode        = CY_U3P_DMA_MODE_BYTE;

			dmaCfg.cb             = CyFxDmaCallback; // Not used for this endpoint, but shouldn't be called because it has no notifications
			dmaCfg.prodHeader     = 0;
			dmaCfg.prodFooter     = 0;
			dmaCfg.consHeader     = 0;
			dmaCfg.prodAvailCount = 0;
			apiRetStatus = CyU3PDmaChannelCreate(&endpoint->dmaHandle, dmaType, &dmaCfg);
			switch (apiRetStatus){
				// Shouldn't happen
				// Could not allocate buffers
			if (addressNum == 10){
				debugChannel = &endpoint->dmaHandle;

			// the 0 tells the DMA not to limit the transfers.
			apiRetStatus = CyU3PDmaChannelSetXfer(&endpoint->dmaHandle, 0);
			switch (apiRetStatus){
				// we passed a null pointer, which shouldn't happen
				// our configuration was wrong, which shouldn't happen
				// no buffer was allocated, which shouldn't happen

			if (!epLeadsToHost){
				// Configure endpoint watermarks
				endpoint->dmaThreadNum = USB_ADDRESS_TO_PIB(addressNum) % 4;
				apiRetStatus = CyU3PGpifSocketConfigure(
						CY_U3P_PIB_SOCKET_0 + USB_ADDRESS_TO_PIB(addressNum),
						0, // buffer contains data if watermark is higher than 0
				if (apiRetStatus != CY_U3P_SUCCESS){

			// Flush the endpoint

			//Configure the GPIF-II socket


	CyU3PMutexPut (&descriptorMutex);
	endpointsAreEnabled = CyTrue;
	if (config->isHighSpeed){ // true
		// The configuration must be high speed. Sending an interrupt without
		// the ready pin asserted indicates that the enumeration was successful,
		// but at the wrong speed
	else {
	// report when it's finished starting up
	extern uint32_t interruptSentTicks;
	interruptSentTicks = CyU3PGetTime();
	interrupt8051(); // Does some GPIO stuff to ping another microcontroller
	breaksAllowed = CyTrue; // First message has been received from host. Who cares if we time out our connection.
	return 0;

// We have 16 bytes to work with because the smallest DMA buffer size increments are 16 bytes
CyU3PDmaChannel *debugChannel;
void debugLog(int length, unsigned char *data, char endpoint){
#ifdef DEBUG_ENDPOINT10 // is defined
	CyU3PReturnStatus_t error;
	CyU3PDmaBuffer_t buffer;
	// Get a buffer to pass in data
	error = CyU3PDmaChannelGetBuffer (
			debugChannel,                /**< Handle to the DMA channel on which to wait. */
	        &buffer,             /**< Output parameter that will be filled with data about the
	                                                     buffer that was obtained. */
	        CYU3P_NO_WAIT                     /**< Duration to wait before returning a timeout status. */
	if (error == CY_U3P_ERROR_TIMEOUT || error == CY_U3P_ERROR_MUTEX_FAILURE){ // Usually gets stuck here, failing to get the Mutex
	else if (error != CY_U3P_SUCCESS){

	// Copy data over
	int transferLength = length; // should be 8 in this example
	char wasClipped = 0;
	if (length > buffer.size - (DEBUG_HEADER_SIZE + DEBUG_FOOTER_SIZE)){ // header is 15, footer is 1, buffer size is 528
		// Shouldn't happen if my buffer sizes are right, but who knows? Better to be safe
		transferLength = buffer.size - (DEBUG_HEADER_SIZE + DEBUG_FOOTER_SIZE);
		wasClipped = 1;
	// An easy pattern to recognize so we know we have the byte order right
	buffer.buffer[0]  = 0xDE;
	buffer.buffer[1]  = 0xAD;
	buffer.buffer[2]  = 0xBE;
	buffer.buffer[3]  = 0xEF;
	// The endpoint this data is associated with, or 0xff is it's a generic log message
	buffer.buffer[4]  = endpoint; // 0 in this example
	// 1 if the message has been clipped. 0 if it has not
	buffer.buffer[5]  = wasClipped;
	// Reserved for more details later
	buffer.buffer[6]  = 0;
	buffer.buffer[7]  = 0;
	buffer.buffer[8]  = 0;
	buffer.buffer[9] = 0;
	buffer.buffer[10] = 0;
	buffer.buffer[11] = 0;
	buffer.buffer[12] = 0;
	buffer.buffer[13] = 0;
	buffer.buffer[14] = 0;
	// the rest of the data
	memcpy(buffer.buffer + DEBUG_HEADER_SIZE, data, transferLength);
	buffer.count = transferLength + DEBUG_HEADER_SIZE + DEBUG_FOOTER_SIZE;
	// checksum
	unsigned char checksum = 0;
	for (int i = 0; i < transferLength + DEBUG_HEADER_SIZE; ++i){
		checksum += buffer.buffer[i];
	buffer.buffer[transferLength + DEBUG_HEADER_SIZE] = checksum;

	error = CyU3PDmaChannelCommitBuffer (
			        debugChannel,                /**< Handle to the DMA channel to be modified. */
			        buffer.count,                         /**< Size of data in the buffer being committed. The buffer
			                                                     address is implicit and is fetched from the active descriptor
			                                                     for the channel. */
			        0                      /**< Current status (end of transfer bit) of the buffer being
			                                                     committed. The occupied bit will automatically be set by
			                                                     the API. */
	if (error != CY_U3P_SUCCESS){



As I said in the comment, at the moment it's failing to get the mutex for some reason I don't understand, but earlier today it was getting farther than that and still nothing went through to the host machine. If you can help me understand what I'm doing wrong, or point out some other things I should check, I'd greatly appreciate it.

6 Replies
250 solutions authored 750 replies posted 50 likes received


Could you remove all the Mutex related APIs from the firmware? This is because the getting and putting of Mutex for a particular API call is already taken care of in the library source file.

Also I can notice that, the first parameter of the getBuffer API is "debugChannel". Has 
"&endpoint->dmaHandle" been assigned to "debugChannel", anywhere else in your source code?

Best Regards,




There's 4 references to debugChannel in the workspace. It's declared at the top of the file these functions come from, it's assigned in the configureEndpoints function when we go through endpoint 10, and it's used only in getBuffer and commitBuffer.

I've moved some calls around so the mutex isn't necessary anymore, but it wasn't protecting the API. My descriptor is a big byte array I copied from our old project, so I have to parse it out to feed the descriptor sections into CyU3PUsbSetDesc(), and while I do that, I copy useful information from it into the structs that we iterate over in the configureEndpoints function. The configureEndpoints function happens in the Event callback when we get a setconf event, so the mutex was making sure that those structs weren't half parsed when the callback happens.

Regardless, I'm still running into the same problem after removing the mutex.



Have you confirmed if the issue is due to mutex failure itself and not timeout error?

How frequent is the error? Is it always due to the mutex failure/timeout error issue?

Could you share the firmware source code with us?

Best Regards,


The only reason I know it's a mutex failure is that it returns CY_U3P_ERROR_MUTEX_FAILURE every time I've looked at it. If a timeout can cause that too, then maybe it's a timeout.

It happens every time as far as I can tell.

I've attached the firmware source. The debugLog function is defined in usb.c, it's supposed to communicate over endpoint 10, and it gets called every 10 seconds from a timer in main.c.



You cannot call CyU3PDmaChannelGetBuffer and CyU3PDmaChannelCommitBuffer in a timer callback.  Do not call debug prints either in a timer callback.

You  can either set a global variable in the timer callback and handle that global variable in your thread or alternatively set an event and have the thread waken on the event.  In either case, the debugLog function should be called from the thread and not the callback.  When that is done, you can read the 24 bytes of data over the IN endpoint 10.

Also note that you can call CyU3PDebugPreamble(CyFalse) after CyFxBulkLpApplnDebugInit() to remove the preamble that doesn't show as ascii characters  in the debug terminal.



Ok, I got it working and it turned out that calling the debug print during a timer callback was part of the problem like frank said.

I didn't end up needing to use it as a manual endpoint after all, so for the other part, my coworker and I walked through the usbDebug sample project line by line. Ultimately, we found that we had to call CyU3PUsbFlushEp on the endpoint right before calling CyU3PDebugInit. Flushing afterwards didn't work.

Edit: I found that the debug print function didn't work for me because the data I wanted to send has 0s in it, which would be interpreted as null characters.

I also found that I may have been configuring the debug out endpoint as if it were a GPIF endpoint like the others even though it was not. I may also have had the MANUAL_IN and MANUAL_OUT mixed up. In USB terms, IN and OUT are relative to the host, but since the DMA in the FX3 isn't just for USB, manual in and out are relative to it instead.